summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorsheu@chromium.org <sheu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-09 22:01:21 +0000
committersheu@chromium.org <sheu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-09 22:01:21 +0000
commitd418203614fe5aacf0f2e03fe21644218c1e4f10 (patch)
tree86ce1fc632d7c258f677fabbfa435491afdf1083 /media
parent309ad6ae56d328c58867bed9567d2045cfa49673 (diff)
downloadchromium_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')
-rw-r--r--media/base/video_decoder_config.cc3
-rw-r--r--media/base/video_frame.cc57
-rw-r--r--media/base/video_frame.h43
-rw-r--r--media/base/video_frame_unittest.cc42
-rw-r--r--media/base/video_util_unittest.cc2
-rw-r--r--media/filters/ffmpeg_video_decoder.cc5
-rw-r--r--media/filters/ffmpeg_video_decoder_unittest.cc10
-rw-r--r--media/filters/gpu_video_decoder.cc27
-rw-r--r--media/filters/gpu_video_decoder.h5
-rw-r--r--media/filters/skcanvas_video_renderer.cc71
-rw-r--r--media/filters/skcanvas_video_renderer_unittest.cc150
-rw-r--r--media/filters/video_frame_generator.cc3
-rw-r--r--media/filters/video_renderer_base_unittest.cc3
-rw-r--r--media/tools/player_wtl/view.h25
-rw-r--r--media/tools/player_x11/gl_video_renderer.cc19
-rw-r--r--media/tools/player_x11/gl_video_renderer.h4
-rw-r--r--media/tools/player_x11/x11_video_renderer.cc47
-rw-r--r--media/tools/player_x11/x11_video_renderer.h4
-rw-r--r--media/tools/scaler_bench/scaler_bench.cc6
-rw-r--r--media/tools/shader_bench/cpu_color_painter.cc14
-rw-r--r--media/tools/shader_bench/gpu_color_painter.cc5
-rw-r--r--media/tools/shader_bench/shader_bench.cc3
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(), &timestamp, &natural_size);
+ GetBufferData(picture.bitstream_buffer_id(), &timestamp, &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);