summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-23 17:53:58 +0000
committeracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-23 17:53:58 +0000
commitc25c7be488ea694d9173374b985e73a5a6eed867 (patch)
tree292a92b9c69fa73fe4ec0a0db22fe7ab8ece947e
parent461da7bce5a15d2c74237f0d284923fe5f2ebd9b (diff)
downloadchromium_src-c25c7be488ea694d9173374b985e73a5a6eed867.zip
chromium_src-c25c7be488ea694d9173374b985e73a5a6eed867.tar.gz
chromium_src-c25c7be488ea694d9173374b985e73a5a6eed867.tar.bz2
Remove mock_ffmpeg and update media unittests.
BUG=92429 TEST=BitstreamConverterTest.*, ChunkDemuxerTest.*, FFmpegDemuxerTest.*, FFmpegGlueTest.*, FFmpegVideoDecoderTest.*, FFmpegH264BitstreamConverterTest.*, FFmpegVideoDecodeEngineTest.* Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=96974 Review URL: http://codereview.chromium.org/7587012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97886 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/base/media.h7
-rw-r--r--media/base/media_posix.cc6
-rw-r--r--media/base/media_win.cc6
-rw-r--r--media/base/mock_ffmpeg.cc224
-rw-r--r--media/base/mock_ffmpeg.h162
-rw-r--r--media/base/run_all_unittests.cc9
-rw-r--r--media/base/test_data_util.cc44
-rw-r--r--media/base/test_data_util.h35
-rw-r--r--media/base/video_decoder_config.cc2
-rw-r--r--media/base/video_decoder_config.h2
-rw-r--r--media/ffmpeg/ffmpeg_common.cc2
-rw-r--r--media/filters/bitstream_converter.h7
-rw-r--r--media/filters/bitstream_converter_unittest.cc168
-rw-r--r--media/filters/chunk_demuxer_unittest.cc100
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc685
-rw-r--r--media/filters/ffmpeg_glue.cc5
-rw-r--r--media/filters/ffmpeg_glue.h11
-rw-r--r--media/filters/ffmpeg_glue_unittest.cc36
-rw-r--r--media/filters/ffmpeg_h264_bitstream_converter_unittest.cc90
-rw-r--r--media/filters/ffmpeg_video_decoder_unittest.cc2
-rw-r--r--media/media.gyp4
-rw-r--r--media/video/ffmpeg_video_decode_engine.cc20
-rw-r--r--media/video/ffmpeg_video_decode_engine.h2
-rw-r--r--media/video/ffmpeg_video_decode_engine_unittest.cc333
24 files changed, 557 insertions, 1405 deletions
diff --git a/media/base/media.h b/media/base/media.h
index 6bbad4c..bd25cbb 100644
--- a/media/base/media.h
+++ b/media/base/media.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -25,6 +25,11 @@ namespace media {
// Returns true if everything was successfully initialized, false otherwise.
bool InitializeMediaLibrary(const FilePath& module_dir);
+// Helper function for unit tests to avoid boiler plate code everywhere. This
+// function will crash if it fails to load the media library. This ensures tests
+// fail if the media library is not available.
+void InitializeMediaLibraryForTesting();
+
// Use this if you need to check whether the media library is initialized
// for the this process, without actually trying to initialize it.
bool IsMediaLibraryInitialized();
diff --git a/media/base/media_posix.cc b/media/base/media_posix.cc
index adad88b..7be3255 100644
--- a/media/base/media_posix.cc
+++ b/media/base/media_posix.cc
@@ -92,6 +92,12 @@ bool InitializeMediaLibrary(const FilePath& module_dir) {
return g_media_library_is_initialized;
}
+void InitializeMediaLibraryForTesting() {
+ FilePath file_path;
+ CHECK(PathService::Get(base::DIR_EXE, &file_path));
+ CHECK(InitializeMediaLibrary(file_path));
+}
+
bool IsMediaLibraryInitialized() {
return g_media_library_is_initialized;
}
diff --git a/media/base/media_win.cc b/media/base/media_win.cc
index a58d977..9462c02 100644
--- a/media/base/media_win.cc
+++ b/media/base/media_win.cc
@@ -78,6 +78,12 @@ bool InitializeMediaLibrary(const FilePath& base_path) {
return g_media_library_is_initialized;
}
+void InitializeMediaLibraryForTesting() {
+ FilePath file_path;
+ CHECK(PathService::Get(base::DIR_EXE, &file_path));
+ CHECK(InitializeMediaLibrary(file_path));
+}
+
bool IsMediaLibraryInitialized() {
return g_media_library_is_initialized;
}
diff --git a/media/base/mock_ffmpeg.cc b/media/base/mock_ffmpeg.cc
deleted file mode 100644
index ebbfbf0..0000000
--- a/media/base/mock_ffmpeg.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright (c) 2011 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 "media/base/mock_ffmpeg.h"
-
-#include "base/logging.h"
-#include "media/ffmpeg/ffmpeg_common.h"
-
-using ::testing::_;
-using ::testing::AtMost;
-using ::testing::DoAll;
-using ::testing::Return;
-using ::testing::SaveArg;
-
-namespace media {
-
-MockFFmpeg* MockFFmpeg::instance_ = NULL;
-URLProtocol* MockFFmpeg::protocol_ = NULL;
-
-MockFFmpeg::MockFFmpeg()
- : outstanding_packets_(0) {
- CHECK(instance_ == NULL) << "Only a single MockFFmpeg instance can exist";
- instance_ = this;
-
- // If we haven't assigned our static copy of URLProtocol, set up expectations
- // to catch the URLProtocol registered when the singleton instance of
- // FFmpegGlue is created.
- //
- // TODO(scherkus): this feels gross and I need to think of a way to better
- // inject/mock singletons.
- if (!protocol_) {
- EXPECT_CALL(*this, AVLogSetLevel(AV_LOG_QUIET))
- .Times(AtMost(1))
- .WillOnce(Return());
- EXPECT_CALL(*this, AVCodecInit())
- .Times(AtMost(1))
- .WillOnce(Return());
- EXPECT_CALL(*this, AVRegisterProtocol2(_,_))
- .Times(AtMost(1))
- .WillOnce(DoAll(SaveArg<0>(&protocol_), Return(0)));
- EXPECT_CALL(*this, AVRegisterAll())
- .Times(AtMost(1))
- .WillOnce(Return());
- }
-}
-
-MockFFmpeg::~MockFFmpeg() {
- CHECK(!outstanding_packets_)
- << "MockFFmpeg destroyed with outstanding packets";
- CHECK(instance_);
- instance_ = NULL;
-}
-
-void MockFFmpeg::inc_outstanding_packets() {
- ++outstanding_packets_;
-}
-
-void MockFFmpeg::dec_outstanding_packets() {
- CHECK(outstanding_packets_ > 0);
- --outstanding_packets_;
-}
-
-// static
-MockFFmpeg* MockFFmpeg::get() {
- return instance_;
-}
-
-// static
-URLProtocol* MockFFmpeg::protocol() {
- return protocol_;
-}
-
-// static
-void MockFFmpeg::DestructPacket(AVPacket* packet) {
- delete [] packet->data;
- packet->data = NULL;
- packet->size = 0;
-}
-
-// FFmpeg stubs that delegate to the FFmpegMock instance.
-extern "C" {
-void avcodec_init() {
- MockFFmpeg::get()->AVCodecInit();
-}
-
-int av_register_protocol2(URLProtocol* protocol, int size) {
- return MockFFmpeg::get()->AVRegisterProtocol2(protocol, size);
-}
-
-void av_register_all() {
- MockFFmpeg::get()->AVRegisterAll();
-}
-
-int av_lockmgr_register(int (*cb)(void**, enum AVLockOp)) {
- // Here |mock| may be NULL when this function is called from ~FFmpegGlue().
- if (MockFFmpeg::get()) {
- return MockFFmpeg::get()->AVRegisterLockManager(cb);
- }
- return 0;
-}
-
-AVCodec* avcodec_find_decoder(enum CodecID id) {
- return MockFFmpeg::get()->AVCodecFindDecoder(id);
-}
-
-int avcodec_open(AVCodecContext* avctx, AVCodec* codec) {
- return MockFFmpeg::get()->AVCodecOpen(avctx, codec);
-}
-
-int avcodec_close(AVCodecContext* avctx) {
- return MockFFmpeg::get()->AVCodecClose(avctx);
-}
-
-void avcodec_flush_buffers(AVCodecContext* avctx) {
- return MockFFmpeg::get()->AVCodecFlushBuffers(avctx);
-}
-
-AVCodecContext* avcodec_alloc_context() {
- return MockFFmpeg::get()->AVCodecAllocContext();
-}
-
-AVFrame* avcodec_alloc_frame() {
- return MockFFmpeg::get()->AVCodecAllocFrame();
-}
-
-int avcodec_decode_video2(AVCodecContext* avctx, AVFrame* picture,
- int* got_picture_ptr, AVPacket* avpkt) {
- return MockFFmpeg::get()->
- AVCodecDecodeVideo2(avctx, picture, got_picture_ptr, avpkt);
-}
-
-AVBitStreamFilterContext* av_bitstream_filter_init(const char* name) {
- return MockFFmpeg::get()->AVBitstreamFilterInit(name);
-}
-
-int av_bitstream_filter_filter(AVBitStreamFilterContext* bsfc,
- AVCodecContext* avctx,
- const char* args,
- uint8_t** poutbuf,
- int* poutbuf_size,
- const uint8_t* buf,
- int buf_size,
- int keyframe) {
- return MockFFmpeg::get()->
- AVBitstreamFilterFilter(bsfc, avctx, args, poutbuf, poutbuf_size, buf,
- buf_size, keyframe);
-}
-
-void av_bitstream_filter_close(AVBitStreamFilterContext* bsf) {
- return MockFFmpeg::get()->AVBitstreamFilterClose(bsf);
-}
-
-int av_open_input_file(AVFormatContext** format, const char* filename,
- AVInputFormat* input_format, int buffer_size,
- AVFormatParameters* parameters) {
- return MockFFmpeg::get()->AVOpenInputFile(format, filename,
- input_format, buffer_size,
- parameters);
-}
-
-void av_close_input_file(AVFormatContext* format) {
- MockFFmpeg::get()->AVCloseInputFile(format);
-}
-
-int av_find_stream_info(AVFormatContext* format) {
- return MockFFmpeg::get()->AVFindStreamInfo(format);
-}
-
-int64 av_rescale_q(int64 a, AVRational bq, AVRational cq) {
- // Because this is a math function there's little point in mocking it, so we
- // implement a cheap version that's capable of overflowing.
- int64 num = bq.num * cq.den;
- int64 den = cq.num * bq.den;
-
- // Rescale a by num/den. The den / 2 is for rounding.
- return (a * num + den / 2) / den;
-}
-
-int av_read_frame(AVFormatContext* format, AVPacket* packet) {
- return MockFFmpeg::get()->AVReadFrame(format, packet);
-}
-
-int av_seek_frame(AVFormatContext *format, int stream_index, int64_t timestamp,
- int flags) {
- return MockFFmpeg::get()->AVSeekFrame(format, stream_index, timestamp,
- flags);
-}
-
-void av_init_packet(AVPacket* pkt) {
- return MockFFmpeg::get()->AVInitPacket(pkt);
-}
-
-int av_new_packet(AVPacket* packet, int size) {
- return MockFFmpeg::get()->AVNewPacket(packet, size);
-}
-
-void av_free_packet(AVPacket* packet) {
- MockFFmpeg::get()->AVFreePacket(packet);
-}
-
-void av_free(void* ptr) {
- // Freeing NULL pointers are valid, but they aren't interesting from a mock
- // perspective.
- if (ptr) {
- MockFFmpeg::get()->AVFree(ptr);
- }
-}
-
-int av_dup_packet(AVPacket* packet) {
- return MockFFmpeg::get()->AVDupPacket(packet);
-}
-
-void av_log_set_level(int level) {
- MockFFmpeg::get()->AVLogSetLevel(level);
-}
-
-void av_destruct_packet(AVPacket *pkt) {
- MockFFmpeg::get()->AVDestructPacket(pkt);
-}
-
-} // extern "C"
-
-} // namespace media
diff --git a/media/base/mock_ffmpeg.h b/media/base/mock_ffmpeg.h
deleted file mode 100644
index df5e69b4..0000000
--- a/media/base/mock_ffmpeg.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright (c) 2011 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.
-
-#ifndef MEDIA_BASE_MOCK_FFMPEG_H_
-#define MEDIA_BASE_MOCK_FFMPEG_H_
-
-// TODO(scherkus): See if we can remove ffmpeg_common from this file.
-#include "media/ffmpeg/ffmpeg_common.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace media {
-
-class MockFFmpeg {
- public:
- MockFFmpeg();
- virtual ~MockFFmpeg();
-
- // TODO(ajwong): Organize this class, and make sure that all mock entrypoints
- // are still used.
- MOCK_METHOD0(AVCodecInit, void());
- MOCK_METHOD2(AVRegisterProtocol2, int(URLProtocol* protocol, int size));
- MOCK_METHOD0(AVRegisterAll, void());
- MOCK_METHOD1(AVRegisterLockManager, int(int (*cb)(void**, enum AVLockOp)));
-
- MOCK_METHOD1(AVCodecFindDecoder, AVCodec*(enum CodecID id));
- MOCK_METHOD2(AVCodecOpen, int(AVCodecContext* avctx, AVCodec* codec));
- MOCK_METHOD1(AVCodecClose, int(AVCodecContext* avctx));
- MOCK_METHOD2(AVCodecThreadInit, int(AVCodecContext* avctx, int threads));
- MOCK_METHOD1(AVCodecFlushBuffers, void(AVCodecContext* avctx));
- MOCK_METHOD0(AVCodecAllocContext, AVCodecContext*());
- MOCK_METHOD0(AVCodecAllocFrame, AVFrame*());
- MOCK_METHOD4(AVCodecDecodeVideo2,
- int(AVCodecContext* avctx, AVFrame* picture,
- int* got_picture_ptr, AVPacket* avpkt));
- MOCK_METHOD1(AVBitstreamFilterInit,
- AVBitStreamFilterContext*(const char *name));
- MOCK_METHOD8(AVBitstreamFilterFilter,
- int(AVBitStreamFilterContext* bsfc, AVCodecContext* avctx,
- const char* args, uint8_t** poutbuf, int* poutbuf_size,
- const uint8_t* buf, int buf_size, int keyframe));
- MOCK_METHOD1(AVBitstreamFilterClose, void(AVBitStreamFilterContext* bsf));
- MOCK_METHOD1(AVDestructPacket, void(AVPacket* packet));
-
- MOCK_METHOD5(AVOpenInputFile, int(AVFormatContext** format,
- const char* filename,
- AVInputFormat* input_format,
- int buffer_size,
- AVFormatParameters* parameters));
- MOCK_METHOD1(AVCloseInputFile, void(AVFormatContext* format));
- MOCK_METHOD1(AVFindStreamInfo, int(AVFormatContext* format));
- MOCK_METHOD2(AVReadFrame, int(AVFormatContext* format, AVPacket* packet));
- MOCK_METHOD4(AVSeekFrame, int(AVFormatContext *format,
- int stream_index,
- int64_t timestamp,
- int flags));
-
- MOCK_METHOD1(AVInitPacket, void(AVPacket* pkt));
- MOCK_METHOD2(AVNewPacket, int(AVPacket* packet, int size));
- MOCK_METHOD1(AVFreePacket, void(AVPacket* packet));
- MOCK_METHOD1(AVFree, void(void* ptr));
- MOCK_METHOD1(AVDupPacket, int(AVPacket* packet));
-
- MOCK_METHOD1(AVLogSetLevel, void(int level));
-
- // Used for verifying check points during tests.
- MOCK_METHOD1(CheckPoint, void(int id));
-
- // Returns the current MockFFmpeg instance.
- static MockFFmpeg* get();
-
- // Returns the URLProtocol registered by the FFmpegGlue singleton.
- static URLProtocol* protocol();
-
- // AVPacket destructor for packets allocated by av_new_packet().
- static void DestructPacket(AVPacket* packet);
-
- // Modifies the number of outstanding packets.
- void inc_outstanding_packets();
- void dec_outstanding_packets();
-
- private:
- static MockFFmpeg* instance_;
- static URLProtocol* protocol_;
-
- // Tracks the number of packets allocated by calls to av_read_frame() and
- // av_free_packet(). We crash the unit test if this is not zero at time of
- // destruction.
- int outstanding_packets_;
-};
-
-// Used for simulating av_read_frame().
-ACTION_P3(CreatePacket, stream_index, data, size) {
- // Confirm we're dealing with AVPacket so we can safely const_cast<>.
- ::testing::StaticAssertTypeEq<AVPacket*, arg1_type>();
- memset(arg1, 0, sizeof(*arg1));
- arg1->stream_index = stream_index;
- arg1->data = const_cast<uint8*>(data);
- arg1->size = size;
-
- // Increment number of packets allocated.
- MockFFmpeg::get()->inc_outstanding_packets();
-
- return 0;
-}
-
-// Used for simulating av_read_frame().
-ACTION_P3(CreatePacketNoCount, stream_index, data, size) {
- // Confirm we're dealing with AVPacket so we can safely const_cast<>.
- ::testing::StaticAssertTypeEq<AVPacket*, arg1_type>();
- memset(arg1, 0, sizeof(*arg1));
- arg1->stream_index = stream_index;
- arg1->data = const_cast<uint8*>(data);
- arg1->size = size;
-
- return 0;
-}
-
-// Used for simulating av_read_frame().
-ACTION_P4(CreatePacketTimeNoCount, stream_index, data, size, pts) {
- // Confirm we're dealing with AVPacket so we can safely const_cast<>.
- ::testing::StaticAssertTypeEq<AVPacket*, arg1_type>();
- memset(arg1, 0, sizeof(*arg1));
- arg1->stream_index = stream_index;
- arg1->data = const_cast<uint8*>(data);
- arg1->size = size;
- arg1->pts = pts;
-
- return 0;
-}
-
-// Used for simulating av_new_packet().
-ACTION(NewPacket) {
- ::testing::StaticAssertTypeEq<AVPacket*, arg0_type>();
- int size = arg1;
- memset(arg0, 0, sizeof(*arg0));
- arg0->data = new uint8[size];
- arg0->size = size;
- arg0->destruct = &MockFFmpeg::DestructPacket;
-
- // Increment number of packets allocated.
- MockFFmpeg::get()->inc_outstanding_packets();
-
- return 0;
-}
-
-// Used for simulating av_free_packet().
-ACTION(FreePacket) {
- ::testing::StaticAssertTypeEq<AVPacket*, arg0_type>();
-
- // Call the destructor if present, such as the one assigned in NewPacket().
- if (arg0->destruct) {
- arg0->destruct(arg0);
- }
-
- // Decrement number of packets allocated.
- MockFFmpeg::get()->dec_outstanding_packets();
-}
-
-} // namespace media
-
-#endif // MEDIA_BASE_MOCK_FFMPEG_H_
diff --git a/media/base/run_all_unittests.cc b/media/base/run_all_unittests.cc
index b715a328b..a24a278 100644
--- a/media/base/run_all_unittests.cc
+++ b/media/base/run_all_unittests.cc
@@ -1,9 +1,14 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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 "base/test/test_suite.h"
+#include "media/base/media.h"
int main(int argc, char** argv) {
- return base::TestSuite(argc, argv).Run();
+ base::TestSuite suite(argc, argv);
+
+ media::InitializeMediaLibraryForTesting();
+
+ return suite.Run();
}
diff --git a/media/base/test_data_util.cc b/media/base/test_data_util.cc
new file mode 100644
index 0000000..fc30744
--- /dev/null
+++ b/media/base/test_data_util.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 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 "media/base/test_data_util.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+
+namespace media {
+
+void ReadTestDataFile(const std::string& name, scoped_array<uint8>* buffer,
+ int* size) {
+ FilePath file_path;
+ CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
+
+ file_path = file_path.Append(FILE_PATH_LITERAL("media"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .AppendASCII(name);
+
+ int64 tmp = 0;
+ CHECK(file_util::GetFileSize(file_path, &tmp))
+ << "Failed to get file size for '" << name << "'";
+
+ int file_size = static_cast<int>(tmp);
+ buffer->reset(new uint8[file_size]);
+
+ CHECK(file_size == file_util::ReadFile(file_path,
+ reinterpret_cast<char*>(buffer->get()),
+ file_size))
+ << "Failed to read '" << name << "'";
+ *size = file_size;
+}
+
+void ReadTestDataFile(const std::string& name, scoped_refptr<Buffer>* buffer) {
+ scoped_array<uint8> buf;
+ int buf_size;
+ ReadTestDataFile(name, &buf, &buf_size);
+ *buffer = new DataBuffer(buf.release(), buf_size);
+}
+
+} // namespace media
diff --git a/media/base/test_data_util.h b/media/base/test_data_util.h
new file mode 100644
index 0000000..42878ae
--- /dev/null
+++ b/media/base/test_data_util.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 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.
+
+#ifndef MEDIA_BASE_TEST_DATA_UTIL_H_
+#define MEDIA_BASE_TEST_DATA_UTIL_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "media/base/data_buffer.h"
+
+namespace media {
+
+// Reads a test file from media/test/data directory and stores it in
+// a scoped_array.
+//
+// |name| - The name of the file.
+// |buffer| - The contents of the file.
+// |size| - The size of the buffer.
+void ReadTestDataFile(const std::string& name,
+ scoped_array<uint8>* buffer,
+ int* size);
+
+// Reads a test file from media/test/data directory and stored it in
+// a Buffer.
+//
+// |name| - The name of the file.
+// |buffer| - The contents of the file.
+void ReadTestDataFile(const std::string& name, scoped_refptr<Buffer>* buffer);
+
+} // namespace media
+
+#endif // MEDIA_BASE_TEST_DATA_UTIL_H_
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc
index 5ec7c02d..0d3ae76 100644
--- a/media/base/video_decoder_config.cc
+++ b/media/base/video_decoder_config.cc
@@ -15,7 +15,7 @@ VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
int surface_height,
int frame_rate_numerator,
int frame_rate_denominator,
- uint8* extra_data,
+ const uint8* extra_data,
size_t extra_data_size)
: codec_(codec),
width_(width),
diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h
index a077312..541f437 100644
--- a/media/base/video_decoder_config.h
+++ b/media/base/video_decoder_config.h
@@ -30,7 +30,7 @@ class VideoDecoderConfig {
VideoDecoderConfig(VideoCodec codec, int width, int height,
int surface_width, int surface_height,
int frame_rate_numerator, int frame_rate_denominator,
- uint8* extra_data, size_t extra_data_size);
+ const uint8* extra_data, size_t extra_data_size);
~VideoDecoderConfig();
VideoCodec codec() const;
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 0be30ed..d03715e 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -43,6 +43,8 @@ VideoCodec CodecIDToVideoCodec(CodecID codec_id) {
CodecID VideoCodecToCodecID(VideoCodec video_codec) {
switch (video_codec) {
+ case kUnknown:
+ return CODEC_ID_NONE;
case kCodecVC1:
return CODEC_ID_VC1;
case kCodecH264:
diff --git a/media/filters/bitstream_converter.h b/media/filters/bitstream_converter.h
index a1ca3c6..7386297 100644
--- a/media/filters/bitstream_converter.h
+++ b/media/filters/bitstream_converter.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -69,11 +69,6 @@ class FFmpegBitstreamConverter : public BitstreamConverter {
virtual bool ConvertPacket(AVPacket* packet);
private:
- FRIEND_TEST_ALL_PREFIXES(BitstreamConverterTest, ConvertPacket_FailedFilter);
- FRIEND_TEST_ALL_PREFIXES(BitstreamConverterTest, ConvertPacket_Success);
- FRIEND_TEST_ALL_PREFIXES(BitstreamConverterTest,
- ConvertPacket_SuccessInPlace);
-
std::string filter_name_;
AVBitStreamFilterContext* stream_filter_;
AVCodecContext* stream_context_;
diff --git a/media/filters/bitstream_converter_unittest.cc b/media/filters/bitstream_converter_unittest.cc
index 1e84341..3330df7 100644
--- a/media/filters/bitstream_converter_unittest.cc
+++ b/media/filters/bitstream_converter_unittest.cc
@@ -4,73 +4,94 @@
#include <deque>
-#include "media/base/mock_ffmpeg.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/bitstream_converter.h"
#include "testing/gtest/include/gtest/gtest.h"
-using ::testing::DoAll;
-using ::testing::Mock;
-using ::testing::Return;
-using ::testing::ReturnNull;
-using ::testing::SetArgumentPointee;
-using ::testing::StrEq;
-using ::testing::StrictMock;
-using ::testing::_;
-
namespace media {
+static const char kTestFilterName[] = "test_filter";
+static uint8_t kFailData[] = { 3, 2, 1 };
+static uint8_t kNewBufferData[] = { 2, 1 };
+static uint8_t kInPlaceData[] = { 1 };
+static const int kFailSize = 3;
+static const int kNewBufferSize = 2;
+static const int kInPlaceSize = 1;
+
+
+// Test filter function that looks for specific input data and changes it's
+// behavior based on what is passed to |buf| & |buf_size|. The three behaviors
+// simulated are the following:
+// - Create a new output buffer. Triggered by |buf| == |kNewBufferData|.
+// - Use the existing output buffer. Triggered by |buf| == |kInPlaceData|.
+// - Signal an error. Triggered by |buf| == |kFailData|.
+static int DoFilter(AVBitStreamFilterContext* bsfc,
+ AVCodecContext* avctx,
+ const char* args,
+ uint8_t** poutbuf,
+ int* poutbuf_size,
+ const uint8_t* buf,
+ int buf_size,
+ int keyframe) {
+ if (buf_size == kNewBufferSize &&
+ !memcmp(buf, kNewBufferData, kNewBufferSize)) {
+ *poutbuf_size = buf_size + 1;
+ *poutbuf = static_cast<uint8*>(av_malloc(*poutbuf_size));
+ *poutbuf[0] = 0;
+ memcpy((*poutbuf) + 1, buf, buf_size);
+ return 0;
+ } else if (buf_size == kInPlaceSize &&
+ !memcmp(buf, kInPlaceData, kInPlaceSize)) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static void DoClose(AVBitStreamFilterContext* bsfc) {}
+
+static AVBitStreamFilter g_stream_filter = {
+ kTestFilterName,
+ 0, // Private Data Size
+ DoFilter,
+ DoClose,
+ 0, // Next filter pointer.
+};
+
class BitstreamConverterTest : public testing::Test {
protected:
BitstreamConverterTest() {
memset(&test_stream_context_, 0, sizeof(test_stream_context_));
- memset(&test_filter_, 0, sizeof(test_filter_));
memset(&test_packet_, 0, sizeof(test_packet_));
- test_packet_.data = kData1;
- test_packet_.size = kTestSize1;
+ test_packet_.data = kFailData;
+ test_packet_.size = kFailSize;
+ }
+
+ virtual ~BitstreamConverterTest() {
+ av_free_packet(&test_packet_);
}
- virtual ~BitstreamConverterTest() {}
+ static void SetUpTestCase() {
+ // Register g_stream_filter if it isn't already registered.
+ if (!g_stream_filter.next)
+ av_register_bitstream_filter(&g_stream_filter);
+ }
AVCodecContext test_stream_context_;
- AVBitStreamFilterContext test_filter_;
AVPacket test_packet_;
- StrictMock<MockFFmpeg> mock_ffmpeg_;
-
- static const char kTestFilterName[];
- static uint8_t kData1[];
- static uint8_t kData2[];
- static const int kTestSize1;
- static const int kTestSize2;
-
private:
DISALLOW_COPY_AND_ASSIGN(BitstreamConverterTest);
};
-const char BitstreamConverterTest::kTestFilterName[] = "test_filter";
-uint8_t BitstreamConverterTest::kData1[] = { 1 };
-uint8_t BitstreamConverterTest::kData2[] = { 2 };
-const int BitstreamConverterTest::kTestSize1 = 1;
-const int BitstreamConverterTest::kTestSize2 = 2;
+TEST_F(BitstreamConverterTest, InitializeFailed) {
+ FFmpegBitstreamConverter converter("BAD_FILTER_NAME", &test_stream_context_);
-TEST_F(BitstreamConverterTest, Initialize) {
- FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_);
-
- // Test Initialize returns false on a bad initialization, and cleanup is not
- // done.
- EXPECT_CALL(mock_ffmpeg_, AVBitstreamFilterInit(StrEq(kTestFilterName)))
- .WillOnce(ReturnNull());
EXPECT_FALSE(converter.Initialize());
+}
- EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_ffmpeg_));
-
- // Test Initialize returns true on successful initialization, and cleanup is
- // done. The cleanup will be activated when the converter object goes out of
- // scope.
- EXPECT_CALL(mock_ffmpeg_, AVBitstreamFilterInit(StrEq(kTestFilterName)))
- .WillOnce(Return(&test_filter_));
- EXPECT_CALL(mock_ffmpeg_, AVBitstreamFilterClose(&test_filter_));
+TEST_F(BitstreamConverterTest, InitializeSuccess) {
+ FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_);
EXPECT_TRUE(converter.Initialize());
}
@@ -83,81 +104,42 @@ TEST_F(BitstreamConverterTest, ConvertPacket_NotInitialized) {
TEST_F(BitstreamConverterTest, ConvertPacket_FailedFilter) {
FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_);
- // Inject mock filter instance.
- converter.stream_filter_ = &test_filter_;
-
- // Simulate a successful filter call, that allocates a new data buffer.
- EXPECT_CALL(mock_ffmpeg_,
- AVBitstreamFilterFilter(&test_filter_, &test_stream_context_,
- NULL, _, _,
- test_packet_.data, test_packet_.size, _))
- .WillOnce(Return(AVERROR(EINVAL)));
+ EXPECT_TRUE(converter.Initialize());
EXPECT_FALSE(converter.ConvertPacket(&test_packet_));
-
- // Uninject mock filter instance to avoid cleanup code on destruction of
- // converter.
- converter.stream_filter_ = NULL;
}
TEST_F(BitstreamConverterTest, ConvertPacket_Success) {
FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_);
- // Inject mock filter instance.
- converter.stream_filter_ = &test_filter_;
+ EXPECT_TRUE(converter.Initialize());
// Ensure our packet doesn't already have a destructor.
ASSERT_TRUE(test_packet_.destruct == NULL);
- // Simulate a successful filter call, that allocates a new data buffer.
- EXPECT_CALL(mock_ffmpeg_,
- AVBitstreamFilterFilter(&test_filter_, &test_stream_context_,
- NULL, _, _,
- test_packet_.data, test_packet_.size, _))
- .WillOnce(DoAll(SetArgumentPointee<3>(&kData2[0]),
- SetArgumentPointee<4>(kTestSize2),
- Return(0)));
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(&test_packet_));
+ test_packet_.data = kNewBufferData;
+ test_packet_.size = kNewBufferSize;
EXPECT_TRUE(converter.ConvertPacket(&test_packet_));
- EXPECT_EQ(kData2, test_packet_.data);
- EXPECT_EQ(kTestSize2, test_packet_.size);
+ EXPECT_NE(kNewBufferData, test_packet_.data);
+ EXPECT_EQ(kNewBufferSize + 1, test_packet_.size);
EXPECT_TRUE(test_packet_.destruct != NULL);
-
- // Uninject mock filter instance to avoid cleanup code on destruction of
- // converter.
- converter.stream_filter_ = NULL;
}
TEST_F(BitstreamConverterTest, ConvertPacket_SuccessInPlace) {
FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_);
- // Inject mock filter instance.
- converter.stream_filter_ = &test_filter_;
+ EXPECT_TRUE(converter.Initialize());
// Ensure our packet is in a sane start state.
ASSERT_TRUE(test_packet_.destruct == NULL);
- ASSERT_EQ(kData1, test_packet_.data);
- ASSERT_EQ(kTestSize1, test_packet_.size);
-
- // Simulate a successful filter call, that reuses the input buffer. We should
- // not free the packet here or alter the packet's destructor.
- EXPECT_CALL(mock_ffmpeg_,
- AVBitstreamFilterFilter(&test_filter_, &test_stream_context_,
- NULL, _, _,
- test_packet_.data, test_packet_.size, _))
- .WillOnce(DoAll(SetArgumentPointee<3>(test_packet_.data),
- SetArgumentPointee<4>(test_packet_.size),
- Return(0)));
+ test_packet_.data = kInPlaceData;
+ test_packet_.size = kInPlaceSize;
EXPECT_TRUE(converter.ConvertPacket(&test_packet_));
- EXPECT_EQ(kData1, test_packet_.data);
- EXPECT_EQ(kTestSize1, test_packet_.size);
+ EXPECT_EQ(kInPlaceData, test_packet_.data);
+ EXPECT_EQ(kInPlaceSize, test_packet_.size);
EXPECT_TRUE(test_packet_.destruct == NULL);
-
- // Uninject mock filter instance to avoid cleanup code on destruction of
- // converter.
- converter.stream_filter_ = NULL;
}
} // namespace media
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index b26b757..e6b3aba 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -2,14 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/base_paths.h"
#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "media/base/media.h"
#include "media/base/mock_callback.h"
-#include "media/base/mock_ffmpeg.h"
#include "media/base/mock_filter_host.h"
+#include "media/base/test_data_util.h"
#include "media/filters/chunk_demuxer.h"
#include "media/filters/chunk_demuxer_client.h"
#include "media/webm/cluster_builder.h"
@@ -58,47 +54,12 @@ class ChunkDemuxerTest : public testing::Test{
ChunkDemuxerTest()
: client_(new MockChunkDemuxerClient()),
demuxer_(new ChunkDemuxer(client_.get())) {
- memset(&format_context_, 0, sizeof(format_context_));
- memset(&streams_, 0, sizeof(streams_));
- memset(&codecs_, 0, sizeof(codecs_));
-
- codecs_[VIDEO].codec_type = AVMEDIA_TYPE_VIDEO;
- codecs_[VIDEO].codec_id = CODEC_ID_VP8;
- codecs_[VIDEO].width = 320;
- codecs_[VIDEO].height = 240;
-
- codecs_[AUDIO].codec_type = AVMEDIA_TYPE_AUDIO;
- codecs_[AUDIO].codec_id = CODEC_ID_VORBIS;
- codecs_[AUDIO].channels = 2;
- codecs_[AUDIO].sample_rate = 44100;
}
virtual ~ChunkDemuxerTest() {
ShutdownDemuxer();
}
- void ReadFile(const std::string& name, scoped_array<uint8>* buffer,
- int* size) {
- FilePath file_path;
- EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
- file_path = file_path.Append(FILE_PATH_LITERAL("media"))
- .Append(FILE_PATH_LITERAL("test"))
- .Append(FILE_PATH_LITERAL("data"))
- .AppendASCII(name);
-
- int64 tmp = 0;
- EXPECT_TRUE(file_util::GetFileSize(file_path, &tmp));
- EXPECT_LT(tmp, 32768);
- int file_size = static_cast<int>(tmp);
-
- buffer->reset(new uint8[file_size]);
- EXPECT_EQ(file_size,
- file_util::ReadFile(file_path,
- reinterpret_cast<char*>(buffer->get()),
- file_size));
- *size = file_size;
- }
-
void CreateInfoTracks(bool has_audio, bool has_video,
scoped_array<uint8>* buffer, int* size) {
scoped_array<uint8> info;
@@ -108,11 +69,11 @@ class ChunkDemuxerTest : public testing::Test{
scoped_array<uint8> video_track_entry;
int video_track_entry_size = 0;
- ReadFile("webm_info_element", &info, &info_size);
- ReadFile("webm_vorbis_track_entry", &audio_track_entry,
- &audio_track_entry_size);
- ReadFile("webm_vp8_track_entry", &video_track_entry,
- &video_track_entry_size);
+ ReadTestDataFile("webm_info_element", &info, &info_size);
+ ReadTestDataFile("webm_vorbis_track_entry", &audio_track_entry,
+ &audio_track_entry_size);
+ ReadTestDataFile("webm_vp8_track_entry", &video_track_entry,
+ &video_track_entry_size);
int tracks_element_size = 0;
@@ -159,24 +120,10 @@ class ChunkDemuxerTest : public testing::Test{
}
void AppendInfoTracks(bool has_audio, bool has_video) {
- EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL))
- .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_),
- Return(0)));
-
- EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_))
- .WillOnce(Return(0));
-
- EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_));
-
- EXPECT_CALL(mock_ffmpeg_, AVRegisterLockManager(_))
- .WillRepeatedly(Return(0));
-
scoped_array<uint8> info_tracks;
int info_tracks_size = 0;
CreateInfoTracks(has_audio, has_video, &info_tracks, &info_tracks_size);
- SetupAVFormatContext(has_audio, has_video);
-
AppendData(info_tracks.get(), info_tracks_size);
}
@@ -211,12 +158,6 @@ class ChunkDemuxerTest : public testing::Test{
EXPECT_CALL(*client_, DemuxerClosed());
demuxer_->Shutdown();
}
-
- if (format_context_.streams) {
- delete[] format_context_.streams;
- format_context_.streams = NULL;
- format_context_.nb_streams = 0;
- }
}
void AddSimpleBlock(ClusterBuilder* cb, int track_num, int64 timecode) {
@@ -226,41 +167,12 @@ class ChunkDemuxerTest : public testing::Test{
MOCK_METHOD1(Checkpoint, void(int id));
- MockFFmpeg mock_ffmpeg_;
MockFilterHost mock_filter_host_;
- AVFormatContext format_context_;
- AVCodecContext codecs_[MAX_CODECS_INDEX];
- AVStream streams_[MAX_CODECS_INDEX];
-
scoped_ptr<MockChunkDemuxerClient> client_;
scoped_refptr<ChunkDemuxer> demuxer_;
private:
- void SetupAVFormatContext(bool has_audio, bool has_video) {
- int i = 0;
- format_context_.streams = new AVStream*[MAX_CODECS_INDEX];
- if (has_audio) {
- format_context_.streams[i] = &streams_[i];
- streams_[i].codec = &codecs_[AUDIO];
- streams_[i].duration = 100;
- streams_[i].time_base.den = base::Time::kMicrosecondsPerSecond;
- streams_[i].time_base.num = 1;
- i++;
- }
-
- if (has_video) {
- format_context_.streams[i] = &streams_[i];
- streams_[i].codec = &codecs_[VIDEO];
- streams_[i].duration = 100;
- streams_[i].time_base.den = base::Time::kMicrosecondsPerSecond;
- streams_[i].time_base.num = 1;
- i++;
- }
-
- format_context_.nb_streams = i;
- }
-
DISALLOW_COPY_AND_ASSIGN(ChunkDemuxerTest);
};
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index 1113e9b..920b877 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -4,15 +4,17 @@
#include <deque>
+#include "base/file_path.h"
+#include "base/path_service.h"
#include "base/threading/thread.h"
#include "media/base/filters.h"
#include "media/base/mock_callback.h"
-#include "media/base/mock_ffmpeg.h"
#include "media/base/mock_filter_host.h"
#include "media/base/mock_filters.h"
#include "media/base/mock_reader.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/ffmpeg_demuxer.h"
+#include "media/filters/file_data_source.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::AnyNumber;
@@ -21,7 +23,8 @@ using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::NotNull;
using ::testing::Return;
-using ::testing::SetArgumentPointee;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
using ::testing::StrictMock;
using ::testing::WithArgs;
using ::testing::_;
@@ -32,36 +35,6 @@ namespace media {
// FFmpeg, pipeline and filter host mocks.
class FFmpegDemuxerTest : public testing::Test {
protected:
- // These constants refer to the stream ordering inside AVFormatContext. We
- // simulate media with a data stream, audio stream and video stream. Having
- // the data stream first forces the audio and video streams to get remapped
- // from indices {1,2} to {0,1} respectively, which covers an important test
- // case.
- enum AVStreamIndex {
- AV_STREAM_DATA,
- AV_STREAM_VIDEO,
- AV_STREAM_AUDIO,
- AV_STREAM_MAX,
- };
-
- // These constants refer to the stream ordering inside an initialized
- // FFmpegDemuxer based on the ordering of the AVStreamIndex constants.
- enum DemuxerStreamIndex {
- DS_STREAM_VIDEO,
- DS_STREAM_AUDIO,
- DS_STREAM_MAX,
- };
-
- static const int kDurations[];
- static const int kChannels;
- static const int kSampleRate;
- static const int kWidth;
- static const int kHeight;
-
- static const size_t kDataSize;
- static const uint8 kAudioData[];
- static const uint8 kVideoData[];
- static const uint8* kNullData;
FFmpegDemuxerTest() {
// Create an FFmpegDemuxer.
@@ -70,45 +43,11 @@ class FFmpegDemuxerTest : public testing::Test {
// Inject a filter host and message loop and prepare a data source.
demuxer_->set_host(&host_);
- data_source_ = new StrictMock<MockDataSource>();
-
- EXPECT_CALL(*data_source_, Stop(NotNull()))
- .WillRepeatedly(Invoke(&RunStopFilterCallback));
-
- // Initialize FFmpeg fixtures.
- memset(&format_context_, 0, sizeof(format_context_));
- memset(&input_format_, 0, sizeof(input_format_));
- memset(&streams_, 0, sizeof(streams_));
- memset(&codecs_, 0, sizeof(codecs_));
-
- // Initialize AVCodecContext structures.
- codecs_[AV_STREAM_DATA].codec_type = AVMEDIA_TYPE_DATA;
- codecs_[AV_STREAM_DATA].codec_id = CODEC_ID_NONE;
-
- codecs_[AV_STREAM_VIDEO].codec_type = AVMEDIA_TYPE_VIDEO;
- codecs_[AV_STREAM_VIDEO].codec_id = CODEC_ID_THEORA;
- codecs_[AV_STREAM_VIDEO].width = kWidth;
- codecs_[AV_STREAM_VIDEO].height = kHeight;
-
- codecs_[AV_STREAM_AUDIO].codec_type = AVMEDIA_TYPE_AUDIO;
- codecs_[AV_STREAM_AUDIO].codec_id = CODEC_ID_VORBIS;
- codecs_[AV_STREAM_AUDIO].channels = kChannels;
- codecs_[AV_STREAM_AUDIO].sample_rate = kSampleRate;
-
- input_format_.name = "foo";
- format_context_.iformat = &input_format_;
-
- // Initialize AVStream and AVFormatContext structures. We set the time base
- // of the streams such that duration is reported in microseconds.
- format_context_.nb_streams = AV_STREAM_MAX;
- format_context_.streams = new AVStream*[AV_STREAM_MAX];
- for (size_t i = 0; i < AV_STREAM_MAX; ++i) {
- format_context_.streams[i] = &streams_[i];
- streams_[i].codec = &codecs_[i];
- streams_[i].duration = kDurations[i];
- streams_[i].time_base.den = 1 * base::Time::kMicrosecondsPerSecond;
- streams_[i].time_base.num = 1;
- }
+
+ EXPECT_CALL(host_, SetTotalBytes(_)).Times(AnyNumber());
+ EXPECT_CALL(host_, SetBufferedBytes(_)).Times(AnyNumber());
+ EXPECT_CALL(host_, SetCurrentReadPosition(_))
+ .WillRepeatedly(SaveArg<0>(&current_read_position_));
}
virtual ~FFmpegDemuxerTest() {
@@ -119,160 +58,117 @@ class FFmpegDemuxerTest : public testing::Test {
message_loop_.RunAllPending();
// Release the reference to the demuxer.
demuxer_ = NULL;
-
- if (format_context_.streams) {
- delete[] format_context_.streams;
- format_context_.streams = NULL;
- format_context_.nb_streams = 0;
- }
}
- // Sets up MockFFmpeg to allow FFmpegDemuxer to successfully initialize.
- void InitializeDemuxerMocks() {
- EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL))
- .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0)));
- EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_))
- .WillOnce(Return(0));
- EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_));
- }
+ scoped_refptr<DataSource> CreateDataSource(const std::string& name) {
+ FilePath file_path;
+ EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
- // Initializes both MockFFmpeg and FFmpegDemuxer.
- void InitializeDemuxer() {
- InitializeDemuxerMocks();
+ file_path = file_path.Append(FILE_PATH_LITERAL("media"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .AppendASCII(name);
+
+ scoped_refptr<FileDataSource> data_source = new FileDataSource();
+
+ EXPECT_EQ(PIPELINE_OK, data_source->Initialize(file_path.MaybeAsASCII()));
+
+ return data_source.get();
+ }
- // Since we ignore data streams, the duration should be equal to the longest
- // supported stream's duration (audio, in this case).
- base::TimeDelta expected_duration =
- base::TimeDelta::FromMicroseconds(kDurations[AV_STREAM_AUDIO]);
- EXPECT_CALL(host_, SetDuration(expected_duration));
+ MOCK_METHOD1(CheckPoint, void(int v));
- demuxer_->Initialize(data_source_.get(),
- NewExpectedStatusCB(PIPELINE_OK));
+ // Initializes FFmpegDemuxer.
+ void InitializeDemuxer(const scoped_refptr<DataSource>& data_source) {
+ EXPECT_CALL(host_, SetDuration(_));
+ demuxer_->Initialize(data_source, NewExpectedStatusCB(PIPELINE_OK));
message_loop_.RunAllPending();
}
+ // Verifies that |buffer| has a specific |size| and |timestamp|.
+ // |location| simply indicates where the call to this function was made.
+ // This makes it easier to track down where test failures occur.
+ void ValidateBuffer(const tracked_objects::Location& location,
+ const scoped_refptr<Buffer>& buffer,
+ size_t size, int64 timestampInMicroseconds) {
+ std::string location_str;
+ location.Write(true, false, &location_str);
+ location_str += "\n";
+ SCOPED_TRACE(location_str);
+ EXPECT_TRUE(buffer.get() != NULL);
+ EXPECT_EQ(size, buffer->GetDataSize());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(timestampInMicroseconds),
+ buffer->GetTimestamp());
+ }
+
// Fixture members.
scoped_refptr<FFmpegDemuxer> demuxer_;
- scoped_refptr<StrictMock<MockDataSource> > data_source_;
StrictMock<MockFilterHost> host_;
MessageLoop message_loop_;
- // FFmpeg fixtures.
- AVFormatContext format_context_;
- AVInputFormat input_format_;
- AVCodecContext codecs_[AV_STREAM_MAX];
- AVStream streams_[AV_STREAM_MAX];
- MockFFmpeg mock_ffmpeg_;
+ int64 current_read_position_;
private:
DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest);
};
-// These durations are picked so that the demuxer chooses the longest supported
-// stream, which would be 30 in this case for the audio stream.
-const int FFmpegDemuxerTest::kDurations[AV_STREAM_MAX] = {100, 20, 30};
-const int FFmpegDemuxerTest::kChannels = 2;
-const int FFmpegDemuxerTest::kSampleRate = 44100;
-const int FFmpegDemuxerTest::kWidth = 1280;
-const int FFmpegDemuxerTest::kHeight = 720;
-
-const size_t FFmpegDemuxerTest::kDataSize = 4;
-const uint8 FFmpegDemuxerTest::kAudioData[kDataSize] = {0, 1, 2, 3};
-const uint8 FFmpegDemuxerTest::kVideoData[kDataSize] = {4, 5, 6, 7};
-const uint8* FFmpegDemuxerTest::kNullData = NULL;
-
TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) {
// Simulate av_open_input_file() failing.
- EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL))
- .WillOnce(Return(-1));
-
- demuxer_->Initialize(data_source_.get(),
+ EXPECT_CALL(host_, SetCurrentReadPosition(_));
+ demuxer_->Initialize(CreateDataSource("ten_byte_file"),
NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN));
- message_loop_.RunAllPending();
-}
-
-TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) {
- // Simulate av_find_stream_info() failing.
- EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL))
- .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0)));
- EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_))
- .WillOnce(Return(AVERROR(EIO)));
- EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_));
- demuxer_->Initialize(
- data_source_.get(),
- NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE));
message_loop_.RunAllPending();
}
-TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) {
- // Simulate media with no parseable streams.
- {
- SCOPED_TRACE("");
- InitializeDemuxerMocks();
- }
- format_context_.nb_streams = 0;
+// TODO(acolwell): Uncomment this test when we discover a file that passes
+// av_open_input_file(), but has av_find_stream_info() fail.
+//
+//TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) {
+// demuxer_->Initialize(
+// CreateDataSource("find_stream_info_fail.webm"),
+// NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE));
+// message_loop_.RunAllPending();
+//}
+TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) {
+ // Open a file with no parseable streams.
+ EXPECT_CALL(host_, SetCurrentReadPosition(_));
demuxer_->Initialize(
- data_source_.get(),
+ CreateDataSource("no_streams.webm"),
NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS));
message_loop_.RunAllPending();
}
-TEST_F(FFmpegDemuxerTest, Initialize_DataStreamOnly) {
- // Simulate media with a data stream but no audio or video streams.
- {
- SCOPED_TRACE("");
- InitializeDemuxerMocks();
- }
- EXPECT_EQ(format_context_.streams[0], &streams_[AV_STREAM_DATA]);
- format_context_.nb_streams = 1;
-
- demuxer_->Initialize(
- data_source_.get(),
- NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS));
- message_loop_.RunAllPending();
-}
+// TODO(acolwell): Find a subtitle only file so we can uncomment this test.
+//
+//TEST_F(FFmpegDemuxerTest, Initialize_DataStreamOnly) {
+// demuxer_->Initialize(
+// CreateDataSource("subtitles_only.mp4"),,
+// NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS));
+// message_loop_.RunAllPending();
+//}
TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
+ InitializeDemuxer(CreateDataSource("bear-320x240.webm"));
// First stream should be video and support the FFmpegDemuxerStream interface.
scoped_refptr<DemuxerStream> stream =
demuxer_->GetStream(DemuxerStream::VIDEO);
ASSERT_TRUE(stream);
EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
- EXPECT_EQ(&streams_[AV_STREAM_VIDEO], stream->GetAVStream());
+ ASSERT_TRUE(stream->GetAVStream());
// Other stream should be audio and support the FFmpegDemuxerStream interface.
stream = demuxer_->GetStream(DemuxerStream::AUDIO);
ASSERT_TRUE(stream);
EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
- EXPECT_EQ(&streams_[AV_STREAM_AUDIO], stream->GetAVStream());
+ ASSERT_TRUE(stream->GetAVStream());
}
-TEST_F(FFmpegDemuxerTest, Read_DiscardUninteresting) {
- // We test that on a successful audio packet read, that the packet is
- // duplicated (FFmpeg memory management safety), and a copy of it ends up in
- // the DemuxerStream.
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
-
- // Ignore all AVFreePacket() calls. We check this elsewhere.
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber());
-
- // The demuxer will read a data packet which will get immediately freed,
- // followed by a read error to end the reading.
- InSequence s;
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_DATA, kNullData, 0));
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(Return(AVERROR(EIO)));
+TEST_F(FFmpegDemuxerTest, Read_Audio) {
+ // We test that on a successful audio packet read.
+ InitializeDemuxer(CreateDataSource("bear-320x240.webm"));
// Attempt a read from the audio stream and run the message loop until done.
scoped_refptr<DemuxerStream> audio =
@@ -280,231 +176,107 @@ TEST_F(FFmpegDemuxerTest, Read_DiscardUninteresting) {
scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader());
reader->Read(audio);
message_loop_.RunAllPending();
-
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- EXPECT_TRUE(reader->buffer()->IsEndOfStream());
-}
-
-TEST_F(FFmpegDemuxerTest, Read_Audio) {
- // We test that on a successful audio packet read, that the packet is
- // duplicated (FFmpeg memory management safety), and a copy of it ends up in
- // the DemuxerStream.
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
+ ValidateBuffer(FROM_HERE, reader->buffer(), 29, 0);
- // Ignore all AVFreePacket() calls. We check this via valgrind.
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber());
-
- // The demuxer will read a data packet which will get immediately freed,
- // followed by reading an audio packet...
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
-
- // Attempt a read from the audio stream and run the message loop until done.
- scoped_refptr<DemuxerStream> audio =
- demuxer_->GetStream(DemuxerStream::AUDIO);
- scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader());
+ reader->Reset();
reader->Read(audio);
message_loop_.RunAllPending();
-
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
+ ValidateBuffer(FROM_HERE, reader->buffer(), 27, 3000);
}
TEST_F(FFmpegDemuxerTest, Read_Video) {
- // We test that on a successful video packet read, that the packet is
- // duplicated (FFmpeg memory management safety), and a copy of it ends up in
- // the DemuxerStream.
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
-
- // Ignore all AVFreePacket() calls. We check this via valgrind.
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber());
-
- // Simulate a successful frame read.
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
+ // We test that on a successful video packet read.
+ InitializeDemuxer(CreateDataSource("bear-320x240.webm"));
// Attempt a read from the video stream and run the message loop until done.
scoped_refptr<DemuxerStream> video =
demuxer_->GetStream(DemuxerStream::VIDEO);
scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader());
+
reader->Read(video);
message_loop_.RunAllPending();
-
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
-}
-
-TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) {
- // Test the start time is the first timestamp of the video and audio stream.
- const int64 kStartTime = 60000;
- // Set the audio and video stream's first timestamp.
- streams_[AV_STREAM_AUDIO].first_dts = kStartTime;
- streams_[AV_STREAM_VIDEO].first_dts = kStartTime;
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
-
- // Ignore all AVFreePacket() calls. We check this via valgrind.
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber());
-
- const base::TimeDelta kExpectedTimestamp =
- base::TimeDelta::FromMicroseconds(kStartTime);
-
- // Simulate a successful frame read.
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketTimeNoCount(AV_STREAM_VIDEO,
- kVideoData,
- kDataSize,
- kStartTime));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
+ ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0);
- // Attempt a read from the video stream and run the message loop until done.
- scoped_refptr<DemuxerStream> video =
- demuxer_->GetStream(DemuxerStream::VIDEO);
- scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader());
+ reader->Reset();
reader->Read(video);
message_loop_.RunAllPending();
-
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(kExpectedTimestamp, reader->buffer()->GetTimestamp());
- EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
-
- EXPECT_EQ(kExpectedTimestamp, demuxer_->GetStartTime());
+ ValidateBuffer(FROM_HERE, reader->buffer(), 1057, 33000);
}
-TEST_F(FFmpegDemuxerTest, CheckMinStartTime) {
- // Test the start time is minimum timestamp of all streams.
- const int64 kAudioStartTime = 5000000;
- const int64 kVideoStartTime = 5033000;
- // Set the audio and video stream's first timestamp.
- streams_[AV_STREAM_AUDIO].first_dts = kAudioStartTime;
- streams_[AV_STREAM_VIDEO].first_dts = kVideoStartTime;
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
-
- // Ignore all AVFreePacket() calls. We check this via valgrind.
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber());
-
- // Expect all calls in sequence.
- InSequence s;
+TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) {
+ // Test the start time is the first timestamp of the video and audio stream.
+ InitializeDemuxer(CreateDataSource("nonzero-start-time.webm"));
- const base::TimeDelta kExpectedAudioTimestamp =
- base::TimeDelta::FromMicroseconds(kAudioStartTime);
- const base::TimeDelta kExpectedVideoTimestamp =
- base::TimeDelta::FromMicroseconds(kVideoStartTime);
-
- // First read a video packet, then an audio packet.
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketTimeNoCount(AV_STREAM_AUDIO,
- kAudioData,
- kDataSize,
- kAudioStartTime));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketTimeNoCount(AV_STREAM_VIDEO,
- kVideoData,
- kDataSize,
- kVideoStartTime));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
+ const base::TimeDelta kExpectedTimestamp =
+ base::TimeDelta::FromMicroseconds(396000);
// Attempt a read from the video stream and run the message loop until done.
scoped_refptr<DemuxerStream> video =
demuxer_->GetStream(DemuxerStream::VIDEO);
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
- ASSERT_TRUE(video);
- ASSERT_TRUE(audio);
-
scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader());
+
+ // Check first buffer in video stream.
reader->Read(video);
message_loop_.RunAllPending();
-
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(kExpectedVideoTimestamp, reader->buffer()->GetTimestamp());
- EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
-
- EXPECT_EQ(kExpectedAudioTimestamp, demuxer_->GetStartTime());
+ ValidateBuffer(FROM_HERE, reader->buffer(), 5636, 400000);
+ const base::TimeDelta video_timestamp = reader->buffer()->GetTimestamp();
+ // Check first buffer in audio stream.
reader->Reset();
reader->Read(audio);
message_loop_.RunAllPending();
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(kExpectedAudioTimestamp, reader->buffer()->GetTimestamp());
- EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
+ ValidateBuffer(FROM_HERE, reader->buffer(), 165, 396000);
+ const base::TimeDelta audio_timestamp = reader->buffer()->GetTimestamp();
- EXPECT_EQ(kExpectedAudioTimestamp, demuxer_->GetStartTime());
+ // Verify that the start time is equal to the lowest timestamp.
+ EXPECT_EQ(std::min(audio_timestamp, video_timestamp),
+ demuxer_->GetStartTime());
}
TEST_F(FFmpegDemuxerTest, Read_EndOfStream) {
- // On end of stream, a new, empty, AVPackets are created without any data for
- // each stream and enqueued into the Buffer stream. Verify that these are
- // indeed inserted.
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
-
- // Ignore all AVFreePacket() calls. We check this via valgrind.
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber());
-
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(Return(AVERROR(EIO)));
+ // Verify that end of stream buffers are created.
+ InitializeDemuxer(CreateDataSource("bear-320x240.webm"));
// We should now expect an end of stream buffer.
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader());
- reader->Read(audio);
- message_loop_.RunAllPending();
- EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- EXPECT_TRUE(reader->buffer()->IsEndOfStream());
- EXPECT_TRUE(reader->buffer()->GetData() == NULL);
- EXPECT_EQ(0u, reader->buffer()->GetDataSize());
+
+ bool got_eos_buffer = false;
+ const int kMaxBuffers = 170;
+ for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) {
+ reader->Read(audio);
+ message_loop_.RunAllPending();
+ EXPECT_TRUE(reader->called());
+ ASSERT_TRUE(reader->buffer());
+
+ if (reader->buffer()->IsEndOfStream()) {
+ got_eos_buffer = true;
+ EXPECT_TRUE(reader->buffer()->GetData() == NULL);
+ EXPECT_EQ(0u, reader->buffer()->GetDataSize());
+ break;
+ }
+
+ EXPECT_TRUE(reader->buffer()->GetData() != NULL);
+ EXPECT_GT(reader->buffer()->GetDataSize(), 0u);
+ reader->Reset();
+ }
+
+ EXPECT_TRUE(got_eos_buffer);
}
TEST_F(FFmpegDemuxerTest, Seek) {
// We're testing that the demuxer frees all queued packets when it receives
// a Seek().
- //
- // Since we can't test which packets are being freed, we use check points to
- // infer that the correct packets have been freed.
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
+ InitializeDemuxer(CreateDataSource("bear-320x240.webm"));
// Get our streams.
scoped_refptr<DemuxerStream> video =
@@ -514,129 +286,52 @@ TEST_F(FFmpegDemuxerTest, Seek) {
ASSERT_TRUE(video);
ASSERT_TRUE(audio);
- // Expected values.
- const int64 kExpectedTimestamp = 1234;
- const int64 kExpectedFlags = AVSEEK_FLAG_BACKWARD;
-
- // Ignore all AVFreePacket() calls. We check this via valgrind.
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber());
-
- // Expect all calls in sequence.
- InSequence s;
-
- // First we'll read a video packet that causes two audio packets to be queued
- // inside FFmpegDemuxer...
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
-
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(1));
-
- // ...then we'll expect a seek call...
- EXPECT_CALL(mock_ffmpeg_,
- AVSeekFrame(&format_context_, -1, kExpectedTimestamp, kExpectedFlags))
- .WillOnce(Return(0));
-
- // ...then our callback will be executed...
- FilterStatusCB seek_cb = NewExpectedStatusCB(PIPELINE_OK);
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(2));
-
- // ...followed by two audio packet reads we'll trigger...
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
-
- // ...followed by two video packet reads...
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize));
- EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_))
- .WillOnce(Return(0));
-
- // ...and finally a sanity checkpoint to make sure everything was released.
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(3));
-
// Read a video packet and release it.
scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader());
reader->Read(video);
message_loop_.RunAllPending();
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
+ ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0);
// Release the video packet and verify the other packets are still queued.
reader->Reset();
message_loop_.RunAllPending();
- mock_ffmpeg_.CheckPoint(1);
// Issue a simple forward seek, which should discard queued packets.
- demuxer_->Seek(base::TimeDelta::FromMicroseconds(kExpectedTimestamp),
- seek_cb);
+ demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
+ NewExpectedStatusCB(PIPELINE_OK));
message_loop_.RunAllPending();
- mock_ffmpeg_.CheckPoint(2);
// Audio read #1.
reader->Read(audio);
message_loop_.RunAllPending();
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
+ ValidateBuffer(FROM_HERE, reader->buffer(), 145, 803000);
// Audio read #2.
reader->Reset();
reader->Read(audio);
message_loop_.RunAllPending();
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
+ ValidateBuffer(FROM_HERE, reader->buffer(), 148, 826000);
// Video read #1.
reader->Reset();
reader->Read(video);
message_loop_.RunAllPending();
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
+ ValidateBuffer(FROM_HERE, reader->buffer(), 5425, 801000);
// Video read #2.
reader->Reset();
reader->Read(video);
message_loop_.RunAllPending();
EXPECT_TRUE(reader->called());
- ASSERT_TRUE(reader->buffer());
- ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize());
- EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(),
- reader->buffer()->GetDataSize()));
+ ValidateBuffer(FROM_HERE, reader->buffer(), 1906, 834000);
// Manually release the last reference to the buffer and verify it was freed.
reader->Reset();
message_loop_.RunAllPending();
- mock_ffmpeg_.CheckPoint(3);
}
// A mocked callback specialization for calling Read(). Since RunWithParams()
@@ -659,21 +354,13 @@ class MockReadCallback : public base::RefCountedThreadSafe<MockReadCallback> {
TEST_F(FFmpegDemuxerTest, Stop) {
// Tests that calling Read() on a stopped demuxer immediately deletes the
// callback.
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
+ InitializeDemuxer(CreateDataSource("bear-320x240.webm"));
// Get our stream.
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
ASSERT_TRUE(audio);
- // Stop the demuxer, overriding the default expectation to assert that
- // data_source_ really is Stop()'d.
- EXPECT_CALL(*data_source_, Stop(_))
- .WillOnce(Invoke(&RunStopFilterCallback))
- .RetiresOnSaturation();
demuxer_->Stop(NewExpectedCallback());
// Expect all calls in sequence.
@@ -686,7 +373,7 @@ TEST_F(FFmpegDemuxerTest, Stop) {
// The callback should be immediately deleted. We'll use a checkpoint to
// verify that it has indeed been deleted.
EXPECT_CALL(*callback, OnDelete());
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(1));
+ EXPECT_CALL(*this, CheckPoint(1));
// Attempt the read...
audio->Read(base::Bind(&MockReadCallback::Run, callback));
@@ -694,7 +381,7 @@ TEST_F(FFmpegDemuxerTest, Stop) {
message_loop_.RunAllPending();
// ...and verify that |callback| was deleted.
- mock_ffmpeg_.CheckPoint(1);
+ CheckPoint(1);
}
TEST_F(FFmpegDemuxerTest, DisableAudioStream) {
@@ -702,38 +389,32 @@ TEST_F(FFmpegDemuxerTest, DisableAudioStream) {
// 1. Initialize the demuxer with audio and video stream.
// 2. Send a "disable audio stream" message to the demuxer.
// 3. Demuxer will free audio packets even if audio stream was initialized.
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
+ InitializeDemuxer(CreateDataSource("bear-320x240.webm"));
// Submit a "disable audio stream" message to the demuxer.
demuxer_->OnAudioRendererDisabled();
message_loop_.RunAllPending();
- // Ignore all AVFreePacket() calls. We check this via valgrind.
- EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber());
-
- // Expect all calls in sequence.
- InSequence s;
-
- // The demuxer will read an audio packet which will get immediately freed.
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kNullData, 0));
-
- // Then an end-of-stream packet is read.
- EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _))
- .WillOnce(Return(AVERROR(EIO)));
-
// Get our streams.
scoped_refptr<DemuxerStream> video =
demuxer_->GetStream(DemuxerStream::VIDEO);
+ scoped_refptr<DemuxerStream> audio =
+ demuxer_->GetStream(DemuxerStream::AUDIO);
ASSERT_TRUE(video);
+ ASSERT_TRUE(audio);
// Attempt a read from the video stream and run the message loop until done.
scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader());
reader->Read(video);
message_loop_.RunAllPending();
+ EXPECT_TRUE(reader->called());
+ ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0);
+
+ reader->Reset();
+ reader->Read(audio);
+ message_loop_.RunAllPending();
+ EXPECT_TRUE(reader->called());
+ EXPECT_TRUE(reader->buffer()->IsEndOfStream());
}
class MockFFmpegDemuxer : public FFmpegDemuxer {
@@ -758,19 +439,25 @@ void RunCallback(size_t size, DataSource::ReadCallback* callback) {
}
TEST_F(FFmpegDemuxerTest, ProtocolRead) {
+ scoped_refptr<StrictMock<MockDataSource> > data_source =
+ new StrictMock<MockDataSource>();
+
+ EXPECT_CALL(*data_source, Stop(NotNull()))
+ .WillRepeatedly(Invoke(&RunStopFilterCallback));
+
// Creates a demuxer.
scoped_refptr<MockFFmpegDemuxer> demuxer(
new MockFFmpegDemuxer(&message_loop_));
ASSERT_TRUE(demuxer);
demuxer->set_host(&host_);
- demuxer->data_source_ = data_source_;
+ demuxer->data_source_ = data_source;
uint8 kBuffer[1];
InSequence s;
// Actions taken in the first read.
- EXPECT_CALL(*data_source_, GetSize(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true)));
- EXPECT_CALL(*data_source_, Read(0, 512, kBuffer, NotNull()))
+ EXPECT_CALL(*data_source, GetSize(_))
+ .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true)));
+ EXPECT_CALL(*data_source, Read(0, 512, kBuffer, NotNull()))
.WillOnce(WithArgs<1, 3>(Invoke(&RunCallback)));
EXPECT_CALL(*demuxer, SignalReadCompleted(512));
EXPECT_CALL(*demuxer, WaitForRead())
@@ -778,9 +465,9 @@ TEST_F(FFmpegDemuxerTest, ProtocolRead) {
EXPECT_CALL(host_, SetCurrentReadPosition(512));
// Second read.
- EXPECT_CALL(*data_source_, GetSize(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true)));
- EXPECT_CALL(*data_source_, Read(512, 512, kBuffer, NotNull()))
+ EXPECT_CALL(*data_source, GetSize(_))
+ .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true)));
+ EXPECT_CALL(*data_source, Read(512, 512, kBuffer, NotNull()))
.WillOnce(WithArgs<1, 3>(Invoke(&RunCallback)));
EXPECT_CALL(*demuxer, SignalReadCompleted(512));
EXPECT_CALL(*demuxer, WaitForRead())
@@ -788,8 +475,8 @@ TEST_F(FFmpegDemuxerTest, ProtocolRead) {
EXPECT_CALL(host_, SetCurrentReadPosition(1024));
// Third read will fail because it exceeds the file size.
- EXPECT_CALL(*data_source_, GetSize(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true)));
+ EXPECT_CALL(*data_source, GetSize(_))
+ .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true)));
// First read.
EXPECT_EQ(512, demuxer->Read(512, kBuffer));
@@ -812,52 +499,42 @@ TEST_F(FFmpegDemuxerTest, ProtocolRead) {
}
TEST_F(FFmpegDemuxerTest, ProtocolGetSetPosition) {
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
+ scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm");
+ InitializeDemuxer(data_source);
InSequence s;
- EXPECT_CALL(*data_source_, GetSize(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true)));
- EXPECT_CALL(*data_source_, GetSize(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true)));
- EXPECT_CALL(*data_source_, GetSize(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true)));
-
+ int64 size;
int64 position;
+ EXPECT_TRUE(demuxer_->GetSize(&size));
EXPECT_TRUE(demuxer_->GetPosition(&position));
- EXPECT_EQ(0, position);
+ EXPECT_EQ(current_read_position_, position);
EXPECT_TRUE(demuxer_->SetPosition(512));
- EXPECT_FALSE(demuxer_->SetPosition(2048));
+ EXPECT_FALSE(demuxer_->SetPosition(size));
+ EXPECT_FALSE(demuxer_->SetPosition(size + 1));
EXPECT_FALSE(demuxer_->SetPosition(-1));
EXPECT_TRUE(demuxer_->GetPosition(&position));
EXPECT_EQ(512, position);
}
TEST_F(FFmpegDemuxerTest, ProtocolGetSize) {
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
-
- EXPECT_CALL(*data_source_, GetSize(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true)));
-
- int64 size;
- EXPECT_TRUE(demuxer_->GetSize(&size));
- EXPECT_EQ(1024, size);
+ scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm");
+ InitializeDemuxer(data_source);
+
+ int64 data_source_size = 0;
+ int64 demuxer_size = 0;
+ EXPECT_TRUE(data_source->GetSize(&data_source_size));
+ EXPECT_TRUE(demuxer_->GetSize(&demuxer_size));
+ EXPECT_NE(0, data_source_size);
+ EXPECT_EQ(data_source_size, demuxer_size);
}
TEST_F(FFmpegDemuxerTest, ProtocolIsStreaming) {
- {
- SCOPED_TRACE("");
- InitializeDemuxer();
- }
- EXPECT_CALL(*data_source_, IsStreaming())
- .WillOnce(Return(false));
+ scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm");
+ InitializeDemuxer(data_source);
+
+ EXPECT_FALSE(data_source->IsStreaming());
EXPECT_FALSE(demuxer_->IsStreaming());
}
diff --git a/media/filters/ffmpeg_glue.cc b/media/filters/ffmpeg_glue.cc
index 7f134e3..bd55901 100644
--- a/media/filters/ffmpeg_glue.cc
+++ b/media/filters/ffmpeg_glue.cc
@@ -146,6 +146,11 @@ FFmpegGlue* FFmpegGlue::GetInstance() {
return Singleton<FFmpegGlue>::get();
}
+// static
+URLProtocol* FFmpegGlue::url_protocol() {
+ return &kFFmpegURLProtocol;
+}
+
std::string FFmpegGlue::AddProtocol(FFmpegURLProtocol* protocol) {
base::AutoLock auto_lock(lock_);
std::string key = GetProtocolKey(protocol);
diff --git a/media/filters/ffmpeg_glue.h b/media/filters/ffmpeg_glue.h
index a98c502..0e91fd3 100644
--- a/media/filters/ffmpeg_glue.h
+++ b/media/filters/ffmpeg_glue.h
@@ -32,15 +32,15 @@
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
+struct URLProtocol;
+
namespace media {
class FFmpegURLProtocol {
public:
- FFmpegURLProtocol() {
- }
+ FFmpegURLProtocol() {}
- virtual ~FFmpegURLProtocol() {
- }
+ virtual ~FFmpegURLProtocol() {}
// Read the given amount of bytes into data, returns the number of bytes read
// if successful, kReadError otherwise.
@@ -99,6 +99,9 @@ class FFmpegGlue {
typedef std::map<std::string, FFmpegURLProtocol*> ProtocolMap;
ProtocolMap protocols_;
+ friend class FFmpegGlueTest;
+ static URLProtocol* url_protocol();
+
DISALLOW_COPY_AND_ASSIGN(FFmpegGlue);
};
diff --git a/media/filters/ffmpeg_glue_unittest.cc b/media/filters/ffmpeg_glue_unittest.cc
index 158ddbb..0ea91f1 100644
--- a/media/filters/ffmpeg_glue_unittest.cc
+++ b/media/filters/ffmpeg_glue_unittest.cc
@@ -4,7 +4,6 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "media/base/mock_ffmpeg.h"
#include "media/base/mock_filters.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/ffmpeg_glue.h"
@@ -36,17 +35,21 @@ class MockProtocol : public FFmpegURLProtocol {
class FFmpegGlueTest : public ::testing::Test {
public:
- FFmpegGlueTest() {}
+ FFmpegGlueTest() : protocol_(NULL) {}
- virtual void SetUp() {
+ static void SetUpTestCase() {
// Singleton should initialize FFmpeg.
CHECK(FFmpegGlue::GetInstance());
+ }
+ virtual void SetUp() {
// Assign our static copy of URLProtocol for the rest of the tests.
- protocol_ = MockFFmpeg::protocol();
+ protocol_ = FFmpegGlue::url_protocol();
CHECK(protocol_);
}
+ MOCK_METHOD1(CheckPoint, void(int val));
+
// Helper to open a URLContext pointing to the given mocked protocol.
// Callers are expected to close the context at the end of their test.
virtual void OpenContext(MockProtocol* protocol, URLContext* context) {
@@ -62,15 +65,12 @@ class FFmpegGlueTest : public ::testing::Test {
protected:
// Fixture members.
- MockFFmpeg mock_ffmpeg_;
- static URLProtocol* protocol_;
+ URLProtocol* protocol_;
private:
DISALLOW_COPY_AND_ASSIGN(FFmpegGlueTest);
};
-URLProtocol* FFmpegGlueTest::protocol_ = NULL;
-
TEST_F(FFmpegGlueTest, InitializeFFmpeg) {
// Make sure URLProtocol was filled out correctly.
EXPECT_STREQ("http", protocol_->name);
@@ -118,7 +118,7 @@ TEST_F(FFmpegGlueTest, AddRemoveGetProtocol) {
InSequence s;
EXPECT_CALL(*protocol_a, OnDestroy());
EXPECT_CALL(*protocol_b, OnDestroy());
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(0));
+ EXPECT_CALL(*this, CheckPoint(0));
glue->RemoveProtocol(protocol_a.get());
glue->GetProtocol(key_a, &protocol_c);
@@ -132,7 +132,7 @@ TEST_F(FFmpegGlueTest, AddRemoveGetProtocol) {
protocol_b.reset();
// Data sources should be deleted by this point.
- mock_ffmpeg_.CheckPoint(0);
+ CheckPoint(0);
}
TEST_F(FFmpegGlueTest, OpenClose) {
@@ -162,22 +162,22 @@ TEST_F(FFmpegGlueTest, OpenClose) {
// held by FFmpeg. Once we close the URLContext, the protocol should be
// destroyed.
InSequence s;
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(0));
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(1));
+ EXPECT_CALL(*this, CheckPoint(0));
+ EXPECT_CALL(*this, CheckPoint(1));
EXPECT_CALL(*protocol, OnDestroy());
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(2));
+ EXPECT_CALL(*this, CheckPoint(2));
// Remove the protocol from the glue layer, releasing a reference.
glue->RemoveProtocol(protocol.get());
- mock_ffmpeg_.CheckPoint(0);
+ CheckPoint(0);
// Remove our own reference -- URLContext should maintain a reference.
- mock_ffmpeg_.CheckPoint(1);
+ CheckPoint(1);
protocol.reset();
// Close the URLContext, which should release the final reference.
EXPECT_EQ(0, protocol_->url_close(&context));
- mock_ffmpeg_.CheckPoint(2);
+ CheckPoint(2);
}
TEST_F(FFmpegGlueTest, Write) {
@@ -309,11 +309,11 @@ TEST_F(FFmpegGlueTest, Destroy) {
// We should expect the protocol to get destroyed when the unit test
// exits.
InSequence s;
- EXPECT_CALL(mock_ffmpeg_, CheckPoint(0));
+ EXPECT_CALL(*this, CheckPoint(0));
EXPECT_CALL(*protocol, OnDestroy());
// Remove our own reference, we shouldn't be destroyed yet.
- mock_ffmpeg_.CheckPoint(0);
+ CheckPoint(0);
protocol.reset();
// ~FFmpegGlue() will be called when this unit test finishes execution. By
diff --git a/media/filters/ffmpeg_h264_bitstream_converter_unittest.cc b/media/filters/ffmpeg_h264_bitstream_converter_unittest.cc
index 5799123..e3d3766 100644
--- a/media/filters/ffmpeg_h264_bitstream_converter_unittest.cc
+++ b/media/filters/ffmpeg_h264_bitstream_converter_unittest.cc
@@ -2,22 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "media/base/mock_ffmpeg.h"
+#include "media/base/media.h"
+#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/ffmpeg_h264_bitstream_converter.h"
#include "testing/gtest/include/gtest/gtest.h"
-using ::testing::_;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::StrictMock;
-
namespace media {
-// Forward declarations for fake FFmpeg packet handling functions.
-static void fake_av_destruct_packet(AVPacket* pkt);
-static void fake_av_init_packet(AVPacket* pkt);
-static int fake_av_new_packet(AVPacket* pkt, int size);
-
// Test data arrays.
static const uint8 kHeaderDataOkWithFieldLen4[] = {
0x01, 0x42, 0x00, 0x28, 0xFF, 0xE1, 0x00, 0x08, 0x67, 0x42, 0x00, 0x28,
@@ -268,14 +259,6 @@ static const uint8 kPacketDataOkWithFieldLen4[] = {
class FFmpegH264BitstreamConverterTest : public testing::Test {
protected:
FFmpegH264BitstreamConverterTest() {
- // Set up the ffmpeg mock and use our local fake functions to do the
- // actual implementation for packet allocation / freeing.
- ON_CALL(ffmpeg_mock_, AVInitPacket(_))
- .WillByDefault(Invoke(fake_av_init_packet));
- ON_CALL(ffmpeg_mock_, AVNewPacket(_, _))
- .WillByDefault(Invoke(fake_av_new_packet));
- ON_CALL(ffmpeg_mock_, AVDestructPacket(_))
- .WillByDefault(Invoke(fake_av_destruct_packet));
// Set up AVCConfigurationRecord correctly for tests.
// It's ok to do const cast here as data in kHeaderDataOkWithFieldLen4 is
// never written to.
@@ -288,16 +271,10 @@ class FFmpegH264BitstreamConverterTest : public testing::Test {
void CreatePacket(AVPacket* packet, const uint8* data, uint32 data_size) {
// Create new packet sized of |data_size| from |data|.
- EXPECT_CALL(ffmpeg_mock_, AVNewPacket(_, _));
- EXPECT_CALL(ffmpeg_mock_, AVInitPacket(_));
EXPECT_EQ(av_new_packet(packet, data_size), 0);
memcpy(packet->data, data, data_size);
}
- // FFmpeg mock implementation. We want strict mock since we will strictly
- // define the order of calls and do not want any extra calls.
- StrictMock<MockFFmpeg> ffmpeg_mock_;
-
// Variable to hold valid dummy context for testing.
AVCodecContext test_context_;
@@ -317,13 +294,9 @@ TEST_F(FFmpegH264BitstreamConverterTest, Conversion_Success) {
// Try out the actual conversion (should be successful and allocate new
// packet and destroy the old one).
- EXPECT_CALL(ffmpeg_mock_, AVNewPacket(_, _));
- EXPECT_CALL(ffmpeg_mock_, AVInitPacket(_));
- EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_));
EXPECT_TRUE(converter.ConvertPacket(&test_packet));
// Clean-up the test packet.
- EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_));
av_destruct_packet(&test_packet);
// Converter will be automatically cleaned up.
@@ -344,38 +317,9 @@ TEST_F(FFmpegH264BitstreamConverterTest, Conversion_SuccessBigPacket) {
// Try out the actual conversion (should be successful and allocate new
// packet and destroy the old one as we do NOT support in place transform).
- EXPECT_CALL(ffmpeg_mock_, AVNewPacket(_, _));
- EXPECT_CALL(ffmpeg_mock_, AVInitPacket(_));
- EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_));
EXPECT_TRUE(converter.ConvertPacket(&test_packet));
// Clean-up the test packet.
- EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_));
- av_destruct_packet(&test_packet);
-
- // Converter will be automatically cleaned up.
-}
-
-TEST_F(FFmpegH264BitstreamConverterTest, Conversion_FailureOutOfMem) {
- FFmpegH264BitstreamConverter converter(&test_context_);
-
- // Initialization should be always successful.
- EXPECT_TRUE(converter.Initialize());
-
- // Create new packet.
- AVPacket test_packet;
- CreatePacket(&test_packet, kPacketDataOkWithFieldLen4,
- sizeof(kPacketDataOkWithFieldLen4));
-
- // Try out the actual conversion (should be successful and allocate new
- // packet and destroy the old one).
- EXPECT_CALL(ffmpeg_mock_, AVNewPacket(_, _))
- .WillOnce(Return(-1));
- EXPECT_FALSE(converter.ConvertPacket(&test_packet))
- << "ConvertPacket() did not return expected failure due to out of mem";
-
- // Clean-up the test packet.
- EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_));
av_destruct_packet(&test_packet);
// Converter will be automatically cleaned up.
@@ -404,39 +348,9 @@ TEST_F(FFmpegH264BitstreamConverterTest, Conversion_FailureNullParams) {
EXPECT_FALSE(converter.ConvertPacket(&test_packet));
// Clean-up the test packet.
- EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_));
av_destruct_packet(&test_packet);
// Converted will be automatically cleaned up.
}
-static void fake_av_destruct_packet(AVPacket* pkt) {
- free(pkt->data);
- pkt->data = NULL;
- pkt->size = 0;
-}
-
-static void fake_av_init_packet(AVPacket* pkt) {
- pkt->pts = AV_NOPTS_VALUE;
- pkt->dts = AV_NOPTS_VALUE;
- pkt->pos = -1;
- pkt->duration = 0;
- pkt->convergence_duration = 0;
- pkt->flags = 0;
- pkt->stream_index = 0;
- pkt->destruct= NULL;
-}
-
-static int fake_av_new_packet(AVPacket* pkt, int size) {
- uint8* data = reinterpret_cast<uint8*>(malloc(size));
- av_init_packet(pkt);
- pkt->data = data;
- pkt->size = size;
- pkt->destruct = av_destruct_packet;
- if (data == NULL)
- return AVERROR(ENOMEM);
- return 0;
-}
-
} // namespace media
-
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 7614d8b..e3dd90d 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -10,7 +10,6 @@
#include "media/base/data_buffer.h"
#include "media/base/filters.h"
#include "media/base/mock_callback.h"
-#include "media/base/mock_ffmpeg.h"
#include "media/base/mock_filter_host.h"
#include "media/base/mock_filters.h"
#include "media/base/mock_task.h"
@@ -220,7 +219,6 @@ class FFmpegVideoDecoderTest : public testing::Test {
AVCodec codec_;
AVFrame yuv_frame_;
scoped_refptr<VideoFrame> video_frame_;
- StrictMock<MockFFmpeg> mock_ffmpeg_;
private:
DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest);
diff --git a/media/media.gyp b/media/media.gyp
index 7cc36e4..c27b430 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -442,8 +442,6 @@
'base/djb2_unittest.cc',
'base/filter_collection_unittest.cc',
'base/h264_bitstream_converter_unittest.cc',
- 'base/mock_ffmpeg.cc',
- 'base/mock_ffmpeg.h',
'base/mock_reader.h',
'base/mock_task.cc',
'base/mock_task.h',
@@ -453,6 +451,8 @@
'base/run_all_unittests.cc',
'base/seekable_buffer_unittest.cc',
'base/state_matrix_unittest.cc',
+ 'base/test_data_util.cc',
+ 'base/test_data_util.h',
'base/video_frame_unittest.cc',
'base/video_util_unittest.cc',
'base/yuv_convert_unittest.cc',
diff --git a/media/video/ffmpeg_video_decode_engine.cc b/media/video/ffmpeg_video_decode_engine.cc
index 4af73a1..0958516 100644
--- a/media/video/ffmpeg_video_decode_engine.cc
+++ b/media/video/ffmpeg_video_decode_engine.cc
@@ -120,6 +120,7 @@ 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 &&
@@ -186,7 +187,6 @@ 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,24 +303,6 @@ 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 32eac45..b7d7661 100644
--- a/media/video/ffmpeg_video_decode_engine.h
+++ b/media/video/ffmpeg_video_decode_engine.h
@@ -33,8 +33,6 @@ 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 261ca45..611bbfa 100644
--- a/media/video/ffmpeg_video_decode_engine_unittest.cc
+++ b/media/video/ffmpeg_video_decode_engine_unittest.cc
@@ -5,9 +5,10 @@
#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"
@@ -16,63 +17,40 @@ using ::testing::_;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::ReturnNull;
+using ::testing::SaveArg;
using ::testing::SetArgumentPointee;
using ::testing::StrictMock;
namespace media {
-static const int kWidth = 320;
-static const int kHeight = 240;
+static const size_t kWidth = 320;
+static const size_t 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);
-}
-
ACTION_P2(DemuxComplete, engine, buffer) {
engine->ConsumeVideoSample(buffer);
}
-ACTION_P(SaveInitializeResult, engine) {
- engine->set_video_codec_info(arg0);
-}
-
class FFmpegVideoDecodeEngineTest
: public testing::Test,
public VideoDecodeEngine::EventHandler {
public:
FFmpegVideoDecodeEngineTest()
- : config_(kCodecH264, kWidth, kHeight, kSurfaceWidth, kSurfaceHeight,
+ : config_(kCodecVP8, 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());
- video_frame_ = VideoFrame::CreateFrame(VideoFrame::YV12,
- kWidth,
- kHeight,
- kNoTimestamp,
- kNoTimestamp);
+ ReadTestDataFile("vp8-I-frame-320x240", &i_frame_buffer_);
+ ReadTestDataFile("vp8-corrupt-I-frame", &corrupt_i_frame_buffer_);
+
+ end_of_stream_buffer_ = new DataBuffer(0);
}
~FFmpegVideoDecodeEngineTest() {
@@ -80,46 +58,57 @@ 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);
-
+ VideoCodecInfo info;
EXPECT_CALL(*this, OnInitializeComplete(_))
- .WillOnce(SaveInitializeResult(this));
+ .WillOnce(SaveArg<0>(&info));
test_engine_->Initialize(MessageLoop::current(), this, NULL, config_);
- EXPECT_TRUE(info_.success);
+ 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)));
-
+ // Decodes the single compressed frame in |buffer| and writes the
+ // uncompressed output to |video_frame|. This method works with single
+ // and multithreaded decoders. End of stream buffers are used to trigger
+ // the frame to be returned in the multithreaded decoder case.
+ void DecodeASingleFrame(const scoped_refptr<Buffer>& buffer,
+ scoped_refptr<VideoFrame>* video_frame) {
EXPECT_CALL(*this, ProduceVideoSample(_))
- .WillOnce(DemuxComplete(test_engine_.get(), buffer_));
+ .WillOnce(DemuxComplete(test_engine_.get(), buffer))
+ .WillRepeatedly(DemuxComplete(test_engine_.get(),
+ end_of_stream_buffer_));
+
EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
- .WillOnce(DecodeComplete(this));
- test_engine_->ProduceVideoFrame(video_frame_);
+ .WillOnce(SaveArg<0>(video_frame));
+ CallProduceVideoFrame();
}
- 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;
+ // Decodes |i_frame_buffer_| and then decodes the data contained in
+ // the file named |test_file_name|. This function expects both buffers
+ // to decode to frames that are the same size.
+ void DecodeIFrameThenTestFile(const std::string& test_file_name) {
+ Initialize();
+
+ scoped_refptr<VideoFrame> video_frame_a;
+ scoped_refptr<VideoFrame> video_frame_b;
+
+ scoped_refptr<Buffer> buffer;
+ ReadTestDataFile(test_file_name, &buffer);
+
+ EXPECT_CALL(*this, ProduceVideoSample(_))
+ .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_))
+ .WillOnce(DemuxComplete(test_engine_.get(), buffer))
+ .WillRepeatedly(DemuxComplete(test_engine_.get(),
+ end_of_stream_buffer_));
+
+ EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
+ .WillOnce(SaveArg<0>(&video_frame_a))
+ .WillOnce(SaveArg<0>(&video_frame_b));
+ CallProduceVideoFrame();
+ CallProduceVideoFrame();
+
+ EXPECT_EQ(kWidth, video_frame_a->width());
+ EXPECT_EQ(kHeight, video_frame_a->height());
+ EXPECT_EQ(kWidth, video_frame_b->width());
+ EXPECT_EQ(kHeight, video_frame_b->height());
}
// VideoDecodeEngine::EventHandler implementation.
@@ -135,27 +124,21 @@ class FFmpegVideoDecodeEngineTest
MOCK_METHOD0(OnSeekComplete, void());
MOCK_METHOD0(OnError, void());
- // Used by gmock actions.
- void set_video_frame(scoped_refptr<VideoFrame> video_frame) {
- video_frame_ = video_frame;
- }
-
- void set_video_codec_info(const VideoCodecInfo& info) {
- info_ = info;
+ void CallProduceVideoFrame() {
+ test_engine_->ProduceVideoFrame(VideoFrame::CreateFrame(VideoFrame::YV12,
+ kWidth,
+ kHeight,
+ kNoTimestamp,
+ kNoTimestamp));
}
protected:
VideoDecoderConfig config_;
- VideoCodecInfo info_;
- scoped_refptr<VideoFrame> video_frame_;
scoped_ptr<FFmpegVideoDecodeEngine> test_engine_;
scoped_array<uint8_t> frame_buffer_;
- StrictMock<MockFFmpeg> mock_ffmpeg_;
-
- AVFrame yuv_frame_;
- AVCodecContext codec_context_;
- AVCodec codec_;
- scoped_refptr<DataBuffer> buffer_;
+ scoped_refptr<Buffer> i_frame_buffer_;
+ scoped_refptr<Buffer> corrupt_i_frame_buffer_;
+ scoped_refptr<Buffer> end_of_stream_buffer_;
private:
DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecodeEngineTest);
@@ -166,150 +149,136 @@ 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);
-
+ VideoCodecInfo info;
EXPECT_CALL(*this, OnInitializeComplete(_))
- .WillOnce(SaveInitializeResult(this));
- test_engine_->Initialize(MessageLoop::current(), this, NULL, config_);
- EXPECT_FALSE(info_.success);
+ .WillOnce(SaveArg<0>(&info));
+ test_engine_->Initialize(MessageLoop::current(), this, NULL, config);
+ EXPECT_FALSE(info.success);
}
TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) {
- // 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);
-
+ // Specify Theora w/o extra data so that avcodec_open() fails.
+ VideoDecoderConfig config(kCodecTheora, kWidth, kHeight, kSurfaceWidth,
+ kSurfaceHeight, kFrameRate.num, kFrameRate.den,
+ NULL, 0);
+ VideoCodecInfo info;
EXPECT_CALL(*this, OnInitializeComplete(_))
- .WillOnce(SaveInitializeResult(this));
- test_engine_->Initialize(MessageLoop::current(), this, NULL, config_);
- EXPECT_FALSE(info_.success);
+ .WillOnce(SaveArg<0>(&info));
+ 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. 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();
+ // 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);
// Simulate decoding a single frame.
- Decode();
+ scoped_refptr<VideoFrame> video_frame;
+ DecodeASingleFrame(i_frame_buffer_, &video_frame);
- // |video_frame_| timestamp is 0 because we set the timestamp based off
+ // |video_frame| timestamp is 0 because we set the timestamp based off
// the buffer timestamp.
- EXPECT_EQ(0, video_frame_->GetTimestamp().ToInternalValue());
+ ASSERT_TRUE(video_frame);
+ EXPECT_EQ(0, video_frame->GetTimestamp().ToInternalValue());
EXPECT_EQ(kDuration.ToInternalValue(),
- video_frame_->GetDuration().ToInternalValue());
+ video_frame->GetDuration().ToInternalValue());
}
+
+// Verify current behavior for 0 byte frames. FFmpeg simply ignores
+// the 0 byte frames.
TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) {
Initialize();
- // 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)));
+ scoped_refptr<DataBuffer> zero_byte_buffer = new DataBuffer(1);
+
+ scoped_refptr<VideoFrame> video_frame_a;
+ scoped_refptr<VideoFrame> video_frame_b;
+ scoped_refptr<VideoFrame> video_frame_c;
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_);
+ .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_))
+ .WillOnce(DemuxComplete(test_engine_.get(), zero_byte_buffer))
+ .WillOnce(DemuxComplete(test_engine_.get(), i_frame_buffer_))
+ .WillRepeatedly(DemuxComplete(test_engine_.get(),
+ end_of_stream_buffer_));
- EXPECT_TRUE(video_frame_.get());
+ EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
+ .WillOnce(SaveArg<0>(&video_frame_a))
+ .WillOnce(SaveArg<0>(&video_frame_b))
+ .WillOnce(SaveArg<0>(&video_frame_c));
+ CallProduceVideoFrame();
+ CallProduceVideoFrame();
+ CallProduceVideoFrame();
+
+ EXPECT_TRUE(video_frame_a);
+ EXPECT_TRUE(video_frame_b);
+ EXPECT_FALSE(video_frame_c);
}
+
TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeError) {
Initialize();
- // 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(), corrupt_i_frame_buffer_))
+ .WillRepeatedly(DemuxComplete(test_engine_.get(), i_frame_buffer_));
EXPECT_CALL(*this, OnError());
- test_engine_->ProduceVideoFrame(video_frame_);
+ CallProduceVideoFrame();
}
-TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) {
+// Multi-threaded decoders have different behavior than single-threaded
+// decoders at the end of the stream. Multithreaded decoders hide errors
+// that happen on the last |codec_context_->thread_count| frames to avoid
+// prematurely signalling EOS. This test just exposes that behavior so we can
+// detect if it changes.
+TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_DecodeErrorAtEndOfStream) {
Initialize();
- ChangeDimensions(kWidth * 2, kHeight);
- Decode();
-}
-TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) {
- Initialize();
- ChangeDimensions(kWidth / 2, kHeight);
- Decode();
-}
+ EXPECT_CALL(*this, ProduceVideoSample(_))
+ .WillOnce(DemuxComplete(test_engine_.get(), corrupt_i_frame_buffer_))
+ .WillRepeatedly(DemuxComplete(test_engine_.get(), end_of_stream_buffer_));
-TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) {
- Initialize();
- ChangeDimensions(kWidth, kHeight * 2);
- Decode();
+ scoped_refptr<VideoFrame> video_frame;
+ EXPECT_CALL(*this, ConsumeVideoFrame(_, _))
+ .WillOnce(SaveArg<0>(&video_frame));
+ CallProduceVideoFrame();
+
+ EXPECT_FALSE(video_frame);
}
-TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) {
- Initialize();
- ChangeDimensions(kWidth, kHeight / 2);
- Decode();
+// Decode |i_frame_buffer_| and then a frame with a larger width and verify
+// the output size didn't change.
+// TODO(acolwell): Fix InvalidRead detected by Valgrind
+//TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) {
+// DecodeIFrameThenTestFile("vp8-I-frame-640x240");
+//}
+
+// Decode |i_frame_buffer_| and then a frame with a smaller width and verify
+// the output size didn't change.
+TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) {
+ DecodeIFrameThenTestFile("vp8-I-frame-160x240");
}
-TEST_F(FFmpegVideoDecodeEngineTest, GetSurfaceFormat) {
- Initialize();
+// Decode |i_frame_buffer_| and then a frame with a larger height and verify
+// the output size didn't change.
+// TODO(acolwell): Fix InvalidRead detected by Valgrind
+//TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) {
+// DecodeIFrameThenTestFile("vp8-I-frame-320x480");
+//}
- // 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());
+// Decode |i_frame_buffer_| and then a frame with a smaller height and verify
+// the output size didn't change.
+TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) {
+ DecodeIFrameThenTestFile("vp8-I-frame-320x120");
}
} // namespace media