summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/base/mock_media_filters.h324
-rw-r--r--media/base/pipeline_impl_unittest.cc118
-rw-r--r--media/build/media_unittests.vcproj4
-rw-r--r--media/media_unittests.scons1
4 files changed, 369 insertions, 78 deletions
diff --git a/media/base/mock_media_filters.h b/media/base/mock_media_filters.h
new file mode 100644
index 0000000..93665d6
--- /dev/null
+++ b/media/base/mock_media_filters.h
@@ -0,0 +1,324 @@
+// 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.
+
+#ifndef MEDIA_BASE_MOCK_MEDIA_FILTERS_H_
+#define MEDIA_BASE_MOCK_MEDIA_FILTERS_H_
+
+#include <string>
+
+#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 "testing/gtest/include/gtest/gtest.h"
+
+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
+};
+
+class MockDataSource : public media::DataSource {
+ public:
+ static FilterFactory* CreateFactory(MockBehavior behavior) {
+ return new FilterFactoryImpl1<MockDataSource, MockBehavior>(behavior);
+ }
+
+ // Implementation of MediaFilter.
+ virtual void Stop() {}
+
+ // Implementation of DataSource.
+ virtual bool Initialize(const std::string& url) {
+ media_format_.SetAsString(MediaFormat::kMimeType,
+ mime_type::kApplicationOctetStream);
+ media_format_.SetAsString(MediaFormat::kURL, url);
+ switch (behavior_) {
+ case MOCK_FILTER_NORMAL_INIT:
+ host_->InitializationComplete();
+ return true;
+ case MOCK_FILTER_NEVER_INIT:
+ return true;
+ case MOCK_FILTER_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:
+ host_->PostTask(NewRunnableMethod(this, &MockDataSource::TaskBehavior));
+ return true;
+ case MOCK_FILTER_ERROR_IN_INIT:
+ host_->Error(PIPELINE_ERROR_NETWORK);
+ return false;
+ case MOCK_FILTER_INIT_RETURN_FALSE:
+ return false;
+ default:
+ NOTREACHED();
+ return false;
+ }
+ }
+
+ virtual const MediaFormat* GetMediaFormat() {
+ return &media_format_;
+ }
+
+ virtual size_t Read(char* data, size_t size) {
+ return 0;
+ }
+
+ virtual bool GetPosition(int64* position_out) {
+ *position_out = 0;
+ return false;
+ }
+
+ virtual bool SetPosition(int64 position) {
+ return true;
+ }
+
+ virtual bool GetSize(int64* size_out) {
+ *size_out = 0;
+ return false;
+ }
+
+ private:
+ friend class media::FilterFactoryImpl1<MockDataSource, MockBehavior>;
+
+ explicit MockDataSource(MockBehavior behavior) : behavior_(behavior) {}
+
+ virtual ~MockDataSource() {}
+
+ void TaskBehavior() {
+ switch (behavior_) {
+ case MOCK_FILTER_TASK_ERROR_POST_INIT:
+ case MOCK_FILTER_TASK_ERROR_PRE_INIT:
+ host_->Error(PIPELINE_ERROR_NETWORK);
+ break;
+ case MOCK_FILTER_TASK_INIT:
+ host_->InitializationComplete();
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ MockBehavior behavior_;
+ MediaFormat media_format_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDataSource);
+};
+
+//------------------------------------------------------------------------------
+
+class MockDemuxer : public Demuxer {
+ public:
+ static FilterFactory* CreateFactory() {
+ return new FilterFactoryImpl0<MockDemuxer>();
+ }
+
+ // Implementation of MediaFilter.
+ virtual void Stop() {}
+
+ // Implementation of Demuxer.
+ virtual bool Initialize(media::DataSource* data_source) {
+ host_->InitializationComplete();
+ return true;
+ }
+
+ virtual size_t GetNumberOfStreams() {
+ return 1;
+ }
+
+ virtual media::DemuxerStream* GetStream(int stream_id) {
+ EXPECT_EQ(stream_id, 0);
+ return &mock_demuxer_stream_;
+ }
+
+ private:
+ friend class media::FilterFactoryImpl0<MockDemuxer>;
+
+ MockDemuxer() {}
+
+ virtual ~MockDemuxer() {}
+
+ // Internal class implements DemuxerStream interface.
+ class MockDemuxerStream : public DemuxerStream {
+ public:
+ MockDemuxerStream() {
+ media_format_.SetAsString(MediaFormat::kMimeType,
+ media::mime_type::kUncompressedAudio);
+ }
+
+ virtual ~MockDemuxerStream() {}
+
+ // Implementation of DemuxerStream.
+ virtual const MediaFormat* GetMediaFormat() {
+ return &media_format_; // TODO(ralphl): implement
+ }
+
+ virtual void Read(Assignable<Buffer>* buffer) {
+ NOTREACHED(); // TODO(ralphl): fix me!!
+ }
+
+ private:
+ MediaFormat media_format_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDemuxerStream);
+ };
+
+ MockDemuxerStream mock_demuxer_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDemuxer);
+};
+
+//------------------------------------------------------------------------------
+
+class MockAudioDecoder : public AudioDecoder {
+ public:
+ static FilterFactory* CreateFactory() {
+ return new FilterFactoryImpl0<MockAudioDecoder>();
+ }
+
+ static bool IsMediaFormatSupported(const MediaFormat* media_format) {
+ return true; // TODO(ralphl): check for a supported format.
+ }
+
+ // Implementation of MediaFilter.
+ virtual void Stop() {}
+
+ // Implementation of AudioDecoder.
+ virtual bool Initialize(DemuxerStream* stream) {
+ host_->InitializationComplete();
+ return true;
+ }
+
+ virtual const MediaFormat* GetMediaFormat() {
+ return &media_format_;
+ }
+
+ virtual void Read(Assignable<Buffer>* buffer) {
+ // TODO(ralphl): implement mock read.
+ NOTREACHED();
+ }
+
+ private:
+ friend class media::FilterFactoryImpl0<MockAudioDecoder>;
+
+ MockAudioDecoder() {
+ media_format_.SetAsString(MediaFormat::kMimeType,
+ media::mime_type::kUncompressedAudio);
+ }
+
+ virtual ~MockAudioDecoder() {}
+
+ MediaFormat media_format_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockAudioDecoder);
+};
+
+//------------------------------------------------------------------------------
+
+class MockAudioRenderer : public AudioRenderer {
+ public:
+ static FilterFactory* CreateFactory() {
+ return new FilterFactoryImpl0<MockAudioRenderer>();
+ }
+
+ static bool IsMediaFormatSupported(const MediaFormat* media_format) {
+ return true; // TODO(ralphl): check for a supported format
+ }
+
+ // Implementation of MediaFilter.
+ virtual void Stop() {}
+
+ // Implementation of AudioRenderer.
+ virtual bool Initialize(AudioDecoder* decoder) {
+ host_->InitializationComplete();
+ return true;
+ }
+
+ virtual void SetVolume(float volume) {}
+
+ private:
+ friend class media::FilterFactoryImpl0<MockAudioRenderer>;
+
+ MockAudioRenderer() {}
+
+ virtual ~MockAudioRenderer() {}
+
+ DISALLOW_COPY_AND_ASSIGN(MockAudioRenderer);
+};
+
+//------------------------------------------------------------------------------
+// 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:
+// Pipeline p;
+// FilterFactoryCollection f;
+// f->AddFactory(a);
+// f->AddFactory(b);
+// ...
+// InitializationHelper h;
+// h.Start(&p, f, uri);
+// h.Wait();
+// (when the Wait() returns, the pipeline is initialized or in error state)
+class InitializationHelper : public base::WaitableEvent {
+ public:
+ InitializationHelper()
+ : WaitableEvent(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 intialization 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) {
+ Reset();
+ waiting_for_callback_ = true;
+ pipeline->Start(filter_factory, uri,
+ NewCallback(this, &InitializationHelper::InitCallback));
+ }
+
+ // Resets the state. This method should not be called if waiting for
+ // a callback from a previous call to Start. Note that the Start method
+ // resets the state, so callers are not required to call this method prior
+ // to calling the start method.
+ void Reset() {
+ EXPECT_FALSE(waiting_for_callback_);
+ base::WaitableEvent::Reset();
+ callback_success_status_ = false;
+ }
+
+ private:
+ void InitCallback(bool success) {
+ EXPECT_TRUE(waiting_for_callback_);
+ EXPECT_FALSE(IsSignaled());
+ waiting_for_callback_ = false;
+ callback_success_status_ = success;
+ Signal();
+ }
+
+ bool callback_success_status_;
+ bool waiting_for_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(InitializationHelper);
+};
+
+} // 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 082f926..53c29ba 100644
--- a/media/base/pipeline_impl_unittest.cc
+++ b/media/base/pipeline_impl_unittest.cc
@@ -12,98 +12,60 @@
#include "media/base/filters.h"
#include "media/base/factory.h"
#include "media/base/filter_host.h"
+#include "media/base/mock_media_filters.h"
#include "testing/gtest/include/gtest/gtest.h"
using media::FilterFactory;
using media::FilterFactoryCollection;
using media::FilterHost;
+using media::InitializationHelper;
using media::MediaFormat;
+using media::MockAudioDecoder;
+using media::MockAudioRenderer;
+using media::MockDataSource;
+using media::MockDemuxer;
using media::PipelineImpl;
-using media::FilterFactoryImpl1;
-class TestDataSource : public media::DataSource {
- public:
- static FilterFactory* CreateFactory(bool hang_in_init) {
- return new FilterFactoryImpl1<TestDataSource, bool>(hang_in_init);
- }
- virtual void Stop() {}
- // This filter will hang in initialization because it never calls
- // FilterHost::InitializationComplete
- virtual bool Initialize(const std::string& uri) {
- if (!hang_in_init_) {
- host_->InitializationComplete();
- }
- return true;
- }
- virtual const MediaFormat* GetMediaFormat() {
- return NULL; // TODO(ralphl): Return octot thingie...
- }
- virtual size_t Read(char* data, size_t size) {
- return 0;
- }
- virtual bool GetPosition(int64* position_out) {
- return 0;
- }
- virtual bool SetPosition(int64 position) {
- return true;
- }
- virtual bool GetSize(int64* size_out) {
- return 0;
- }
-
- protected:
- bool hang_in_init_;
- friend class media::FilterFactoryImpl1<TestDataSource, bool>;
- explicit TestDataSource(bool hang_in_init) : hang_in_init_(hang_in_init) {}
- ~TestDataSource() {}
-
- DISALLOW_COPY_AND_ASSIGN(TestDataSource);
-};
-
-
-class InitWaiter : public base::WaitableEvent {
- public:
- InitWaiter()
- : WaitableEvent(true, false),
- callback_success_status_(false) {}
- void InitializationComplete(bool success) {
- callback_success_status_ = success;
- Signal();
- }
- bool HasBeenCalled() { return IsSignaled(); }
- bool CallbackSuccessStatus() { return callback_success_status_; }
- Callback1<bool>::Type* NewInitCallback() {
- return NewCallback(this, &InitWaiter::InitializationComplete);
- }
- void Reset() {
- base::WaitableEvent::Reset();
- callback_success_status_ = false;
- }
-
- private:
- bool callback_success_status_;
-
- DISALLOW_COPY_AND_ASSIGN(InitWaiter);
-};
-
-
-TEST(PipelineImplTest, Basic) {
- std::string url("test.mov");
+TEST(PipelineImplTest, Initialization) {
+ std::string u("");
PipelineImpl p;
- InitWaiter w;
- p.Start(TestDataSource::CreateFactory(true), url, w.NewInitCallback());
- w.TimedWait(base::TimeDelta::FromSeconds(1));
- EXPECT_FALSE(w.HasBeenCalled());
+ InitializationHelper h;
+ h.Start(&p, MockDataSource::CreateFactory(media::MOCK_FILTER_NEVER_INIT), u);
+ h.TimedWait(base::TimeDelta::FromMilliseconds(300));
+ EXPECT_TRUE(h.waiting_for_callback());
EXPECT_FALSE(p.IsInitialized());
EXPECT_TRUE(media::PIPELINE_OK == p.GetError());
p.Stop();
+ EXPECT_FALSE(h.waiting_for_callback());
+ EXPECT_FALSE(h.callback_success_status());
+ EXPECT_TRUE(media::PIPELINE_OK == p.GetError());
- w.Reset();
- p.Start(TestDataSource::CreateFactory(false), url, w.NewInitCallback());
- w.TimedWait(base::TimeDelta::FromSeconds(1));
- EXPECT_TRUE(w.HasBeenCalled());
- EXPECT_FALSE(w.CallbackSuccessStatus());
+ h.Start(&p, MockDataSource::CreateFactory(media::MOCK_FILTER_TASK_INIT), u);
+ h.TimedWait(base::TimeDelta::FromSeconds(5));
+ EXPECT_FALSE(h.waiting_for_callback());
+ EXPECT_FALSE(h.callback_success_status());
EXPECT_FALSE(p.IsInitialized());
EXPECT_FALSE(media::PIPELINE_OK == p.GetError());
p.Stop();
}
+
+TEST(PipelineImplTest, FullMockPipeline) {
+ std::string url("");
+ PipelineImpl p;
+ scoped_refptr<FilterFactoryCollection> c = new FilterFactoryCollection();
+ c->AddFactory(MockDataSource::CreateFactory(media::MOCK_FILTER_NORMAL_INIT));
+ c->AddFactory(MockDemuxer::CreateFactory());
+ c->AddFactory(MockAudioDecoder::CreateFactory());
+ c->AddFactory(MockAudioRenderer::CreateFactory());
+ InitializationHelper h;
+ h.Start(&p, c, url);
+ h.TimedWait(base::TimeDelta::FromSeconds(5));
+ EXPECT_FALSE(h.waiting_for_callback());
+ EXPECT_TRUE(h.callback_success_status());
+ EXPECT_TRUE(p.IsInitialized());
+ EXPECT_TRUE(media::PIPELINE_OK == p.GetError());
+ p.SetPlaybackRate(1.0f);
+ p.SetVolume(0.5f);
+ p.Stop();
+ EXPECT_FALSE(p.IsInitialized());
+}
diff --git a/media/build/media_unittests.vcproj b/media/build/media_unittests.vcproj
index 333c899..a565c33 100644
--- a/media/build/media_unittests.vcproj
+++ b/media/build/media_unittests.vcproj
@@ -160,6 +160,10 @@
>
</File>
<File
+ RelativePath="..\base\mock_media_filters.h"
+ >
+ </File>
+ <File
RelativePath="..\base\pipeline_impl_unittest.cc"
>
</File>
diff --git a/media/media_unittests.scons b/media/media_unittests.scons
index 8930e95..3ce9f68 100644
--- a/media/media_unittests.scons
+++ b/media/media_unittests.scons
@@ -48,6 +48,7 @@ if env.Bit('windows'):
input_files = [
'base/data_buffer_unittest.cc',
+ 'base/mock_media_filters.h',
'base/pipeline_impl_unittest.cc',
'base/run_all_unittests.cc',
]