summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-08 00:56:37 +0000
committercevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-08 00:56:37 +0000
commite8f0fdbe0968e9b331cfe998e06de356a7aedc4c (patch)
treee41387478259c4300786afd4f9623c6a20bc22bf
parent09baac99cc972d0bce4c7f5ada8f7fd10d78a49c (diff)
downloadchromium_src-e8f0fdbe0968e9b331cfe998e06de356a7aedc4c.zip
chromium_src-e8f0fdbe0968e9b331cfe998e06de356a7aedc4c.tar.gz
chromium_src-e8f0fdbe0968e9b331cfe998e06de356a7aedc4c.tar.bz2
Merge 70703 - Handle changes in video frame size.
BUG=67303 TEST=media_unittests Review URL: http://codereview.chromium.org/6034007 TBR=scherkus@chromium.org Review URL: http://codereview.chromium.org/6156002 git-svn-id: svn://svn.chromium.org/chrome/branches/597/src@70818 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/video/ffmpeg_video_decode_engine.cc20
-rw-r--r--media/video/ffmpeg_video_decode_engine_unittest.cc91
2 files changed, 78 insertions, 33 deletions
diff --git a/media/video/ffmpeg_video_decode_engine.cc b/media/video/ffmpeg_video_decode_engine.cc
index a2009f4..8c72907 100644
--- a/media/video/ffmpeg_video_decode_engine.cc
+++ b/media/video/ffmpeg_video_decode_engine.cc
@@ -127,24 +127,29 @@ void FFmpegVideoDecodeEngine::Initialize(
event_handler_->OnInitializeComplete(info);
}
-// TODO(fbarchard): Find way to remove this memcpy of the entire image.
+// TODO(scherkus): Move this function to a utility class and unit test.
static void CopyPlane(size_t plane,
scoped_refptr<VideoFrame> video_frame,
- const AVFrame* frame) {
+ const AVFrame* frame,
+ size_t source_height) {
DCHECK_EQ(video_frame->width() % 2, 0u);
const uint8* source = frame->data[plane];
const size_t source_stride = frame->linesize[plane];
uint8* dest = video_frame->data(plane);
const size_t dest_stride = video_frame->stride(plane);
+
+ // Calculate amounts to copy and clamp to minium frame dimensions.
size_t bytes_per_line = video_frame->width();
- size_t copy_lines = video_frame->height();
+ size_t copy_lines = std::min(video_frame->height(), source_height);
if (plane != VideoFrame::kYPlane) {
bytes_per_line /= 2;
if (video_frame->format() == VideoFrame::YV12) {
copy_lines = (copy_lines + 1) / 2;
}
}
- DCHECK(bytes_per_line <= source_stride && bytes_per_line <= dest_stride);
+ bytes_per_line = std::min(bytes_per_line, source_stride);
+
+ // Copy!
for (size_t i = 0; i < copy_lines; ++i) {
memcpy(dest, source, bytes_per_line);
source += source_stride;
@@ -278,9 +283,10 @@ void FFmpegVideoDecodeEngine::DecodeFrame(scoped_refptr<Buffer> buffer) {
// Copy the frame data since FFmpeg reuses internal buffers for AVFrame
// output, meaning the data is only valid until the next
// avcodec_decode_video() call.
- CopyPlane(VideoFrame::kYPlane, video_frame.get(), av_frame_.get());
- CopyPlane(VideoFrame::kUPlane, video_frame.get(), av_frame_.get());
- CopyPlane(VideoFrame::kVPlane, video_frame.get(), av_frame_.get());
+ size_t height = codec_context_->height;
+ CopyPlane(VideoFrame::kYPlane, video_frame.get(), av_frame_.get(), height);
+ CopyPlane(VideoFrame::kUPlane, video_frame.get(), av_frame_.get(), height);
+ CopyPlane(VideoFrame::kVPlane, video_frame.get(), av_frame_.get(), height);
} else {
// Get the VideoFrame from allocator which associate with av_frame_.
video_frame = allocator_->DecodeDone(codec_context_, av_frame_.get());
diff --git a/media/video/ffmpeg_video_decode_engine_unittest.cc b/media/video/ffmpeg_video_decode_engine_unittest.cc
index b9ff34f..5f8a866 100644
--- a/media/video/ffmpeg_video_decode_engine_unittest.cc
+++ b/media/video/ffmpeg_video_decode_engine_unittest.cc
@@ -24,6 +24,23 @@ static const int kWidth = 320;
static const int kHeight = 240;
static const AVRational kTimeBase = { 1, 100 };
+static void InitializeFrame(uint8_t* data, int width, AVFrame* frame) {
+ frame->data[0] = data;
+ frame->data[1] = data;
+ frame->data[2] = data;
+ frame->linesize[0] = width;
+ frame->linesize[1] = width / 2;
+ frame->linesize[2] = width / 2;
+}
+
+ACTION_P(DecodeComplete, decoder) {
+ decoder->video_frame_ = arg0;
+}
+
+ACTION_P2(DemuxComplete, engine, buffer) {
+ engine->ConsumeVideoSample(buffer);
+}
+
ACTION_P(SaveInitializeResult, engine) {
engine->info_ = arg0;
}
@@ -35,12 +52,7 @@ class FFmpegVideoDecodeEngineTest : public testing::Test,
// Setup FFmpeg structures.
frame_buffer_.reset(new uint8[kWidth * kHeight]);
memset(&yuv_frame_, 0, sizeof(yuv_frame_));
-
- // DecodeFrame will check these pointers as non-NULL value.
- yuv_frame_.data[0] = yuv_frame_.data[1] = yuv_frame_.data[2]
- = frame_buffer_.get();
- yuv_frame_.linesize[0] = kWidth;
- yuv_frame_.linesize[1] = yuv_frame_.linesize[2] = kWidth >> 1;
+ InitializeFrame(frame_buffer_.get(), kWidth, &yuv_frame_);
memset(&codec_context_, 0, sizeof(codec_context_));
codec_context_.width = kWidth;
@@ -96,6 +108,27 @@ class FFmpegVideoDecodeEngineTest : public testing::Test,
EXPECT_TRUE(info_.success);
}
+ void Decode() {
+ EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_));
+ EXPECT_CALL(mock_ffmpeg_,
+ AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame.
+ Return(0)));
+
+ EXPECT_CALL(*this, ProduceVideoSample(_))
+ .WillOnce(DemuxComplete(test_engine_.get(), buffer_));
+ EXPECT_CALL(*this, ConsumeVideoFrame(_))
+ .WillOnce(DecodeComplete(this));
+ test_engine_->ProduceVideoFrame(video_frame_);
+ }
+
+ void ChangeDimensions(int width, int height) {
+ frame_buffer_.reset(new uint8[width * height]);
+ InitializeFrame(frame_buffer_.get(), width, &yuv_frame_);
+ codec_context_.width = width;
+ codec_context_.height = height;
+ }
+
public:
MOCK_METHOD1(ConsumeVideoFrame,
void(scoped_refptr<VideoFrame> video_frame));
@@ -193,14 +226,6 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) {
EXPECT_FALSE(info_.success);
}
-ACTION_P2(DemuxComplete, engine, buffer) {
- engine->ConsumeVideoSample(buffer);
-}
-
-ACTION_P(DecodeComplete, decoder) {
- decoder->video_frame_ = arg0;
-}
-
TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) {
Initialize();
@@ -211,18 +236,8 @@ TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) {
yuv_frame_.repeat_pict = 1;
yuv_frame_.reordered_opaque = kTimestamp.InMicroseconds();
- // Expect a bunch of avcodec calls.
- EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_));
- EXPECT_CALL(mock_ffmpeg_,
- AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame.
- Return(0)));
-
- EXPECT_CALL(*this, ProduceVideoSample(_))
- .WillOnce(DemuxComplete(test_engine_.get(), buffer_));
- EXPECT_CALL(*this, ConsumeVideoFrame(_))
- .WillOnce(DecodeComplete(this));
- test_engine_->ProduceVideoFrame(video_frame_);
+ // Simulate decoding a single frame.
+ Decode();
// |video_frame_| timestamp is 0 because we set the timestamp based off
// the buffer timestamp.
@@ -272,6 +287,30 @@ TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeError) {
EXPECT_FALSE(video_frame_.get());
}
+TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) {
+ Initialize();
+ ChangeDimensions(kWidth * 2, kHeight);
+ Decode();
+}
+
+TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) {
+ Initialize();
+ ChangeDimensions(kWidth / 2, kHeight);
+ Decode();
+}
+
+TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) {
+ Initialize();
+ ChangeDimensions(kWidth, kHeight * 2);
+ Decode();
+}
+
+TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) {
+ Initialize();
+ ChangeDimensions(kWidth, kHeight / 2);
+ Decode();
+}
+
TEST_F(FFmpegVideoDecodeEngineTest, GetSurfaceFormat) {
// YV12 formats.
codec_context_.pix_fmt = PIX_FMT_YUV420P;