diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-15 17:39:56 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-15 17:39:56 +0000 |
commit | 2216d02d83e8c7ef50187384f6ce24ebeb16962c (patch) | |
tree | 4eab5dbf6b59a363925d7fa4f7cc1e12c360f752 /media | |
parent | aa8cc5a24cb681eb307635679a69512548896b5e (diff) | |
download | chromium_src-2216d02d83e8c7ef50187384f6ce24ebeb16962c.zip chromium_src-2216d02d83e8c7ef50187384f6ce24ebeb16962c.tar.gz chromium_src-2216d02d83e8c7ef50187384f6ce24ebeb16962c.tar.bz2 |
Revert "Splitting media filter's Initialize() into Create() + callback and Seek() + callback."
Review URL: http://codereview.chromium.org/149682
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20745 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
24 files changed, 159 insertions, 697 deletions
diff --git a/media/base/filter_host.h b/media/base/filter_host.h index 982b3e5..4907df2a 100644 --- a/media/base/filter_host.h +++ b/media/base/filter_host.h @@ -24,6 +24,11 @@ namespace media { class FilterHost { public: + // Filters must call this method to indicate that their initialization is + // complete. They may call this from within their Initialize() method or may + // choose call it after processing some data. + virtual void InitializationComplete() = 0; + // Stops execution of the pipeline due to a fatal error. Do not call this // method with PIPELINE_OK or PIPELINE_STOPPING (used internally by pipeline). virtual void Error(PipelineError error) = 0; diff --git a/media/base/filter_host_impl.cc b/media/base/filter_host_impl.cc index 4192afd..09f1791 100644 --- a/media/base/filter_host_impl.cc +++ b/media/base/filter_host_impl.cc @@ -6,6 +6,10 @@ namespace media { +void FilterHostImpl::InitializationComplete() { + pipeline_internal_->InitializationComplete(this); +} + void FilterHostImpl::Error(PipelineError error) { pipeline_internal_->Error(error); } diff --git a/media/base/filter_host_impl.h b/media/base/filter_host_impl.h index cb33a48..71e2417 100644 --- a/media/base/filter_host_impl.h +++ b/media/base/filter_host_impl.h @@ -16,6 +16,7 @@ namespace media { class FilterHostImpl : public FilterHost { public: // FilterHost interface. + virtual void InitializationComplete(); virtual void Error(PipelineError error); virtual base::TimeDelta GetTime() const; virtual void SetTime(base::TimeDelta time); diff --git a/media/base/filters.h b/media/base/filters.h index 84df0966..b892961 100644 --- a/media/base/filters.h +++ b/media/base/filters.h @@ -53,8 +53,6 @@ enum FilterType { FILTER_VIDEO_RENDERER }; -// Used for completing asynchronous methods. -typedef Callback0::Type FilterCallback; class MediaFilter : public base::RefCountedThreadSafe<MediaFilter> { public: @@ -96,14 +94,9 @@ class MediaFilter : public base::RefCountedThreadSafe<MediaFilter> { // method if they need to respond to this call. virtual void SetPlaybackRate(float playback_rate) {} - // Carry out any actions required to seek to the given time, executing the - // callback upon completion. - virtual void Seek(base::TimeDelta time, FilterCallback* callback) { - scoped_ptr<FilterCallback> seek_callback(callback); - if (seek_callback.get()) { - seek_callback->Run(); - } - } + // The pipeline is seeking to the specified time. Filters may implement + // this method if they need to respond to this call. + virtual void Seek(base::TimeDelta time) {} protected: // Only allow scoped_refptr<> to delete filters. @@ -135,9 +128,8 @@ class DataSource : public MediaFilter { static const size_t kReadError = static_cast<size_t>(-1); - // Initialize a DataSource for the given URL, executing the callback upon - // completion. - virtual void Initialize(const std::string& url, FilterCallback* callback) = 0; + // Initializes this filter, returns true if successful, false otherwise. + virtual bool Initialize(const std::string& url) = 0; // Returns the MediaFormat for this filter. virtual const MediaFormat& media_format() = 0; @@ -174,10 +166,8 @@ class Demuxer : public MediaFilter { mime_type == mime_type::kApplicationOctetStream); } - // Initialize a Demuxer with the given DataSource, executing the callback upon - // completion. - virtual void Initialize(DataSource* data_source, - FilterCallback* callback) = 0; + // Initializes this filter, returns true if successful, false otherwise. + virtual bool Initialize(DataSource* data_source) = 0; // Returns the number of streams available virtual size_t GetNumberOfStreams() = 0; @@ -233,9 +223,8 @@ class VideoDecoder : public MediaFilter { return mime_type::kMajorTypeVideo; } - // Initialize a VideoDecoder with the given DemuxerStream, executing the - // callback upon completion. - virtual void Initialize(DemuxerStream* stream, FilterCallback* callback) = 0; + // Initializes this filter, returns true if successful, false otherwise. + virtual bool Initialize(DemuxerStream* demuxer_stream) = 0; // Returns the MediaFormat for this filter. virtual const MediaFormat& media_format() = 0; @@ -257,9 +246,8 @@ class AudioDecoder : public MediaFilter { return mime_type::kMajorTypeAudio; } - // Initialize a AudioDecoder with the given DemuxerStream, executing the - // callback upon completion. - virtual void Initialize(DemuxerStream* stream, FilterCallback* callback) = 0; + // Initializes this filter, returns true if successful, false otherwise. + virtual bool Initialize(DemuxerStream* demuxer_stream) = 0; // Returns the MediaFormat for this filter. virtual const MediaFormat& media_format() = 0; @@ -281,9 +269,8 @@ class VideoRenderer : public MediaFilter { return mime_type::kMajorTypeVideo; } - // Initialize a VideoRenderer with the given VideoDecoder, executing the - // callback upon completion. - virtual void Initialize(VideoDecoder* decoder, FilterCallback* callback) = 0; + // Initializes this filter, returns true if successful, false otherwise. + virtual bool Initialize(VideoDecoder* decoder) = 0; }; @@ -297,9 +284,8 @@ class AudioRenderer : public MediaFilter { return mime_type::kMajorTypeAudio; } - // Initialize a AudioRenderer with the given AudioDecoder, executing the - // callback upon completion. - virtual void Initialize(AudioDecoder* decoder, FilterCallback* callback) = 0; + // Initializes this filter, returns true if successful, false otherwise. + virtual bool Initialize(AudioDecoder* decoder) = 0; // Sets the output volume. virtual void SetVolume(float volume) = 0; diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc deleted file mode 100644 index 7b854fc..0000000 --- a/media/base/mock_filters.cc +++ /dev/null @@ -1,18 +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. - -#include "media/base/mock_filters.h" - -namespace media { - -void RunFilterCallback(::testing::Unused, FilterCallback* callback) { - callback->Run(); - delete callback; -} - -void DestroyFilterCallback(::testing::Unused, FilterCallback* callback) { - delete callback; -} - -} // namespace media diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index 6d8c8a9..bffba6f 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h @@ -40,52 +40,6 @@ class Destroyable : public MockClass { DISALLOW_COPY_AND_ASSIGN(Destroyable); }; -// Helper class used to test that callbacks are executed. It is recommend you -// combine this class with StrictMock<> to verify that the callback is executed. -// You can reuse the same instance of a MockFilterCallback many times since -// gmock will track the number of times the methods are executed. -class MockFilterCallback { - public: - MockFilterCallback() {} - virtual ~MockFilterCallback() {} - - MOCK_METHOD0(OnCallbackDestroyed, void()); - MOCK_METHOD0(OnFilterCallback, void()); - - // Helper method to create a new callback for this mock. The callback will - // call OnFilterCallback() when executed and OnCallbackDestroyed() when - // destroyed. Clients should use NiceMock<> or StrictMock<> depending on the - // test. - FilterCallback* NewCallback() { - return new CallbackImpl(this); - } - - private: - // Private implementation of CallbackRunner used to trigger expectations on - // MockFilterCallback. - class CallbackImpl : public CallbackRunner<Tuple0> { - public: - CallbackImpl(MockFilterCallback* mock_callback) - : mock_callback_(mock_callback) { - } - - virtual ~CallbackImpl() { - mock_callback_->OnCallbackDestroyed(); - } - - virtual void RunWithParams(const Tuple0& params) { - mock_callback_->OnFilterCallback(); - } - - private: - MockFilterCallback* mock_callback_; - - DISALLOW_COPY_AND_ASSIGN(CallbackImpl); - }; - - DISALLOW_COPY_AND_ASSIGN(MockFilterCallback); -}; - class MockDataSource : public DataSource { public: MockDataSource() {} @@ -93,11 +47,10 @@ class MockDataSource : public DataSource { // MediaFilter implementation. MOCK_METHOD0(Stop, void()); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); - MOCK_METHOD2(Seek, void(base::TimeDelta time, FilterCallback* callback)); + MOCK_METHOD1(Seek, void(base::TimeDelta time)); // DataSource implementation. - MOCK_METHOD2(Initialize, void(const std::string& url, - FilterCallback* callback)); + MOCK_METHOD1(Initialize, bool(const std::string& url)); const MediaFormat& media_format() { return media_format_; } MOCK_METHOD2(Read, size_t(uint8* data, size_t size)); MOCK_METHOD1(GetPosition, bool(int64* position_out)); @@ -121,11 +74,10 @@ class MockDemuxer : public Demuxer { // MediaFilter implementation. MOCK_METHOD0(Stop, void()); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); - MOCK_METHOD2(Seek, void(base::TimeDelta time, FilterCallback* callback)); + MOCK_METHOD1(Seek, void(base::TimeDelta time)); // Demuxer implementation. - MOCK_METHOD2(Initialize, void(DataSource* data_source, - FilterCallback* callback)); + MOCK_METHOD1(Initialize, bool(DataSource* data_source)); MOCK_METHOD0(GetNumberOfStreams, size_t()); MOCK_METHOD1(GetStream, scoped_refptr<DemuxerStream>(int stream_id)); @@ -164,21 +116,13 @@ class MockVideoDecoder : public VideoDecoder { public: MockVideoDecoder() {} - // Sets the essential media format keys for this decoder. - MockVideoDecoder(const std::string& mime_type, int width, int height) { - media_format_.SetAsString(MediaFormat::kMimeType, mime_type); - media_format_.SetAsInteger(MediaFormat::kWidth, width); - media_format_.SetAsInteger(MediaFormat::kHeight, height); - } - // MediaFilter implementation. MOCK_METHOD0(Stop, void()); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); - MOCK_METHOD2(Seek, void(base::TimeDelta time, FilterCallback* callback)); + MOCK_METHOD1(Seek, void(base::TimeDelta time)); // VideoDecoder implementation. - MOCK_METHOD2(Initialize, void(DemuxerStream* stream, - FilterCallback* callback)); + MOCK_METHOD1(Initialize, bool(DemuxerStream* demuxer_stream)); const MediaFormat& media_format() { return media_format_; } MOCK_METHOD1(Read, void(Callback1<VideoFrame*>::Type* read_callback)); @@ -198,11 +142,10 @@ class MockAudioDecoder : public AudioDecoder { // MediaFilter implementation. MOCK_METHOD0(Stop, void()); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); - MOCK_METHOD2(Seek, void(base::TimeDelta time, FilterCallback* callback)); + MOCK_METHOD1(Seek, void(base::TimeDelta time)); // AudioDecoder implementation. - MOCK_METHOD2(Initialize, void(DemuxerStream* stream, - FilterCallback* callback)); + MOCK_METHOD1(Initialize, bool(DemuxerStream* demuxer_stream)); const MediaFormat& media_format() { return media_format_; } MOCK_METHOD1(Read, void(Callback1<Buffer*>::Type* read_callback)); @@ -222,11 +165,10 @@ class MockVideoRenderer : public VideoRenderer { // MediaFilter implementation. MOCK_METHOD0(Stop, void()); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); - MOCK_METHOD2(Seek, void(base::TimeDelta time, FilterCallback* callback)); + MOCK_METHOD1(Seek, void(base::TimeDelta time)); // VideoRenderer implementation. - MOCK_METHOD2(Initialize, void(VideoDecoder* decoder, - FilterCallback* callback)); + MOCK_METHOD1(Initialize, bool(VideoDecoder* decoder)); protected: virtual ~MockVideoRenderer() {} @@ -242,11 +184,10 @@ class MockAudioRenderer : public AudioRenderer { // MediaFilter implementation. MOCK_METHOD0(Stop, void()); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); - MOCK_METHOD2(Seek, void(base::TimeDelta time, FilterCallback* callback)); + MOCK_METHOD1(Seek, void(base::TimeDelta time)); // AudioRenderer implementation. - MOCK_METHOD2(Initialize, void(AudioDecoder* decoder, - FilterCallback* callback)); + MOCK_METHOD1(Initialize, bool(AudioDecoder* decoder)); MOCK_METHOD1(SetVolume, void(float volume)); protected: @@ -322,15 +263,11 @@ class MockFilterFactory : public FilterFactory { DISALLOW_COPY_AND_ASSIGN(MockFilterFactory); }; -// Helper gmock function that immediately executes and destroys the -// FilterCallback on behalf of the provided filter. Can be used when mocking -// the Initialize() and Seek() methods. -void RunFilterCallback(::testing::Unused, FilterCallback* callback); - -// Helper gmock function that immediately destroys the FilterCallback on behalf -// of the provided filter. Can be used when mocking the Initialize() and Seek() -// methods. -void DestroyFilterCallback(::testing::Unused, FilterCallback* callback); +// 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) { diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc index 7ef051d..f021ad3 100644 --- a/media/base/pipeline_impl.cc +++ b/media/base/pipeline_impl.cc @@ -328,6 +328,15 @@ void PipelineInternal::VolumeChanged(float volume) { NewRunnableMethod(this, &PipelineInternal::VolumeChangedTask, volume)); } +// Called from any thread. +void PipelineInternal::InitializationComplete(FilterHostImpl* host) { + if (IsPipelineOk()) { + // Continue the initialize task by proceeding to the next stage. + message_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &PipelineInternal::InitializeTask)); + } +} + // Called from any thread. Updates the pipeline time. void PipelineInternal::SetTime(base::TimeDelta time) { // TODO(scherkus): why not post a task? @@ -341,19 +350,6 @@ void PipelineInternal::Error(PipelineError error) { NewRunnableMethod(this, &PipelineInternal::ErrorTask, error)); } -// Called from any thread. -void PipelineInternal::OnFilterInitialize() { - // Continue the initialize task by proceeding to the next stage. - message_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, &PipelineInternal::InitializeTask)); -} - -// Called from any thread. -void PipelineInternal::OnFilterSeek() { - // TODO(scherkus): have PipelineInternal wait to receive replies from every - // filter before calling the client's |seek_callback_|. -} - void PipelineInternal::StartTask(FilterFactory* filter_factory, const std::string& url, PipelineCallback* start_callback) { @@ -387,8 +383,8 @@ void PipelineInternal::StartTask(FilterFactory* filter_factory, void PipelineInternal::InitializeTask() { DCHECK_EQ(MessageLoop::current(), message_loop_); - // If we have received the stop or error signal, return immediately. - if (state_ == kStopped || state_ == kError) + // If we have received the stop signal, return immediately. + if (state_ == kStopped) return; DCHECK(state_ == kCreated || IsPipelineInitializing()); @@ -555,8 +551,7 @@ void PipelineInternal::SeekTask(base::TimeDelta time, for (FilterHostVector::iterator iter = filter_hosts_.begin(); iter != filter_hosts_.end(); ++iter) { - (*iter)->media_filter()->Seek(time, - NewCallback(this, &PipelineInternal::OnFilterSeek)); + (*iter)->media_filter()->Seek(time); } // TODO(hclam): we should set the time when the above seek operations were all @@ -607,8 +602,9 @@ void PipelineInternal::CreateFilter(FilterFactory* filter_factory, filter_hosts_.push_back(host.release()); // Now initialize the filter. - filter->Initialize(source, - NewCallback(this, &PipelineInternal::OnFilterInitialize)); + if (!filter->Initialize(source)) { + Error(PIPELINE_ERROR_INITIALIZATION_FAILED); + } } void PipelineInternal::CreateDataSource() { diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h index e9f44d5..911d253 100644 --- a/media/base/pipeline_impl.h +++ b/media/base/pipeline_impl.h @@ -191,6 +191,11 @@ class PipelineInternal : public base::RefCountedThreadSafe<PipelineInternal> { // Methods called by a FilterHostImpl object. These methods may be called // on any thread, either the pipeline's thread or any other. + // When a filter calls it's FilterHost, the filter host calls back to the + // pipeline thread. If the pipeline thread is running a nested message loop + // then it will be exited. + void InitializationComplete(FilterHostImpl* host); + // Sets the pipeline time and schedules a task to call back to any filters // that have registered a time update callback. void SetTime(base::TimeDelta time); @@ -240,10 +245,6 @@ class PipelineInternal : public base::RefCountedThreadSafe<PipelineInternal> { state_ == kInitVideoRenderer; } - // Callback executed by filters upon completing initialization and seeking. - void OnFilterInitialize(); - void OnFilterSeek(); - // The following "task" methods correspond to the public methods, but these // methods are run as the result of posting a task to the PipelineInternal's // message loop. diff --git a/media/base/pipeline_impl_unittest.cc b/media/base/pipeline_impl_unittest.cc index d6bd285..b673cfb 100644 --- a/media/base/pipeline_impl_unittest.cc +++ b/media/base/pipeline_impl_unittest.cc @@ -14,9 +14,7 @@ #include "testing/gtest/include/gtest/gtest.h" using ::testing::DoAll; -using ::testing::Invoke; using ::testing::Mock; -using ::testing::NotNull; using ::testing::Return; using ::testing::StrictMock; @@ -65,8 +63,9 @@ class PipelineImplTest : public ::testing::Test { protected: // Sets up expectations to allow the data source to initialize. void InitializeDataSource() { - EXPECT_CALL(*mocks_->data_source(), Initialize("", NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->data_source(), Initialize("")) + .WillOnce(DoAll(InitializationComplete(mocks_->data_source()), + Return(true))); EXPECT_CALL(*mocks_->data_source(), SetPlaybackRate(0.0f)); EXPECT_CALL(*mocks_->data_source(), Stop()); } @@ -74,9 +73,9 @@ class PipelineImplTest : public ::testing::Test { // Sets up expectations to allow the demuxer to initialize. typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector; void InitializeDemuxer(MockDemuxerStreamVector* streams) { - EXPECT_CALL(*mocks_->demuxer(), - Initialize(mocks_->data_source(), NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + 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(), SetPlaybackRate(0.0f)); @@ -92,34 +91,36 @@ class PipelineImplTest : public ::testing::Test { // Sets up expectations to allow the video decoder to initialize. void InitializeVideoDecoder(MockDemuxerStream* stream) { - EXPECT_CALL(*mocks_->video_decoder(), Initialize(stream, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->video_decoder(), Initialize(stream)) + .WillOnce(DoAll(InitializationComplete(mocks_->video_decoder()), + Return(true))); EXPECT_CALL(*mocks_->video_decoder(), SetPlaybackRate(0.0f)); 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, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->audio_decoder(), Initialize(stream)) + .WillOnce(DoAll(InitializationComplete(mocks_->audio_decoder()), + Return(true))); EXPECT_CALL(*mocks_->audio_decoder(), SetPlaybackRate(0.0f)); 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(), NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->video_renderer(), Initialize(mocks_->video_decoder())) + .WillOnce(DoAll(InitializationComplete(mocks_->video_renderer()), + Return(true))); EXPECT_CALL(*mocks_->video_renderer(), SetPlaybackRate(0.0f)); 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(), NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->audio_renderer(), Initialize(mocks_->audio_decoder())) + .WillOnce(DoAll(InitializationComplete(mocks_->audio_renderer()), + Return(true))); EXPECT_CALL(*mocks_->audio_renderer(), SetPlaybackRate(0.0f)); EXPECT_CALL(*mocks_->audio_renderer(), SetVolume(1.0f)); EXPECT_CALL(*mocks_->audio_renderer(), Stop()); @@ -200,8 +201,8 @@ TEST_F(PipelineImplTest, NotStarted) { } TEST_F(PipelineImplTest, NeverInitializes) { - EXPECT_CALL(*mocks_->data_source(), Initialize("", NotNull())) - .WillOnce(Invoke(&DestroyFilterCallback)); + EXPECT_CALL(*mocks_->data_source(), Initialize("")) + .WillOnce(Return(true)); EXPECT_CALL(*mocks_->data_source(), Stop()); // This test hangs during initialization by never calling @@ -232,10 +233,10 @@ TEST_F(PipelineImplTest, RequiredFilterMissing) { } TEST_F(PipelineImplTest, URLNotFound) { - EXPECT_CALL(*mocks_->data_source(), Initialize("", NotNull())) + EXPECT_CALL(*mocks_->data_source(), Initialize("")) .WillOnce(DoAll(Error(mocks_->data_source(), PIPELINE_ERROR_URL_NOT_FOUND), - Invoke(&RunFilterCallback))); + Return(false))); EXPECT_CALL(*mocks_->data_source(), Stop()); InitializePipeline(); @@ -246,12 +247,14 @@ TEST_F(PipelineImplTest, URLNotFound) { TEST_F(PipelineImplTest, NoStreams) { // Manually set these expecations because SetPlaybackRate() is not called if // we cannot fully initialize the pipeline. - EXPECT_CALL(*mocks_->data_source(), Initialize("", NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->data_source(), Initialize("")) + .WillOnce(DoAll(InitializationComplete(mocks_->data_source()), + Return(true))); EXPECT_CALL(*mocks_->data_source(), Stop()); - EXPECT_CALL(*mocks_->demuxer(), Initialize(mocks_->data_source(), NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + EXPECT_CALL(*mocks_->demuxer(), Initialize(mocks_->data_source())) + .WillOnce(DoAll(InitializationComplete(mocks_->demuxer()), + Return(true))); EXPECT_CALL(*mocks_->demuxer(), GetNumberOfStreams()) .WillRepeatedly(Return(0)); EXPECT_CALL(*mocks_->demuxer(), Stop()); @@ -338,18 +341,12 @@ TEST_F(PipelineImplTest, Seek) { // Every filter should receive a call to Seek(). base::TimeDelta expected = base::TimeDelta::FromSeconds(2000); - EXPECT_CALL(*mocks_->data_source(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->demuxer(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->audio_decoder(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->audio_renderer(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->video_decoder(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); - EXPECT_CALL(*mocks_->video_renderer(), Seek(expected, NotNull())) - .WillOnce(Invoke(&RunFilterCallback)); + 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)); // We expect a successful seek callback. EXPECT_CALL(callbacks_, OnSeek()); diff --git a/media/filters/audio_renderer_base.cc b/media/filters/audio_renderer_base.cc index d0bad99..ba52fe0 100644 --- a/media/filters/audio_renderer_base.cc +++ b/media/filters/audio_renderer_base.cc @@ -38,7 +38,7 @@ void AudioRendererBase::Stop() { stopped_ = true; } -void AudioRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { +void AudioRendererBase::Seek(base::TimeDelta time) { AutoLock auto_lock(lock_); last_fill_buffer_time_ = base::TimeDelta(); @@ -53,12 +53,9 @@ void AudioRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { } } -void AudioRendererBase::Initialize(AudioDecoder* decoder, - FilterCallback* callback) { +bool AudioRendererBase::Initialize(AudioDecoder* decoder) { DCHECK(decoder); - DCHECK(callback); decoder_ = decoder; - initialize_callback_.reset(callback); // Schedule our initial reads. for (size_t i = 0; i < max_queue_size_; ++i) { @@ -66,11 +63,7 @@ void AudioRendererBase::Initialize(AudioDecoder* decoder, } // Defer initialization until all scheduled reads have completed. - if (!OnInitialize(decoder_->media_format())) { - host()->Error(PIPELINE_ERROR_INITIALIZATION_FAILED); - initialize_callback_->Run(); - initialize_callback_.reset(); - } + return OnInitialize(decoder_->media_format()); } void AudioRendererBase::OnReadComplete(Buffer* buffer_in) { @@ -99,9 +92,8 @@ void AudioRendererBase::OnReadComplete(Buffer* buffer_in) { host()->Error(PIPELINE_ERROR_NO_DATA); } else { initialized_ = true; + host()->InitializationComplete(); } - initialize_callback_->Run(); - initialize_callback_.reset(); } } diff --git a/media/filters/audio_renderer_base.h b/media/filters/audio_renderer_base.h index 3d31474..e3ec686 100644 --- a/media/filters/audio_renderer_base.h +++ b/media/filters/audio_renderer_base.h @@ -32,10 +32,10 @@ class AudioRendererBase : public AudioRenderer { // MediaFilter implementation. virtual void Stop(); - virtual void Seek(base::TimeDelta time, FilterCallback* callback); + virtual void Seek(base::TimeDelta time); // AudioRenderer implementation. - virtual void Initialize(AudioDecoder* decoder, FilterCallback* callback); + virtual bool Initialize(AudioDecoder* decoder); protected: // The default maximum size of the queue. @@ -116,9 +116,6 @@ class AudioRendererBase : public AudioRenderer { // TODO(ralphl): Update this value after seeking. base::TimeDelta last_fill_buffer_time_; - // Filter callbacks. - scoped_ptr<FilterCallback> initialize_callback_; - DISALLOW_COPY_AND_ASSIGN(AudioRendererBase); }; diff --git a/media/filters/audio_renderer_base_unittest.cc b/media/filters/audio_renderer_base_unittest.cc deleted file mode 100644 index aa0808c..0000000 --- a/media/filters/audio_renderer_base_unittest.cc +++ /dev/null @@ -1,135 +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. - -#include "base/stl_util-inl.h" -#include "media/base/data_buffer.h" -#include "media/base/mock_filter_host.h" -#include "media/base/mock_filters.h" -#include "media/filters/audio_renderer_base.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::NotNull; -using ::testing::Return; -using ::testing::StrictMock; - -namespace media { - -// Mocked subclass of AudioRendererBase for testing purposes. -class MockAudioRendererBase : public AudioRendererBase { - public: - MockAudioRendererBase(size_t max_queue_size) - : AudioRendererBase(max_queue_size) {} - virtual ~MockAudioRendererBase() {} - - // AudioRenderer implementation. - MOCK_METHOD1(SetVolume, void(float volume)); - - // AudioRendererBase implementation. - MOCK_METHOD1(OnInitialize, bool(const MediaFormat& media_format)); - MOCK_METHOD0(OnStop, void()); - - // Used for verifying check points during tests. - MOCK_METHOD1(CheckPoint, void(int id)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockAudioRendererBase); -}; - -class AudioRendererBaseTest : public ::testing::Test { - public: - AudioRendererBaseTest() - : renderer_(new MockAudioRendererBase(kMaxQueueSize)), - decoder_(new MockAudioDecoder()) { - renderer_->set_host(&host_); - - // Queue all reads from the decoder. - EXPECT_CALL(*decoder_, Read(NotNull())) - .WillRepeatedly(Invoke(this, &AudioRendererBaseTest::EnqueueCallback)); - } - - virtual ~AudioRendererBaseTest() { - STLDeleteElements(&read_queue_); - - // Expect a call into the subclass. - EXPECT_CALL(*renderer_, OnStop()); - renderer_->Stop(); - } - - protected: - static const size_t kMaxQueueSize; - - // Fixture members. - scoped_refptr<MockAudioRendererBase> renderer_; - scoped_refptr<MockAudioDecoder> decoder_; - StrictMock<MockFilterHost> host_; - StrictMock<MockFilterCallback> callback_; - - // Receives asynchronous read requests sent to |decoder_|. - std::deque<Callback1<Buffer*>::Type*> read_queue_; - - private: - void EnqueueCallback(Callback1<Buffer*>::Type* callback) { - read_queue_.push_back(callback); - } - - DISALLOW_COPY_AND_ASSIGN(AudioRendererBaseTest); -}; - -const size_t AudioRendererBaseTest::kMaxQueueSize = 16u; - -TEST_F(AudioRendererBaseTest, Initialize_Failed) { - InSequence s; - - // Our subclass will fail when asked to initialize. - EXPECT_CALL(*renderer_, OnInitialize(_)) - .WillOnce(Return(false)); - - // We expect to receive an error. - EXPECT_CALL(host_, Error(PIPELINE_ERROR_INITIALIZATION_FAILED)); - - // We expect our callback to be executed. - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - - // Initialize, we expect to get a bunch of read requests. - renderer_->Initialize(decoder_, callback_.NewCallback()); - EXPECT_EQ(kMaxQueueSize, read_queue_.size()); -} - -TEST_F(AudioRendererBaseTest, Initialize_Successful) { - InSequence s; - - // Then our subclass will be asked to initialize. - EXPECT_CALL(*renderer_, OnInitialize(_)) - .WillOnce(Return(true)); - - // Set up a check point to verify that the callback hasn't been executed yet. - EXPECT_CALL(*renderer_, CheckPoint(0)); - - // After finishing preroll, we expect our callback to be executed. - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - - // Initialize, we expect to get a bunch of read requests. - renderer_->Initialize(decoder_, callback_.NewCallback()); - EXPECT_EQ(kMaxQueueSize, read_queue_.size()); - - // Verify our callback hasn't been executed yet. - renderer_->CheckPoint(0); - - // Now satisfy the read requests. Our callback should be executed after - // exiting this loop. - while (!read_queue_.empty()) { - scoped_refptr<DataBuffer> buffer = new DataBuffer(); - buffer->GetWritableData(1); - read_queue_.front()->Run(buffer); - delete read_queue_.front(); - read_queue_.pop_front(); - } -} - -} // namespace media diff --git a/media/filters/decoder_base.h b/media/filters/decoder_base.h index 3e1ba52c..775d3f9 100644 --- a/media/filters/decoder_base.h +++ b/media/filters/decoder_base.h @@ -33,18 +33,16 @@ class DecoderBase : public Decoder { NewRunnableMethod(this, &DecoderBase::StopTask)); } - virtual void Seek(base::TimeDelta time, - FilterCallback* callback) { + virtual void Seek(base::TimeDelta time) { this->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &DecoderBase::SeekTask, time, callback)); + NewRunnableMethod(this, &DecoderBase::SeekTask, time)); } // Decoder implementation. - virtual void Initialize(DemuxerStream* demuxer_stream, - FilterCallback* callback) { + virtual bool Initialize(DemuxerStream* demuxer_stream) { this->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &DecoderBase::InitializeTask, demuxer_stream, - callback)); + NewRunnableMethod(this, &DecoderBase::InitializeTask, demuxer_stream)); + return true; } virtual const MediaFormat& media_format() { return media_format_; } @@ -129,9 +127,8 @@ class DecoderBase : public Decoder { state_ = STOPPED; } - void SeekTask(base::TimeDelta time, FilterCallback* callback) { + void SeekTask(base::TimeDelta time) { DCHECK_EQ(MessageLoop::current(), this->message_loop()); - scoped_ptr<FilterCallback> c(callback); // Delegate to the subclass first. OnSeek(time); @@ -142,30 +139,24 @@ class DecoderBase : public Decoder { // Turn on the seeking flag so that we can discard buffers until a // discontinuous buffer is received. seeking_ = true; - - // For now, signal that we're done seeking. - // TODO(scherkus): implement asynchronous seeking for decoder_base.h - callback->Run(); } - void InitializeTask(DemuxerStream* demuxer_stream, FilterCallback* callback) { + void InitializeTask(DemuxerStream* demuxer_stream) { DCHECK_EQ(MessageLoop::current(), this->message_loop()); DCHECK(state_ == UNINITIALIZED); DCHECK(!demuxer_stream_); - scoped_ptr<FilterCallback> c(callback); demuxer_stream_ = demuxer_stream; // Delegate to subclass first. if (!OnInitialize(demuxer_stream_)) { this->host()->Error(PIPELINE_ERROR_DECODE); - callback->Run(); return; } // TODO(scherkus): subclass shouldn't mutate superclass media format. DCHECK(!media_format_.empty()) << "Subclass did not set media_format_"; state_ = INITIALIZED; - callback->Run(); + this->host()->InitializationComplete(); } void ReadTask(ReadCallback* read_callback) { diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 8526b4e..aa7ff27 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc @@ -261,20 +261,19 @@ void FFmpegDemuxer::Stop() { NewRunnableMethod(this, &FFmpegDemuxer::StopTask)); } -void FFmpegDemuxer::Seek(base::TimeDelta time, FilterCallback* callback) { +void FFmpegDemuxer::Seek(base::TimeDelta time) { // TODO(hclam): by returning from this method, it is assumed that the seek // operation is completed and filters behind the demuxer is good to issue // more reads, but we are posting a task here, which makes the seek operation // asynchronous, should change how seek works to make it fully asynchronous. message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time, callback)); + NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time)); } -void FFmpegDemuxer::Initialize(DataSource* data_source, - FilterCallback* callback) { +bool FFmpegDemuxer::Initialize(DataSource* data_source) { message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, &FFmpegDemuxer::InititalizeTask, data_source, - callback)); + NewRunnableMethod(this, &FFmpegDemuxer::InititalizeTask, data_source)); + return true; } size_t FFmpegDemuxer::GetNumberOfStreams() { @@ -287,10 +286,8 @@ scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) { return streams_[stream].get(); } -void FFmpegDemuxer::InititalizeTask(DataSource* data_source, - FilterCallback* callback) { +void FFmpegDemuxer::InititalizeTask(DataSource* data_source) { DCHECK_EQ(MessageLoop::current(), message_loop()); - scoped_ptr<FilterCallback> c(callback); // In order to get FFmpeg to use |data_source| for file IO we must transfer // ownership via FFmpegGlue. We'll add |data_source| to FFmpegGlue and pass @@ -314,7 +311,6 @@ void FFmpegDemuxer::InititalizeTask(DataSource* data_source, if (result < 0) { host()->Error(DEMUXER_ERROR_COULD_NOT_OPEN); - callback->Run(); return; } @@ -329,7 +325,6 @@ void FFmpegDemuxer::InititalizeTask(DataSource* data_source, result = av_find_stream_info(format_context_); if (result < 0) { host()->Error(DEMUXER_ERROR_COULD_NOT_PARSE); - callback->Run(); return; } } @@ -352,18 +347,16 @@ void FFmpegDemuxer::InititalizeTask(DataSource* data_source, } if (streams_.empty()) { host()->Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); - callback->Run(); return; } // Good to go: set the duration and notify we're done initializing. host()->SetDuration(max_duration); - callback->Run(); + host()->InitializationComplete(); } -void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) { +void FFmpegDemuxer::SeekTask(base::TimeDelta time) { DCHECK_EQ(MessageLoop::current(), message_loop()); - scoped_ptr<FilterCallback> c(callback); // Tell streams to flush buffers due to seeking. StreamVector::iterator iter; @@ -382,9 +375,6 @@ void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) { // TODO(scherkus): signal error. NOTIMPLEMENTED(); } - - // Notify we're finished seeking. - callback->Run(); } void FFmpegDemuxer::DemuxTask() { diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h index 20b77e4..9d68e35 100644 --- a/media/filters/ffmpeg_demuxer.h +++ b/media/filters/ffmpeg_demuxer.h @@ -120,10 +120,10 @@ class FFmpegDemuxer : public Demuxer { // MediaFilter implementation. virtual void Stop(); - virtual void Seek(base::TimeDelta time, FilterCallback* callback); + virtual void Seek(base::TimeDelta time); // Demuxer implementation. - virtual void Initialize(DataSource* data_source, FilterCallback* callback); + virtual bool Initialize(DataSource* data_source); virtual size_t GetNumberOfStreams(); virtual scoped_refptr<DemuxerStream> GetStream(int stream_id); @@ -134,10 +134,10 @@ class FFmpegDemuxer : public Demuxer { virtual ~FFmpegDemuxer(); // Carries out initialization on the demuxer thread. - void InititalizeTask(DataSource* data_source, FilterCallback* callback); + void InititalizeTask(DataSource* data_source); // Carries out a seek on the demuxer thread. - void SeekTask(base::TimeDelta time, FilterCallback* callback); + void SeekTask(base::TimeDelta time); // Carries out demuxing and satisfying stream reads on the demuxer thread. void DemuxTask(); diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc index 18cec27..43b14c7 100644 --- a/media/filters/ffmpeg_demuxer_unittest.cc +++ b/media/filters/ffmpeg_demuxer_unittest.cc @@ -133,8 +133,7 @@ class FFmpegDemuxerTest : public testing::Test { InitializeDemuxerMocks(); // We expect a successful initialization. - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); + EXPECT_CALL(host_, InitializationComplete()); // Since we ignore data streams, the duration should be equal to the longest // supported stream's duration (audio, in this case). @@ -142,7 +141,7 @@ class FFmpegDemuxerTest : public testing::Test { base::TimeDelta::FromMicroseconds(kDurations[AV_STREAM_AUDIO]); EXPECT_CALL(host_, SetDuration(expected_duration)); - demuxer_->Initialize(data_source_.get(), callback_.NewCallback()); + EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); message_loop_.RunAllPending(); } @@ -151,7 +150,6 @@ class FFmpegDemuxerTest : public testing::Test { scoped_refptr<FFmpegDemuxer> demuxer_; scoped_refptr<StrictMock<MockDataSource> > data_source_; StrictMock<MockFilterHost> host_; - StrictMock<MockFilterCallback> callback_; MessageLoop message_loop_; // FFmpeg fixtures. @@ -198,10 +196,8 @@ TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { EXPECT_CALL(*MockFFmpeg::get(), AVOpenInputFile(_, _, NULL, 0, NULL)) .WillOnce(Return(-1)); EXPECT_CALL(host_, Error(DEMUXER_ERROR_COULD_NOT_OPEN)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - demuxer_->Initialize(data_source_.get(), callback_.NewCallback()); + EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); message_loop_.RunAllPending(); } @@ -213,10 +209,8 @@ TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { .WillOnce(Return(AVERROR_IO)); EXPECT_CALL(*MockFFmpeg::get(), AVCloseInputFile(&format_context_)); EXPECT_CALL(host_, Error(DEMUXER_ERROR_COULD_NOT_PARSE)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - demuxer_->Initialize(data_source_.get(), callback_.NewCallback()); + EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); message_loop_.RunAllPending(); } @@ -227,11 +221,9 @@ TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { InitializeDemuxerMocks(); } EXPECT_CALL(host_, Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); format_context_.nb_streams = 0; - demuxer_->Initialize(data_source_.get(), callback_.NewCallback()); + EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); message_loop_.RunAllPending(); } @@ -242,12 +234,10 @@ TEST_F(FFmpegDemuxerTest, Initialize_DataStreamOnly) { InitializeDemuxerMocks(); } EXPECT_CALL(host_, Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); EXPECT_EQ(format_context_.streams[0], &streams_[AV_STREAM_DATA]); format_context_.nb_streams = 1; - demuxer_->Initialize(data_source_.get(), callback_.NewCallback()); + EXPECT_TRUE(demuxer_->Initialize(data_source_.get())); message_loop_.RunAllPending(); } @@ -456,11 +446,6 @@ TEST_F(FFmpegDemuxerTest, Seek) { EXPECT_CALL(*MockFFmpeg::get(), AVSeekFrame(&format_context_, -1, kExpectedTimestamp, kExpectedFlags)) .WillOnce(Return(0)); - - // ...then our callback will be executed... - StrictMock<MockFilterCallback> seek_callback; - EXPECT_CALL(seek_callback, OnFilterCallback()); - EXPECT_CALL(seek_callback, OnCallbackDestroyed()); EXPECT_CALL(*MockFFmpeg::get(), CheckPoint(2)); // ...followed by two audio packet reads we'll trigger... @@ -498,8 +483,7 @@ TEST_F(FFmpegDemuxerTest, Seek) { MockFFmpeg::get()->CheckPoint(1); // Now issue a simple forward seek, which should discard queued packets. - demuxer_->Seek(base::TimeDelta::FromMicroseconds(kExpectedTimestamp), - seek_callback.NewCallback()); + demuxer_->Seek(base::TimeDelta::FromMicroseconds(kExpectedTimestamp)); message_loop_.RunAllPending(); MockFFmpeg::get()->CheckPoint(2); diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc index 407f685..b4d4ace 100644 --- a/media/filters/ffmpeg_video_decoder_unittest.cc +++ b/media/filters/ffmpeg_video_decoder_unittest.cc @@ -118,7 +118,6 @@ class FFmpegVideoDecoderTest : public testing::Test { scoped_refptr<DataBuffer> buffer_; scoped_refptr<DataBuffer> end_of_stream_buffer_; StrictMock<MockFilterHost> host_; - StrictMock<MockFilterCallback> callback_; MessageLoop message_loop_; // FFmpeg fixtures. @@ -163,10 +162,8 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_QueryInterfaceFails) { EXPECT_CALL(*demuxer_, QueryInterface(AVStreamProvider::interface_id())) .WillOnce(ReturnNull()); EXPECT_CALL(host_, Error(PIPELINE_ERROR_DECODE)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - decoder_->Initialize(demuxer_, callback_.NewCallback()); + EXPECT_TRUE(decoder_->Initialize(demuxer_)); message_loop_.RunAllPending(); } @@ -180,10 +177,8 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_FindDecoderFails) { EXPECT_CALL(*MockFFmpeg::get(), AVCodecFindDecoder(CODEC_ID_NONE)) .WillOnce(ReturnNull()); EXPECT_CALL(host_, Error(PIPELINE_ERROR_DECODE)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - decoder_->Initialize(demuxer_, callback_.NewCallback()); + EXPECT_TRUE(decoder_->Initialize(demuxer_)); message_loop_.RunAllPending(); } @@ -199,10 +194,8 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_InitThreadFails) { EXPECT_CALL(*MockFFmpeg::get(), AVCodecThreadInit(&codec_context_, 2)) .WillOnce(Return(-1)); EXPECT_CALL(host_, Error(PIPELINE_ERROR_DECODE)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - decoder_->Initialize(demuxer_, callback_.NewCallback()); + EXPECT_TRUE(decoder_->Initialize(demuxer_)); message_loop_.RunAllPending(); } @@ -220,10 +213,8 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) { EXPECT_CALL(*MockFFmpeg::get(), AVCodecOpen(&codec_context_, &codec_)) .WillOnce(Return(-1)); EXPECT_CALL(host_, Error(PIPELINE_ERROR_DECODE)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - decoder_->Initialize(demuxer_, callback_.NewCallback()); + EXPECT_TRUE(decoder_->Initialize(demuxer_)); message_loop_.RunAllPending(); } @@ -240,10 +231,9 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_Successful) { .WillOnce(Return(0)); EXPECT_CALL(*MockFFmpeg::get(), AVCodecOpen(&codec_context_, &codec_)) .WillOnce(Return(0)); - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); + EXPECT_CALL(host_, InitializationComplete()); - decoder_->Initialize(demuxer_, callback_.NewCallback()); + EXPECT_TRUE(decoder_->Initialize(demuxer_)); message_loop_.RunAllPending(); // Test that the output media format is an uncompressed video surface that diff --git a/media/filters/file_data_source.cc b/media/filters/file_data_source.cc index 8ac4499..2e13a59 100644 --- a/media/filters/file_data_source.cc +++ b/media/filters/file_data_source.cc @@ -20,10 +20,8 @@ FileDataSource::~FileDataSource() { Stop(); } -void FileDataSource::Initialize(const std::string& url, - FilterCallback* callback) { +bool FileDataSource::Initialize(const std::string& url) { DCHECK(!file_); - scoped_ptr<FilterCallback> c(callback); #if defined(OS_WIN) FilePath file_path(UTF8ToWide(url)); #else @@ -35,15 +33,15 @@ void FileDataSource::Initialize(const std::string& url, if (!file_) { file_size_ = 0; host()->Error(PIPELINE_ERROR_URL_NOT_FOUND); - callback->Run(); - return; + return false; } media_format_.SetAsString(MediaFormat::kMimeType, mime_type::kApplicationOctetStream); media_format_.SetAsString(MediaFormat::kURL, url); host()->SetTotalBytes(file_size_); host()->SetBufferedBytes(file_size_); - callback->Run(); + host()->InitializationComplete(); + return true; } void FileDataSource::Stop() { diff --git a/media/filters/file_data_source.h b/media/filters/file_data_source.h index 5c91ce1..e58e4aa 100644 --- a/media/filters/file_data_source.h +++ b/media/filters/file_data_source.h @@ -26,7 +26,7 @@ class FileDataSource : public DataSource { virtual void Stop(); // Implementation of DataSource. - virtual void Initialize(const std::string& url, FilterCallback* callback); + virtual bool Initialize(const std::string& url); virtual const MediaFormat& media_format(); virtual size_t Read(uint8* data, size_t size); virtual bool GetPosition(int64* position_out); @@ -41,7 +41,6 @@ class FileDataSource : public DataSource { // of my tests!!! FRIEND_TEST(FileDataSourceTest, OpenFile); FRIEND_TEST(FileDataSourceTest, ReadData); - FRIEND_TEST(FileDataSourceTest, Seek); friend class FilterFactoryImpl0<FileDataSource>; FileDataSource(); virtual ~FileDataSource(); diff --git a/media/filters/file_data_source_unittest.cc b/media/filters/file_data_source_unittest.cc index 9c4b9ee8..dd41e88 100644 --- a/media/filters/file_data_source_unittest.cc +++ b/media/filters/file_data_source_unittest.cc @@ -8,7 +8,6 @@ #include "base/file_path.h" #include "base/string_util.h" #include "media/base/mock_filter_host.h" -#include "media/base/mock_filters.h" #include "media/filters/file_data_source.h" using ::testing::NiceMock; @@ -39,15 +38,13 @@ std::string TestFileURL() { // Test that FileDataSource call the appropriate methods on its filter host. TEST(FileDataSourceTest, OpenFile) { StrictMock<MockFilterHost> host; - StrictMock<MockFilterCallback> callback; EXPECT_CALL(host, SetTotalBytes(10)); EXPECT_CALL(host, SetBufferedBytes(10)); - EXPECT_CALL(callback, OnFilterCallback()); - EXPECT_CALL(callback, OnCallbackDestroyed()); + EXPECT_CALL(host, InitializationComplete()); scoped_refptr<FileDataSource> filter = new FileDataSource(); filter->set_host(&host); - filter->Initialize(TestFileURL(), callback.NewCallback()); + EXPECT_TRUE(filter->Initialize(TestFileURL())); } // Use the mock filter host to directly call the Read and GetPosition methods. @@ -58,10 +55,9 @@ TEST(FileDataSourceTest, ReadData) { // Create our mock filter host and initialize the data source. NiceMock<MockFilterHost> host; - NiceMock<MockFilterCallback> callback; scoped_refptr<FileDataSource> filter = new FileDataSource(); filter->set_host(&host); - filter->Initialize(TestFileURL(), callback.NewCallback()); + EXPECT_TRUE(filter->Initialize(TestFileURL())); EXPECT_TRUE(filter->GetSize(&size)); EXPECT_EQ(10, size); @@ -84,15 +80,4 @@ TEST(FileDataSourceTest, ReadData) { EXPECT_EQ(10, position); } -// Test that FileDataSource does nothing on Seek(). -TEST(FileDataSourceTest, Seek) { - StrictMock<MockFilterCallback> callback; - EXPECT_CALL(callback, OnFilterCallback()); - EXPECT_CALL(callback, OnCallbackDestroyed()); - const base::TimeDelta kZero; - - scoped_refptr<FileDataSource> filter = new FileDataSource(); - filter->Seek(kZero, callback.NewCallback()); -} - } // namespace media diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc index 3ca45dc..7eace6f 100644 --- a/media/filters/video_renderer_base.cc +++ b/media/filters/video_renderer_base.cc @@ -81,7 +81,7 @@ void VideoRendererBase::SetPlaybackRate(float playback_rate) { playback_rate_ = playback_rate; } -void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { +void VideoRendererBase::Seek(base::TimeDelta time) { AutoLock auto_lock(lock_); // We need the first frame in |frames_| to run the VideoRendererBase main // loop, but we don't need decoded frames after the first frame since we are @@ -93,44 +93,29 @@ void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { } } -void VideoRendererBase::Initialize(VideoDecoder* decoder, - FilterCallback* callback) { +bool VideoRendererBase::Initialize(VideoDecoder* decoder) { AutoLock auto_lock(lock_); - DCHECK(decoder); - DCHECK(callback); DCHECK_EQ(state_, UNINITIALIZED); state_ = INITIALIZING; decoder_ = decoder; - initialize_callback_.reset(callback); // Notify the pipeline of the video dimensions. int width = 0; int height = 0; - if (!ParseMediaFormat(decoder->media_format(), &width, &height)) { - host()->Error(PIPELINE_ERROR_INITIALIZATION_FAILED); - initialize_callback_->Run(); - initialize_callback_.reset(); - return; - } + if (!ParseMediaFormat(decoder->media_format(), &width, &height)) + return false; host()->SetVideoSize(width, height); // Initialize the subclass. // TODO(scherkus): do we trust subclasses not to do something silly while // we're holding the lock? - if (!OnInitialize(decoder)) { - host()->Error(PIPELINE_ERROR_INITIALIZATION_FAILED); - initialize_callback_->Run(); - initialize_callback_.reset(); - return; - } + if (!OnInitialize(decoder)) + return false; // Create our video thread. if (!PlatformThread::Create(0, this, &thread_)) { NOTREACHED() << "Video thread creation failed"; - host()->Error(PIPELINE_ERROR_INITIALIZATION_FAILED); - initialize_callback_->Run(); - initialize_callback_.reset(); - return; + return false; } #if defined(OS_WIN) @@ -143,6 +128,8 @@ void VideoRendererBase::Initialize(VideoDecoder* decoder, for (size_t i = 0; i < kMaxFrames; ++i) { ScheduleRead(); } + + return true; } // PlatformThread::Delegate implementation. @@ -261,15 +248,11 @@ void VideoRendererBase::OnReadComplete(VideoFrame* frame) { if (frames_.empty()) { // We should have initialized but there's no decoded frames in the queue. // Raise an error. - state_ = ERRORED; host()->Error(PIPELINE_ERROR_NO_DATA); - initialize_callback_->Run(); - initialize_callback_.reset(); } else { state_ = INITIALIZED; current_frame_ = frames_.front(); - initialize_callback_->Run(); - initialize_callback_.reset(); + host()->InitializationComplete(); } } } @@ -283,11 +266,12 @@ bool VideoRendererBase::WaitForInitialized() { // initialized so we can call OnFrameAvailable() to provide subclasses with // the first frame. AutoLock auto_lock(lock_); + DCHECK_EQ(state_, INITIALIZING); while (state_ == INITIALIZING) { frame_available_.Wait(); - } - if (state_ == STOPPED || state_ == ERRORED) { - return false; + if (state_ == STOPPED) { + return false; + } } DCHECK_EQ(state_, INITIALIZED); DCHECK(current_frame_); diff --git a/media/filters/video_renderer_base.h b/media/filters/video_renderer_base.h index b1b46ab..e71befa 100644 --- a/media/filters/video_renderer_base.h +++ b/media/filters/video_renderer_base.h @@ -39,10 +39,10 @@ class VideoRendererBase : public VideoRenderer, // MediaFilter implementation. virtual void Stop(); virtual void SetPlaybackRate(float playback_rate); - virtual void Seek(base::TimeDelta time, FilterCallback* callback); + virtual void Seek(base::TimeDelta time); // VideoRenderer implementation. - virtual void Initialize(VideoDecoder* decoder, FilterCallback* callback); + virtual bool Initialize(VideoDecoder* decoder); // PlatformThread::Delegate implementation. virtual void ThreadMain(); @@ -106,7 +106,6 @@ class VideoRendererBase : public VideoRenderer, INITIALIZING, INITIALIZED, STOPPED, - ERRORED, }; State state_; @@ -118,9 +117,6 @@ class VideoRendererBase : public VideoRenderer, float playback_rate_; - // Filter callbacks. - scoped_ptr<FilterCallback> initialize_callback_; - DISALLOW_COPY_AND_ASSIGN(VideoRendererBase); }; diff --git a/media/filters/video_renderer_base_unittest.cc b/media/filters/video_renderer_base_unittest.cc deleted file mode 100644 index 691815d..0000000 --- a/media/filters/video_renderer_base_unittest.cc +++ /dev/null @@ -1,215 +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. - -#include "base/stl_util-inl.h" -#include "media/base/data_buffer.h" -#include "media/base/mock_filter_host.h" -#include "media/base/mock_filters.h" -#include "media/base/video_frame_impl.h" -#include "media/filters/video_renderer_base.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::NotNull; -using ::testing::Return; -using ::testing::StrictMock; - -namespace media { - -// Mocked subclass of VideoRendererBase for testing purposes. -class MockVideoRendererBase : public VideoRendererBase { - public: - MockVideoRendererBase() {} - virtual ~MockVideoRendererBase() {} - - // VideoRendererBase implementation. - MOCK_METHOD1(OnInitialize, bool (VideoDecoder* decoder)); - MOCK_METHOD0(OnStop, void()); - MOCK_METHOD0(OnFrameAvailable, void()); - - // Used for verifying check points during tests. - MOCK_METHOD1(CheckPoint, void(int id)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockVideoRendererBase); -}; - -class VideoRendererBaseTest : public ::testing::Test { - public: - VideoRendererBaseTest() - : renderer_(new MockVideoRendererBase()), - decoder_(new MockVideoDecoder(mime_type::kUncompressedVideo, kWidth, - kHeight)) { - renderer_->set_host(&host_); - - // Queue all reads from the decoder. - EXPECT_CALL(*decoder_, Read(NotNull())) - .WillRepeatedly(Invoke(this, &VideoRendererBaseTest::EnqueueCallback)); - } - - virtual ~VideoRendererBaseTest() { - STLDeleteElements(&read_queue_); - - // Expect a call into the subclass. - EXPECT_CALL(*renderer_, OnStop()); - renderer_->Stop(); - } - - protected: - static const size_t kWidth; - static const size_t kHeight; - - // Fixture members. - scoped_refptr<MockVideoRendererBase> renderer_; - scoped_refptr<MockVideoDecoder> decoder_; - StrictMock<MockFilterHost> host_; - StrictMock<MockFilterCallback> callback_; - - // Receives asynchronous read requests sent to |decoder_|. - std::deque<Callback1<VideoFrame*>::Type*> read_queue_; - - private: - void EnqueueCallback(Callback1<VideoFrame*>::Type* callback) { - read_queue_.push_back(callback); - } - - DISALLOW_COPY_AND_ASSIGN(VideoRendererBaseTest); -}; - -const size_t VideoRendererBaseTest::kWidth = 16u; -const size_t VideoRendererBaseTest::kHeight = 16u; - -// Test initialization where the decoder's media format is malformed. -TEST_F(VideoRendererBaseTest, Initialize_BadMediaFormat) { - InSequence s; - - // Don't set a media format. - scoped_refptr<MockVideoDecoder> bad_decoder = new MockVideoDecoder(); - - // We expect to receive an error. - EXPECT_CALL(host_, Error(PIPELINE_ERROR_INITIALIZATION_FAILED)); - - // We expect our callback to be executed. - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - - // Initialize, we expect to have no reads. - renderer_->Initialize(bad_decoder, callback_.NewCallback()); - EXPECT_EQ(0u, read_queue_.size()); -} - -// Test initialization where the subclass failed for some reason. -TEST_F(VideoRendererBaseTest, Initialize_Failed) { - InSequence s; - - // We expect the video size to be set. - EXPECT_CALL(host_, SetVideoSize(kWidth, kHeight)); - - // Our subclass will fail when asked to initialize. - EXPECT_CALL(*renderer_, OnInitialize(_)) - .WillOnce(Return(false)); - - // We expect to receive an error. - EXPECT_CALL(host_, Error(PIPELINE_ERROR_INITIALIZATION_FAILED)); - - // We expect our callback to be executed. - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - - // Initialize, we expect to have no reads. - renderer_->Initialize(decoder_, callback_.NewCallback()); - EXPECT_EQ(0u, read_queue_.size()); -} - -// Tests successful initialization, but when we immediately return an end of -// stream frame. -TEST_F(VideoRendererBaseTest, Initialize_NoData) { - InSequence s; - - // We expect the video size to be set. - EXPECT_CALL(host_, SetVideoSize(kWidth, kHeight)); - - // Then our subclass will be asked to initialize. - EXPECT_CALL(*renderer_, OnInitialize(_)) - .WillOnce(Return(true)); - - // Set up a check point to verify that the callback hasn't been executed yet. - EXPECT_CALL(*renderer_, CheckPoint(0)); - - // We'll provide end-of-stream immediately, which results in an error. - EXPECT_CALL(host_, Error(PIPELINE_ERROR_NO_DATA)); - - // Then we expect our callback to be executed. - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - - // Since the callbacks are on a separate thread, expect any number of calls. - EXPECT_CALL(*renderer_, OnFrameAvailable()) - .Times(AnyNumber()); - - // Initialize, we should expect to get a bunch of read requests. - renderer_->Initialize(decoder_, callback_.NewCallback()); - EXPECT_EQ(3u, read_queue_.size()); - - // Verify our callback hasn't been executed yet. - renderer_->CheckPoint(0); - - // Now satisfy the read requests. Our callback should be executed after - // exiting this loop. - while (!read_queue_.empty()) { - const base::TimeDelta kZero; - scoped_refptr<VideoFrame> frame; - VideoFrameImpl::CreateEmptyFrame(&frame); - read_queue_.front()->Run(frame); - delete read_queue_.front(); - read_queue_.pop_front(); - } -} - -// Test successful initialization and preroll. -TEST_F(VideoRendererBaseTest, Initialize_Successful) { - InSequence s; - - // We expect the video size to be set. - EXPECT_CALL(host_, SetVideoSize(kWidth, kHeight)); - - // Then our subclass will be asked to initialize. - EXPECT_CALL(*renderer_, OnInitialize(_)) - .WillOnce(Return(true)); - - // Set up a check point to verify that the callback hasn't been executed yet. - EXPECT_CALL(*renderer_, CheckPoint(0)); - - // After finishing preroll, we expect our callback to be executed. - EXPECT_CALL(callback_, OnFilterCallback()); - EXPECT_CALL(callback_, OnCallbackDestroyed()); - - // Since the callbacks are on a separate thread, expect any number of calls. - EXPECT_CALL(*renderer_, OnFrameAvailable()) - .Times(AnyNumber()); - - // Initialize, we should expect to get a bunch of read requests. - renderer_->Initialize(decoder_, callback_.NewCallback()); - EXPECT_EQ(3u, read_queue_.size()); - - // Verify our callback hasn't been executed yet. - renderer_->CheckPoint(0); - - // Now satisfy the read requests. Our callback should be executed after - // exiting this loop. - while (!read_queue_.empty()) { - const base::TimeDelta kZero; - scoped_refptr<VideoFrame> frame; - VideoFrameImpl::CreateFrame(VideoSurface::RGB32, kWidth, kHeight, kZero, - kZero, &frame); - read_queue_.front()->Run(frame); - delete read_queue_.front(); - read_queue_.pop_front(); - } -} - -} // namespace media diff --git a/media/media.gyp b/media/media.gyp index 5b4b96a..3b15e80 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -155,7 +155,6 @@ 'base/mock_ffmpeg.cc', 'base/mock_ffmpeg.h', 'base/mock_filter_host.h', - 'base/mock_filters.cc', 'base/mock_filters.h', 'base/mock_reader.h', 'base/pipeline_impl_unittest.cc', @@ -163,12 +162,10 @@ 'base/seekable_buffer_unittest.cc', 'base/video_frame_impl_unittest.cc', 'base/yuv_convert_unittest.cc', - 'filters/audio_renderer_base_unittest.cc', 'filters/ffmpeg_demuxer_unittest.cc', 'filters/ffmpeg_glue_unittest.cc', 'filters/ffmpeg_video_decoder_unittest.cc', 'filters/file_data_source_unittest.cc', - 'filters/video_renderer_base_unittest.cc', ], 'conditions': [ ['OS=="linux"', { |