summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-06 02:05:51 +0000
committerscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-06 02:05:51 +0000
commit8e0476c65cc2eb9d84a62d484c0358f9a0e325b0 (patch)
treeb24b3ec35e0c42ced3e2020c5501b280f6f7bd6d /media
parent22b23cd21840b9a148857c60a7f6ca8b0417e190 (diff)
downloadchromium_src-8e0476c65cc2eb9d84a62d484c0358f9a0e325b0.zip
chromium_src-8e0476c65cc2eb9d84a62d484c0358f9a0e325b0.tar.gz
chromium_src-8e0476c65cc2eb9d84a62d484c0358f9a0e325b0.tar.bz2
Fixed up MockFilterHost and MockPipeline to support tasks and callbacks.
I changed the constructor to MockFilterHost to *not* create and initialize filters to allow for testing for conditions where create/initialize would fail. Also multiple MockFilterHosts can now share a common MockPipeline, which simulates how it is supposed to work. Finally, updated the VideoRendererBase tests to be deterministic and completely mocked and fixing failing unittests. BUG=8379 Review URL: http://codereview.chromium.org/39234 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11085 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/mock_filter_host.h75
-rw-r--r--media/base/mock_pipeline.h31
-rw-r--r--media/filters/file_data_source_unittest.cc30
-rw-r--r--media/filters/video_renderer_unittest.cc106
-rw-r--r--media/media.gyp3
5 files changed, 139 insertions, 106 deletions
diff --git a/media/base/mock_filter_host.h b/media/base/mock_filter_host.h
index 490587f..3af36ac 100644
--- a/media/base/mock_filter_host.h
+++ b/media/base/mock_filter_host.h
@@ -2,6 +2,11 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
+// The corresponding FilterHost implementation for MockPipeline. Maintains a
+// reference to the parent MockPipeline and a reference to the Filter its
+// hosting. Common usage is to check if the hosted filter has initialized by
+// calling IsInitialized().
+
#ifndef MEDIA_BASE_MOCK_FILTER_HOST_H_
#define MEDIA_BASE_MOCK_FILTER_HOST_H_
@@ -16,85 +21,93 @@
namespace media {
-template <class Filter, class Source>
+template <class Filter>
class MockFilterHost : public FilterHost {
public:
- MockFilterHost(const MediaFormat* media_format, Source source) {
- scoped_refptr<FilterFactory> factory = Filter::CreateFactory();
- filter_ = factory->Create<Filter>(media_format);
- EXPECT_TRUE(filter_.get());
- if (filter_.get()) {
- filter_->SetFilterHost(this);
- filter_->Initialize(source);
- }
+ MockFilterHost(MockPipeline* mock_pipeline, Filter* filter)
+ : mock_pipeline_(mock_pipeline),
+ filter_(filter),
+ initialized_(false) {
+ EXPECT_TRUE(mock_pipeline_);
+ EXPECT_TRUE(filter_);
+ filter_->SetFilterHost(this);
}
- virtual ~MockFilterHost() {
- filter_->Stop();
- }
+ virtual ~MockFilterHost() {}
virtual const PipelineStatus* GetPipelineStatus() const {
- return &mock_pipeline_;
+ return mock_pipeline_;
}
virtual void SetTimeUpdateCallback(Callback1<base::TimeDelta>::Type* cb) {
- time_update_callback_.reset(cb);
+ time_update_callback_.reset(cb);
}
virtual void ScheduleTimeUpdateCallback(base::TimeDelta time) {
- // TODO(ralphl): Implement MockFilte::ScheduleTimeUpdateCallback.
- NOTIMPLEMENTED();
+ scheduled_callback_time_ = time;
}
virtual void InitializationComplete() {
- EXPECT_FALSE(mock_pipeline_.IsInitialized());
- mock_pipeline_.SetInitialized(true);
+ EXPECT_FALSE(initialized_);
+ initialized_ = true;
}
virtual void PostTask(Task* task) {
- // TODO(ralphl): Implement MockPipeline::PostTask.
- NOTIMPLEMENTED();
+ mock_pipeline_->PostTask(task);
}
virtual void Error(PipelineError error) {
- mock_pipeline_.Error(error);
+ mock_pipeline_->Error(error);
}
virtual void SetTime(base::TimeDelta time) {
- mock_pipeline_.SetTime(time);
+ mock_pipeline_->SetTime(time);
}
virtual void SetDuration(base::TimeDelta duration) {
- mock_pipeline_.SetDuration(duration);
+ mock_pipeline_->SetDuration(duration);
}
virtual void SetBufferedTime(base::TimeDelta buffered_time) {
- mock_pipeline_.SetBufferedTime(buffered_time);
+ mock_pipeline_->SetBufferedTime(buffered_time);
}
virtual void SetTotalBytes(int64 total_bytes) {
- mock_pipeline_.SetTotalBytes(total_bytes);
+ mock_pipeline_->SetTotalBytes(total_bytes);
}
virtual void SetBufferedBytes(int64 buffered_bytes) {
- mock_pipeline_.SetBufferedBytes(buffered_bytes);
+ mock_pipeline_->SetBufferedBytes(buffered_bytes);
}
- // Sets the size of the video output in pixel units.
virtual void SetVideoSize(size_t width, size_t height) {
- mock_pipeline_.SetVideoSize(width, height);
+ mock_pipeline_->SetVideoSize(width, height);
}
// Used by unit tests to manipulate the filter.
- Filter* filter() const { return filter_; }
+ base::TimeDelta GetScheduledCallbackTime() const {
+ return scheduled_callback_time_;
+ }
+
+ Callback1<base::TimeDelta>::Type* GetTimeUpdateCallback() const {
+ return time_update_callback_.get();
+ }
- MockPipeline* mock_pipeline() const { return &mock_pipeline_; }
+ bool IsInitialized() const {
+ return initialized_;
+ }
private:
- MockPipeline mock_pipeline_;
+ MockPipeline* mock_pipeline_;
scoped_refptr<Filter> filter_;
scoped_ptr<Callback1<base::TimeDelta>::Type> time_update_callback_;
+ // Keeps track of the time passed into ScheduleTimeUpdateCallback().
+ base::TimeDelta scheduled_callback_time_;
+
+ // Tracks if the filter has executed InitializationComplete().
+ bool initialized_;
+
DISALLOW_COPY_AND_ASSIGN(MockFilterHost);
};
diff --git a/media/base/mock_pipeline.h b/media/base/mock_pipeline.h
index d353c41..8741cc2 100644
--- a/media/base/mock_pipeline.h
+++ b/media/base/mock_pipeline.h
@@ -2,9 +2,16 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
+// Mock implementation of Pipeline. Simply provides getters/setters for every
+// pipeline state variable and queues all tasks posted to the "pipeline thread."
+// Since there actually isn't a separate thread unit tests can control when
+// they want to execute queued tasks by calling RunAllTasks(), which helps to
+// assert pre- and post-conditions.
+
#ifndef MEDIA_BASE_MOCK_PIPELINE_H_
#define MEDIA_BASE_MOCK_PIPELINE_H_
+#include <deque>
#include <string>
#include "media/base/media_format.h"
@@ -117,8 +124,24 @@ class MockPipeline : public media::Pipeline {
total_bytes_ = 0;
}
- void SetInitialized(bool init_value) {
- initialized_ = init_value;
+ // Runs all queued tasks until there are no more.
+ //
+ // Although it is possible for tasks to run indefinitely (executing tasks post
+ // additional tasks), such situations should be treated as a bug. Since the
+ // pipeline is request/pull-based, only enough tasks to satisfy the request
+ // should ever be executed.
+ void RunAllTasks() {
+ while (!task_queue_.empty()) {
+ Task* task = task_queue_.front();
+ task_queue_.pop_front();
+ task->Run();
+ delete task;
+ }
+ }
+
+ void PostTask(Task* task) {
+ EXPECT_TRUE(task);
+ task_queue_.push_back(task);
}
void Error(media::PipelineError error) {
@@ -146,7 +169,6 @@ class MockPipeline : public media::Pipeline {
buffered_bytes_ = buffered_bytes;
}
- // Sets the size of the video output in pixel units.
virtual void SetVideoSize(size_t width, size_t height) {
width_ = width;
height_ = height;
@@ -165,6 +187,9 @@ class MockPipeline : public media::Pipeline {
int64 buffered_bytes_;
int64 total_bytes_;
+ typedef std::deque<Task*> TaskQueue;
+ TaskQueue task_queue_;
+
DISALLOW_COPY_AND_ASSIGN(MockPipeline);
};
diff --git a/media/filters/file_data_source_unittest.cc b/media/filters/file_data_source_unittest.cc
index 3eb5262..3bce493 100644
--- a/media/filters/file_data_source_unittest.cc
+++ b/media/filters/file_data_source_unittest.cc
@@ -17,11 +17,13 @@
#include "media/base/factory.h"
#include "media/base/filter_host.h"
#include "media/base/mock_filter_host.h"
+#include "media/base/mock_pipeline.h"
#include "media/filters/file_data_source.h"
#include "media/base/mock_media_filters.h"
#include "testing/gtest/include/gtest/gtest.h"
using media::FileDataSource;
+using media::FilterFactory;
using media::FilterFactoryCollection;
using media::InitializationHelper;
using media::MediaFormat;
@@ -30,6 +32,7 @@ using media::MockAudioDecoder;
using media::MockAudioRenderer;
using media::MockFilterConfig;
using media::MockFilterHost;
+using media::MockPipeline;
using media::PipelineImpl;
namespace {
@@ -84,25 +87,34 @@ TEST(FileDataSourceTest, ReadData) {
std::string url = TestFileURL();
url_format.SetAsString(MediaFormat::kMimeType, media::mime_type::kURL);
url_format.SetAsString(MediaFormat::kURL, url);
- MockFilterHost<FileDataSource, std::string> mock_host(&url_format, url);
- EXPECT_TRUE(mock_host.filter()->GetSize(&size));
+ // Create our data source.
+ scoped_refptr<FilterFactory> factory = FileDataSource::CreateFactory();
+ FileDataSource* filter = factory->Create<FileDataSource>(&url_format);
+ EXPECT_TRUE(filter);
+
+ // Create our mock pipeline and filter host and initialize the data source.
+ MockPipeline pipeline;
+ MockFilterHost<FileDataSource> mock_host(&pipeline, filter);
+ EXPECT_TRUE(filter->Initialize(url));
+
+ EXPECT_TRUE(filter->GetSize(&size));
EXPECT_EQ(10, size);
- EXPECT_TRUE(mock_host.filter()->GetPosition(&position));
+ EXPECT_TRUE(filter->GetPosition(&position));
EXPECT_EQ(0, position);
- EXPECT_EQ(10u, mock_host.filter()->Read(ten_bytes, sizeof(ten_bytes)));
+ EXPECT_EQ(10u, filter->Read(ten_bytes, sizeof(ten_bytes)));
EXPECT_EQ('0', ten_bytes[0]);
EXPECT_EQ('5', ten_bytes[5]);
EXPECT_EQ('9', ten_bytes[9]);
- EXPECT_TRUE(mock_host.filter()->GetPosition(&position));
+ EXPECT_TRUE(filter->GetPosition(&position));
EXPECT_EQ(10, position);
- EXPECT_EQ(0u, mock_host.filter()->Read(ten_bytes, sizeof(ten_bytes)));
+ EXPECT_EQ(0u, filter->Read(ten_bytes, sizeof(ten_bytes)));
- EXPECT_TRUE(mock_host.filter()->SetPosition(5));
- EXPECT_EQ(5u, mock_host.filter()->Read(ten_bytes, sizeof(ten_bytes)));
+ EXPECT_TRUE(filter->SetPosition(5));
+ EXPECT_EQ(5u, filter->Read(ten_bytes, sizeof(ten_bytes)));
EXPECT_EQ('5', ten_bytes[0]);
- EXPECT_TRUE(mock_host.filter()->GetPosition(&position));
+ EXPECT_TRUE(filter->GetPosition(&position));
EXPECT_EQ(10, position);
}
diff --git a/media/filters/video_renderer_unittest.cc b/media/filters/video_renderer_unittest.cc
index e1f3f49..96c04f1 100644
--- a/media/filters/video_renderer_unittest.cc
+++ b/media/filters/video_renderer_unittest.cc
@@ -2,79 +2,59 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#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/mock_media_filters.h"
-#include "media/base/pipeline_impl.h"
+#include "media/base/mock_filter_host.h"
#include "media/filters/test_video_renderer.h"
#include "testing/gtest/include/gtest/gtest.h"
-using media::FilterFactoryCollection;
-using media::InstanceFilterFactory;
-using media::MockAudioDecoder;
-using media::MockAudioRenderer;
-using media::MockDataSource;
-using media::MockDemuxer;
+using media::FilterFactory;
using media::MockFilterConfig;
+using media::MockFilterHost;
+using media::MockPipeline;
using media::MockVideoDecoder;
-using media::PipelineImpl;
using media::TestVideoRenderer;
-using media::VideoFrame;
-TEST(VideoRenderer, DISABLED_CreateTestRenderer) {
- base::TimeDelta test_time = base::TimeDelta::FromMilliseconds(500);
- std::string url("");
- PipelineImpl p;
- scoped_refptr<TestVideoRenderer> test_renderer = new TestVideoRenderer();
+TEST(VideoRenderer, CreateAndPlay) {
+ // Prepare test data.
MockFilterConfig config;
- scoped_refptr<FilterFactoryCollection> c = new FilterFactoryCollection();
- c->AddFactory(MockDataSource::CreateFactory(&config));
- c->AddFactory(MockDemuxer::CreateFactory(&config));
- c->AddFactory(MockAudioDecoder::CreateFactory(&config));
- c->AddFactory(MockAudioRenderer::CreateFactory(&config));
- c->AddFactory(MockVideoDecoder::CreateFactory(&config));
- c->AddFactory(new InstanceFilterFactory<TestVideoRenderer>(test_renderer));
- media::InitializationHelper h;
- h.Start(&p, c, url);
- h.Wait();
- EXPECT_TRUE(p.IsInitialized());
- p.SetPlaybackRate(1.0f);
- PlatformThread::Sleep(static_cast<int>(test_time.InMilliseconds()));
- p.Stop();
- // Allow a decent amount of variability here. We expect 15 or 16 frames
- // but for now make sure it's within a reasonable range.
- // TODO(ralphl): This test is now DISABLED because sometimes on linux we
- // only get the first frame. Investigate why, but for now disabled.
- int64 num_expected_frames = test_time / config.frame_duration;
- EXPECT_GT(test_renderer->unique_frames(), num_expected_frames - 3);
- EXPECT_LT(test_renderer->unique_frames(), num_expected_frames + 3);
-}
+ scoped_refptr<FilterFactory> factory
+ = MockVideoDecoder::CreateFactory(&config);
+ scoped_refptr<MockVideoDecoder> decoder
+ = factory->Create<MockVideoDecoder>(NULL);
+ scoped_refptr<TestVideoRenderer> renderer = new TestVideoRenderer();
-TEST(VideoRenderer, SingleVideoFrame) {
- base::TimeDelta test_time = base::TimeDelta::FromMilliseconds(100);
- std::string url("");
- PipelineImpl p;
- scoped_refptr<TestVideoRenderer> test_renderer = new TestVideoRenderer();
- MockFilterConfig config;
- config.media_duration = config.frame_duration;
- scoped_refptr<FilterFactoryCollection> c = new FilterFactoryCollection();
- c->AddFactory(MockDataSource::CreateFactory(&config));
- c->AddFactory(MockDemuxer::CreateFactory(&config));
- c->AddFactory(MockAudioDecoder::CreateFactory(&config));
- c->AddFactory(MockAudioRenderer::CreateFactory(&config));
- c->AddFactory(MockVideoDecoder::CreateFactory(&config));
- c->AddFactory(new InstanceFilterFactory<TestVideoRenderer>(test_renderer));
- media::InitializationHelper h;
- h.Start(&p, c, url);
- h.TimedWait(base::TimeDelta::FromSeconds(1));
- EXPECT_TRUE(p.IsInitialized());
- p.SetPlaybackRate(1.0f);
- PlatformThread::Sleep(static_cast<int>(test_time.InMilliseconds()));
- p.Stop();
- EXPECT_EQ(test_renderer->unique_frames(), 1u);
- EXPECT_EQ(test_renderer->paint_called(), 1u);
+ // Setup our mock pipeline.
+ MockPipeline pipeline;
+ MockFilterHost<MockVideoDecoder> filter_host_a(&pipeline, decoder);
+ MockFilterHost<TestVideoRenderer> filter_host_b(&pipeline, renderer);
+
+ // Initialize the video renderer and run pending tasks. It should set its
+ // time update callback and scheduled its first callback time.
+ EXPECT_TRUE(renderer->Initialize(decoder));
+ EXPECT_FALSE(filter_host_b.IsInitialized());
+ pipeline.RunAllTasks();
+ EXPECT_TRUE(filter_host_b.IsInitialized());
+ EXPECT_TRUE(filter_host_b.GetTimeUpdateCallback());
+ EXPECT_NE(0, filter_host_b.GetScheduledCallbackTime().InMicroseconds());
+
+ // We also expect one unique frame due to the preroll paint.
+ EXPECT_EQ(1u, renderer->unique_frames());
+
+ // Now lets simulate playing 10 frames...
+ for (int i = 0; i < 10; ++i) {
+ base::TimeDelta previous_time = filter_host_b.GetScheduledCallbackTime();
+ size_t previous_unique_frames = renderer->unique_frames();
+
+ // Advance time to the callback time and execute.
+ pipeline.SetTime(previous_time);
+ filter_host_b.GetTimeUpdateCallback()->Run(previous_time);
+ pipeline.RunAllTasks();
+
+ // Renderer should have scheduled a new callback time and painted a frame.
+ EXPECT_GT(filter_host_b.GetScheduledCallbackTime().InMicroseconds(),
+ previous_time.InMicroseconds());
+ EXPECT_EQ(previous_unique_frames + 1, renderer->unique_frames());
+ }
}
diff --git a/media/media.gyp b/media/media.gyp
index 59832ba..0300d65 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -62,6 +62,8 @@
'filters/file_data_source.h',
'filters/null_audio_renderer.cc',
'filters/null_audio_renderer.h',
+ 'filters/video_renderer_base.cc',
+ 'filters/video_renderer_base.h',
'player/player.cc',
],
'direct_dependent_settings': {
@@ -84,6 +86,7 @@
'base/pipeline_impl_unittest.cc',
'base/run_all_unittests.cc',
'filters/file_data_source_unittest.cc',
+ 'filters/video_renderer_unittest.cc',
],
},
],