diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-12 00:35:50 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-12 00:35:50 +0000 |
commit | 8b61723c6bcf581a2c32b77bd5647784b019e2a9 (patch) | |
tree | c309d8ea7cc5e947f5fd4bafa13f365af9cbaa29 /media | |
parent | f284f57828e03251b44e6468b133b94639199651 (diff) | |
download | chromium_src-8b61723c6bcf581a2c32b77bd5647784b019e2a9.zip chromium_src-8b61723c6bcf581a2c32b77bd5647784b019e2a9.tar.gz chromium_src-8b61723c6bcf581a2c32b77bd5647784b019e2a9.tar.bz2 |
Unit tests for FFmpegVideoDecoder using gmock.
Review URL: http://codereview.chromium.org/123030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18233 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/filters/decoder_base.h | 12 | ||||
-rw-r--r-- | media/filters/ffmpeg_video_decoder.cc | 1 | ||||
-rw-r--r-- | media/filters/ffmpeg_video_decoder_unittest.cc | 263 | ||||
-rw-r--r-- | media/media.gyp | 4 |
4 files changed, 274 insertions, 6 deletions
diff --git a/media/filters/decoder_base.h b/media/filters/decoder_base.h index 38bd387..63de905 100644 --- a/media/filters/decoder_base.h +++ b/media/filters/decoder_base.h @@ -71,15 +71,17 @@ class DecoderBase : public Decoder { return false; } } - if (OnInitialize(demuxer_stream)) { - DCHECK(!media_format_.empty()); - host()->InitializationComplete(); - return true; - } else { + + if (!OnInitialize(demuxer_stream)) { + host()->Error(PIPELINE_ERROR_DECODE); demuxer_stream_ = NULL; decode_thread_.reset(); return false; } + + DCHECK(!media_format_.empty()); + host()->InitializationComplete(); + return true; } virtual const MediaFormat& media_format() { return media_format_; } diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc index 1f44091..004e4fe 100644 --- a/media/filters/ffmpeg_video_decoder.cc +++ b/media/filters/ffmpeg_video_decoder.cc @@ -65,7 +65,6 @@ bool FFmpegVideoDecoder::OnInitialize(DemuxerStream* demuxer_stream) { if (!codec || avcodec_thread_init(codec_context_, kDecodeThreads) < 0 || avcodec_open(codec_context_, codec) < 0) { - host_->Error(media::PIPELINE_ERROR_DECODE); return false; } return true; diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc new file mode 100644 index 0000000..7cb0d7b --- /dev/null +++ b/media/filters/ffmpeg_video_decoder_unittest.cc @@ -0,0 +1,263 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <deque> + +#include "base/singleton.h" +#include "media/base/filters.h" +#include "media/base/mock_filter_host.h" +#include "media/filters/ffmpeg_common.h" +#include "media/filters/ffmpeg_interfaces.h" +#include "media/filters/ffmpeg_video_decoder.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::Return; +using ::testing::ReturnNull; + +namespace media { + +class MockDemuxerStream : public DemuxerStream, public AVStreamProvider { + public: + // DemuxerStream interface. + MOCK_METHOD0(media_format, const MediaFormat&()); + MOCK_METHOD1(Read, void(Callback1<Buffer*>::Type* read_callback)); + MOCK_METHOD1(QueryInterface, void*(const char* interface_id)); + + // AVStreamProvider interface. + MOCK_METHOD0(GetAVStream, AVStream*()); +}; + +class MockFFmpeg { + public: + MOCK_METHOD1(AVCodecFindDecoder, AVCodec*(enum CodecID id)); + MOCK_METHOD2(AVCodecOpen, int(AVCodecContext* avctx, AVCodec* codec)); + MOCK_METHOD2(AVCodecThreadInit, int(AVCodecContext* avctx, int threads)); + + // Setter/getter for the global instance of MockFFmpeg. + static void set(MockFFmpeg* instance) { + instance_ = instance; + } + + static MockFFmpeg* get() { + return instance_; + } + + private: + static MockFFmpeg* instance_; +}; + +MockFFmpeg* MockFFmpeg::instance_ = NULL; + +} // namespace media + +// FFmpeg mocks to remove dependency on having the DLLs present. +extern "C" { + +AVCodec* avcodec_find_decoder(enum CodecID id) { + return media::MockFFmpeg::get()->AVCodecFindDecoder(id); +} + +int avcodec_open(AVCodecContext* avctx, AVCodec* codec) { + return media::MockFFmpeg::get()->AVCodecOpen(avctx, codec); +} + +int avcodec_thread_init(AVCodecContext* avctx, int threads) { + return media::MockFFmpeg::get()->AVCodecThreadInit(avctx, threads); +} + +void avcodec_flush_buffers(AVCodecContext* avctx) { + NOTREACHED(); +} + +AVFrame* avcodec_alloc_frame() { + NOTREACHED(); + return NULL; +} + +int avcodec_decode_video2(AVCodecContext* avctx, AVFrame* picture, + int* got_picture_ptr, AVPacket* avpkt) { + NOTREACHED(); + return 0; +} + +void av_init_packet(AVPacket* pkt) { + NOTREACHED(); +} + +} // extern "C" + +namespace media { + +// Fixture class to facilitate writing tests. Takes care of setting up the +// FFmpeg, pipeline and filter host mocks. +class FFmpegVideoDecoderTest : public testing::Test { + protected: + static const int kWidth = 1280; + static const int kHeight = 720; + + FFmpegVideoDecoderTest() { + MediaFormat media_format; + media_format.SetAsString(MediaFormat::kMimeType, mime_type::kFFmpegVideo); + + // Create an FFmpegVideoDecoder. + factory_ = FFmpegVideoDecoder::CreateFactory(); + decoder_ = factory_->Create<VideoDecoder>(media_format); + DCHECK(decoder_); + + // Prepare a filter host, pipeline and demuxer for the video decoder. + pipeline_.reset(new MockPipeline()); + filter_host_.reset(new MockFilterHost<VideoDecoder>(pipeline_.get(), + decoder_)); + demuxer_ = new MockDemuxerStream(); + + // Initialize FFmpeg fixtures. + memset(&stream_, 0, sizeof(stream_)); + memset(&codec_context_, 0, sizeof(codec_context_)); + memset(&codec_, 0, sizeof(codec_)); + stream_.codec = &codec_context_; + codec_context_.width = kWidth; + codec_context_.height = kHeight; + + // Initialize MockFFmpeg. + MockFFmpeg::set(&mock_ffmpeg_); + } + + virtual ~FFmpegVideoDecoderTest() { + // Call Stop() to shut down internal threads. + decoder_->Stop(); + + // Reset MockFFmpeg. + MockFFmpeg::set(NULL); + } + + // Fixture members. + scoped_refptr<FilterFactory> factory_; + scoped_refptr<VideoDecoder> decoder_; + scoped_ptr<MockPipeline> pipeline_; + scoped_ptr< MockFilterHost<VideoDecoder> > filter_host_; + scoped_refptr<MockDemuxerStream> demuxer_; + + // FFmpeg fixtures. + AVStream stream_; + AVCodecContext codec_context_; + AVCodec codec_; + MockFFmpeg mock_ffmpeg_; + + private: + DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest); +}; + +TEST(FFmpegVideoDecoderFactoryTest, Create) { + // Should only accept video/x-ffmpeg mime type. + scoped_refptr<FilterFactory> factory = FFmpegVideoDecoder::CreateFactory(); + MediaFormat media_format; + media_format.SetAsString(MediaFormat::kMimeType, "foo/x-bar"); + scoped_refptr<VideoDecoder> decoder = + factory->Create<VideoDecoder>(media_format); + ASSERT_FALSE(decoder); + + // Try again with video/x-ffmpeg mime type. + media_format.Clear(); + media_format.SetAsString(MediaFormat::kMimeType, + mime_type::kFFmpegVideo); + decoder = factory->Create<VideoDecoder>(media_format); + ASSERT_TRUE(decoder); +} + +TEST_F(FFmpegVideoDecoderTest, Initialize_QueryInterfaceFails) { + // Test QueryInterface returning NULL. + EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id())) + .WillOnce(ReturnNull()); + + EXPECT_FALSE(decoder_->Initialize(demuxer_)); + EXPECT_TRUE(filter_host_->WaitForError(PIPELINE_ERROR_DECODE)); + EXPECT_FALSE(filter_host_->IsInitialized()); +} + +TEST_F(FFmpegVideoDecoderTest, Initialize_FindDecoderFails) { + // Test avcodec_find_decoder() returning NULL. + AVStreamProvider* av_stream_provider = demuxer_; + EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id())) + .WillOnce(Return(av_stream_provider)); + EXPECT_CALL(*demuxer_, GetAVStream()) + .WillOnce(Return(&stream_)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE)) + .WillOnce(ReturnNull()); + + EXPECT_FALSE(decoder_->Initialize(demuxer_)); + EXPECT_TRUE(filter_host_->WaitForError(PIPELINE_ERROR_DECODE)); + EXPECT_FALSE(filter_host_->IsInitialized()); +} + +TEST_F(FFmpegVideoDecoderTest, Initialize_InitThreadFails) { + // Test avcodec_thread_init() failing. + AVStreamProvider* av_stream_provider = demuxer_; + EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id())) + .WillOnce(Return(av_stream_provider)); + EXPECT_CALL(*demuxer_, GetAVStream()) + .WillOnce(Return(&stream_)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE)) + .WillOnce(Return(&codec_)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecThreadInit(&codec_context_, 2)) + .WillOnce(Return(-1)); + + EXPECT_FALSE(decoder_->Initialize(demuxer_)); + EXPECT_TRUE(filter_host_->WaitForError(PIPELINE_ERROR_DECODE)); + EXPECT_FALSE(filter_host_->IsInitialized()); +} + +TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) { + // Test avcodec_open() failing. + AVStreamProvider* av_stream_provider = demuxer_; + EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id())) + .WillOnce(Return(av_stream_provider)); + EXPECT_CALL(*demuxer_, GetAVStream()) + .WillOnce(Return(&stream_)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE)) + .WillOnce(Return(&codec_)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecThreadInit(&codec_context_, 2)) + .WillOnce(Return(0)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecOpen(&codec_context_, &codec_)) + .WillOnce(Return(-1)); + + EXPECT_FALSE(decoder_->Initialize(demuxer_)); + EXPECT_TRUE(filter_host_->WaitForError(PIPELINE_ERROR_DECODE)); + EXPECT_FALSE(filter_host_->IsInitialized()); +} + +TEST_F(FFmpegVideoDecoderTest, Initialize_Successful) { + // Test successful initialization. + AVStreamProvider* av_stream_provider = demuxer_; + EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id())) + .WillOnce(Return(av_stream_provider)); + EXPECT_CALL(*demuxer_, GetAVStream()) + .WillOnce(Return(&stream_)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE)) + .WillOnce(Return(&codec_)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecThreadInit(&codec_context_, 2)) + .WillOnce(Return(0)); + EXPECT_CALL(*MockFFmpeg::get(), AVCodecOpen(&codec_context_, &codec_)) + .WillOnce(Return(0)); + + EXPECT_TRUE(decoder_->Initialize(demuxer_)); + EXPECT_TRUE(filter_host_->WaitForInitialized()); + EXPECT_TRUE(filter_host_->IsInitialized()); + EXPECT_EQ(PIPELINE_OK, pipeline_->GetError()); + + // Test that the output media format is an uncompressed video surface that + // matches the dimensions specified by FFmpeg. + const MediaFormat& media_format = decoder_->media_format(); + std::string mime_type; + int width = 0; + int height = 0; + EXPECT_TRUE(media_format.GetAsString(MediaFormat::kMimeType, &mime_type)); + EXPECT_STREQ(mime_type::kUncompressedVideo, mime_type.c_str()); + EXPECT_TRUE(media_format.GetAsInteger(MediaFormat::kWidth, &width)); + EXPECT_EQ(kWidth, width); + EXPECT_TRUE(media_format.GetAsInteger(MediaFormat::kHeight, &height)); + EXPECT_EQ(kHeight, height); +} + +} // namespace media diff --git a/media/media.gyp b/media/media.gyp index 4091c45..8453038 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -141,6 +141,7 @@ 'dependencies': [ 'media', '../base/base.gyp:base', + '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', '../third_party/ffmpeg/ffmpeg.gyp:ffmpeg', ], @@ -156,6 +157,7 @@ 'base/yuv_convert_unittest.cc', 'filters/ffmpeg_demuxer_unittest.cc', 'filters/ffmpeg_glue_unittest.cc', + 'filters/ffmpeg_video_decoder_unittest.cc', 'filters/file_data_source_unittest.cc', 'filters/video_decoder_unittest.cc', 'filters/video_renderer_unittest.cc', @@ -172,12 +174,14 @@ 'sources!': [ 'filters/ffmpeg_demuxer_unittest.cc', 'filters/ffmpeg_glue_unittest.cc', + 'filters/ffmpeg_video_decoder_unittest.cc', ], }], ['OS=="mac"', { 'sources!': [ 'filters/ffmpeg_demuxer_unittest.cc', 'filters/ffmpeg_glue_unittest.cc', + 'filters/ffmpeg_video_decoder_unittest.cc', ], }], ], |