diff options
author | cevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-08 00:56:37 +0000 |
---|---|---|
committer | cevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-08 00:56:37 +0000 |
commit | e8f0fdbe0968e9b331cfe998e06de356a7aedc4c (patch) | |
tree | e41387478259c4300786afd4f9623c6a20bc22bf | |
parent | 09baac99cc972d0bce4c7f5ada8f7fd10d78a49c (diff) | |
download | chromium_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.cc | 20 | ||||
-rw-r--r-- | media/video/ffmpeg_video_decode_engine_unittest.cc | 91 |
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; |