summaryrefslogtreecommitdiffstats
path: root/media/base
diff options
context:
space:
mode:
Diffstat (limited to 'media/base')
-rw-r--r--media/base/mock_ffmpeg.cc41
-rw-r--r--media/base/mock_ffmpeg.h8
-rw-r--r--media/base/mock_filters.h51
-rw-r--r--media/base/mock_media_filters.h656
-rw-r--r--media/base/pipeline_impl_unittest.cc248
-rw-r--r--media/base/video_frame_impl_unittest.cc50
6 files changed, 298 insertions, 756 deletions
diff --git a/media/base/mock_ffmpeg.cc b/media/base/mock_ffmpeg.cc
index 054f996..562aff2 100644
--- a/media/base/mock_ffmpeg.cc
+++ b/media/base/mock_ffmpeg.cc
@@ -7,12 +7,36 @@
#include "base/logging.h"
#include "media/filters/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) {
+ // 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, AVCodecInit())
+ .Times(AtMost(1))
+ .WillOnce(Return());
+ EXPECT_CALL(*this, AVRegisterProtocol(_))
+ .Times(AtMost(1))
+ .WillOnce(DoAll(SaveArg<0>(&protocol_), Return(0)));
+ EXPECT_CALL(*this, AVRegisterAll())
+ .Times(AtMost(1))
+ .WillOnce(Return());
+ }
}
MockFFmpeg::~MockFFmpeg() {
@@ -40,6 +64,11 @@ MockFFmpeg* MockFFmpeg::get() {
}
// static
+URLProtocol* MockFFmpeg::protocol() {
+ return protocol_;
+}
+
+// static
void MockFFmpeg::DestructPacket(AVPacket* packet) {
delete [] packet->data;
packet->data = NULL;
@@ -49,6 +78,18 @@ void MockFFmpeg::DestructPacket(AVPacket* packet) {
// FFmpeg stubs that delegate to the FFmpegMock instance.
extern "C" {
+void avcodec_init() {
+ media::MockFFmpeg::get()->AVCodecInit();
+}
+
+int av_register_protocol(URLProtocol* protocol) {
+ return media::MockFFmpeg::get()->AVRegisterProtocol(protocol);
+}
+
+void av_register_all() {
+ media::MockFFmpeg::get()->AVRegisterAll();
+}
+
AVCodec* avcodec_find_decoder(enum CodecID id) {
return media::MockFFmpeg::get()->AVCodecFindDecoder(id);
}
diff --git a/media/base/mock_ffmpeg.h b/media/base/mock_ffmpeg.h
index 3afdef9..4ba38fc 100644
--- a/media/base/mock_ffmpeg.h
+++ b/media/base/mock_ffmpeg.h
@@ -16,6 +16,10 @@ class MockFFmpeg {
MockFFmpeg();
virtual ~MockFFmpeg();
+ MOCK_METHOD0(AVCodecInit, void());
+ MOCK_METHOD1(AVRegisterProtocol, int(URLProtocol* protocol));
+ MOCK_METHOD0(AVRegisterAll, void());
+
MOCK_METHOD1(AVCodecFindDecoder, AVCodec*(enum CodecID id));
MOCK_METHOD2(AVCodecOpen, int(AVCodecContext* avctx, AVCodec* codec));
MOCK_METHOD1(AVCodecClose, int(AVCodecContext* avctx));
@@ -51,6 +55,9 @@ class MockFFmpeg {
static void set(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);
@@ -60,6 +67,7 @@ class MockFFmpeg {
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
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index bef46a7..bffba6f 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -19,6 +19,27 @@
namespace media {
+// Use this template to test for object destruction by setting expectations on
+// the method OnDestroy().
+//
+// TODO(scherkus): not sure about the naming... perhaps contribute this back
+// to gmock itself!
+template<class MockClass>
+class Destroyable : public MockClass {
+ public:
+ Destroyable() {}
+
+ MOCK_METHOD0(OnDestroy, void());
+
+ protected:
+ virtual ~Destroyable() {
+ OnDestroy();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Destroyable);
+};
+
class MockDataSource : public DataSource {
public:
MockDataSource() {}
@@ -71,6 +92,12 @@ class MockDemuxerStream : public DemuxerStream {
public:
MockDemuxerStream() {}
+ // Sets the mime type of this object's media format, which is usually checked
+ // to determine the type of decoder to create.
+ explicit MockDemuxerStream(const std::string& mime_type) {
+ media_format_.SetAsString(MediaFormat::kMimeType, mime_type);
+ }
+
// DemuxerStream implementation.
const MediaFormat& media_format() { return media_format_; }
MOCK_METHOD1(Read, void(Callback1<Buffer*>::Type* read_callback));
@@ -175,7 +202,8 @@ class MockAudioRenderer : public AudioRenderer {
class MockFilterFactory : public FilterFactory {
public:
MockFilterFactory()
- : data_source_(new MockDataSource()),
+ : creation_successful_(true),
+ data_source_(new MockDataSource()),
demuxer_(new MockDemuxer()),
video_decoder_(new MockVideoDecoder()),
audio_decoder_(new MockAudioDecoder()),
@@ -185,6 +213,11 @@ class MockFilterFactory : public FilterFactory {
virtual ~MockFilterFactory() {}
+ // Controls whether the Create() method is successful or not.
+ void set_creation_successful(bool creation_successful) {
+ creation_successful_ = creation_successful;
+ }
+
// Mock accessors.
MockDataSource* data_source() const { return data_source_; }
MockDemuxer* demuxer() const { return demuxer_; }
@@ -195,6 +228,10 @@ class MockFilterFactory : public FilterFactory {
protected:
MediaFilter* Create(FilterType filter_type, const MediaFormat& media_format) {
+ if (!creation_successful_) {
+ return NULL;
+ }
+
switch (filter_type) {
case FILTER_DATA_SOURCE:
return data_source_;
@@ -215,6 +252,7 @@ class MockFilterFactory : public FilterFactory {
}
private:
+ bool creation_successful_;
scoped_refptr<MockDataSource> data_source_;
scoped_refptr<MockDemuxer> demuxer_;
scoped_refptr<MockVideoDecoder> video_decoder_;
@@ -225,6 +263,17 @@ class MockFilterFactory : public FilterFactory {
DISALLOW_COPY_AND_ASSIGN(MockFilterFactory);
};
+// Helper gmock action that calls InitializationComplete() on behalf of the
+// provided filter.
+ACTION_P(InitializationComplete, filter) {
+ filter->host()->InitializationComplete();
+}
+
+// Helper gmock action that calls Error() on behalf of the provided filter.
+ACTION_P2(Error, filter, error) {
+ filter->host()->Error(error);
+}
+
} // namespace media
#endif // MEDIA_BASE_MOCK_FILTERS_H_
diff --git a/media/base/mock_media_filters.h b/media/base/mock_media_filters.h
deleted file mode 100644
index 698815f..0000000
--- a/media/base/mock_media_filters.h
+++ /dev/null
@@ -1,656 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
-// source code is governed by a BSD-style license that can be found in the
-// LICENSE file.
-//
-// TODO(ajwong): This whole file is deprecated in favor or gmock style mocks.
-// The deprecated classes have been moved into the old_mocks to avoid colliding
-// with the newer mock classes. Once all the unittests have been migrated, this
-// should be deleted.
-
-#ifndef MEDIA_BASE_MOCK_MEDIA_FILTERS_H_
-#define MEDIA_BASE_MOCK_MEDIA_FILTERS_H_
-
-#include <string>
-
-#include "base/scoped_ptr.h"
-#include "base/waitable_event.h"
-#include "media/base/buffers.h"
-#include "media/base/factory.h"
-#include "media/base/filter_host.h"
-#include "media/base/filters.h"
-#include "media/base/media_format.h"
-#include "media/base/pipeline.h"
-#include "media/base/video_frame_impl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace media {
-
-namespace old_mocks {
-
-// Behaviors for MockDataSource filter.
-enum MockDataSourceBehavior {
- MOCK_DATA_SOURCE_NORMAL_INIT,
- MOCK_DATA_SOURCE_NEVER_INIT,
- MOCK_DATA_SOURCE_URL_ERROR_IN_INIT,
- MOCK_DATA_SOURCE_INIT_RETURN_FALSE,
-};
-
-
-// This class is used by all of the mock filters to change the configuration
-// of the desired pipeline. The test using this must ensure that the lifetime
-// of the object is at least as long as the lifetime of the filters, as this
-// is typically allocated on the stack.
-struct MockFilterConfig {
- MockFilterConfig()
- : create_filter(true),
- data_source_behavior(MOCK_DATA_SOURCE_NORMAL_INIT),
- data_source_value('!'),
- has_video(true),
- video_width(1280u),
- video_height(720u),
- video_surface_format(VideoSurface::YV12),
- has_audio(true),
- compressed_audio_mime_type(mime_type::kAACAudio),
- uncompressed_audio_mime_type(mime_type::kUncompressedAudio),
- compressed_video_mime_type(mime_type::kH264AnnexB),
- uncompressed_video_mime_type(mime_type::kUncompressedVideo),
- frame_duration(base::TimeDelta::FromMicroseconds(33333)),
- media_duration(base::TimeDelta::FromSeconds(5)),
- media_total_bytes(media_duration.InMilliseconds() * 250) {
- }
-
- bool create_filter;
- MockDataSourceBehavior data_source_behavior;
- char data_source_value;
- bool has_video;
- size_t video_width;
- size_t video_height;
- VideoSurface::Format video_surface_format;
- bool has_audio;
- std::string compressed_audio_mime_type;
- std::string uncompressed_audio_mime_type;
- std::string compressed_video_mime_type;
- std::string uncompressed_video_mime_type;
- base::TimeDelta frame_duration;
- base::TimeDelta media_duration;
- int64 media_total_bytes;
-};
-
-
-class MockDataSource : public DataSource {
- public:
- explicit MockDataSource(const MockFilterConfig* config)
- : config_(config),
- position_(0),
- deleted_(NULL) {
- }
-
- MockDataSource(const MockFilterConfig* config, bool* deleted)
- : config_(config),
- position_(0),
- deleted_(deleted) {
- EXPECT_TRUE(deleted);
- EXPECT_FALSE(*deleted);
- }
-
- // Implementation of MediaFilter.
- virtual void Stop() {}
-
- virtual void Seek(base::TimeDelta time) {
- seek_time_ = time;
- }
-
- // Implementation of DataSource.
- virtual bool Initialize(const std::string& url) {
- media_format_.SetAsString(MediaFormat::kMimeType,
- mime_type::kApplicationOctetStream);
- media_format_.SetAsString(MediaFormat::kURL, url);
- host()->SetTotalBytes(config_->media_total_bytes);
- switch (config_->data_source_behavior) {
- case MOCK_DATA_SOURCE_NORMAL_INIT:
- host()->InitializationComplete();
- return true;
- case MOCK_DATA_SOURCE_NEVER_INIT:
- return true;
- case MOCK_DATA_SOURCE_URL_ERROR_IN_INIT:
- host()->Error(PIPELINE_ERROR_URL_NOT_FOUND);
- return false;
- case MOCK_DATA_SOURCE_INIT_RETURN_FALSE:
- return false;
- default:
- NOTREACHED();
- return false;
- }
- }
-
- virtual const MediaFormat& media_format() {
- return media_format_;
- }
-
- virtual size_t Read(uint8* data, size_t size) {
- size_t read = static_cast<size_t>(config_->media_total_bytes - position_);
- if (size < read) {
- read = size;
- }
- memset(data, config_->data_source_value, read);
- return read;
- }
-
- virtual bool GetPosition(int64* position_out) {
- *position_out = position_;
- return true;
- }
-
- virtual bool SetPosition(int64 position) {
- if (position < 0u || position > config_->media_total_bytes) {
- return false;
- }
- position_ = position;
- return true;
- }
-
- virtual bool GetSize(int64* size_out) {
- if (config_->media_total_bytes >= 0) {
- *size_out = config_->media_total_bytes;
- return true;
- }
- return false;
- }
-
- virtual bool IsSeekable() {
- return true;
- }
-
- // Mock accessors.
- int64 position() const { return position_; }
- const base::TimeDelta& seek_time() const { return seek_time_; }
-
- private:
- virtual ~MockDataSource() {
- if (deleted_) {
- *deleted_ = true;
- }
- }
-
- const MockFilterConfig* config_;
- int64 position_;
- MediaFormat media_format_;
- base::TimeDelta seek_time_;
-
- // Set to true inside the destructor. Used in FFmpegGlue unit tests for
- // testing proper reference counting.
- bool* deleted_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDataSource);
-};
-
-
-class MockDemuxerStream : public DemuxerStream {
- public:
- MockDemuxerStream(const MockFilterConfig* config, bool is_audio) {
- if (is_audio) {
- media_format_.SetAsString(MediaFormat::kMimeType,
- config->compressed_audio_mime_type);
- } else {
- media_format_.SetAsString(MediaFormat::kMimeType,
- config->compressed_video_mime_type);
- media_format_.SetAsInteger(MediaFormat::kWidth, config->video_width);
- media_format_.SetAsInteger(MediaFormat::kHeight, config->video_height);
- }
- }
-
- // Implementation of DemuxerStream.
- virtual const MediaFormat& media_format() {
- return media_format_;
- }
-
- virtual void Read(Callback1<Buffer*>::Type* read_callback) {
- NOTREACHED(); // TODO(ralphl): fix me!!
- }
-
- private:
- virtual ~MockDemuxerStream() {}
-
- MediaFormat media_format_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDemuxerStream);
-};
-
-
-class MockDemuxer : public Demuxer {
- public:
- explicit MockDemuxer(const MockFilterConfig* config)
- : config_(config),
- mock_audio_stream_(new MockDemuxerStream(config, true)),
- mock_video_stream_(new MockDemuxerStream(config, false)) {
- }
-
- // Implementation of MediaFilter.
- virtual void Stop() {}
-
- virtual void Seek(base::TimeDelta time) {
- seek_time_ = time;
- }
-
- // Implementation of Demuxer.
- virtual bool Initialize(DataSource* data_source) {
- host()->InitializationComplete();
- return true;
- }
-
- virtual size_t GetNumberOfStreams() {
- size_t num_streams = 0;
- if (config_->has_audio) {
- ++num_streams;
- }
- if (config_->has_video) {
- ++num_streams;
- }
- return num_streams;
- }
-
- virtual scoped_refptr<DemuxerStream> GetStream(int stream_id) {
- switch (stream_id) {
- case 0:
- if (config_->has_audio) {
- return mock_audio_stream_;
- } else if (config_->has_video) {
- return mock_video_stream_;
- }
- break;
- case 1:
- if (config_->has_audio && config_->has_video) {
- return mock_video_stream_;
- }
- break;
- }
- ADD_FAILURE();
- return NULL;
- }
-
- // Mock accessors.
- const base::TimeDelta& seek_time() const { return seek_time_; }
-
- private:
- virtual ~MockDemuxer() {}
-
- const MockFilterConfig* config_;
- scoped_refptr<DemuxerStream> mock_audio_stream_;
- scoped_refptr<DemuxerStream> mock_video_stream_;
- base::TimeDelta seek_time_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDemuxer);
-};
-
-
-class MockAudioDecoder : public AudioDecoder {
- public:
- explicit MockAudioDecoder(const MockFilterConfig* config) {
- media_format_.SetAsString(MediaFormat::kMimeType,
- config->uncompressed_audio_mime_type);
- }
-
- // Implementation of MediaFilter.
- virtual void Stop() {}
-
- virtual void Seek(base::TimeDelta time) {
- seek_time_ = time;
- }
-
- // Implementation of AudioDecoder.
- virtual bool Initialize(DemuxerStream* stream) {
- host()->InitializationComplete();
- return true;
- }
-
- virtual const MediaFormat& media_format() {
- return media_format_;
- }
-
- virtual void Read(Callback1<Buffer*>::Type* callback) {
- // TODO(ralphl): implement mock read.
- NOTREACHED();
- }
-
- // Mock accessors.
- const base::TimeDelta& seek_time() const { return seek_time_; }
-
- private:
- virtual ~MockAudioDecoder() {}
-
- MediaFormat media_format_;
- base::TimeDelta seek_time_;
-
- DISALLOW_COPY_AND_ASSIGN(MockAudioDecoder);
-};
-
-
-class MockAudioRenderer : public AudioRenderer {
- public:
- explicit MockAudioRenderer(const MockFilterConfig* config) {}
-
- // Implementation of MediaFilter.
- virtual void Stop() {}
-
- virtual void Seek(base::TimeDelta time) {
- seek_time_ = time;
- }
-
- // Implementation of AudioRenderer.
- virtual bool Initialize(AudioDecoder* decoder) {
- host()->InitializationComplete();
- return true;
- }
-
- virtual void SetVolume(float volume) {}
-
- // Mock accessors.
- const base::TimeDelta& seek_time() const { return seek_time_; }
-
- private:
- virtual ~MockAudioRenderer() {}
-
- base::TimeDelta seek_time_;
-
- DISALLOW_COPY_AND_ASSIGN(MockAudioRenderer);
-};
-
-
-class MockVideoDecoder : public VideoDecoder {
- public:
- // Helper function that initializes a YV12 frame with white and black scan
- // lines based on the |white_to_black| parameter. If 0, then the entire
- // frame will be black, if 1 then the entire frame will be white.
- static void InitializeYV12Frame(VideoFrame* frame, double white_to_black) {
- VideoSurface surface;
- if (!frame->Lock(&surface)) {
- ADD_FAILURE();
- } else {
- EXPECT_EQ(surface.format, VideoSurface::YV12);
- size_t first_black_row = static_cast<size_t>(surface.height *
- white_to_black);
- uint8* y_plane = surface.data[VideoSurface::kYPlane];
- for (size_t row = 0; row < surface.height; ++row) {
- int color = (row < first_black_row) ? 0xFF : 0x00;
- memset(y_plane, color, surface.width);
- y_plane += surface.strides[VideoSurface::kYPlane];
- }
- uint8* u_plane = surface.data[VideoSurface::kUPlane];
- uint8* v_plane = surface.data[VideoSurface::kVPlane];
- for (size_t row = 0; row < surface.height; row += 2) {
- memset(u_plane, 0x80, surface.width / 2);
- memset(v_plane, 0x80, surface.width / 2);
- u_plane += surface.strides[VideoSurface::kUPlane];
- v_plane += surface.strides[VideoSurface::kVPlane];
- }
- frame->Unlock();
- }
- }
-
- explicit MockVideoDecoder(const MockFilterConfig* config)
- : config_(config) {
- media_format_.SetAsString(MediaFormat::kMimeType,
- config->uncompressed_video_mime_type);
- media_format_.SetAsInteger(MediaFormat::kWidth, config->video_width);
- media_format_.SetAsInteger(MediaFormat::kHeight, config->video_height);
- }
-
- // Implementation of MediaFilter.
- virtual void Stop() {}
-
- virtual void Seek(base::TimeDelta time) {
- seek_time_ = time;
- }
-
- // Implementation of VideoDecoder.
- virtual bool Initialize(DemuxerStream* stream) {
- host()->InitializationComplete();
- return true;
- }
-
- virtual const MediaFormat& media_format() {
- return media_format_;
- }
-
- virtual void Read(Callback1<VideoFrame*>::Type* callback) {
- DoRead(callback);
- }
-
- // Mock accessors.
- const base::TimeDelta& seek_time() const { return seek_time_; }
-
- private:
- virtual ~MockVideoDecoder() {}
-
- void DoRead(Callback1<VideoFrame*>::Type* callback) {
- scoped_ptr<Callback1<VideoFrame*>::Type> scoped_callback(callback);
- if (mock_frame_time_ < config_->media_duration) {
- // TODO(ralphl): Mock video decoder only works with YV12. Implement other
- // formats as needed.
- EXPECT_EQ(config_->video_surface_format, VideoSurface::YV12);
- scoped_refptr<VideoFrame> frame;
- VideoFrameImpl::CreateFrame(config_->video_surface_format,
- config_->video_width,
- config_->video_height,
- mock_frame_time_,
- config_->frame_duration,
- &frame);
- if (!frame) {
- host()->Error(PIPELINE_ERROR_OUT_OF_MEMORY);
- ADD_FAILURE();
- } else {
- mock_frame_time_ += config_->frame_duration;
- if (mock_frame_time_ >= config_->media_duration) {
- VideoFrameImpl::CreateEmptyFrame(&frame);
- } else {
- InitializeYV12Frame(frame, (mock_frame_time_.InSecondsF() /
- config_->media_duration.InSecondsF()));
- }
- callback->Run(frame);
- }
- }
- }
-
- MediaFormat media_format_;
- base::TimeDelta mock_frame_time_;
- base::TimeDelta seek_time_;
- const MockFilterConfig* config_;
-
- DISALLOW_COPY_AND_ASSIGN(MockVideoDecoder);
-};
-
-
-class MockVideoRenderer : public VideoRenderer {
- public:
- explicit MockVideoRenderer(const MockFilterConfig* config)
- : config_(config) {
- }
-
- // Implementation of MediaFilter.
- virtual void Stop() {}
-
- virtual void Seek(base::TimeDelta time) {
- seek_time_ = time;
- }
-
- // Implementation of VideoRenderer.
- virtual bool Initialize(VideoDecoder* decoder) {
- host()->SetVideoSize(config_->video_width, config_->video_height);
- host()->InitializationComplete();
- return true;
- }
-
- // Mock accessors.
- const base::TimeDelta& seek_time() const { return seek_time_; }
-
- private:
- virtual ~MockVideoRenderer() {}
-
- base::TimeDelta seek_time_;
- const MockFilterConfig* config_;
-
- DISALLOW_COPY_AND_ASSIGN(MockVideoRenderer);
-};
-
-
-// FilterFactory capable of creating each mock filter type. Only one instance
-// of each filter type can exist at any time. Filters can be inspected for
-// expectations using the accessors, which may return NULL if the filter was
-// never created (i.e., streams containing no video).
-class MockFilterFactory : public FilterFactory {
- public:
- explicit MockFilterFactory(const MockFilterConfig* config)
- : config_(config) {
- }
-
- // Mock accessors.
- MockDataSource* data_source() const { return data_source_; }
- MockDemuxer* demuxer() const { return demuxer_; }
- MockAudioDecoder* audio_decoder() const { return audio_decoder_; }
- MockVideoDecoder* video_decoder() const { return video_decoder_; }
- MockAudioRenderer* audio_renderer() const { return audio_renderer_; }
- MockVideoRenderer* video_renderer() const { return video_renderer_; }
-
- protected:
- MediaFilter* Create(FilterType filter_type, const MediaFormat& media_format) {
- if (!config_->create_filter)
- return NULL;
-
- switch (filter_type) {
- case FILTER_DATA_SOURCE:
- DCHECK(!data_source_);
- data_source_ = new MockDataSource(config_);
- return data_source_;
-
- case FILTER_DEMUXER:
- DCHECK(!demuxer_);
- demuxer_ = new MockDemuxer(config_);
- return demuxer_;
-
- case FILTER_AUDIO_DECODER:
- DCHECK(!audio_decoder_);
- audio_decoder_ = new MockAudioDecoder(config_);
- return audio_decoder_;
-
- case FILTER_VIDEO_DECODER:
- DCHECK(!video_decoder_);
- video_decoder_ = new MockVideoDecoder(config_);
- return video_decoder_;
-
- case FILTER_AUDIO_RENDERER:
- DCHECK(!audio_renderer_);
- audio_renderer_ = new MockAudioRenderer(config_);
- return audio_renderer_;
-
- case FILTER_VIDEO_RENDERER:
- DCHECK(!video_renderer_);
- video_renderer_ = new MockVideoRenderer(config_);
- return video_renderer_;
-
- default:
- NOTREACHED();
- }
- return NULL;
- }
-
- private:
- const MockFilterConfig* config_;
- scoped_refptr<MockDataSource> data_source_;
- scoped_refptr<MockDemuxer> demuxer_;
- scoped_refptr<MockAudioDecoder> audio_decoder_;
- scoped_refptr<MockVideoDecoder> video_decoder_;
- scoped_refptr<MockAudioRenderer> audio_renderer_;
- scoped_refptr<MockVideoRenderer> video_renderer_;
-
- DISALLOW_COPY_AND_ASSIGN(MockFilterFactory);
-};
-
-// A simple class that waits for a pipeline to be started and checks some
-// basic initialization values. The Start() method will not return until
-// either a pre-determined amount of time has passed or the pipeline calls the
-// InitCallback() callback. A typical use would be:
-// Pipeline p;
-// FilterFactoryCollection f;
-// f->AddFactory(a);
-// f->AddFactory(b);
-// ...
-// InitializationHelper h;
-// h.Start(&p, f, uri);
-//
-// If the test is expecting to produce an error use would be:
-// h.Start(&p, f, uri, PIPELINE_ERROR_REQUIRED_FILTER_MISSING)
-//
-// If the test expects the pipeline to hang during initialization (a filter
-// never calls FilterHost::InitializationComplete()) then the use would be:
-// h.Start(&p, f, uri, PIPELINE_OK, true);
-//
-// TODO(scherkus): Keep refactoring tests until we can remove this entirely.
-class InitializationHelper {
- public:
- InitializationHelper()
- : event_(true, false),
- callback_success_status_(false),
- waiting_for_callback_(false) {}
-
- // If callback has been called, then returns the boolean passed by the
- // pipeline to the callback.
- bool callback_success_status() { return callback_success_status_; }
-
- // Returns true if Start has been called, but the pipeline has not yet
- // called the initialization complete callback.
- bool waiting_for_callback() { return waiting_for_callback_; }
-
- // Starts the pipeline, providing an initialization callback that points
- // to this object.
- void Start(Pipeline* pipeline,
- FilterFactory* filter_factory,
- const std::string& uri,
- PipelineError expect_error = PIPELINE_OK,
- bool expect_hang = false) {
- // For tests that we expect to hang in initialization, we want to
- // wait a short time. If a hang is not expected, then wait long enough
- // to make sure that the filters have time to initalize. 1/2 second if
- // we expect to hang, and 3 seconds if we expect success.
- base::TimeDelta max_wait = base::TimeDelta::FromMilliseconds(expect_hang ?
- 500 : 3000);
- EXPECT_FALSE(waiting_for_callback_);
- waiting_for_callback_ = true;
- callback_success_status_ = false;
- event_.Reset();
- pipeline->Start(filter_factory, uri,
- NewCallback(this, &InitializationHelper::InitCallback));
- bool signaled = event_.TimedWait(max_wait);
- if (expect_hang) {
- EXPECT_FALSE(signaled);
- EXPECT_FALSE(pipeline->IsInitialized());
- EXPECT_TRUE(waiting_for_callback_);
- } else {
- EXPECT_TRUE(signaled);
- EXPECT_FALSE(waiting_for_callback_);
- EXPECT_EQ(pipeline->GetError(), expect_error);
- EXPECT_EQ(callback_success_status_, (expect_error == PIPELINE_OK));
- EXPECT_EQ(pipeline->IsInitialized(), (expect_error == PIPELINE_OK));
- }
- }
-
- private:
- void InitCallback(bool success) {
- EXPECT_TRUE(waiting_for_callback_);
- EXPECT_FALSE(event_.IsSignaled());
- waiting_for_callback_ = false;
- callback_success_status_ = success;
- event_.Signal();
- }
-
- base::WaitableEvent event_;
- bool callback_success_status_;
- bool waiting_for_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(InitializationHelper);
-};
-
-} // namespace old_mocks
-
-} // namespace media
-
-#endif // MEDIA_BASE_MOCK_MEDIA_FILTERS_H_
diff --git a/media/base/pipeline_impl_unittest.cc b/media/base/pipeline_impl_unittest.cc
index 56aa246..4183126 100644
--- a/media/base/pipeline_impl_unittest.cc
+++ b/media/base/pipeline_impl_unittest.cc
@@ -10,34 +10,38 @@
#include "media/base/filters.h"
#include "media/base/factory.h"
#include "media/base/filter_host.h"
-#include "media/base/mock_media_filters.h"
+#include "media/base/mock_filters.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace {
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::StrictMock;
-class PipelineImplTest : public testing::Test {
- protected:
+namespace media {
+
+typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector;
+
+class PipelineImplTest : public ::testing::Test {
+ public:
PipelineImplTest()
- : initialize_result_(false),
+ : mocks_(new MockFilterFactory()),
+ initialize_result_(false),
seek_result_(false),
initialize_event_(false, false),
seek_event_(false, false) {
}
- virtual ~PipelineImplTest() {}
-
- virtual void TearDown() {
+ virtual ~PipelineImplTest() {
// Force the pipeline to shut down its thread.
pipeline_.Stop();
}
+ protected:
// Called by tests after they have finished setting up MockFilterConfig.
// Initializes the pipeline and returns true if the initialization callback
// was executed, false otherwise.
bool InitializeAndWait() {
- DCHECK(!filters_);
- filters_ = new media::old_mocks::MockFilterFactory(&config_);
- pipeline_.Start(filters_, "",
+ pipeline_.Start(mocks_, "",
NewCallback(this, &PipelineImplTest::OnInitialize));
return initialize_event_.TimedWait(base::TimeDelta::FromMilliseconds(500));
}
@@ -49,10 +53,66 @@ class PipelineImplTest : public testing::Test {
return seek_event_.TimedWait(base::TimeDelta::FromMilliseconds(500));
}
+ // Sets up expectations to allow the data source to initialize.
+ void InitializeDataSource() {
+ EXPECT_CALL(*mocks_->data_source(), Initialize(""))
+ .WillOnce(DoAll(InitializationComplete(mocks_->data_source()),
+ Return(true)));
+ EXPECT_CALL(*mocks_->data_source(), Stop());
+ }
+
+ // Sets up expectations to allow the demuxer to initialize.
+ void InitializeDemuxer(MockDemuxerStreamVector* streams) {
+ EXPECT_CALL(*mocks_->demuxer(), Initialize(mocks_->data_source()))
+ .WillOnce(DoAll(InitializationComplete(mocks_->demuxer()),
+ Return(true)));
+ EXPECT_CALL(*mocks_->demuxer(), GetNumberOfStreams())
+ .WillRepeatedly(Return(streams->size()));
+ EXPECT_CALL(*mocks_->demuxer(), Stop());
+
+ // Configure the demuxer to return the streams.
+ for (size_t i = 0; i < streams->size(); ++i) {
+ scoped_refptr<DemuxerStream> stream = (*streams)[i];
+ EXPECT_CALL(*mocks_->demuxer(), GetStream(i))
+ .WillRepeatedly(Return(stream));
+ }
+ }
+
+ // Sets up expectations to allow the video decoder to initialize.
+ void InitializeVideoDecoder(MockDemuxerStream* stream) {
+ EXPECT_CALL(*mocks_->video_decoder(), Initialize(stream))
+ .WillOnce(DoAll(InitializationComplete(mocks_->video_decoder()),
+ Return(true)));
+ EXPECT_CALL(*mocks_->video_decoder(), Stop());
+ }
+
+ // Sets up expectations to allow the audio decoder to initialize.
+ void InitializeAudioDecoder(MockDemuxerStream* stream) {
+ EXPECT_CALL(*mocks_->audio_decoder(), Initialize(stream))
+ .WillOnce(DoAll(InitializationComplete(mocks_->audio_decoder()),
+ Return(true)));
+ EXPECT_CALL(*mocks_->audio_decoder(), Stop());
+ }
+
+ // Sets up expectations to allow the video renderer to initialize.
+ void InitializeVideoRenderer() {
+ EXPECT_CALL(*mocks_->video_renderer(), Initialize(mocks_->video_decoder()))
+ .WillOnce(DoAll(InitializationComplete(mocks_->video_renderer()),
+ Return(true)));
+ EXPECT_CALL(*mocks_->video_renderer(), Stop());
+ }
+
+ // Sets up expectations to allow the audio renderer to initialize.
+ void InitializeAudioRenderer() {
+ EXPECT_CALL(*mocks_->audio_renderer(), Initialize(mocks_->audio_decoder()))
+ .WillOnce(DoAll(InitializationComplete(mocks_->audio_renderer()),
+ Return(true)));
+ EXPECT_CALL(*mocks_->audio_renderer(), Stop());
+ }
+
// Fixture members.
media::PipelineImpl pipeline_;
- scoped_refptr<media::old_mocks::MockFilterFactory> filters_;
- media::old_mocks::MockFilterConfig config_;
+ scoped_refptr<media::MockFilterFactory> mocks_;
bool initialize_result_;
bool seek_result_;
@@ -75,7 +135,9 @@ class PipelineImplTest : public testing::Test {
};
TEST_F(PipelineImplTest, NeverInitializes) {
- config_.data_source_behavior = media::old_mocks::MOCK_DATA_SOURCE_NEVER_INIT;
+ EXPECT_CALL(*mocks_->data_source(), Initialize(""))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mocks_->data_source(), Stop());
// This test hangs during initialization by never calling
// InitializationComplete(). Make sure we tear down the pipeline properly.
@@ -86,7 +148,7 @@ TEST_F(PipelineImplTest, NeverInitializes) {
}
TEST_F(PipelineImplTest, RequiredFilterMissing) {
- config_.create_filter = false;
+ mocks_->set_creation_successful(false);
ASSERT_TRUE(InitializeAndWait());
EXPECT_FALSE(initialize_result_);
@@ -96,8 +158,11 @@ TEST_F(PipelineImplTest, RequiredFilterMissing) {
}
TEST_F(PipelineImplTest, URLNotFound) {
- config_.data_source_behavior =
- media::old_mocks::MOCK_DATA_SOURCE_URL_ERROR_IN_INIT;
+ EXPECT_CALL(*mocks_->data_source(), Initialize(""))
+ .WillOnce(DoAll(Error(mocks_->data_source(),
+ PIPELINE_ERROR_URL_NOT_FOUND),
+ Return(false)));
+ EXPECT_CALL(*mocks_->data_source(), Stop());
ASSERT_TRUE(InitializeAndWait());
EXPECT_FALSE(initialize_result_);
@@ -106,117 +171,128 @@ TEST_F(PipelineImplTest, URLNotFound) {
}
TEST_F(PipelineImplTest, NoStreams) {
- config_.has_audio = false;
- config_.has_video = false;
+ MockDemuxerStreamVector streams;
+ InitializeDataSource();
+ InitializeDemuxer(&streams);
ASSERT_TRUE(InitializeAndWait());
EXPECT_FALSE(initialize_result_);
EXPECT_FALSE(pipeline_.IsInitialized());
EXPECT_EQ(media::PIPELINE_ERROR_COULD_NOT_RENDER, pipeline_.GetError());
-
- EXPECT_FALSE(filters_->audio_decoder());
- EXPECT_FALSE(filters_->audio_renderer());
- EXPECT_FALSE(filters_->video_decoder());
- EXPECT_FALSE(filters_->video_renderer());
}
TEST_F(PipelineImplTest, AudioStream) {
- config_.has_video = false;
+ scoped_refptr<StrictMock<MockDemuxerStream> > stream =
+ new StrictMock<MockDemuxerStream>("audio/x-foo");
+ MockDemuxerStreamVector streams;
+ streams.push_back(stream);
+
+ InitializeDataSource();
+ InitializeDemuxer(&streams);
+ InitializeAudioDecoder(stream);
+ InitializeAudioRenderer();
ASSERT_TRUE(InitializeAndWait());
EXPECT_TRUE(initialize_result_);
EXPECT_TRUE(pipeline_.IsInitialized());
EXPECT_EQ(media::PIPELINE_OK, pipeline_.GetError());
-
- size_t width, height;
- pipeline_.GetVideoSize(&width, &height);
- EXPECT_EQ(0u, width);
- EXPECT_EQ(0u, height);
EXPECT_TRUE(pipeline_.IsRendered(media::mime_type::kMajorTypeAudio));
EXPECT_FALSE(pipeline_.IsRendered(media::mime_type::kMajorTypeVideo));
-
- EXPECT_TRUE(filters_->audio_decoder());
- EXPECT_TRUE(filters_->audio_renderer());
- EXPECT_FALSE(filters_->video_decoder());
- EXPECT_FALSE(filters_->video_renderer());
}
TEST_F(PipelineImplTest, VideoStream) {
- config_.has_audio = false;
+ scoped_refptr<StrictMock<MockDemuxerStream> > stream =
+ new StrictMock<MockDemuxerStream>("video/x-foo");
+ MockDemuxerStreamVector streams;
+ streams.push_back(stream);
+
+ InitializeDataSource();
+ InitializeDemuxer(&streams);
+ InitializeVideoDecoder(stream);
+ InitializeVideoRenderer();
ASSERT_TRUE(InitializeAndWait());
EXPECT_TRUE(initialize_result_);
EXPECT_TRUE(pipeline_.IsInitialized());
EXPECT_EQ(media::PIPELINE_OK, pipeline_.GetError());
-
- size_t width, height;
- pipeline_.GetVideoSize(&width, &height);
- EXPECT_EQ(config_.video_width, width);
- EXPECT_EQ(config_.video_height, height);
EXPECT_FALSE(pipeline_.IsRendered(media::mime_type::kMajorTypeAudio));
EXPECT_TRUE(pipeline_.IsRendered(media::mime_type::kMajorTypeVideo));
-
- EXPECT_FALSE(filters_->audio_decoder());
- EXPECT_FALSE(filters_->audio_renderer());
- EXPECT_TRUE(filters_->video_decoder());
- EXPECT_TRUE(filters_->video_renderer());
}
TEST_F(PipelineImplTest, AudioVideoStream) {
+ scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream =
+ new StrictMock<MockDemuxerStream>("audio/x-foo");
+ scoped_refptr<StrictMock<MockDemuxerStream> > video_stream =
+ new StrictMock<MockDemuxerStream>("video/x-foo");
+ MockDemuxerStreamVector streams;
+ streams.push_back(audio_stream);
+ streams.push_back(video_stream);
+
+ InitializeDataSource();
+ InitializeDemuxer(&streams);
+ InitializeAudioDecoder(audio_stream);
+ InitializeAudioRenderer();
+ InitializeVideoDecoder(video_stream);
+ InitializeVideoRenderer();
+
ASSERT_TRUE(InitializeAndWait());
EXPECT_TRUE(initialize_result_);
EXPECT_TRUE(pipeline_.IsInitialized());
EXPECT_EQ(media::PIPELINE_OK, pipeline_.GetError());
-
- size_t width, height;
- pipeline_.GetVideoSize(&width, &height);
- EXPECT_EQ(config_.video_width, width);
- EXPECT_EQ(config_.video_height, height);
EXPECT_TRUE(pipeline_.IsRendered(media::mime_type::kMajorTypeAudio));
EXPECT_TRUE(pipeline_.IsRendered(media::mime_type::kMajorTypeVideo));
-
- EXPECT_TRUE(filters_->audio_decoder());
- EXPECT_TRUE(filters_->audio_renderer());
- EXPECT_TRUE(filters_->video_decoder());
- EXPECT_TRUE(filters_->video_renderer());
}
TEST_F(PipelineImplTest, Seek) {
- ASSERT_TRUE(InitializeAndWait());
-
- // Seek and verify callback returned true.
+ scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream =
+ new StrictMock<MockDemuxerStream>("audio/x-foo");
+ scoped_refptr<StrictMock<MockDemuxerStream> > video_stream =
+ new StrictMock<MockDemuxerStream>("video/x-foo");
+ MockDemuxerStreamVector streams;
+ streams.push_back(audio_stream);
+ streams.push_back(video_stream);
+
+ InitializeDataSource();
+ InitializeDemuxer(&streams);
+ InitializeAudioDecoder(audio_stream);
+ InitializeAudioRenderer();
+ InitializeVideoDecoder(video_stream);
+ InitializeVideoRenderer();
+
+ // Every filter should receive a call to Seek().
base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
+ EXPECT_CALL(*mocks_->data_source(), Seek(expected));
+ EXPECT_CALL(*mocks_->demuxer(), Seek(expected));
+ EXPECT_CALL(*mocks_->audio_decoder(), Seek(expected));
+ EXPECT_CALL(*mocks_->audio_renderer(), Seek(expected));
+ EXPECT_CALL(*mocks_->video_decoder(), Seek(expected));
+ EXPECT_CALL(*mocks_->video_renderer(), Seek(expected));
+
+ // Initialize then seek!
+ ASSERT_TRUE(InitializeAndWait());
EXPECT_TRUE(SeekAndWait(expected));
EXPECT_TRUE(seek_result_);
-
- // Verify every filter received the seek.
- // TODO(scherkus): implement whatever it takes so I can use EXPECT_EQ with
- // base::TimeDelta.
- EXPECT_TRUE(expected == filters_->data_source()->seek_time());
- EXPECT_TRUE(expected == filters_->demuxer()->seek_time());
- EXPECT_TRUE(expected == filters_->audio_decoder()->seek_time());
- EXPECT_TRUE(expected == filters_->audio_renderer()->seek_time());
- EXPECT_TRUE(expected == filters_->video_decoder()->seek_time());
- EXPECT_TRUE(expected == filters_->video_renderer()->seek_time());
}
-// Try to execute Start()/Stop() on the Pipeline many times and very fast. This
-// test is trying to simulate the situation where the pipeline can get dead
-// locked very easily by quickly calling Start()/Stop().
-TEST_F(PipelineImplTest, StressTestPipelineStartStop) {
- media::old_mocks::MockFilterConfig config;
- const int kTimes = 1000;
- for (int i = 0; i < kTimes; ++i) {
- scoped_refptr<media::old_mocks::MockFilterFactory> factory =
- new media::old_mocks::MockFilterFactory(&config);
- media::PipelineImpl pipeline;
- pipeline.Start(factory.get(), "", NULL);
- pipeline.Stop();
- }
+TEST_F(PipelineImplTest, SetVolume) {
+ scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream =
+ new StrictMock<MockDemuxerStream>("audio/x-foo");
+ MockDemuxerStreamVector streams;
+ streams.push_back(audio_stream);
+
+ InitializeDataSource();
+ InitializeDemuxer(&streams);
+ InitializeAudioDecoder(audio_stream);
+ InitializeAudioRenderer();
+
+ // The audio renderer should receive a call to SetVolume().
+ float expected = 0.5f;
+ EXPECT_CALL(*mocks_->audio_renderer(), SetVolume(expected));
+
+ // Initialize then set volume!
+ ASSERT_TRUE(InitializeAndWait());
+ pipeline_.SetVolume(expected);
}
-// TODO(ralphl): Add a unit test that makes sure that the mock audio filter
-// is actually called on a SetVolume() call to the pipeline. I almost checked
-// in code that broke this, but all unit tests were passing.
+} // namespace media
-} // namespace
diff --git a/media/base/video_frame_impl_unittest.cc b/media/base/video_frame_impl_unittest.cc
index a6a1a6a..eeec716 100644
--- a/media/base/video_frame_impl_unittest.cc
+++ b/media/base/video_frame_impl_unittest.cc
@@ -3,15 +3,40 @@
// found in the LICENSE file.
#include "media/base/buffers.h"
-#include "media/base/mock_media_filters.h"
+#include "media/base/mock_filters.h"
#include "media/base/video_frame_impl.h"
#include "media/base/yuv_convert.h"
#include "testing/gtest/include/gtest/gtest.h"
-using media::VideoFrameImpl;
-using media::VideoSurface;
+namespace media {
-namespace {
+// Helper function that initializes a YV12 frame with white and black scan
+// lines based on the |white_to_black| parameter. If 0, then the entire
+// frame will be black, if 1 then the entire frame will be white.
+void InitializeYV12Frame(VideoFrame* frame, double white_to_black) {
+ VideoSurface surface;
+ if (!frame->Lock(&surface)) {
+ ADD_FAILURE();
+ return;
+ }
+ EXPECT_EQ(surface.format, VideoSurface::YV12);
+ size_t first_black_row = static_cast<size_t>(surface.height * white_to_black);
+ uint8* y_plane = surface.data[VideoSurface::kYPlane];
+ for (size_t row = 0; row < surface.height; ++row) {
+ int color = (row < first_black_row) ? 0xFF : 0x00;
+ memset(y_plane, color, surface.width);
+ y_plane += surface.strides[VideoSurface::kYPlane];
+ }
+ uint8* u_plane = surface.data[VideoSurface::kUPlane];
+ uint8* v_plane = surface.data[VideoSurface::kVPlane];
+ for (size_t row = 0; row < surface.height; row += 2) {
+ memset(u_plane, 0x80, surface.width / 2);
+ memset(v_plane, 0x80, surface.width / 2);
+ u_plane += surface.strides[VideoSurface::kUPlane];
+ v_plane += surface.strides[VideoSurface::kVPlane];
+ }
+ frame->Unlock();
+}
// Given a |yv12_frame| this method converts the YV12 frame to RGBA and
// makes sure that all the pixels of the RBG frame equal |expect_rgb_color|.
@@ -65,10 +90,7 @@ void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) {
yv12_frame->Unlock();
}
-} // namespace
-
-
-TEST(VideoFrameImpl, Basic) {
+TEST(VideoFrameImpl, CreateFrame) {
const size_t kWidth = 64;
const size_t kHeight = 48;
const base::TimeDelta kTimestampA = base::TimeDelta::FromMicroseconds(1337);
@@ -78,8 +100,8 @@ TEST(VideoFrameImpl, Basic) {
// Create a YV12 Video Frame.
scoped_refptr<media::VideoFrame> frame;
- media::VideoFrameImpl::CreateFrame(media::VideoSurface::YV12, kWidth, kHeight,
- kTimestampA, kDurationA, &frame);
+ VideoFrameImpl::CreateFrame(media::VideoSurface::YV12, kWidth, kHeight,
+ kTimestampA, kDurationA, &frame);
ASSERT_TRUE(frame);
// Test StreamSample implementation.
@@ -98,12 +120,14 @@ TEST(VideoFrameImpl, Basic) {
EXPECT_FALSE(frame->IsDiscontinuous());
// Test VideoFrame implementation.
- media::old_mocks::MockVideoDecoder::InitializeYV12Frame(frame, 0.0f);
+ InitializeYV12Frame(frame, 0.0f);
ExpectFrameColor(frame, 0xFF000000);
- media::old_mocks::MockVideoDecoder::InitializeYV12Frame(frame, 1.0f);
+ InitializeYV12Frame(frame, 1.0f);
ExpectFrameColor(frame, 0xFFFFFFFF);
// Test an empty frame.
- media::VideoFrameImpl::CreateEmptyFrame(&frame);
+ VideoFrameImpl::CreateEmptyFrame(&frame);
EXPECT_TRUE(frame->IsEndOfStream());
}
+
+} // namespace media