diff options
author | sheu@chromium.org <sheu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-09 22:01:21 +0000 |
---|---|---|
committer | sheu@chromium.org <sheu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-09 22:01:21 +0000 |
commit | d418203614fe5aacf0f2e03fe21644218c1e4f10 (patch) | |
tree | 86ce1fc632d7c258f677fabbfa435491afdf1083 /media | |
parent | 309ad6ae56d328c58867bed9567d2045cfa49673 (diff) | |
download | chromium_src-d418203614fe5aacf0f2e03fe21644218c1e4f10.zip chromium_src-d418203614fe5aacf0f2e03fe21644218c1e4f10.tar.gz chromium_src-d418203614fe5aacf0f2e03fe21644218c1e4f10.tar.bz2 |
Plumb through cropped output size for VideoFrame
The video playback path needs to be able to handle cropped video frames,
e.g. for HW decoders that output to macroblock-rounded buffer sizes.
* Composite only the visible subrect from WebVideoFrame in
cc::VideoLayerImpl
* Remove some extraneous cropping logic from cc::VideoLayerImpl now that
we have exact cropping info.
* media::VideoFrame replaces "data_size_" member with "coded_size_", and
adds a "visible_rect_" gfx::Rect to indicate the sub-rect of the
entire frame that should be visible (after cropping)
* Associated changes to various decoder/capture pipelines to plumb this
through.
TEST=build, run on x86, ARM
BUG=155416,140509,chrome-os-partner:15230
Change-Id: I284bc893959db427bc9ae677aed8b07292d228ae
Review URL: https://chromiumcodereview.appspot.com/11269017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166988 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
22 files changed, 393 insertions, 155 deletions
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc index a42808fc..93f05b7 100644 --- a/media/base/video_decoder_config.cc +++ b/media/base/video_decoder_config.cc @@ -114,7 +114,8 @@ bool VideoDecoderConfig::IsValidConfig() const { return codec_ != kUnknownVideoCodec && natural_size_.width() > 0 && natural_size_.height() > 0 && - VideoFrame::IsValidConfig(format_, visible_rect().size(), natural_size_); + VideoFrame::IsValidConfig(format_, coded_size_, visible_rect_, + natural_size_); } bool VideoDecoderConfig::Matches(const VideoDecoderConfig& config) const { diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index 6303f09b..3d76410 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc @@ -19,12 +19,13 @@ namespace media { // static scoped_refptr<VideoFrame> VideoFrame::CreateFrame( VideoFrame::Format format, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp) { - DCHECK(IsValidConfig(format, data_size, natural_size)); + DCHECK(IsValidConfig(format, coded_size, visible_rect, natural_size)); scoped_refptr<VideoFrame> frame(new VideoFrame( - format, data_size, natural_size, timestamp)); + format, coded_size, visible_rect, natural_size, timestamp)); switch (format) { case VideoFrame::RGB32: frame->AllocateRGB(4u); @@ -41,30 +42,37 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrame( // static bool VideoFrame::IsValidConfig(VideoFrame::Format format, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size) { return (format != VideoFrame::INVALID && - data_size.width() > 0 && data_size.height() > 0 && - data_size.width() <= limits::kMaxDimension && - data_size.height() <= limits::kMaxDimension && - data_size.width() * data_size.height() <= limits::kMaxCanvas && - natural_size.width() > 0 && natural_size.height() > 0 && + !coded_size.IsEmpty() && + coded_size.GetArea() <= limits::kMaxCanvas && + coded_size.width() <= limits::kMaxDimension && + coded_size.height() <= limits::kMaxDimension && + !visible_rect.IsEmpty() && + visible_rect.x() >= 0 && visible_rect.y() >= 0 && + visible_rect.right() <= coded_size.width() && + visible_rect.bottom() <= coded_size.height() && + !natural_size.IsEmpty() && + natural_size.GetArea() <= limits::kMaxCanvas && natural_size.width() <= limits::kMaxDimension && - natural_size.height() <= limits::kMaxDimension && - natural_size.width() * natural_size.height() <= limits::kMaxCanvas); + natural_size.height() <= limits::kMaxDimension); } // static scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( uint32 texture_id, uint32 texture_target, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp, const ReadPixelsCB& read_pixels_cb, const base::Closure& no_longer_needed) { scoped_refptr<VideoFrame> frame( - new VideoFrame(NATIVE_TEXTURE, data_size, natural_size, timestamp)); + new VideoFrame(NATIVE_TEXTURE, coded_size, visible_rect, natural_size, + timestamp)); frame->texture_id_ = texture_id; frame->texture_target_ = texture_target; frame->read_pixels_cb_ = read_pixels_cb; @@ -81,7 +89,8 @@ void VideoFrame::ReadPixelsFromNativeTexture(void* pixels) { // static scoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() { return new VideoFrame( - VideoFrame::EMPTY, gfx::Size(), gfx::Size(), base::TimeDelta()); + VideoFrame::EMPTY, gfx::Size(), gfx::Rect(), gfx::Size(), + base::TimeDelta()); } // static @@ -89,9 +98,9 @@ scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame( const gfx::Size& size, uint8 y, uint8 u, uint8 v, base::TimeDelta timestamp) { - DCHECK(IsValidConfig(VideoFrame::YV12, size, size)); + DCHECK(IsValidConfig(VideoFrame::YV12, size, gfx::Rect(size), size)); scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( - VideoFrame::YV12, size, size, timestamp); + VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); FillYUV(frame, y, u, v); return frame; } @@ -117,9 +126,9 @@ static const int kFramePadBytes = 15; void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { // Round up to align at least at a 16-byte boundary for each row. // This is sufficient for MMX and SSE2 reads (movq/movdqa). - size_t bytes_per_row = RoundUp(data_size_.width(), + size_t bytes_per_row = RoundUp(coded_size_.width(), kFrameSizeAlignment) * bytes_per_pixel; - size_t aligned_height = RoundUp(data_size_.height(), kFrameSizeAlignment); + size_t aligned_height = RoundUp(coded_size_.height(), kFrameSizeAlignment); strides_[VideoFrame::kRGBPlane] = bytes_per_row; #if !defined(OS_ANDROID) // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery @@ -151,7 +160,7 @@ void VideoFrame::AllocateYUV() { // The *2 here is because some formats (e.g. h264) allow interlaced coding, // and then the size needs to be a multiple of two macroblocks (vertically). // See libavcodec/utils.c:avcodec_align_dimensions2(). - size_t y_height = RoundUp(data_size_.height(), kFrameSizeAlignment * 2); + size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2); size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height; size_t y_bytes = y_height * y_stride; size_t uv_bytes = uv_height * uv_stride; @@ -178,11 +187,13 @@ void VideoFrame::AllocateYUV() { } VideoFrame::VideoFrame(VideoFrame::Format format, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp) : format_(format), - data_size_(data_size), + coded_size_(coded_size), + visible_rect_(visible_rect), natural_size_(natural_size), texture_id_(0), texture_target_(0), @@ -238,7 +249,7 @@ int VideoFrame::stride(size_t plane) const { int VideoFrame::row_bytes(size_t plane) const { DCHECK(IsValidPlane(plane)); - int width = data_size_.width(); + int width = coded_size_.width(); switch (format_) { // 32bpp. case RGB32: @@ -262,7 +273,7 @@ int VideoFrame::row_bytes(size_t plane) const { int VideoFrame::rows(size_t plane) const { DCHECK(IsValidPlane(plane)); - int height = data_size_.height(); + int height = coded_size_.height(); switch (format_) { case RGB32: case YV16: diff --git a/media/base/video_frame.h b/media/base/video_frame.h index 0840839..effdafd 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h @@ -8,6 +8,7 @@ #include "base/callback.h" #include "base/md5.h" #include "media/base/buffers.h" +#include "ui/gfx/rect.h" #include "ui/gfx/size.h" namespace media { @@ -40,19 +41,23 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Creates a new frame in system memory with given parameters. Buffers for // the frame are allocated but not initialized. - // |data_size| is the width and height of the frame data in pixels. + // |coded_size| is the width and height of the frame data in pixels. + // |visible_rect| is the visible portion of |coded_size|, after cropping (if + // any) is applied. // |natural_size| is the width and height of the frame when the frame's aspect - // ratio is applied to |data_size|. + // ratio is applied to |visible_rect|. static scoped_refptr<VideoFrame> CreateFrame( Format format, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp); // Call prior to CreateFrame to ensure validity of frame configuration. Called // automatically by VideoDecoderConfig::IsValidConfig(). // TODO(scherkus): VideoDecoderConfig shouldn't call this method - static bool IsValidConfig(Format format, const gfx::Size& data_size, + static bool IsValidConfig(Format format, const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size); // CB to write pixels from the texture backing this frame into the @@ -61,15 +66,18 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Wraps a native texture of the given parameters with a VideoFrame. When the // frame is destroyed |no_longer_needed.Run()| will be called. - // |data_size| is the width and height of the frame data in pixels. + // |coded_size| is the width and height of the frame data in pixels. + // |visible_rect| is the visible portion of |coded_size|, after cropping (if + // any) is applied. // |natural_size| is the width and height of the frame when the frame's aspect - // ratio is applied to |size|. + // ratio is applied to |visible_rect|. // |read_pixels_cb| may be used to do (slow!) readbacks from the // texture to main memory. static scoped_refptr<VideoFrame> WrapNativeTexture( uint32 texture_id, uint32 texture_target, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp, const ReadPixelsCB& read_pixels_cb, @@ -77,7 +85,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Read pixels from the native texture backing |*this| and write // them to |*pixels| as BGRA. |pixels| must point to a buffer at - // least as large as 4*data_size().width()*data_size().height(). + // least as large as 4*visible_rect().width()*visible_rect().height(). void ReadPixelsFromNativeTexture(void* pixels); // Creates a frame with format equals to VideoFrame::EMPTY, width, height, @@ -86,7 +94,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Allocates YV12 frame based on |size|, and sets its data to the YUV(y,u,v). static scoped_refptr<VideoFrame> CreateColorFrame( - const gfx::Size& data_size, + const gfx::Size& size, uint8 y, uint8 u, uint8 v, base::TimeDelta timestamp); @@ -96,7 +104,8 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { Format format() const { return format_; } - const gfx::Size& data_size() const { return data_size_; } + const gfx::Size& coded_size() const { return coded_size_; } + const gfx::Rect& visible_rect() const { return visible_rect_; } const gfx::Size& natural_size() const { return natural_size_; } int stride(size_t plane) const; @@ -104,7 +113,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Returns the number of bytes per row and number of rows for a given plane. // // As opposed to stride(), row_bytes() refers to the bytes representing - // visible pixels. + // frame data scanlines (coded_size.width() pixels, without stride padding). int row_bytes(size_t plane) const; int rows(size_t plane) const; @@ -137,7 +146,8 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { friend class base::RefCountedThreadSafe<VideoFrame>; // Clients must use the static CreateFrame() method to create a new frame. VideoFrame(Format format, - const gfx::Size& size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp); virtual ~VideoFrame(); @@ -153,10 +163,13 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { Format format_; // Width and height of the video frame. - gfx::Size data_size_; + gfx::Size coded_size_; - // Width and height of the video frame with aspect ratio taken - // into account. + // Width, height, and offsets of the visible portion of the video frame. + gfx::Rect visible_rect_; + + // Width and height of the visible portion of the video frame with aspect + // ratio taken into account. gfx::Size natural_size_; // Array of strides for each plane, typically greater or equal to the width diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc index ebbf92b..18cc1d3 100644 --- a/media/base/video_frame_unittest.cc +++ b/media/base/video_frame_unittest.cc @@ -20,19 +20,19 @@ using base::MD5DigestToBase16; // frame will be black, if 1 then the entire frame will be white. void InitializeYV12Frame(VideoFrame* frame, double white_to_black) { EXPECT_EQ(VideoFrame::YV12, frame->format()); - int first_black_row = static_cast<int>(frame->data_size().height() * + int first_black_row = static_cast<int>(frame->coded_size().height() * white_to_black); uint8* y_plane = frame->data(VideoFrame::kYPlane); - for (int row = 0; row < frame->data_size().height(); ++row) { + for (int row = 0; row < frame->coded_size().height(); ++row) { int color = (row < first_black_row) ? 0xFF : 0x00; - memset(y_plane, color, frame->data_size().width()); + memset(y_plane, color, frame->stride(VideoFrame::kYPlane)); y_plane += frame->stride(VideoFrame::kYPlane); } uint8* u_plane = frame->data(VideoFrame::kUPlane); uint8* v_plane = frame->data(VideoFrame::kVPlane); - for (int row = 0; row < frame->data_size().height(); row += 2) { - memset(u_plane, 0x80, frame->data_size().width() / 2); - memset(v_plane, 0x80, frame->data_size().width() / 2); + for (int row = 0; row < frame->coded_size().height(); row += 2) { + memset(u_plane, 0x80, frame->stride(VideoFrame::kUPlane)); + memset(v_plane, 0x80, frame->stride(VideoFrame::kVPlane)); u_plane += frame->stride(VideoFrame::kUPlane); v_plane += frame->stride(VideoFrame::kVPlane); } @@ -47,29 +47,32 @@ void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) { scoped_refptr<media::VideoFrame> rgb_frame; rgb_frame = media::VideoFrame::CreateFrame(VideoFrame::RGB32, - yv12_frame->data_size(), + yv12_frame->coded_size(), + yv12_frame->visible_rect(), yv12_frame->natural_size(), yv12_frame->GetTimestamp()); - ASSERT_EQ(yv12_frame->data_size().width(), rgb_frame->data_size().width()); - ASSERT_EQ(yv12_frame->data_size().height(), rgb_frame->data_size().height()); + ASSERT_EQ(yv12_frame->coded_size().width(), + rgb_frame->coded_size().width()); + ASSERT_EQ(yv12_frame->coded_size().height(), + rgb_frame->coded_size().height()); media::ConvertYUVToRGB32(yv12_frame->data(VideoFrame::kYPlane), yv12_frame->data(VideoFrame::kUPlane), yv12_frame->data(VideoFrame::kVPlane), rgb_frame->data(VideoFrame::kRGBPlane), - rgb_frame->data_size().width(), - rgb_frame->data_size().height(), + rgb_frame->coded_size().width(), + rgb_frame->coded_size().height(), yv12_frame->stride(VideoFrame::kYPlane), yv12_frame->stride(VideoFrame::kUPlane), rgb_frame->stride(VideoFrame::kRGBPlane), media::YV12); - for (int row = 0; row < rgb_frame->data_size().height(); ++row) { + for (int row = 0; row < rgb_frame->coded_size().height(); ++row) { uint32* rgb_row_data = reinterpret_cast<uint32*>( rgb_frame->data(VideoFrame::kRGBPlane) + (rgb_frame->stride(VideoFrame::kRGBPlane) * row)); - for (int col = 0; col < rgb_frame->data_size().width(); ++col) { + for (int col = 0; col < rgb_frame->coded_size().width(); ++col) { SCOPED_TRACE( base::StringPrintf("Checking (%d, %d)", row, col)); EXPECT_EQ(expect_rgb_color, rgb_row_data[col]); @@ -89,7 +92,7 @@ void ExpectFrameExtents(VideoFrame::Format format, int planes, gfx::Size size(kWidth, kHeight); scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( - format, size, size, kTimestamp); + format, size, gfx::Rect(size), size, kTimestamp); ASSERT_TRUE(frame); for(int plane = 0; plane < planes; plane++) { @@ -124,7 +127,8 @@ TEST(VideoFrame, CreateFrame) { // Create a YV12 Video Frame. gfx::Size size(kWidth, kHeight); scoped_refptr<media::VideoFrame> frame = - VideoFrame::CreateFrame(media::VideoFrame::YV12, size, size, kTimestamp); + VideoFrame::CreateFrame(media::VideoFrame::YV12, size, gfx::Rect(size), + size, kTimestamp); ASSERT_TRUE(frame); // Test VideoFrame implementation. @@ -171,19 +175,19 @@ TEST(VideoFrame, CreateBlackFrame) { // Test |frame| properties. EXPECT_EQ(VideoFrame::YV12, frame->format()); - EXPECT_EQ(kWidth, frame->data_size().width()); - EXPECT_EQ(kHeight, frame->data_size().height()); + EXPECT_EQ(kWidth, frame->coded_size().width()); + EXPECT_EQ(kHeight, frame->coded_size().height()); // Test frames themselves. uint8* y_plane = frame->data(VideoFrame::kYPlane); - for (int y = 0; y < frame->data_size().height(); ++y) { + for (int y = 0; y < frame->coded_size().height(); ++y) { EXPECT_EQ(0, memcmp(kExpectedYRow, y_plane, arraysize(kExpectedYRow))); y_plane += frame->stride(VideoFrame::kYPlane); } uint8* u_plane = frame->data(VideoFrame::kUPlane); uint8* v_plane = frame->data(VideoFrame::kVPlane); - for (int y = 0; y < frame->data_size().height() / 2; ++y) { + for (int y = 0; y < frame->coded_size().height() / 2; ++y) { EXPECT_EQ(0, memcmp(kExpectedUVRow, u_plane, arraysize(kExpectedUVRow))); EXPECT_EQ(0, memcmp(kExpectedUVRow, v_plane, arraysize(kExpectedUVRow))); u_plane += frame->stride(VideoFrame::kUPlane); diff --git a/media/base/video_util_unittest.cc b/media/base/video_util_unittest.cc index 326907d..d4f2e29 100644 --- a/media/base/video_util_unittest.cc +++ b/media/base/video_util_unittest.cc @@ -39,7 +39,7 @@ class VideoUtilTest : public testing::Test { void CreateDestinationFrame(int width, int height) { gfx::Size size(width, height); destination_frame_ = - VideoFrame::CreateFrame(VideoFrame::YV12, size, size, + VideoFrame::CreateFrame(VideoFrame::YV12, size, gfx::Rect(size), size, base::TimeDelta()); } diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc index aaf7bd7..d75782f 100644 --- a/media/filters/ffmpeg_video_decoder.cc +++ b/media/filters/ffmpeg_video_decoder.cc @@ -91,11 +91,12 @@ int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context, natural_size = demuxer_stream_->video_decoder_config().natural_size(); } - if (!VideoFrame::IsValidConfig(format, size, natural_size)) + if (!VideoFrame::IsValidConfig(format, size, gfx::Rect(size), natural_size)) return AVERROR(EINVAL); scoped_refptr<VideoFrame> video_frame = - VideoFrame::CreateFrame(format, size, natural_size, kNoTimestamp()); + VideoFrame::CreateFrame(format, size, gfx::Rect(size), natural_size, + kNoTimestamp()); for (int i = 0; i < 3; i++) { frame->base[i] = video_frame->data(i); diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc index 9d9c24d..52e02d2 100644 --- a/media/filters/ffmpeg_video_decoder_unittest.cc +++ b/media/filters/ffmpeg_video_decoder_unittest.cc @@ -218,10 +218,12 @@ class FFmpegVideoDecoderTest : public testing::Test { EXPECT_EQ(VideoDecoder::kOk, status_b); ASSERT_TRUE(video_frame_a); ASSERT_TRUE(video_frame_b); - EXPECT_EQ(original_size.width(), video_frame_a->data_size().width()); - EXPECT_EQ(original_size.height(), video_frame_a->data_size().height()); - EXPECT_EQ(expected_width, video_frame_b->data_size().width()); - EXPECT_EQ(expected_height, video_frame_b->data_size().height()); + EXPECT_EQ(original_size.width(), + video_frame_a->visible_rect().size().width()); + EXPECT_EQ(original_size.height(), + video_frame_a->visible_rect().size().height()); + EXPECT_EQ(expected_width, video_frame_b->visible_rect().size().width()); + EXPECT_EQ(expected_height, video_frame_b->visible_rect().size().height()); } void Read(VideoDecoder::Status* status, diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index 092e127..d59364b 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc @@ -42,8 +42,9 @@ GpuVideoDecoder::BufferPair::BufferPair( GpuVideoDecoder::BufferPair::~BufferPair() {} GpuVideoDecoder::BufferData::BufferData( - int32 bbid, base::TimeDelta ts, const gfx::Size& ns) - : bitstream_buffer_id(bbid), timestamp(ts), natural_size(ns) { + int32 bbid, base::TimeDelta ts, const gfx::Rect& vr, const gfx::Size& ns) + : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr), + natural_size(ns) { } GpuVideoDecoder::BufferData::~BufferData() {} @@ -325,6 +326,7 @@ void GpuVideoDecoder::RecordBufferData( const BitstreamBuffer& bitstream_buffer, const Buffer& buffer) { input_buffer_data_.push_front(BufferData( bitstream_buffer.id(), buffer.GetTimestamp(), + demuxer_stream_->video_decoder_config().visible_rect(), demuxer_stream_->video_decoder_config().natural_size())); // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but // that's too small for some pathological B-frame test videos. The cost of @@ -337,6 +339,7 @@ void GpuVideoDecoder::RecordBufferData( } void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp, + gfx::Rect* visible_rect, gfx::Size* natural_size) { for (std::list<BufferData>::const_iterator it = input_buffer_data_.begin(); it != input_buffer_data_.end(); @@ -344,6 +347,7 @@ void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp, if (it->bitstream_buffer_id != id) continue; *timestamp = it->timestamp; + *visible_rect = it->visible_rect; *natural_size = it->natural_size; return; } @@ -425,16 +429,19 @@ void GpuVideoDecoder::PictureReady(const media::Picture& picture) { // Update frame's timestamp. base::TimeDelta timestamp; + gfx::Rect visible_rect; gfx::Size natural_size; - GetBufferData(picture.bitstream_buffer_id(), ×tamp, &natural_size); + GetBufferData(picture.bitstream_buffer_id(), ×tamp, &visible_rect, + &natural_size); DCHECK(decoder_texture_target_); - scoped_refptr<VideoFrame> frame(VideoFrame::WrapNativeTexture( - pb.texture_id(), decoder_texture_target_, pb.size(), natural_size, - timestamp, - base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(), - decoder_texture_target_, pb.size()), - base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this, - picture.picture_buffer_id()))); + scoped_refptr<VideoFrame> frame( + VideoFrame::WrapNativeTexture( + pb.texture_id(), decoder_texture_target_, pb.size(), visible_rect, + natural_size, timestamp, + base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(), + decoder_texture_target_, pb.size()), + base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this, + picture.picture_buffer_id()))); EnqueueFrameAndTriggerFrameDelivery(frame); } diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h index 745505f..da3248c 100644 --- a/media/filters/gpu_video_decoder.h +++ b/media/filters/gpu_video_decoder.h @@ -127,7 +127,7 @@ class MEDIA_EXPORT GpuVideoDecoder void RecordBufferData( const BitstreamBuffer& bitstream_buffer, const Buffer& buffer); void GetBufferData(int32 id, base::TimeDelta* timetamp, - gfx::Size* natural_size); + gfx::Rect* visible_rect, gfx::Size* natural_size); // Set |vda_| and |weak_vda_| on the VDA thread (in practice the render // thread). @@ -208,11 +208,12 @@ class MEDIA_EXPORT GpuVideoDecoder uint32 decoder_texture_target_; struct BufferData { - BufferData(int32 bbid, base::TimeDelta ts, + BufferData(int32 bbid, base::TimeDelta ts, const gfx::Rect& visible_rect, const gfx::Size& natural_size); ~BufferData(); int32 bitstream_buffer_id; base::TimeDelta timestamp; + gfx::Rect visible_rect; gfx::Size natural_size; }; std::list<BufferData> input_buffer_data_; diff --git a/media/filters/skcanvas_video_renderer.cc b/media/filters/skcanvas_video_renderer.cc index bef015e..53b5b2d 100644 --- a/media/filters/skcanvas_video_renderer.cc +++ b/media/filters/skcanvas_video_renderer.cc @@ -68,9 +68,12 @@ static void FastPaint( video_frame->stride(media::VideoFrame::kVPlane)); const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); - media::YUVType yuv_type = (video_frame->format() == media::VideoFrame::YV12) ? - media::YV12 : media::YV16; - int y_shift = yuv_type; // 1 for YV12, 0 for YV16. + media::YUVType yuv_type = media::YV16; + int y_shift = 0; + if (video_frame->format() == media::VideoFrame::YV12) { + yuv_type = media::YV12; + y_shift = 1; + } // Transform the destination rectangle to local coordinates. const SkMatrix& local_matrix = canvas->getTotalMatrix(); @@ -109,27 +112,29 @@ static void FastPaint( DCHECK_NE(0, dest_rect.width()); DCHECK_NE(0, dest_rect.height()); size_t frame_clip_width = local_dest_irect.width() * - video_frame->data_size().width() / local_dest_irect_saved.width(); + video_frame->visible_rect().width() / local_dest_irect_saved.width(); size_t frame_clip_height = local_dest_irect.height() * - video_frame->data_size().height() / local_dest_irect_saved.height(); + video_frame->visible_rect().height() / local_dest_irect_saved.height(); // Project the "left" and "top" of the final destination rect to local // coordinates of the video frame, use these values to find the offsets // in the video frame to start reading. size_t frame_clip_left = + video_frame->visible_rect().x() + (local_dest_irect.fLeft - local_dest_irect_saved.fLeft) * - video_frame->data_size().width() / local_dest_irect_saved.width(); + video_frame->visible_rect().width() / local_dest_irect_saved.width(); size_t frame_clip_top = + video_frame->visible_rect().y() + (local_dest_irect.fTop - local_dest_irect_saved.fTop) * - video_frame->data_size().height() / local_dest_irect_saved.height(); + video_frame->visible_rect().height() / local_dest_irect_saved.height(); // Use the "left" and "top" of the destination rect to locate the offset // in Y, U and V planes. - size_t y_offset = video_frame->stride(media::VideoFrame::kYPlane) * - frame_clip_top + frame_clip_left; + size_t y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * + frame_clip_top) + frame_clip_left; // For format YV12, there is one U, V value per 2x2 block. - // For format YV16, there is one u, V value per 2x1 block. + // For format YV16, there is one U, V value per 2x1 block. size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * (frame_clip_top >> y_shift)) + (frame_clip_left >> 1); uint8* frame_clip_y = @@ -174,26 +179,48 @@ static void ConvertVideoFrameToBitmap( // Check if |bitmap| needs to be (re)allocated. if (bitmap->isNull() || - bitmap->width() != video_frame->data_size().width() || - bitmap->height() != video_frame->data_size().height()) { + bitmap->width() != video_frame->visible_rect().width() || + bitmap->height() != video_frame->visible_rect().height()) { bitmap->setConfig(SkBitmap::kARGB_8888_Config, - video_frame->data_size().width(), - video_frame->data_size().height()); + video_frame->visible_rect().width(), + video_frame->visible_rect().height()); bitmap->allocPixels(); bitmap->setIsVolatile(true); } bitmap->lockPixels(); if (IsEitherYV12OrYV16(video_frame->format())) { - media::YUVType yuv_type = - (video_frame->format() == media::VideoFrame::YV12) ? - media::YV12 : media::YV16; - media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane), - video_frame->data(media::VideoFrame::kUPlane), - video_frame->data(media::VideoFrame::kVPlane), + media::YUVType yuv_type = media::YV16; + int y_shift = 0; + if (video_frame->format() == media::VideoFrame::YV12) { + yuv_type = media::YV12; + y_shift = 1; + } + + // Use the "left" and "top" of the destination rect to locate the offset + // in Y, U and V planes. + size_t y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * + video_frame->visible_rect().y()) + + video_frame->visible_rect().x(); + + // For format YV12, there is one U, V value per 2x2 block. + // For format YV16, there is one U, V value per 2x1 block. + size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * + (video_frame->visible_rect().y() >> y_shift)) + + (video_frame->visible_rect().x() >> 1); + uint8* frame_clip_y = + video_frame->data(media::VideoFrame::kYPlane) + y_offset; + uint8* frame_clip_u = + video_frame->data(media::VideoFrame::kUPlane) + uv_offset; + uint8* frame_clip_v = + video_frame->data(media::VideoFrame::kVPlane) + uv_offset; + + media::ConvertYUVToRGB32(frame_clip_y, + frame_clip_u, + frame_clip_v, static_cast<uint8*>(bitmap->getPixels()), - video_frame->data_size().width(), - video_frame->data_size().height(), + video_frame->visible_rect().width(), + video_frame->visible_rect().height(), video_frame->stride(media::VideoFrame::kYPlane), video_frame->stride(media::VideoFrame::kUPlane), bitmap->rowBytes(), diff --git a/media/filters/skcanvas_video_renderer_unittest.cc b/media/filters/skcanvas_video_renderer_unittest.cc index a7ac30c..a50f266 100644 --- a/media/filters/skcanvas_video_renderer_unittest.cc +++ b/media/filters/skcanvas_video_renderer_unittest.cc @@ -26,18 +26,24 @@ void FillCanvas(SkCanvas* canvas, SkColor color) { } // Helper for returning the color of a solid |canvas|. -SkColor GetColor(SkCanvas* canvas) { +SkColor GetColorAt(SkCanvas* canvas, int x, int y) { const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); bitmap.lockPixels(); - SkColor c = bitmap.getColor(0, 0); + SkColor c = bitmap.getColor(x, y); bitmap.unlockPixels(); return c; } +SkColor GetColor(SkCanvas* canvas) { + return GetColorAt(canvas, 0, 0); +} + class SkCanvasVideoRendererTest : public testing::Test { public: enum Color { + kNone, kRed, + kGreen, kBlue, }; @@ -55,6 +61,7 @@ class SkCanvasVideoRendererTest : public testing::Test { VideoFrame* natural_frame() { return natural_frame_; } VideoFrame* larger_frame() { return larger_frame_; } VideoFrame* smaller_frame() { return smaller_frame_; } + VideoFrame* cropped_frame() { return cropped_frame_; } // Getters for canvases that trigger the various painting paths. SkCanvas* fast_path_canvas() { return &fast_path_canvas_; } @@ -66,6 +73,7 @@ class SkCanvasVideoRendererTest : public testing::Test { scoped_refptr<VideoFrame> natural_frame_; scoped_refptr<VideoFrame> larger_frame_; scoped_refptr<VideoFrame> smaller_frame_; + scoped_refptr<VideoFrame> cropped_frame_; SkDevice fast_path_device_; SkCanvas fast_path_canvas_; @@ -81,6 +89,12 @@ SkCanvasVideoRendererTest::SkCanvasVideoRendererTest() gfx::Size(kWidth * 2, kHeight * 2))), smaller_frame_(VideoFrame::CreateBlackFrame( gfx::Size(kWidth / 2, kHeight / 2))), + cropped_frame_(VideoFrame::CreateFrame( + VideoFrame::YV12, + gfx::Size(16, 16), + gfx::Rect(6, 6, 8, 6), + gfx::Size(8, 6), + base::TimeDelta::FromMilliseconds(4))), fast_path_device_(SkBitmap::kARGB_8888_Config, kWidth, kHeight, true), fast_path_canvas_(&fast_path_device_), slow_path_device_(SkBitmap::kARGB_8888_Config, kWidth, kHeight, false), @@ -89,6 +103,86 @@ SkCanvasVideoRendererTest::SkCanvasVideoRendererTest() natural_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(1)); larger_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(2)); smaller_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(3)); + + // Make sure the cropped video frame's aspect ratio matches the output device. + // Update cropped_frame_'s crop dimensions if this is not the case. + EXPECT_EQ(cropped_frame()->natural_size().width() * kHeight, + cropped_frame()->natural_size().height() * kWidth); + + // Fill in the cropped frame's entire data with colors: + // + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // + // The visible crop of the frame (as set by its visible_rect_) has contents: + // + // Bl Bl R R R R R R + // Bl Bl R R R R R R + // G G B B B B B B + // G G B B B B B B + // G G B B B B B B + // G G B B B B B B + // + // Each color region in the cropped frame is on a 2x2 block granularity, to + // avoid sharing UV samples between regions. + + static const uint8 cropped_y_plane[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + }; + + static const uint8 cropped_u_plane[] = { + 128, 128, 128, 128, 84, 84, 84, 84, + 128, 128, 128, 128, 84, 84, 84, 84, + 128, 128, 128, 128, 84, 84, 84, 84, + 128, 128, 128, 128, 84, 84, 84, 84, + 43, 43, 43, 43, 255, 255, 255, 255, + 43, 43, 43, 43, 255, 255, 255, 255, + 43, 43, 43, 43, 255, 255, 255, 255, + 43, 43, 43, 43, 255, 255, 255, 255, + }; + static const uint8 cropped_v_plane[] = { + 128, 128, 128, 128, 255, 255, 255, 255, + 128, 128, 128, 128, 255, 255, 255, 255, + 128, 128, 128, 128, 255, 255, 255, 255, + 128, 128, 128, 128, 255, 255, 255, 255, + 21, 21, 21, 21, 107, 107, 107, 107, + 21, 21, 21, 21, 107, 107, 107, 107, + 21, 21, 21, 21, 107, 107, 107, 107, + 21, 21, 21, 21, 107, 107, 107, 107, + }; + + media::CopyYPlane(cropped_y_plane, 16, 16, cropped_frame()); + media::CopyUPlane(cropped_u_plane, 8, 8, cropped_frame()); + media::CopyVPlane(cropped_v_plane, 8, 8, cropped_frame()); } SkCanvasVideoRendererTest::~SkCanvasVideoRendererTest() {} @@ -101,9 +195,14 @@ void SkCanvasVideoRendererTest::Paint(VideoFrame* video_frame, SkCanvas* canvas, Color color) { switch (color) { + case kNone: + break; case kRed: media::FillYUV(video_frame, 76, 84, 255); break; + case kGreen: + media::FillYUV(video_frame, 149, 43, 21); + break; case kBlue: media::FillYUV(video_frame, 29, 255, 107); break; @@ -199,4 +298,51 @@ TEST_F(SkCanvasVideoRendererTest, SlowPaint_SameVideoFrame) { EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas())); } +TEST_F(SkCanvasVideoRendererTest, FastPaint_CroppedFrame) { + Paint(cropped_frame(), fast_path_canvas(), kNone); + // Check the corners. + EXPECT_EQ(SK_ColorBLACK, GetColorAt(fast_path_canvas(), 0, 0)); + EXPECT_EQ(SK_ColorRED, GetColorAt(fast_path_canvas(), kWidth - 1, 0)); + EXPECT_EQ(SK_ColorGREEN, GetColorAt(fast_path_canvas(), 0, kHeight - 1)); + EXPECT_EQ(SK_ColorBLUE, GetColorAt(fast_path_canvas(), kWidth - 1, + kHeight - 1)); + // Check the interior along the border between color regions. Note that we're + // bilinearly upscaling, so we'll need to take care to pick sample points that + // are just outside the "zone of resampling". + // TODO(sheu): commenting out two checks due to http://crbug.com/158462. +#if 0 + EXPECT_EQ(SK_ColorBLACK, GetColorAt(fast_path_canvas(), kWidth * 1 / 8 - 1, + kHeight * 1 / 6 - 1)); +#endif + EXPECT_EQ(SK_ColorRED, GetColorAt(fast_path_canvas(), kWidth * 3 / 8, + kHeight * 1 / 6 - 1)); +#if 0 + EXPECT_EQ(SK_ColorGREEN, GetColorAt(fast_path_canvas(), kWidth * 1 / 8 - 1, + kHeight * 3 / 6)); +#endif + EXPECT_EQ(SK_ColorBLUE, GetColorAt(fast_path_canvas(), kWidth * 3 / 8, + kHeight * 3 / 6)); +} + +TEST_F(SkCanvasVideoRendererTest, SlowPaint_CroppedFrame) { + Paint(cropped_frame(), slow_path_canvas(), kNone); + // Check the corners. + EXPECT_EQ(SK_ColorBLACK, GetColorAt(slow_path_canvas(), 0, 0)); + EXPECT_EQ(SK_ColorRED, GetColorAt(slow_path_canvas(), kWidth - 1, 0)); + EXPECT_EQ(SK_ColorGREEN, GetColorAt(slow_path_canvas(), 0, kHeight - 1)); + EXPECT_EQ(SK_ColorBLUE, GetColorAt(slow_path_canvas(), kWidth - 1, + kHeight - 1)); + // Check the interior along the border between color regions. Note that we're + // bilinearly upscaling, so we'll need to take care to pick sample points that + // are just outside the "zone of resampling". + EXPECT_EQ(SK_ColorBLACK, GetColorAt(slow_path_canvas(), kWidth * 1 / 8 - 1, + kHeight * 1 / 6 - 1)); + EXPECT_EQ(SK_ColorRED, GetColorAt(slow_path_canvas(), kWidth * 3 / 8, + kHeight * 1 / 6 - 1)); + EXPECT_EQ(SK_ColorGREEN, GetColorAt(slow_path_canvas(), kWidth * 1 / 8 - 1, + kHeight * 3 / 6)); + EXPECT_EQ(SK_ColorBLUE, GetColorAt(slow_path_canvas(), kWidth * 3 / 8, + kHeight * 3 / 6)); +} + } // namespace media diff --git a/media/filters/video_frame_generator.cc b/media/filters/video_frame_generator.cc index 4429c19..c72fe13 100644 --- a/media/filters/video_frame_generator.cc +++ b/media/filters/video_frame_generator.cc @@ -72,7 +72,8 @@ void VideoFrameGenerator::ReadOnDecoderThread(const ReadCB& read_cb) { // // TODO(scherkus): migrate this to proper buffer recycling. scoped_refptr<VideoFrame> video_frame = - VideoFrame::CreateFrame(VideoFrame::YV12, size_, size_, current_time_); + VideoFrame::CreateFrame(VideoFrame::YV12, size_, gfx::Rect(size_), size_, + current_time_); current_time_ += frame_duration_; // TODO(wjia): set pixel data to pre-defined patterns if it's desired to diff --git a/media/filters/video_renderer_base_unittest.cc b/media/filters/video_renderer_base_unittest.cc index b81c40d..9ce8a9c 100644 --- a/media/filters/video_renderer_base_unittest.cc +++ b/media/filters/video_renderer_base_unittest.cc @@ -287,7 +287,8 @@ class VideoRendererBaseTest : public ::testing::Test { // Creates a frame with given timestamp. scoped_refptr<VideoFrame> CreateFrame(int timestamp) { scoped_refptr<VideoFrame> frame = - VideoFrame::CreateFrame(VideoFrame::RGB32, kNaturalSize, kNaturalSize, + VideoFrame::CreateFrame(VideoFrame::RGB32, kNaturalSize, + gfx::Rect(kNaturalSize), kNaturalSize, base::TimeDelta::FromMilliseconds(timestamp)); return frame; } diff --git a/media/tools/player_wtl/view.h b/media/tools/player_wtl/view.h index b0e4737..cc34aa8 100644 --- a/media/tools/player_wtl/view.h +++ b/media/tools/player_wtl/view.h @@ -144,11 +144,12 @@ class WtlVideoWindow : public CScrollWindowImpl<WtlVideoWindow> { uint8 *movie_dib_bits = reinterpret_cast<uint8 *>(bm.bmBits) + bm.bmWidthBytes * (bm.bmHeight - 1); int dibrowbytes = -bm.bmWidthBytes; - int clipped_width = video_frame->data_size().width(); + // Not accounting for cropping presently. + int clipped_width = video_frame->coded_size().width(); if (dibwidth < clipped_width) { clipped_width = dibwidth; } - int clipped_height = video_frame->data_size().height(); + int clipped_height = video_frame->coded_size().height(); if (dibheight < clipped_height) { clipped_height = dibheight; } @@ -243,7 +244,7 @@ class WtlVideoWindow : public CScrollWindowImpl<WtlVideoWindow> { if (frame) { // Size the window the first time we get a frame. if (!last_frame_) - SetSize(frame->data_size().width(), frame->data_size().height()); + SetSize(frame->coded_size().width(), frame->coded_size().height()); base::TimeDelta frame_timestamp = frame->GetTimestamp(); if (frame != last_frame_ || frame_timestamp != last_timestamp_) { @@ -436,24 +437,24 @@ class WtlVideoWindow : public CScrollWindowImpl<WtlVideoWindow> { if (file_yuv != NULL) { fseek(file_yuv, 0, SEEK_END); const int frame_size = - video_frame->data_size().width() * video_frame->data_size().height(); - for (int y = 0; y < video_frame->data_size().height(); ++y) + video_frame->coded_size().width() * video_frame->coded_size().height(); + for (int y = 0; y < video_frame->coded_size().height(); ++y) fwrite(video_frame->data(0) + video_frame->stride(0)*y, - video_frame->data_size().width(), sizeof(uint8), file_yuv); - for (int y = 0; y < video_frame->data_size().height()/2; ++y) + video_frame->coded_size().width(), sizeof(uint8), file_yuv); + for (int y = 0; y < video_frame->coded_size().height()/2; ++y) fwrite(video_frame->data(1) + video_frame->stride(1)*y, - video_frame->data_size().width() / 2, sizeof(uint8), file_yuv); - for (int y = 0; y < video_frame->data_size().height()/2; ++y) + video_frame->coded_size().width() / 2, sizeof(uint8), file_yuv); + for (int y = 0; y < video_frame->coded_size().height()/2; ++y) fwrite(video_frame->data(2) + video_frame->stride(2)*y, - video_frame->data_size().width() / 2, sizeof(uint8), file_yuv); + video_frame->coded_size().width() / 2, sizeof(uint8), file_yuv); fclose(file_yuv); #if TESTING static int frame_dump_count = 0; char outputbuf[512]; _snprintf_s(outputbuf, sizeof(outputbuf), "yuvdump %4d %dx%d stride %d\n", - frame_dump_count, video_frame->data_size().width(), - video_frame->data_size().height(), + frame_dump_count, video_frame->coded_size().width(), + video_frame->coded_size().height(), video_frame->stride(0)); OutputDebugStringA(outputbuf); ++frame_dump_count; diff --git a/media/tools/player_x11/gl_video_renderer.cc b/media/tools/player_x11/gl_video_renderer.cc index 50abdd9..334dfad 100644 --- a/media/tools/player_x11/gl_video_renderer.cc +++ b/media/tools/player_x11/gl_video_renderer.cc @@ -121,8 +121,7 @@ GlVideoRenderer::~GlVideoRenderer() { void GlVideoRenderer::Paint(media::VideoFrame* video_frame) { if (!gl_context_) - Initialize(video_frame->data_size().width(), - video_frame->data_size().height()); + Initialize(video_frame->coded_size(), video_frame->visible_rect()); // Convert YUV frame to RGB. DCHECK(video_frame->format() == media::VideoFrame::YV12 || @@ -147,12 +146,12 @@ void GlVideoRenderer::Paint(media::VideoFrame* video_frame) { glXSwapBuffers(display_, window_); } -void GlVideoRenderer::Initialize(int width, int height) { +void GlVideoRenderer::Initialize(gfx::Size coded_size, gfx::Rect visible_rect) { CHECK(!gl_context_); LOG(INFO) << "Initializing GL Renderer..."; // Resize the window to fit that of the video. - XResizeWindow(display_, window_, width, height); + XResizeWindow(display_, window_, visible_rect.width(), visible_rect.height()); gl_context_ = InitGLContext(display_, window_); CHECK(gl_context_) << "Failed to initialize GL context"; @@ -241,8 +240,16 @@ void GlVideoRenderer::Initialize(int width, int height) { int tc_location = glGetAttribLocation(program, "in_tc"); glEnableVertexAttribArray(tc_location); - glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, - kTextureCoords); + float verts[8]; + float x0 = static_cast<float>(visible_rect.x()) / coded_size.width(); + float y0 = static_cast<float>(visible_rect.y()) / coded_size.height(); + float x1 = static_cast<float>(visible_rect.right()) / coded_size.width(); + float y1 = static_cast<float>(visible_rect.bottom()) / coded_size.height(); + verts[0] = x0; verts[1] = y0; + verts[2] = x0; verts[3] = y1; + verts[4] = x1; verts[5] = y0; + verts[6] = x1; verts[7] = y1; + glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, verts); // We are getting called on a thread. Release the context so that it can be // made current on the main thread. diff --git a/media/tools/player_x11/gl_video_renderer.h b/media/tools/player_x11/gl_video_renderer.h index 28d3ffb..b8818a1 100644 --- a/media/tools/player_x11/gl_video_renderer.h +++ b/media/tools/player_x11/gl_video_renderer.h @@ -7,6 +7,8 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" #include "ui/gl/gl_bindings.h" class MessageLoop; @@ -27,7 +29,7 @@ class GlVideoRenderer : public base::RefCountedThreadSafe<GlVideoRenderer> { private: // Initializes GL rendering for the given dimensions. - void Initialize(int width, int height); + void Initialize(gfx::Size coded_size, gfx::Rect visible_rect); Display* display_; Window window_; diff --git a/media/tools/player_x11/x11_video_renderer.cc b/media/tools/player_x11/x11_video_renderer.cc index d259d6b..43a18cd 100644 --- a/media/tools/player_x11/x11_video_renderer.cc +++ b/media/tools/player_x11/x11_video_renderer.cc @@ -84,16 +84,18 @@ X11VideoRenderer::~X11VideoRenderer() { } void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { - int width = video_frame->data_size().width(); - int height = video_frame->data_size().height(); - if (!image_) - Initialize(width, height); + Initialize(video_frame->coded_size(), video_frame->visible_rect()); + + const int coded_width = video_frame->coded_size().width(); + const int coded_height = video_frame->coded_size().height(); + const int visible_width = video_frame->visible_rect().width(); + const int visible_height = video_frame->visible_rect().height(); // Check if we need to reallocate our XImage. - if (image_->width != width || image_->height != height) { + if (image_->width != coded_width || image_->height != coded_height) { XDestroyImage(image_); - image_ = CreateImage(display_, width, height); + image_ = CreateImage(display_, coded_width, coded_height); } // Convert YUV frame to RGB. @@ -109,9 +111,7 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane), video_frame->data(media::VideoFrame::kUPlane), video_frame->data(media::VideoFrame::kVPlane), - (uint8*)image_->data, - video_frame->data_size().width(), - video_frame->data_size().height(), + (uint8*)image_->data, coded_width, coded_height, video_frame->stride(media::VideoFrame::kYPlane), video_frame->stride(media::VideoFrame::kUPlane), image_->bytes_per_line, @@ -125,8 +125,8 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { // Creates a XImage. XImage image; memset(&image, 0, sizeof(image)); - image.width = width; - image.height = height; + image.width = coded_width; + image.height = coded_height; image.depth = 32; image.bits_per_pixel = 32; image.format = ZPixmap; @@ -140,15 +140,15 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { image.data = image_->data; // Creates a pixmap and uploads from the XImage. - unsigned long pixmap = XCreatePixmap(display_, - window_, - width, - height, + unsigned long pixmap = XCreatePixmap(display_, window_, + visible_width, visible_height, 32); GC gc = XCreateGC(display_, pixmap, 0, NULL); XPutImage(display_, pixmap, gc, &image, - 0, 0, 0, 0, - width, height); + video_frame->visible_rect().x(), + video_frame->visible_rect().y(), + 0, 0, + visible_width, visible_height); XFreeGC(display_, gc); // Creates the picture representing the pixmap. @@ -158,7 +158,7 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { // Composite the picture over the picture representing the window. XRenderComposite(display_, PictOpSrc, picture, 0, picture_, 0, 0, 0, 0, 0, 0, - width, height); + visible_width, visible_height); XRenderFreePicture(display_, picture); XFreePixmap(display_, pixmap); @@ -171,18 +171,21 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { // to the window. GC gc = XCreateGC(display_, window_, 0, NULL); XPutImage(display_, window_, gc, image_, - 0, 0, 0, 0, width, height); + video_frame->visible_rect().x(), + video_frame->visible_rect().y(), + 0, 0, visible_width, visible_height); XFlush(display_); XFreeGC(display_, gc); } -void X11VideoRenderer::Initialize(int width, int height) { +void X11VideoRenderer::Initialize(gfx::Size coded_size, + gfx::Rect visible_rect) { CHECK(!image_); LOG(INFO) << "Initializing X11 Renderer..."; // Resize the window to fit that of the video. - XResizeWindow(display_, window_, width, height); - image_ = CreateImage(display_, width, height); + XResizeWindow(display_, window_, visible_rect.width(), visible_rect.height()); + image_ = CreateImage(display_, coded_size.width(), coded_size.height()); // Testing XRender support. We'll use the very basic of XRender // so if it presents it is already good enough. We don't need diff --git a/media/tools/player_x11/x11_video_renderer.h b/media/tools/player_x11/x11_video_renderer.h index b91c565..05c624c 100644 --- a/media/tools/player_x11/x11_video_renderer.h +++ b/media/tools/player_x11/x11_video_renderer.h @@ -9,6 +9,8 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" class MessageLoop; @@ -28,7 +30,7 @@ class X11VideoRenderer : public base::RefCountedThreadSafe<X11VideoRenderer> { private: // Initializes X11 rendering for the given dimensions. - void Initialize(int width, int height); + void Initialize(gfx::Size coded_size, gfx::Rect visible_rect); Display* display_; Window window_; diff --git a/media/tools/scaler_bench/scaler_bench.cc b/media/tools/scaler_bench/scaler_bench.cc index d8525d1..18c4ca1 100644 --- a/media/tools/scaler_bench/scaler_bench.cc +++ b/media/tools/scaler_bench/scaler_bench.cc @@ -122,7 +122,8 @@ static double BenchmarkFilter(media::ScaleFilter filter) { gfx::Size dest_size(dest_width, dest_height); dest_frames.push_back( - VideoFrame::CreateFrame(VideoFrame::RGB32, dest_size, dest_size, + VideoFrame::CreateFrame(VideoFrame::RGB32, dest_size, + gfx::Rect(dest_size), dest_size, TimeDelta::FromSeconds(0))); } @@ -160,7 +161,8 @@ static double BenchmarkScaleWithRect() { gfx::Size dest_size(dest_width, dest_height); dest_frames.push_back( - VideoFrame::CreateFrame(VideoFrame::RGB32, dest_size, dest_size, + VideoFrame::CreateFrame(VideoFrame::RGB32, dest_size, + gfx::Rect(dest_size), dest_size, TimeDelta::FromSeconds(0))); } diff --git a/media/tools/shader_bench/cpu_color_painter.cc b/media/tools/shader_bench/cpu_color_painter.cc index b99b803..a7cb570 100644 --- a/media/tools/shader_bench/cpu_color_painter.cc +++ b/media/tools/shader_bench/cpu_color_painter.cc @@ -67,7 +67,8 @@ void CPUColorPainter::Paint(scoped_refptr<media::VideoFrame> video_frame) { // Convert to RGB32 frame. scoped_refptr<media::VideoFrame> rgba_frame = media::VideoFrame::CreateFrame(media::VideoFrame::RGB32, - video_frame->data_size(), + video_frame->coded_size(), + video_frame->visible_rect(), video_frame->natural_size(), base::TimeDelta()); @@ -75,16 +76,19 @@ void CPUColorPainter::Paint(scoped_refptr<media::VideoFrame> video_frame) { video_frame->data(media::VideoFrame::kUPlane), video_frame->data(media::VideoFrame::kVPlane), rgba_frame->data(0), - video_frame->data_size().width(), - video_frame->data_size().height(), + video_frame->coded_size().width(), + video_frame->coded_size().height(), video_frame->stride(media::VideoFrame::kYPlane), video_frame->stride(media::VideoFrame::kUPlane), rgba_frame->stride(0), media::YV12); glBindTexture(GL_TEXTURE_2D, textures_[0]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rgba_frame->data_size().width(), - rgba_frame->data_size().height(), GL_RGBA, GL_UNSIGNED_BYTE, + // Not accounting for x/y offset presently. + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + rgba_frame->visible_rect().width(), + rgba_frame->visible_rect().height(), + GL_RGBA, GL_UNSIGNED_BYTE, rgba_frame->data(0)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); diff --git a/media/tools/shader_bench/gpu_color_painter.cc b/media/tools/shader_bench/gpu_color_painter.cc index a408de2..17155ee 100644 --- a/media/tools/shader_bench/gpu_color_painter.cc +++ b/media/tools/shader_bench/gpu_color_painter.cc @@ -104,8 +104,9 @@ void GPUColorWithLuminancePainter::Initialize(int width, int height) { void GPUColorWithLuminancePainter::Paint( scoped_refptr<media::VideoFrame> video_frame) { - int width = video_frame->data_size().width(); - int height = video_frame->data_size().height(); + // Not accounting for x/y offset presently. + int width = video_frame->visible_rect().width(); + int height = video_frame->visible_rect().height(); for (unsigned int i = 0; i < kNumYUVPlanes; ++i) { unsigned int plane_width = (i == media::VideoFrame::kYPlane) ? width : width / 2; diff --git a/media/tools/shader_bench/shader_bench.cc b/media/tools/shader_bench/shader_bench.cc index 17a45a4..897e588 100644 --- a/media/tools/shader_bench/shader_bench.cc +++ b/media/tools/shader_bench/shader_bench.cc @@ -53,7 +53,8 @@ void GetFrames(std::string file_name, gfx::Size size(width, height); for (int i = 0; i < num_frames; i++) { scoped_refptr<media::VideoFrame> video_frame = - media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size, size, + media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size, + gfx::Rect(size), size, base::TimeDelta()); long bytes_read = fread(video_frame->data(0), 1, frame_size, file_handle); |