diff options
author | rvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-16 18:10:42 +0000 |
---|---|---|
committer | rvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-16 18:10:42 +0000 |
commit | 92e4afc1fbcb3850b505e5caceabbbcca491974a (patch) | |
tree | 8068f2be68df618aade295db81e5be32aeb1b13f /media/video | |
parent | 3d143e9b4beec02c615bd47a6a267a0ba24992cd (diff) | |
download | chromium_src-92e4afc1fbcb3850b505e5caceabbbcca491974a.zip chromium_src-92e4afc1fbcb3850b505e5caceabbbcca491974a.tar.gz chromium_src-92e4afc1fbcb3850b505e5caceabbbcca491974a.tar.bz2 |
Revert 96974 - Remove mock_ffmpeg and update media unittests.
BUG=92429
TEST=BitstreamConverterTest.*, ChunkDemuxerTest.*, FFmpegDemuxerTest.*, FFmpegGlueTest.*, FFmpegVideoDecoderTest.*, FFmpegH264BitstreamConverterTest.*, FFmpegVideoDecodeEngineTest.*
Review URL: http://codereview.chromium.org/7587012
TBR=acolwell@chromium.org
Review URL: http://codereview.chromium.org/7658017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96977 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/video')
-rw-r--r-- | media/video/ffmpeg_video_decode_engine.cc | 20 | ||||
-rw-r--r-- | media/video/ffmpeg_video_decode_engine.h | 2 | ||||
-rw-r--r-- | media/video/ffmpeg_video_decode_engine_unittest.cc | 228 |
3 files changed, 159 insertions, 91 deletions
diff --git a/media/video/ffmpeg_video_decode_engine.cc b/media/video/ffmpeg_video_decode_engine.cc index 0958516..4af73a1 100644 --- a/media/video/ffmpeg_video_decode_engine.cc +++ b/media/video/ffmpeg_video_decode_engine.cc @@ -120,7 +120,6 @@ void FFmpegVideoDecodeEngine::Initialize( kNoTimestamp); frame_queue_available_.push_back(video_frame); } - codec_context_->thread_count = decode_threads; if (codec && avcodec_open(codec_context_, codec) >= 0 && @@ -187,6 +186,7 @@ void FFmpegVideoDecodeEngine::DecodeFrame(scoped_refptr<Buffer> buffer) { av_frame_.get(), &frame_decoded, &packet); + // Log the problem if we can't decode a video frame and exit early. if (result < 0) { LOG(ERROR) << "Error decoding a video frame with timestamp: " @@ -303,6 +303,24 @@ void FFmpegVideoDecodeEngine::ReadInput() { event_handler_->ProduceVideoSample(NULL); } +VideoFrame::Format FFmpegVideoDecodeEngine::GetSurfaceFormat() const { + // J (Motion JPEG) versions of YUV are full range 0..255. + // Regular (MPEG) YUV is 16..240. + // For now we will ignore the distinction and treat them the same. + switch (codec_context_->pix_fmt) { + case PIX_FMT_YUV420P: + case PIX_FMT_YUVJ420P: + return VideoFrame::YV12; + case PIX_FMT_YUV422P: + case PIX_FMT_YUVJ422P: + return VideoFrame::YV16; + default: + // TODO(scherkus): More formats here? + break; + } + return VideoFrame::INVALID; +} + } // namespace media // Disable refcounting for this object because this object only lives diff --git a/media/video/ffmpeg_video_decode_engine.h b/media/video/ffmpeg_video_decode_engine.h index b7d7661..32eac45 100644 --- a/media/video/ffmpeg_video_decode_engine.h +++ b/media/video/ffmpeg_video_decode_engine.h @@ -33,6 +33,8 @@ class FFmpegVideoDecodeEngine : public VideoDecodeEngine { virtual void Flush(); virtual void Seek(); + VideoFrame::Format GetSurfaceFormat() const; + private: void DecodeFrame(scoped_refptr<Buffer> buffer); void ReadInput(); diff --git a/media/video/ffmpeg_video_decode_engine_unittest.cc b/media/video/ffmpeg_video_decode_engine_unittest.cc index 665fb86..261ca45 100644 --- a/media/video/ffmpeg_video_decode_engine_unittest.cc +++ b/media/video/ffmpeg_video_decode_engine_unittest.cc @@ -5,10 +5,9 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "media/base/data_buffer.h" +#include "media/base/mock_ffmpeg.h" #include "media/base/mock_task.h" #include "media/base/pipeline.h" -#include "media/base/test_data_util.h" -#include "media/filters/ffmpeg_glue.h" #include "media/video/ffmpeg_video_decode_engine.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -22,12 +21,21 @@ using ::testing::StrictMock; namespace media { -static const size_t kWidth = 320; -static const size_t kHeight = 240; +static const int kWidth = 320; +static const int kHeight = 240; static const int kSurfaceWidth = 522; static const int kSurfaceHeight = 288; static const AVRational kFrameRate = { 100, 1 }; +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->set_video_frame(arg0); } @@ -45,12 +53,18 @@ class FFmpegVideoDecodeEngineTest public VideoDecodeEngine::EventHandler { public: FFmpegVideoDecodeEngineTest() - : config_(kCodecVP8, kWidth, kHeight, kSurfaceWidth, kSurfaceHeight, + : config_(kCodecH264, kWidth, kHeight, kSurfaceWidth, kSurfaceHeight, kFrameRate.num, kFrameRate.den, NULL, 0) { - CHECK(FFmpegGlue::GetInstance()); // Setup FFmpeg structures. frame_buffer_.reset(new uint8[kWidth * kHeight]); + memset(&yuv_frame_, 0, sizeof(yuv_frame_)); + InitializeFrame(frame_buffer_.get(), kWidth, &yuv_frame_); + + memset(&codec_context_, 0, sizeof(codec_context_)); + memset(&codec_, 0, sizeof(codec_)); + + buffer_ = new DataBuffer(1); test_engine_.reset(new FFmpegVideoDecodeEngine()); @@ -59,8 +73,6 @@ class FFmpegVideoDecodeEngineTest kHeight, kNoTimestamp, kNoTimestamp); - - ReadTestDataFile("vp8-I-frame-320x240", &i_frame_buffer_); } ~FFmpegVideoDecodeEngineTest() { @@ -68,20 +80,48 @@ class FFmpegVideoDecodeEngineTest } void Initialize() { + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) + .WillOnce(Return(&codec_context_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) + .WillOnce(Return(&codec_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) + .WillOnce(Return(&yuv_frame_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecOpen(&codec_context_, &codec_)) + .WillOnce(Return(0)); + EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) + .WillOnce(Return(0)); + EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) + .Times(1); + EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) + .Times(1); + EXPECT_CALL(*this, OnInitializeComplete(_)) .WillOnce(SaveInitializeResult(this)); test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); EXPECT_TRUE(info_.success); } - void Decode(const scoped_refptr<Buffer>& buffer) { + 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)); + .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; + } + // VideoDecodeEngine::EventHandler implementation. MOCK_METHOD2(ConsumeVideoFrame, void(scoped_refptr<VideoFrame> video_frame, @@ -110,7 +150,12 @@ class FFmpegVideoDecodeEngineTest scoped_refptr<VideoFrame> video_frame_; scoped_ptr<FFmpegVideoDecodeEngine> test_engine_; scoped_array<uint8_t> frame_buffer_; - scoped_refptr<Buffer> i_frame_buffer_; + StrictMock<MockFFmpeg> mock_ffmpeg_; + + AVFrame yuv_frame_; + AVCodecContext codec_context_; + AVCodec codec_; + scoped_refptr<DataBuffer> buffer_; private: DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecodeEngineTest); @@ -121,36 +166,61 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_Normal) { } TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) { - VideoDecoderConfig config(kUnknown, kWidth, kHeight, kSurfaceWidth, - kSurfaceHeight, kFrameRate.num, kFrameRate.den, - NULL, 0); // Test avcodec_find_decoder() returning NULL. + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) + .WillOnce(Return(&codec_context_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) + .WillOnce(ReturnNull()); + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) + .WillOnce(Return(&yuv_frame_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) + .WillOnce(Return(0)); + EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) + .Times(1); + EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) + .Times(1); + EXPECT_CALL(*this, OnInitializeComplete(_)) .WillOnce(SaveInitializeResult(this)); - test_engine_->Initialize(MessageLoop::current(), this, NULL, config); + test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); EXPECT_FALSE(info_.success); } TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) { - // Specify Theora w/o extra data so that avcodec_open() fails. - VideoDecoderConfig config(kCodecTheora, kWidth, kHeight, kSurfaceWidth, - kSurfaceHeight, kFrameRate.num, kFrameRate.den, - NULL, 0); + // Test avcodec_open() failing. + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) + .WillOnce(Return(&codec_context_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) + .WillOnce(Return(&codec_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) + .WillOnce(Return(&yuv_frame_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecOpen(&codec_context_, &codec_)) + .WillOnce(Return(-1)); + EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) + .WillOnce(Return(0)); + EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) + .Times(1); + EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) + .Times(1); + EXPECT_CALL(*this, OnInitializeComplete(_)) .WillOnce(SaveInitializeResult(this)); - test_engine_->Initialize(MessageLoop::current(), this, NULL, config); + test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); EXPECT_FALSE(info_.success); } TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) { Initialize(); - // We rely on FFmpeg for timestamp and duration reporting. - const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(0); - const base::TimeDelta kDuration = base::TimeDelta::FromMicroseconds(10000); + // We rely on FFmpeg for timestamp and duration reporting. The one tricky + // bit is calculating the duration when |repeat_pict| > 0. + const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(123); + const base::TimeDelta kDuration = base::TimeDelta::FromMicroseconds(15000); + yuv_frame_.repeat_pict = 1; + yuv_frame_.reordered_opaque = kTimestamp.InMicroseconds(); // Simulate decoding a single frame. - Decode(i_frame_buffer_); + Decode(); // |video_frame_| timestamp is 0 because we set the timestamp based off // the buffer timestamp. @@ -162,11 +232,19 @@ TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) { TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) { Initialize(); - scoped_refptr<Buffer> buffer_a = new DataBuffer(1); + // Expect a bunch of avcodec calls. + EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_)) + .Times(2); + EXPECT_CALL(mock_ffmpeg_, + AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _)) + .WillOnce(DoAll(SetArgumentPointee<2>(0), // Simulate 0 byte frame. + Return(0))) + .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame. + Return(0))); EXPECT_CALL(*this, ProduceVideoSample(_)) - .WillOnce(DemuxComplete(test_engine_.get(), buffer_a)) - .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_)); + .WillOnce(DemuxComplete(test_engine_.get(), buffer_)) + .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); EXPECT_CALL(*this, ConsumeVideoFrame(_, _)) .WillOnce(DecodeComplete(this)); test_engine_->ProduceVideoFrame(video_frame_); @@ -177,19 +255,14 @@ TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) { TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeError) { Initialize(); - scoped_refptr<DataBuffer> buffer = - new DataBuffer(i_frame_buffer_->GetDataSize()); - buffer->SetDataSize(i_frame_buffer_->GetDataSize()); - - uint8* buf = buffer->GetWritableData(); - memcpy(buf, i_frame_buffer_->GetData(), buffer->GetDataSize()); - - // Corrupt bytes by flipping bits w/ xor. - for (size_t i = 0; i < buffer->GetDataSize(); i++) - buf[i] ^= 0xA5; + // Expect a bunch of avcodec calls. + EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_)); + EXPECT_CALL(mock_ffmpeg_, + AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _)) + .WillOnce(Return(-1)); EXPECT_CALL(*this, ProduceVideoSample(_)) - .WillOnce(DemuxComplete(test_engine_.get(), buffer)); + .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); EXPECT_CALL(*this, OnError()); test_engine_->ProduceVideoFrame(video_frame_); @@ -197,71 +270,46 @@ TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeError) { TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) { Initialize(); - - // Decode a frame and verify the width. - Decode(i_frame_buffer_); - EXPECT_EQ(video_frame_->width(), kWidth); - EXPECT_EQ(video_frame_->height(), kHeight); - - // Now decode a frame with a larger width and verify the output size didn't - // change. - scoped_refptr<Buffer> buffer; - ReadTestDataFile("vp8-I-frame-640x240", &buffer); - Decode(buffer); - - EXPECT_EQ(kWidth, video_frame_->width()); - EXPECT_EQ(kHeight, video_frame_->height()); + ChangeDimensions(kWidth * 2, kHeight); + Decode(); } TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) { Initialize(); - - // Decode a frame and verify the width. - Decode(i_frame_buffer_); - EXPECT_EQ(video_frame_->width(), kWidth); - EXPECT_EQ(video_frame_->height(), kHeight); - - // Now decode a frame with a smaller width and verify the output size didn't - // change. - scoped_refptr<Buffer> buffer; - ReadTestDataFile("vp8-I-frame-160x240", &buffer); - Decode(buffer); - EXPECT_EQ(video_frame_->width(), kWidth); - EXPECT_EQ(video_frame_->height(), kHeight); + ChangeDimensions(kWidth / 2, kHeight); + Decode(); } TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) { Initialize(); - - // Decode a frame and verify the width. - Decode(i_frame_buffer_); - EXPECT_EQ(video_frame_->width(), kWidth); - EXPECT_EQ(video_frame_->height(), kHeight); - - // Now decode a frame with a larger height and verify the output - // size didn't change. - scoped_refptr<Buffer> buffer; - ReadTestDataFile("vp8-I-frame-320x480", &buffer); - Decode(buffer); - EXPECT_EQ(kWidth, video_frame_->width()); - EXPECT_EQ(kHeight, video_frame_->height()); + ChangeDimensions(kWidth, kHeight * 2); + Decode(); } TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) { Initialize(); + ChangeDimensions(kWidth, kHeight / 2); + Decode(); +} + +TEST_F(FFmpegVideoDecodeEngineTest, GetSurfaceFormat) { + Initialize(); - // Decode a frame and verify the width. - Decode(i_frame_buffer_); - EXPECT_EQ(video_frame_->width(), kWidth); - EXPECT_EQ(video_frame_->height(), kHeight); - - // Now decode a frame with a smaller height and verify the output size - // didn't change. - scoped_refptr<Buffer> buffer; - ReadTestDataFile("vp8-I-frame-320x120", &buffer); - Decode(buffer); - EXPECT_EQ(kWidth, video_frame_->width()); - EXPECT_EQ(kHeight, video_frame_->height()); + // YV12 formats. + codec_context_.pix_fmt = PIX_FMT_YUV420P; + EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); + codec_context_.pix_fmt = PIX_FMT_YUVJ420P; + EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); + + // YV16 formats. + codec_context_.pix_fmt = PIX_FMT_YUV422P; + EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat()); + codec_context_.pix_fmt = PIX_FMT_YUVJ422P; + EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat()); + + // Invalid value. + codec_context_.pix_fmt = PIX_FMT_NONE; + EXPECT_EQ(VideoFrame::INVALID, test_engine_->GetSurfaceFormat()); } } // namespace media |