summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-12 00:35:50 +0000
committerscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-12 00:35:50 +0000
commit8b61723c6bcf581a2c32b77bd5647784b019e2a9 (patch)
treec309d8ea7cc5e947f5fd4bafa13f365af9cbaa29 /media
parentf284f57828e03251b44e6468b133b94639199651 (diff)
downloadchromium_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.h12
-rw-r--r--media/filters/ffmpeg_video_decoder.cc1
-rw-r--r--media/filters/ffmpeg_video_decoder_unittest.cc263
-rw-r--r--media/media.gyp4
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',
],
}],
],