Index: media/base/mock_media_filters.h |
=================================================================== |
--- media/base/mock_media_filters.h (revision 9872) |
+++ media/base/mock_media_filters.h (working copy) |
@@ -7,6 +7,8 @@ |
#include <string> |
+#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" |
@@ -17,20 +19,60 @@ |
namespace media { |
// Behaviors for MockDataSource filter. |
-enum MockBehavior { |
- MOCK_FILTER_NORMAL_INIT, |
- MOCK_FILTER_NEVER_INIT, |
- MOCK_FILTER_TASK_INIT, |
- MOCK_FILTER_ERROR_IN_INIT, |
- MOCK_FILTER_INIT_RETURN_FALSE, |
- MOCK_FILTER_TASK_ERROR_PRE_INIT, |
- MOCK_FILTER_TASK_ERROR_POST_INIT |
+enum MockDataSourceBehavior { |
+ MOCK_DATA_SOURCE_NORMAL_INIT, |
+ MOCK_DATA_SOURCE_NEVER_INIT, |
+ MOCK_DATA_SOURCE_TASK_INIT, |
+ MOCK_DATA_SOURCE_ERROR_IN_INIT, |
+ MOCK_DATA_SOURCE_INIT_RETURN_FALSE, |
+ MOCK_DATA_SOURCE_TASK_ERROR_PRE_INIT, |
+ MOCK_DATA_SOURCE_TASK_ERROR_POST_INIT |
}; |
+ |
+// 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() |
+ : data_source_behavior(MOCK_DATA_SOURCE_NORMAL_INIT), |
+ video_width(1280u), |
+ video_height(720u), |
+ video_surface_format(VideoSurface::YV12), |
+ 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)) { |
+ } |
+ |
+ void set_no_video() { |
+ video_width = 0; |
+ video_height = 0; |
+ } |
+ |
+ bool has_video() const { |
+ return video_width > 0; |
+ } |
+ |
+ MockDataSourceBehavior data_source_behavior; |
+ size_t video_width; |
+ size_t video_height; |
+ VideoSurface::Format video_surface_format; |
+ 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; |
+}; |
+ |
+ |
class MockDataSource : public media::DataSource { |
public: |
- static FilterFactory* CreateFactory(MockBehavior behavior) { |
- return new FilterFactoryImpl1<MockDataSource, MockBehavior>(behavior); |
+ static FilterFactory* CreateFactory(const MockFilterConfig* config) { |
+ return new FilterFactoryImpl1<MockDataSource, |
+ const MockFilterConfig*>(config); |
} |
// Implementation of MediaFilter. |
@@ -42,22 +84,22 @@ |
mime_type::kApplicationOctetStream); |
media_format_.SetAsString(MediaFormat::kURL, url); |
switch (behavior_) { |
- case MOCK_FILTER_NORMAL_INIT: |
+ case MOCK_DATA_SOURCE_NORMAL_INIT: |
host_->InitializationComplete(); |
return true; |
- case MOCK_FILTER_NEVER_INIT: |
+ case MOCK_DATA_SOURCE_NEVER_INIT: |
return true; |
- case MOCK_FILTER_TASK_ERROR_POST_INIT: |
+ case MOCK_DATA_SOURCE_TASK_ERROR_POST_INIT: |
host_->InitializationComplete(); |
// Yes, we want to fall through to schedule the task... |
- case MOCK_FILTER_TASK_ERROR_PRE_INIT: |
- case MOCK_FILTER_TASK_INIT: |
+ case MOCK_DATA_SOURCE_TASK_ERROR_PRE_INIT: |
+ case MOCK_DATA_SOURCE_TASK_INIT: |
host_->PostTask(NewRunnableMethod(this, &MockDataSource::TaskBehavior)); |
return true; |
- case MOCK_FILTER_ERROR_IN_INIT: |
+ case MOCK_DATA_SOURCE_ERROR_IN_INIT: |
host_->Error(PIPELINE_ERROR_NETWORK); |
return false; |
- case MOCK_FILTER_INIT_RETURN_FALSE: |
+ case MOCK_DATA_SOURCE_INIT_RETURN_FALSE: |
return false; |
default: |
NOTREACHED(); |
@@ -88,19 +130,22 @@ |
} |
private: |
- friend class media::FilterFactoryImpl1<MockDataSource, MockBehavior>; |
+ friend class media::FilterFactoryImpl1<MockDataSource, |
+ const MockFilterConfig*>; |
- explicit MockDataSource(MockBehavior behavior) : behavior_(behavior) {} |
+ explicit MockDataSource(const MockFilterConfig* config) |
+ : behavior_(config->data_source_behavior) { |
+ } |
virtual ~MockDataSource() {} |
void TaskBehavior() { |
switch (behavior_) { |
- case MOCK_FILTER_TASK_ERROR_POST_INIT: |
- case MOCK_FILTER_TASK_ERROR_PRE_INIT: |
+ case MOCK_DATA_SOURCE_TASK_ERROR_POST_INIT: |
+ case MOCK_DATA_SOURCE_TASK_ERROR_PRE_INIT: |
host_->Error(PIPELINE_ERROR_NETWORK); |
break; |
- case MOCK_FILTER_TASK_INIT: |
+ case MOCK_DATA_SOURCE_TASK_INIT: |
host_->InitializationComplete(); |
break; |
default: |
@@ -108,7 +153,7 @@ |
} |
} |
- MockBehavior behavior_; |
+ MockDataSourceBehavior behavior_; |
MediaFormat media_format_; |
DISALLOW_COPY_AND_ASSIGN(MockDataSource); |
@@ -118,8 +163,9 @@ |
class MockDemuxer : public Demuxer { |
public: |
- static FilterFactory* CreateFactory() { |
- return new FilterFactoryImpl0<MockDemuxer>(); |
+ static FilterFactory* CreateFactory(const MockFilterConfig* config) { |
+ return new FilterFactoryImpl1<MockDemuxer, |
+ const MockFilterConfig*>(config); |
} |
// Implementation of MediaFilter. |
@@ -132,27 +178,43 @@ |
} |
virtual size_t GetNumberOfStreams() { |
+ if (config_->has_video()) { |
+ return 2; |
+ } |
return 1; |
} |
virtual media::DemuxerStream* GetStream(int stream_id) { |
- EXPECT_EQ(stream_id, 0); |
- return &mock_demuxer_stream_; |
+ switch (stream_id) { |
+ case 0: |
+ return &mock_audio_stream_; |
+ case 1: |
+ if (config_->has_video()) { |
+ return &mock_video_stream_; |
+ } |
+ // Fall-through is correct if no video. |
+ default: |
+ ADD_FAILURE(); |
+ return NULL; |
+ } |
} |
private: |
- friend class media::FilterFactoryImpl0<MockDemuxer>; |
+ friend class media::FilterFactoryImpl1<MockDemuxer, const MockFilterConfig*>; |
- MockDemuxer() {} |
+ explicit MockDemuxer(const MockFilterConfig* config) |
+ : config_(config), |
+ mock_audio_stream_(config->compressed_audio_mime_type), |
+ mock_video_stream_(config->compressed_video_mime_type) { |
+ } |
virtual ~MockDemuxer() {} |
// Internal class implements DemuxerStream interface. |
class MockDemuxerStream : public DemuxerStream { |
public: |
- MockDemuxerStream() { |
- media_format_.SetAsString(MediaFormat::kMimeType, |
- media::mime_type::kUncompressedAudio); |
+ explicit MockDemuxerStream(const std::string& mime_type) { |
+ media_format_.SetAsString(MediaFormat::kMimeType, mime_type); |
} |
virtual ~MockDemuxerStream() {} |
@@ -172,7 +234,9 @@ |
DISALLOW_COPY_AND_ASSIGN(MockDemuxerStream); |
}; |
- MockDemuxerStream mock_demuxer_stream_; |
+ const MockFilterConfig* config_; |
+ MockDemuxerStream mock_audio_stream_; |
+ MockDemuxerStream mock_video_stream_; |
DISALLOW_COPY_AND_ASSIGN(MockDemuxer); |
}; |
@@ -181,8 +245,9 @@ |
class MockAudioDecoder : public AudioDecoder { |
public: |
- static FilterFactory* CreateFactory() { |
- return new FilterFactoryImpl0<MockAudioDecoder>(); |
+ static FilterFactory* CreateFactory(const MockFilterConfig* config) { |
+ return new FilterFactoryImpl1<MockAudioDecoder, |
+ const MockFilterConfig*>(config); |
} |
static bool IsMediaFormatSupported(const MediaFormat* media_format) { |
@@ -208,11 +273,12 @@ |
} |
private: |
- friend class media::FilterFactoryImpl0<MockAudioDecoder>; |
+ friend class media::FilterFactoryImpl1<MockAudioDecoder, |
+ const MockFilterConfig*>; |
- MockAudioDecoder() { |
+ explicit MockAudioDecoder(const MockFilterConfig* config) { |
media_format_.SetAsString(MediaFormat::kMimeType, |
- media::mime_type::kUncompressedAudio); |
+ config->uncompressed_audio_mime_type); |
} |
virtual ~MockAudioDecoder() {} |
@@ -226,8 +292,9 @@ |
class MockAudioRenderer : public AudioRenderer { |
public: |
- static FilterFactory* CreateFactory() { |
- return new FilterFactoryImpl0<MockAudioRenderer>(); |
+ static FilterFactory* CreateFactory(const MockFilterConfig* config) { |
+ return new FilterFactoryImpl1<MockAudioRenderer, |
+ const MockFilterConfig*>(config); |
} |
static bool IsMediaFormatSupported(const MediaFormat* media_format) { |
@@ -246,9 +313,10 @@ |
virtual void SetVolume(float volume) {} |
private: |
- friend class media::FilterFactoryImpl0<MockAudioRenderer>; |
+ friend class media::FilterFactoryImpl1<MockAudioRenderer, |
+ const MockFilterConfig*>; |
- MockAudioRenderer() {} |
+ explicit MockAudioRenderer(const MockFilterConfig* config) {} |
virtual ~MockAudioRenderer() {} |
@@ -256,6 +324,165 @@ |
}; |
//------------------------------------------------------------------------------ |
+ |
+class MockVideoFrame : public VideoFrame { |
+ public: |
+ explicit MockVideoFrame(const MockFilterConfig* config, |
+ base::TimeDelta timestamp) |
+ : config_(config), |
+ surface_locked_(false), |
+ timestamp_(timestamp), |
+ duration_(config->frame_duration) { |
+ } |
+ |
+ virtual ~MockVideoFrame() {} |
+ |
+ virtual base::TimeDelta GetTimestamp() const { |
+ return timestamp_; |
+ } |
+ |
+ virtual base::TimeDelta GetDuration() const { |
+ return duration_; |
+ } |
+ |
+ virtual void SetTimestamp(const base::TimeDelta& timestamp) { |
+ timestamp_ = timestamp; |
+ } |
+ |
+ virtual void SetDuration(const base::TimeDelta& duration) { |
+ duration_ = duration; |
+ } |
+ |
+ virtual bool Lock(VideoSurface* surface) { |
+ EXPECT_FALSE(surface_locked_); |
+ surface_locked_ = true; |
+ surface->format = config_->video_surface_format; |
+ surface->width = config_->video_width; |
+ surface->height = config_->video_height; |
+ // TODO(ralphl): mock the data for video surfaces too. |
+ surface->planes = 3; |
+ surface->data[0] = NULL; |
+ surface->data[1] = NULL; |
+ surface->data[2] = NULL; |
+ surface->strides[0] = 0; |
+ surface->strides[1] = 0; |
+ surface->strides[2] = 0; |
+ return false; |
+ } |
+ |
+ virtual void Unlock() { |
+ EXPECT_TRUE(surface_locked_); |
+ surface_locked_ = false; |
+ } |
+ |
+ private: |
+ const MockFilterConfig* config_; |
+ bool surface_locked_; |
+ base::TimeDelta timestamp_; |
+ base::TimeDelta duration_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MockVideoFrame); |
+}; |
+ |
+class MockVideoDecoder : public VideoDecoder { |
+ public: |
+ static FilterFactory* CreateFactory(const MockFilterConfig* config) { |
+ return new FilterFactoryImpl1<MockVideoDecoder, |
+ const MockFilterConfig*>(config); |
+ } |
+ |
+ static bool IsMediaFormatSupported(const MediaFormat* media_format) { |
+ return true; // TODO(ralphl): check for a supported format. |
+ } |
+ |
+ // Implementation of MediaFilter. |
+ virtual void Stop() {} |
+ |
+ // Implementation of VideoDecoder. |
+ virtual bool Initialize(DemuxerStream* stream) { |
+ host_->InitializationComplete(); |
+ return true; |
+ } |
+ |
+ virtual const MediaFormat* GetMediaFormat() { |
+ return &media_format_; |
+ } |
+ |
+ virtual void Read(Assignable<VideoFrame>* buffer) { |
+ buffer->AddRef(); |
+ host_->PostTask(NewRunnableMethod(this, &MockVideoDecoder::DoRead, buffer)); |
+ } |
+ |
+ private: |
+ friend class media::FilterFactoryImpl1<MockVideoDecoder, |
+ const MockFilterConfig*>; |
+ |
+ 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); |
+ } |
+ |
+ void DoRead(Assignable<VideoFrame>* buffer) { |
+ VideoFrame* frame = new MockVideoFrame(config_, mock_frame_time_); |
+ mock_frame_time_ += config_->frame_duration; |
+ buffer->SetBuffer(frame); |
+ buffer->OnAssignment(); |
+ buffer->Release(); |
+ } |
+ |
+ virtual ~MockVideoDecoder() {} |
+ |
+ MediaFormat media_format_; |
+ base::TimeDelta mock_frame_time_; |
+ const MockFilterConfig* config_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MockVideoDecoder); |
+}; |
+ |
+//------------------------------------------------------------------------------ |
+ |
+class MockVideoRenderer : public VideoRenderer { |
+ public: |
+ static FilterFactory* CreateFactory(const MockFilterConfig* config) { |
+ return new FilterFactoryImpl1<MockVideoRenderer, |
+ const MockFilterConfig*>(config); |
+ } |
+ |
+ static bool IsMediaFormatSupported(const MediaFormat* media_format) { |
+ return true; // TODO(ralphl): check for a supported format |
+ } |
+ |
+ // Implementation of MediaFilter. |
+ virtual void Stop() {} |
+ |
+ // Implementation of VideoRenderer. |
+ virtual bool Initialize(VideoDecoder* decoder) { |
+ host_->SetVideoSize(config_->video_width, config_->video_height); |
+ host_->InitializationComplete(); |
+ return true; |
+ } |
+ |
+ private: |
+ friend class media::FilterFactoryImpl1<MockVideoRenderer, |
+ const MockFilterConfig*>; |
+ |
+ explicit MockVideoRenderer(const MockFilterConfig* config) |
+ : config_(config) { |
+ } |
+ |
+ virtual ~MockVideoRenderer() {} |
+ |
+ const MockFilterConfig* config_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(MockVideoRenderer); |
+}; |
+ |
+ |
+ |
+//------------------------------------------------------------------------------ |
// Simple class that derives from the WaitableEvent class. The event remains |
// in the reset state until the initialization complete callback is called from |
// a media pipeline. The normal use of this object looks like: |