diff options
35 files changed, 361 insertions, 347 deletions
diff --git a/chrome/renderer/media/audio_renderer_impl_unittest.cc b/chrome/renderer/media/audio_renderer_impl_unittest.cc index b5f80e6..249c987 100644 --- a/chrome/renderer/media/audio_renderer_impl_unittest.cc +++ b/chrome/renderer/media/audio_renderer_impl_unittest.cc @@ -46,7 +46,6 @@ class AudioRendererImplTest : public ::testing::Test { // Create and initialize audio renderer. renderer_ = new AudioRendererImpl(filter_); renderer_->set_host(&host_); - renderer_->set_message_loop(message_loop_.get()); renderer_->Initialize(decoder_, media::NewExpectedCallback()); // Run pending tasks and simulate responding with a created audio stream. diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 9395eca..f16ae6f 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -106,6 +106,7 @@ #include "grit/renderer_resources.h" #include "media/base/filter_collection.h" #include "media/base/media_switches.h" +#include "media/base/message_loop_factory_impl.h" #include "net/base/data_url.h" #include "net/base/escape.h" #include "net/base/net_errors.h" @@ -2811,6 +2812,8 @@ WebSharedWorker* RenderView::createSharedWorker( WebMediaPlayer* RenderView::createMediaPlayer( WebFrame* frame, WebMediaPlayerClient* client) { + scoped_ptr<media::MessageLoopFactory> message_loop_factory( + new media::MessageLoopFactoryImpl()); scoped_ptr<media::FilterCollection> collection( new media::FilterCollection()); @@ -2846,7 +2849,9 @@ WebMediaPlayer* RenderView::createMediaPlayer( video_renderer = renderer; scoped_ptr<webkit_glue::WebMediaPlayerImpl> result( - new webkit_glue::WebMediaPlayerImpl(client, collection.release())); + new webkit_glue::WebMediaPlayerImpl(client, + collection.release(), + message_loop_factory.release())); if (!result->Initialize(frame, cmd_line->HasSwitch(switches::kSimpleDataSource), video_renderer)) { diff --git a/media/base/composite_filter.cc b/media/base/composite_filter.cc index 94665fd..41eb31c 100644 --- a/media/base/composite_filter.cc +++ b/media/base/composite_filter.cc @@ -4,6 +4,7 @@ #include "media/base/composite_filter.h" +#include "base/message_loop.h" #include "base/stl_util-inl.h" #include "media/base/callback.h" @@ -40,46 +41,21 @@ class CompositeFilter::FilterHostImpl : public FilterHost { DISALLOW_COPY_AND_ASSIGN(FilterHostImpl); }; -CompositeFilter::CompositeFilter(MessageLoop* message_loop) { - Init(message_loop, NULL); -} - -CompositeFilter::CompositeFilter(MessageLoop* message_loop, - ThreadFactoryFunction thread_factory) { - DCHECK(thread_factory); - Init(message_loop, thread_factory); -} - -void CompositeFilter::Init(MessageLoop* message_loop, - ThreadFactoryFunction thread_factory) { +CompositeFilter::CompositeFilter(MessageLoop* message_loop) + : state_(kCreated), + sequence_index_(0), + message_loop_(message_loop), + error_(PIPELINE_OK) { DCHECK(message_loop); - message_loop_ = message_loop; - thread_factory_ = thread_factory; runnable_factory_.reset( new ScopedRunnableMethodFactory<CompositeFilter>(this)); - - if (!thread_factory_) { - thread_factory_ = &CompositeFilter::DefaultThreadFactory; - } - - state_ = kCreated; - sequence_index_ = 0; - error_ = PIPELINE_OK; } CompositeFilter::~CompositeFilter() { DCHECK_EQ(message_loop_, MessageLoop::current()); DCHECK(state_ == kCreated || state_ == kStopped); - // Stop every running filter thread. - for (FilterThreadVector::iterator iter = filter_threads_.begin(); - iter != filter_threads_.end(); - ++iter) { - (*iter)->Stop(); - } - filters_.clear(); - STLDeleteElements(&filter_threads_); } bool CompositeFilter::AddFilter(scoped_refptr<Filter> filter) { @@ -87,19 +63,6 @@ bool CompositeFilter::AddFilter(scoped_refptr<Filter> filter) { if (!filter.get() || state_ != kCreated || !host()) return false; - // Create a dedicated thread for this filter if applicable. - if (filter->requires_message_loop()) { - scoped_ptr<base::Thread> thread( - thread_factory_(filter->message_loop_name())); - - if (!thread.get() || !thread->Start()) { - return false; - } - - filter->set_message_loop(thread->message_loop()); - filter_threads_.push_back(thread.release()); - } - // Register ourselves as the filter's host. filter->set_host(host_impl_.get()); filters_.push_back(make_scoped_refptr(filter.get())); @@ -121,22 +84,6 @@ FilterHost* CompositeFilter::host() { return host_impl_.get() ? host_impl_->host() : NULL; } -bool CompositeFilter::requires_message_loop() const { - return false; -} - -const char* CompositeFilter::message_loop_name() const { - return "CompositeFilter"; -} - -void CompositeFilter::set_message_loop(MessageLoop* message_loop) { - NOTREACHED() << "Message loop should not be set."; -} - -MessageLoop* CompositeFilter::message_loop() { - return NULL; -} - void CompositeFilter::Play(FilterCallback* play_callback) { DCHECK_EQ(message_loop_, MessageLoop::current()); scoped_ptr<FilterCallback> callback(play_callback); @@ -278,11 +225,6 @@ void CompositeFilter::OnAudioRendererDisabled() { } } -base::Thread* CompositeFilter::DefaultThreadFactory( - const char* thread_name) { - return new base::Thread(thread_name); -} - void CompositeFilter::ChangeState(State new_state) { DCHECK_EQ(message_loop_, MessageLoop::current()); state_ = new_state; @@ -529,9 +471,9 @@ void CompositeFilter::SetError(PipelineError error) { } CompositeFilter::FilterHostImpl::FilterHostImpl(CompositeFilter* parent, - FilterHost* host) : - parent_(parent), - host_(host) { + FilterHost* host) + : parent_(parent), + host_(host) { } FilterHost* CompositeFilter::FilterHostImpl::host() { diff --git a/media/base/composite_filter.h b/media/base/composite_filter.h index c1bd8c0..daac421 100644 --- a/media/base/composite_filter.h +++ b/media/base/composite_filter.h @@ -5,39 +5,29 @@ #ifndef MEDIA_BASE_COMPOSITE_FILTER_H_ #define MEDIA_BASE_COMPOSITE_FILTER_H_ -#include "base/threading/thread.h" +#include "base/task.h" #include "media/base/filter_host.h" #include "media/base/filters.h" +class MessageLoop; + namespace media { class CompositeFilter : public Filter { public: - typedef base::Thread* (*ThreadFactoryFunction)(const char* thread_name); - - CompositeFilter(MessageLoop* message_loop); - - // Constructor that allows the default thread creation strategy to be - // overridden. - CompositeFilter(MessageLoop* message_loop, - ThreadFactoryFunction thread_factory); + explicit CompositeFilter(MessageLoop* message_loop); // Adds a filter to the composite. This is only allowed after set_host() // is called and before the first state changing operation such as Play(), // Flush(), Stop(), or Seek(). True is returned if the filter was successfully // added to the composite. False is returned if the filter couldn't be added - // because the composite is in the wrong state or the filter needed a thread - // and the composite was unable to create one. + // because the composite is in the wrong state. bool AddFilter(scoped_refptr<Filter> filter); // media::Filter methods. virtual const char* major_mime_type() const; virtual void set_host(FilterHost* host); virtual FilterHost* host(); - virtual bool requires_message_loop() const; - virtual const char* message_loop_name() const; - virtual void set_message_loop(MessageLoop* message_loop); - virtual MessageLoop* message_loop(); virtual void Play(FilterCallback* play_callback); virtual void Pause(FilterCallback* pause_callback); virtual void Flush(FilterCallback* flush_callback); @@ -49,9 +39,6 @@ class CompositeFilter : public Filter { protected: virtual ~CompositeFilter(); - /// Default thread factory strategy. - static base::Thread* DefaultThreadFactory(const char* thread_name); - void SetError(PipelineError error); private: @@ -75,9 +62,6 @@ class CompositeFilter : public Filter { kError }; - // Initialization method called by constructors. - void Init(MessageLoop* message_loop, ThreadFactoryFunction thread_factory); - // Transition to a new state. void ChangeState(State new_state); @@ -124,17 +108,10 @@ class CompositeFilter : public Filter { // to the host of this filter. bool CanForwardError(); - // Vector of threads owned by the composite and used by filters in |filters_|. - typedef std::vector<base::Thread*> FilterThreadVector; - FilterThreadVector filter_threads_; - // Vector of the filters added to the composite. typedef std::vector<scoped_refptr<Filter> > FilterVector; FilterVector filters_; - // Factory function used to create filter threads. - ThreadFactoryFunction thread_factory_; - // Callback for the pending request. scoped_ptr<FilterCallback> callback_; diff --git a/media/base/composite_filter_unittest.cc b/media/base/composite_filter_unittest.cc index 4ce96c1..0be2185 100644 --- a/media/base/composite_filter_unittest.cc +++ b/media/base/composite_filter_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop.h" #include "media/base/composite_filter.h" #include "media/base/mock_callback.h" #include "media/base/mock_filter_host.h" @@ -297,56 +298,29 @@ void CompositeFilterTest::RunFilter2Callback() { delete callback; } -static base::Thread* NullThreadFactory(const char* thread_name) { - return NULL; -} - // Test AddFilter() failure cases. TEST_F(CompositeFilterTest, TestAddFilterFailCases) { // Test adding a null pointer. EXPECT_FALSE(composite_->AddFilter(NULL)); - scoped_refptr<StrictMock<MockFilter> > filter = - new StrictMock<MockFilter>(true); + scoped_refptr<StrictMock<MockFilter> > filter = new StrictMock<MockFilter>(); EXPECT_EQ(NULL, filter->host()); - EXPECT_EQ(NULL, filter->message_loop()); // Test failing because set_host() hasn't been called yet. EXPECT_FALSE(composite_->AddFilter(filter)); - - // Test thread creation failure. - composite_ = new CompositeFilter(&message_loop_, &NullThreadFactory); - composite_->set_host(mock_filter_host_.get()); - EXPECT_FALSE(composite_->AddFilter(filter)); - EXPECT_EQ(NULL, filter->host()); - EXPECT_EQ(NULL, filter->message_loop()); } // Test successful AddFilter() cases. TEST_F(CompositeFilterTest, TestAddFilter) { composite_->set_host(mock_filter_host_.get()); - // Add a filter that doesn't require a message loop. + // Add a filter. scoped_refptr<StrictMock<MockFilter> > filter = new StrictMock<MockFilter>(); EXPECT_EQ(NULL, filter->host()); - EXPECT_EQ(NULL, filter->message_loop()); EXPECT_TRUE(composite_->AddFilter(filter)); EXPECT_TRUE(filter->host() != NULL); - EXPECT_EQ(NULL, filter->message_loop()); - - // Add a filter that requires a message loop. - scoped_refptr<StrictMock<MockFilter> > filter_2 = - new StrictMock<MockFilter>(true); - - EXPECT_EQ(NULL, filter_2->host()); - EXPECT_EQ(NULL, filter_2->message_loop()); - - EXPECT_TRUE(composite_->AddFilter(filter_2)); - - EXPECT_TRUE(filter_2->host() != NULL); - EXPECT_TRUE(filter_2->message_loop() != NULL); } TEST_F(CompositeFilterTest, TestPlay) { diff --git a/media/base/filters.cc b/media/base/filters.cc index d3d3bcb..eff50b4 100644 --- a/media/base/filters.cc +++ b/media/base/filters.cc @@ -5,11 +5,10 @@ #include "media/base/filters.h" #include "base/logging.h" -#include "base/message_loop.h" namespace media { -Filter::Filter() : host_(NULL), message_loop_(NULL) {} +Filter::Filter() : host_(NULL) {} Filter::~Filter() {} @@ -27,24 +26,6 @@ FilterHost* Filter::host() { return host_; } -bool Filter::requires_message_loop() const { - return false; -} - -const char* Filter::message_loop_name() const { - return "FilterThread"; -} - -void Filter::set_message_loop(MessageLoop* message_loop) { - DCHECK(message_loop); - DCHECK(!message_loop_); - message_loop_ = message_loop; -} - -MessageLoop* Filter::message_loop() { - return message_loop_; -} - void Filter::Play(FilterCallback* callback) { DCHECK(callback); if (callback) { @@ -93,26 +74,10 @@ bool DataSource::IsUrlSupported(const std::string& url) { return true; } -bool Demuxer::requires_message_loop() const { - return true; -} - -const char* Demuxer::message_loop_name() const { - return "DemuxerThread"; -} - const char* AudioDecoder::major_mime_type() const { return mime_type::kMajorTypeAudio; } -bool AudioDecoder::requires_message_loop() const { - return true; -} - -const char* AudioDecoder::message_loop_name() const { - return "AudioDecoderThread"; -} - const char* AudioRenderer::major_mime_type() const { return mime_type::kMajorTypeAudio; } @@ -121,14 +86,6 @@ const char* VideoDecoder::major_mime_type() const { return mime_type::kMajorTypeVideo; } -bool VideoDecoder::requires_message_loop() const { - return true; -} - -const char* VideoDecoder::message_loop_name() const { - return "VideoDecoderThread"; -} - const char* VideoRenderer::major_mime_type() const { return mime_type::kMajorTypeVideo; } diff --git a/media/base/filters.h b/media/base/filters.h index 49fa347..84c466d 100644 --- a/media/base/filters.h +++ b/media/base/filters.h @@ -33,8 +33,6 @@ #include "media/base/media_format.h" #include "media/base/video_frame.h" -class MessageLoop; - namespace media { class Buffer; @@ -61,20 +59,6 @@ class Filter : public base::RefCountedThreadSafe<Filter> { virtual FilterHost* host(); - // Indicates whether this filter requires a message loop to operate. - virtual bool requires_message_loop() const; - - // The name to associate with this filter's message loop. - virtual const char* message_loop_name() const; - - // Sets the private member |message_loop_|, which is used by filters for - // processing asynchronous tasks and maintaining synchronized access to - // internal data members. The message loop should be running and exceed the - // lifetime of the filter. - virtual void set_message_loop(MessageLoop* message_loop); - - virtual MessageLoop* message_loop(); - // The pipeline has resumed playback. Filters can continue requesting reads. // Filters may implement this method if they need to respond to this call. // TODO(boliu): Check that callback is not NULL in subclasses. @@ -114,11 +98,9 @@ class Filter : public base::RefCountedThreadSafe<Filter> { virtual ~Filter(); FilterHost* host() const { return host_; } - MessageLoop* message_loop() const { return message_loop_; } private: FilterHost* host_; - MessageLoop* message_loop_; DISALLOW_COPY_AND_ASSIGN(Filter); }; @@ -154,9 +136,6 @@ class DataSource : public Filter { class Demuxer : public Filter { public: - virtual bool requires_message_loop() const; - virtual const char* message_loop_name() const; - // Initialize a Demuxer with the given DataSource, executing the callback upon // completion. virtual void Initialize(DataSource* data_source, @@ -211,9 +190,6 @@ class DemuxerStream : public base::RefCountedThreadSafe<DemuxerStream> { class VideoDecoder : public Filter { public: virtual const char* major_mime_type() const; - virtual bool requires_message_loop() const; - virtual const char* message_loop_name() const; - // Initialize a VideoDecoder with the given DemuxerStream, executing the // callback upon completion. @@ -256,8 +232,6 @@ class VideoDecoder : public Filter { class AudioDecoder : public Filter { public: virtual const char* major_mime_type() const; - virtual bool requires_message_loop() const; - virtual const char* message_loop_name() const; // Initialize a AudioDecoder with the given DemuxerStream, executing the // callback upon completion. diff --git a/media/base/message_loop_factory.cc b/media/base/message_loop_factory.cc new file mode 100644 index 0000000..e5b1d33 --- /dev/null +++ b/media/base/message_loop_factory.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2011 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/message_loop_factory.h" + +namespace media { + +MessageLoopFactory::~MessageLoopFactory() {} + +} // namespace media diff --git a/media/base/message_loop_factory.h b/media/base/message_loop_factory.h new file mode 100644 index 0000000..dacfab2 --- /dev/null +++ b/media/base/message_loop_factory.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 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_MESSAGE_LOOP_FACTORY_H_ +#define MEDIA_BASE_MESSAGE_LOOP_FACTORY_H_ + +#include <string> + +#include "base/scoped_ptr.h" + +class MessageLoop; + +namespace media { + +// Factory object that manages named MessageLoops. +class MessageLoopFactory { + public: + // Get the message loop associated with |name|. A new MessageLoop + // is created if the factory doesn't have one associated with |name|. + // NULL is returned if |name| is an empty string, or a new + // MessageLoop needs to be created and a failure occurs during the + // creation process. + virtual MessageLoop* GetMessageLoop(const std::string& name) = 0; + + protected: + // Only allow scoped_ptr<> to delete factory. + friend class scoped_ptr<MessageLoopFactory>; + virtual ~MessageLoopFactory(); +}; + +} // namespace media + +#endif // MEDIA_BASE_MESSAGE_LOOP_FACTORY_H_ diff --git a/media/base/message_loop_factory_impl.cc b/media/base/message_loop_factory_impl.cc new file mode 100644 index 0000000..bcf3bf8 --- /dev/null +++ b/media/base/message_loop_factory_impl.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011 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/message_loop_factory_impl.h" + +namespace media { + +MessageLoopFactoryImpl::MessageLoopFactoryImpl() {} + +MessageLoopFactoryImpl::~MessageLoopFactoryImpl() { + AutoLock auto_lock(lock_); + + for (ThreadMap::iterator iter = thread_map_.begin(); + iter != thread_map_.end(); + ++iter) { + base::Thread* thread = (*iter).second; + + if (thread) { + thread->Stop(); + delete thread; + } + } + thread_map_.clear(); +} + +// MessageLoopFactory methods. +MessageLoop* MessageLoopFactoryImpl::GetMessageLoop(const std::string& name) { + if (name.empty()) { + return NULL; + } + + AutoLock auto_lock(lock_); + + ThreadMap::iterator it = thread_map_.find(name); + if (it != thread_map_.end()) + return (*it).second->message_loop(); + + scoped_ptr<base::Thread> thread(new base::Thread(name.c_str())); + + if (thread->Start()) { + MessageLoop* message_loop = thread->message_loop(); + thread_map_[name] = thread.release(); + return message_loop; + } + + LOG(ERROR) << "Failed to start '" << name << "' thread!"; + return NULL; +} + +} // namespace media diff --git a/media/base/message_loop_factory_impl.h b/media/base/message_loop_factory_impl.h new file mode 100644 index 0000000..1c8a61a --- /dev/null +++ b/media/base/message_loop_factory_impl.h @@ -0,0 +1,38 @@ +// Copyright (c) 2011 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_MESSAGE_LOOP_FACTORY_IMPL_H_ +#define MEDIA_BASE_MESSAGE_LOOP_FACTORY_IMPL_H_ + +#include <map> +#include <string> + +#include "base/threading/thread.h" +#include "media/base/message_loop_factory.h" + +namespace media { + +class MessageLoopFactoryImpl : public MessageLoopFactory { + public: + MessageLoopFactoryImpl(); + + // MessageLoopFactory methods. + virtual MessageLoop* GetMessageLoop(const std::string& name); + + protected: + virtual ~MessageLoopFactoryImpl(); + + private: + // Lock used to serialize access for the following data members. + Lock lock_; + + typedef std::map<std::string, base::Thread*> ThreadMap; + ThreadMap thread_map_; + + DISALLOW_COPY_AND_ASSIGN(MessageLoopFactoryImpl); +}; + +} // namespace media + +#endif // MEDIA_BASE_MESSAGE_LOOP_FACTORY_IMPL_H_ diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc index 90df69b..8aa5458 100644 --- a/media/base/mock_filters.cc +++ b/media/base/mock_filters.cc @@ -74,23 +74,9 @@ void RunStopFilterCallback(FilterCallback* callback) { delete callback; } -MockFilter::MockFilter() : - requires_message_loop_(false) { -} - -MockFilter::MockFilter(bool requires_message_loop) : - requires_message_loop_(requires_message_loop) { +MockFilter::MockFilter() { } MockFilter::~MockFilter() {} -bool MockFilter::requires_message_loop() const { - return requires_message_loop_; -} - -const char* MockFilter::message_loop_name() const { - return "MockFilter"; -} - - } // namespace media diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index 45c1e29..3439597 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h @@ -46,12 +46,8 @@ class Destroyable : public MockClass { class MockFilter : public Filter { public: MockFilter(); - MockFilter(bool requires_message_loop); // Filter implementation. - virtual bool requires_message_loop() const; - virtual const char* message_loop_name() const; - MOCK_METHOD1(Play, void(FilterCallback* callback)); MOCK_METHOD1(Pause, void(FilterCallback* callback)); MOCK_METHOD1(Flush, void(FilterCallback* callback)); @@ -64,9 +60,6 @@ class MockFilter : public Filter { virtual ~MockFilter(); private: - - bool requires_message_loop_; - DISALLOW_COPY_AND_ASSIGN(MockFilter); }; diff --git a/media/filters/decoder_base.h b/media/filters/decoder_base.h index f8b26ab..7ddd16e 100644 --- a/media/filters/decoder_base.h +++ b/media/filters/decoder_base.h @@ -26,17 +26,16 @@ namespace media { template <class Decoder, class Output> class DecoderBase : public Decoder { public: - // Filter implementation. virtual void Stop(FilterCallback* callback) { - this->message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &DecoderBase::StopTask, callback)); } virtual void Seek(base::TimeDelta time, FilterCallback* callback) { - this->message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &DecoderBase::SeekTask, time, callback)); } @@ -44,7 +43,7 @@ class DecoderBase : public Decoder { // Decoder implementation. virtual void Initialize(DemuxerStream* demuxer_stream, FilterCallback* callback) { - this->message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &DecoderBase::InitializeTask, @@ -58,13 +57,14 @@ class DecoderBase : public Decoder { // Note that this class is only used by the audio decoder, this will // eventually be merged into FFmpegAudioDecoder. virtual void ProduceAudioSamples(scoped_refptr<Output> output) { - this->message_loop()->PostTask(FROM_HERE, + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &DecoderBase::ReadTask, output)); } protected: - DecoderBase() - : pending_reads_(0), + explicit DecoderBase(MessageLoop* message_loop) + : message_loop_(message_loop), + pending_reads_(0), pending_requests_(0), state_(kUninitialized) { } @@ -78,7 +78,7 @@ class DecoderBase : public Decoder { // It places an output buffer in the result queue. It must be called from // within the OnDecode method. void EnqueueResult(Output* output) { - DCHECK_EQ(MessageLoop::current(), this->message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); if (!IsStopped()) { result_queue_.push_back(output); } @@ -136,6 +136,9 @@ class DecoderBase : public Decoder { } } + // Provide access to subclasses. + MessageLoop* message_loop() { return message_loop_; } + private: bool IsStopped() { return state_ == kStopped; } @@ -146,12 +149,12 @@ class DecoderBase : public Decoder { // TODO(scherkus): change the callback format to pass a scoped_refptr<> or // better yet see if we can get away with not using reference counting. scoped_refptr<Buffer> buffer_ref = buffer; - this->message_loop()->PostTask(FROM_HERE, + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &DecoderBase::ReadCompleteTask, buffer_ref)); } void StopTask(FilterCallback* callback) { - DCHECK_EQ(MessageLoop::current(), this->message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); // Delegate to the subclass first. DoStop(NewRunnableMethod(this, &DecoderBase::OnStopComplete, callback)); @@ -169,7 +172,7 @@ class DecoderBase : public Decoder { } void SeekTask(base::TimeDelta time, FilterCallback* callback) { - DCHECK_EQ(MessageLoop::current(), this->message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed"; DCHECK_EQ(0u, pending_requests_) << "Pending requests should be empty"; @@ -190,7 +193,7 @@ class DecoderBase : public Decoder { } void InitializeTask(DemuxerStream* demuxer_stream, FilterCallback* callback) { - DCHECK_EQ(MessageLoop::current(), this->message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); CHECK(kUninitialized == state_); CHECK(!demuxer_stream_); demuxer_stream_ = demuxer_stream; @@ -208,7 +211,7 @@ class DecoderBase : public Decoder { scoped_ptr<bool> success_deleter(success); AutoCallbackRunner done_runner(done_cb); - DCHECK_EQ(MessageLoop::current(), this->message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); // Delegate to subclass first. if (!*success) { this->host()->SetError(PIPELINE_ERROR_DECODE); @@ -220,7 +223,7 @@ class DecoderBase : public Decoder { } void ReadTask(scoped_refptr<Output> output) { - DCHECK_EQ(MessageLoop::current(), this->message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); // TODO(scherkus): should reply with a null operation (empty buffer). if (IsStopped()) @@ -239,7 +242,7 @@ class DecoderBase : public Decoder { } void ReadCompleteTask(scoped_refptr<Buffer> buffer) { - DCHECK_EQ(MessageLoop::current(), this->message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK_GT(pending_reads_, 0u); --pending_reads_; if (IsStopped()) { @@ -255,7 +258,7 @@ class DecoderBase : public Decoder { // // Return true if one read request is fulfilled. bool FulfillPendingRead() { - DCHECK_EQ(MessageLoop::current(), this->message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); if (!pending_requests_ || result_queue_.empty()) { return false; } @@ -274,6 +277,8 @@ class DecoderBase : public Decoder { return true; } + MessageLoop* message_loop_; + // Tracks the number of asynchronous reads issued to |demuxer_stream_|. // Using size_t since it is always compared against deque::size(). size_t pending_reads_; diff --git a/media/filters/decoder_base_unittest.cc b/media/filters/decoder_base_unittest.cc index 2fefb56..661ba4e 100644 --- a/media/filters/decoder_base_unittest.cc +++ b/media/filters/decoder_base_unittest.cc @@ -62,7 +62,8 @@ class MockDecoderCallback { class MockDecoderImpl : public media::DecoderBase< MockDecoder, MockDecoderOutput> { public: - MockDecoderImpl() { + explicit MockDecoderImpl(MessageLoop* message_loop) + : media::DecoderBase<MockDecoder, MockDecoderOutput>(message_loop) { media_format_.SetAsString(media::MediaFormat::kMimeType, "mock"); } @@ -117,12 +118,11 @@ ACTION(CompleteDemuxRequest) { // \ ReadCallback() -> client TEST(DecoderBaseTest, FlowControl) { MessageLoop message_loop; - scoped_refptr<MockDecoderImpl> decoder(new MockDecoderImpl()); + scoped_refptr<MockDecoderImpl> decoder(new MockDecoderImpl(&message_loop)); MockDecoderCallback read_callback; decoder->set_consume_audio_samples_callback( NewCallback(&read_callback, &MockDecoderCallback::OnReadComplete)); scoped_refptr<MockDemuxerStream> demuxer_stream(new MockDemuxerStream()); - decoder->set_message_loop(&message_loop); // Initailize. EXPECT_CALL(*decoder, DoInitialize(NotNull(), NotNull(), NotNull())) diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc index 2e8e9ad..030149a 100644 --- a/media/filters/ffmpeg_audio_decoder.cc +++ b/media/filters/ffmpeg_audio_decoder.cc @@ -27,8 +27,9 @@ namespace media { const size_t FFmpegAudioDecoder::kOutputBufferSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; -FFmpegAudioDecoder::FFmpegAudioDecoder() - : codec_context_(NULL), +FFmpegAudioDecoder::FFmpegAudioDecoder(MessageLoop* message_loop) + : DecoderBase<AudioDecoder, Buffer>(message_loop), + codec_context_(NULL), estimated_next_timestamp_(kNoTimestamp) { } diff --git a/media/filters/ffmpeg_audio_decoder.h b/media/filters/ffmpeg_audio_decoder.h index 0a7a915..20bc22e 100644 --- a/media/filters/ffmpeg_audio_decoder.h +++ b/media/filters/ffmpeg_audio_decoder.h @@ -1,6 +1,6 @@ -// 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. +// 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_FILTERS_FFMPEG_AUDIO_DECODER_H_ #define MEDIA_FILTERS_FFMPEG_AUDIO_DECODER_H_ @@ -16,7 +16,7 @@ class ScopedPtrAVFree; class FFmpegAudioDecoder : public DecoderBase<AudioDecoder, Buffer> { public: - FFmpegAudioDecoder(); + explicit FFmpegAudioDecoder(MessageLoop* message_loop); virtual ~FFmpegAudioDecoder(); protected: diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 7c4f763..17248c6 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc @@ -239,12 +239,14 @@ base::TimeDelta FFmpegDemuxerStream::ConvertStreamTimestamp( // // FFmpegDemuxer // -FFmpegDemuxer::FFmpegDemuxer() - : format_context_(NULL), +FFmpegDemuxer::FFmpegDemuxer(MessageLoop* message_loop) + : message_loop_(message_loop), + format_context_(NULL), read_event_(false, false), read_has_failed_(false), last_read_bytes_(0), read_position_(0) { + DCHECK(message_loop_); } FFmpegDemuxer::~FFmpegDemuxer() { @@ -279,13 +281,13 @@ FFmpegDemuxer::~FFmpegDemuxer() { } void FFmpegDemuxer::PostDemuxTask() { - message_loop()->PostTask(FROM_HERE, + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &FFmpegDemuxer::DemuxTask)); } void FFmpegDemuxer::Stop(FilterCallback* callback) { // Post a task to notify the streams to stop as well. - message_loop()->PostTask(FROM_HERE, + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &FFmpegDemuxer::StopTask, callback)); // Then wakes up the thread from reading. @@ -297,18 +299,18 @@ void FFmpegDemuxer::Seek(base::TimeDelta time, FilterCallback* callback) { // 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, + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time, callback)); } void FFmpegDemuxer::OnAudioRendererDisabled() { - message_loop()->PostTask(FROM_HERE, + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &FFmpegDemuxer::DisableAudioStreamTask)); } void FFmpegDemuxer::Initialize(DataSource* data_source, FilterCallback* callback) { - message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &FFmpegDemuxer::InitializeTask, @@ -391,9 +393,13 @@ bool FFmpegDemuxer::IsStreaming() { return data_source_->IsStreaming(); } +MessageLoop* FFmpegDemuxer::message_loop() { + return message_loop_; +} + void FFmpegDemuxer::InitializeTask(DataSource* data_source, FilterCallback* callback) { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); scoped_ptr<FilterCallback> c(callback); data_source_ = data_source; @@ -477,7 +483,7 @@ void FFmpegDemuxer::InitializeTask(DataSource* data_source, } void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); scoped_ptr<FilterCallback> c(callback); // Tell streams to flush buffers due to seeking. @@ -504,7 +510,7 @@ void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) { } void FFmpegDemuxer::DemuxTask() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); // Make sure we have work to do before demuxing. if (!StreamsHavePendingReads()) { @@ -556,7 +562,7 @@ void FFmpegDemuxer::DemuxTask() { } void FFmpegDemuxer::StopTask(FilterCallback* callback) { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); StreamVector::iterator iter; for (iter = streams_.begin(); iter != streams_.end(); ++iter) { (*iter)->Stop(); @@ -568,7 +574,7 @@ void FFmpegDemuxer::StopTask(FilterCallback* callback) { } void FFmpegDemuxer::DisableAudioStreamTask() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); StreamVector::iterator iter; for (size_t i = 0; i < packet_streams_.size(); ++i) { @@ -586,7 +592,7 @@ void FFmpegDemuxer::DisableAudioStreamTask() { } bool FFmpegDemuxer::StreamsHavePendingReads() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); StreamVector::iterator iter; for (iter = streams_.begin(); iter != streams_.end(); ++iter) { if ((*iter)->HasPendingReads()) { @@ -597,7 +603,7 @@ bool FFmpegDemuxer::StreamsHavePendingReads() { } void FFmpegDemuxer::StreamHasEnded() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); StreamVector::iterator iter; for (iter = streams_.begin(); iter != streams_.end(); ++iter) { AVPacket* packet = new AVPacket(); diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h index e5355203..2123563 100644 --- a/media/filters/ffmpeg_demuxer.h +++ b/media/filters/ffmpeg_demuxer.h @@ -121,7 +121,7 @@ class FFmpegDemuxerStream : public DemuxerStream, public AVStreamProvider { class FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol { public: - FFmpegDemuxer(); + explicit FFmpegDemuxer(MessageLoop* message_loop); virtual ~FFmpegDemuxer(); // Posts a task to perform additional demuxing. @@ -144,6 +144,9 @@ class FFmpegDemuxer : public Demuxer, virtual bool GetSize(int64* size_out); virtual bool IsStreaming(); + // Provide access to FFmpegDemuxerStream. + MessageLoop* message_loop(); + private: // Only allow a factory to create this class. friend class MockFFmpegDemuxer; @@ -187,6 +190,8 @@ class FFmpegDemuxer : public Demuxer, // Signal that read has completed, and |size| bytes have been read. virtual void SignalReadCompleted(size_t size); + MessageLoop* message_loop_; + // FFmpeg context handle. AVFormatContext* format_context_; diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc index 0bb21c0..5ba6fd3 100644 --- a/media/filters/ffmpeg_demuxer_unittest.cc +++ b/media/filters/ffmpeg_demuxer_unittest.cc @@ -65,12 +65,11 @@ class FFmpegDemuxerTest : public testing::Test { FFmpegDemuxerTest() { // Create an FFmpegDemuxer. - demuxer_ = new FFmpegDemuxer(); + demuxer_ = new FFmpegDemuxer(&message_loop_); DCHECK(demuxer_); // Inject a filter host and message loop and prepare a data source. demuxer_->set_host(&host_); - demuxer_->set_message_loop(&message_loop_); data_source_ = new StrictMock<MockDataSource>(); // Initialize FFmpeg fixtures. @@ -619,7 +618,9 @@ TEST_F(FFmpegDemuxerTest, DisableAudioStream) { class MockFFmpegDemuxer : public FFmpegDemuxer { public: - MockFFmpegDemuxer() {} + explicit MockFFmpegDemuxer(MessageLoop* message_loop) + : FFmpegDemuxer(message_loop) { + } virtual ~MockFFmpegDemuxer() {} MOCK_METHOD0(WaitForRead, size_t()); @@ -638,10 +639,10 @@ void RunCallback(size_t size, DataSource::ReadCallback* callback) { TEST_F(FFmpegDemuxerTest, ProtocolRead) { // Creates a demuxer. - scoped_refptr<MockFFmpegDemuxer> demuxer(new MockFFmpegDemuxer()); + scoped_refptr<MockFFmpegDemuxer> demuxer( + new MockFFmpegDemuxer(&message_loop_)); ASSERT_TRUE(demuxer); demuxer->set_host(&host_); - demuxer->set_message_loop(&message_loop_); demuxer->data_source_ = data_source_; uint8 kBuffer[1]; diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc index bdaee8c..13b26b2 100644 --- a/media/filters/ffmpeg_video_decoder.cc +++ b/media/filters/ffmpeg_video_decoder.cc @@ -21,8 +21,10 @@ namespace media { -FFmpegVideoDecoder::FFmpegVideoDecoder(VideoDecodeContext* decode_context) - : width_(0), +FFmpegVideoDecoder::FFmpegVideoDecoder(MessageLoop* message_loop, + VideoDecodeContext* decode_context) + : message_loop_(message_loop), + width_(0), height_(0), time_base_(new AVRational()), state_(kUnInitialized), @@ -36,8 +38,8 @@ FFmpegVideoDecoder::~FFmpegVideoDecoder() { void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask( + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &FFmpegVideoDecoder::Initialize, @@ -46,7 +48,7 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, return; } - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(!demuxer_stream_); DCHECK(!initialize_callback_.get()); @@ -98,11 +100,11 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, config.width = width_; config.height = height_; state_ = kInitializing; - decode_engine_->Initialize(message_loop(), this, NULL, config); + decode_engine_->Initialize(message_loop_, this, NULL, config); } void FFmpegVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(initialize_callback_.get()); info_ = info; // Save a copy. @@ -128,15 +130,15 @@ void FFmpegVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { } void FFmpegVideoDecoder::Stop(FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask(FROM_HERE, + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &FFmpegVideoDecoder::Stop, callback)); return; } - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(!uninitialize_callback_.get()); uninitialize_callback_.reset(callback); @@ -147,7 +149,7 @@ void FFmpegVideoDecoder::Stop(FilterCallback* callback) { } void FFmpegVideoDecoder::OnUninitializeComplete() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(uninitialize_callback_.get()); AutoCallbackRunner done_runner(uninitialize_callback_.release()); @@ -157,8 +159,8 @@ void FFmpegVideoDecoder::OnUninitializeComplete() { } void FFmpegVideoDecoder::Pause(FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask(FROM_HERE, + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &FFmpegVideoDecoder::Pause, callback)); @@ -170,15 +172,15 @@ void FFmpegVideoDecoder::Pause(FilterCallback* callback) { } void FFmpegVideoDecoder::Flush(FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask(FROM_HERE, + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &FFmpegVideoDecoder::Flush, callback)); return; } - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(!flush_callback_.get()); state_ = kFlushing; @@ -191,7 +193,7 @@ void FFmpegVideoDecoder::Flush(FilterCallback* callback) { } void FFmpegVideoDecoder::OnFlushComplete() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(flush_callback_.get()); AutoCallbackRunner done_runner(flush_callback_.release()); @@ -206,8 +208,8 @@ void FFmpegVideoDecoder::OnFlushComplete() { void FFmpegVideoDecoder::Seek(base::TimeDelta time, FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask(FROM_HERE, + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &FFmpegVideoDecoder::Seek, time, @@ -215,7 +217,7 @@ void FFmpegVideoDecoder::Seek(base::TimeDelta time, return; } - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(!seek_callback_.get()); seek_callback_.reset(callback); @@ -223,7 +225,7 @@ void FFmpegVideoDecoder::Seek(base::TimeDelta time, } void FFmpegVideoDecoder::OnSeekComplete() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(seek_callback_.get()); AutoCallbackRunner done_runner(seek_callback_.release()); @@ -239,7 +241,7 @@ void FFmpegVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) { void FFmpegVideoDecoder::OnReadComplete(Buffer* buffer_in) { scoped_refptr<Buffer> buffer(buffer_in); - message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &FFmpegVideoDecoder::OnReadCompleteTask, @@ -247,7 +249,7 @@ void FFmpegVideoDecoder::OnReadComplete(Buffer* buffer_in) { } void FFmpegVideoDecoder::OnReadCompleteTask(scoped_refptr<Buffer> buffer) { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK_NE(state_, kStopped); // because of Flush() before Stop(). // During decode, because reads are issued asynchronously, it is possible to @@ -301,15 +303,15 @@ const MediaFormat& FFmpegVideoDecoder::media_format() { void FFmpegVideoDecoder::ProduceVideoFrame( scoped_refptr<VideoFrame> video_frame) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask( + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &FFmpegVideoDecoder::ProduceVideoFrame, video_frame)); return; } - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); // Synchronized flushing before stop should prevent this. DCHECK_NE(state_, kStopped); @@ -330,7 +332,7 @@ void FFmpegVideoDecoder::ProduceVideoFrame( void FFmpegVideoDecoder::ConsumeVideoFrame( scoped_refptr<VideoFrame> video_frame) { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK_NE(state_, kStopped); if (video_frame.get()) { @@ -365,7 +367,7 @@ void FFmpegVideoDecoder::ConsumeVideoFrame( void FFmpegVideoDecoder::ProduceVideoSample( scoped_refptr<Buffer> buffer) { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK_NE(state_, kStopped); demuxer_stream_->Read( diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h index 76e60e8..82e5a8c 100644 --- a/media/filters/ffmpeg_video_decoder.h +++ b/media/filters/ffmpeg_video_decoder.h @@ -25,7 +25,8 @@ class VideoDecodeEngine; class FFmpegVideoDecoder : public VideoDecoder, public VideoDecodeEngine::EventHandler { public: - explicit FFmpegVideoDecoder(VideoDecodeContext* decode_context); + FFmpegVideoDecoder(MessageLoop* message_loop, + VideoDecodeContext* decode_context); virtual ~FFmpegVideoDecoder(); // Filter implementation. @@ -109,6 +110,7 @@ class FFmpegVideoDecoder : public VideoDecoder, // the provided engine. virtual void SetVideoDecodeEngineForTest(VideoDecodeEngine* engine); + MessageLoop* message_loop_; size_t width_; size_t height_; MediaFormat media_format_; diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc index 3db54c0..128e531 100644 --- a/media/filters/ffmpeg_video_decoder_unittest.cc +++ b/media/filters/ffmpeg_video_decoder_unittest.cc @@ -71,8 +71,9 @@ class MockVideoDecodeEngine : public VideoDecodeEngine { // Class that just mocks the private functions. class DecoderPrivateMock : public FFmpegVideoDecoder { public: - explicit DecoderPrivateMock(VideoDecodeContext* context) - : FFmpegVideoDecoder(context) { + DecoderPrivateMock(MessageLoop* message_loop, + VideoDecodeContext* context) + : FFmpegVideoDecoder(message_loop, context) { } // change access qualifier for test: used in actions. @@ -125,7 +126,7 @@ class FFmpegVideoDecoderTest : public testing::Test { // Create an FFmpegVideoDecoder, and MockVideoDecodeEngine. // // TODO(ajwong): Break the test's dependency on FFmpegVideoDecoder. - decoder_ = new DecoderPrivateMock(NULL); + decoder_ = new DecoderPrivateMock(&message_loop_, NULL); renderer_ = new MockVideoRenderer(); engine_ = new StrictMock<MockVideoDecodeEngine>(); @@ -133,7 +134,6 @@ class FFmpegVideoDecoderTest : public testing::Test { // Inject mocks and prepare a demuxer stream. decoder_->set_host(&host_); - decoder_->set_message_loop(&message_loop_); decoder_->SetVideoDecodeEngineForTest(engine_); demuxer_ = new StrictMock<MockFFmpegDemuxerStream>(); diff --git a/media/filters/omx_video_decoder.cc b/media/filters/omx_video_decoder.cc index 15ba4f1..3a31bf7 100644 --- a/media/filters/omx_video_decoder.cc +++ b/media/filters/omx_video_decoder.cc @@ -16,8 +16,10 @@ namespace media { OmxVideoDecoder::OmxVideoDecoder( + MessageLoop* message_loop, VideoDecodeContext* context) - : decode_engine_(new OmxVideoDecodeEngine()), + : message_loop_(message_loop), + decode_engine_(new OmxVideoDecodeEngine()), decode_context_(context), width_(0), height_(0) { DCHECK(decode_engine_.get()); @@ -30,8 +32,8 @@ OmxVideoDecoder::~OmxVideoDecoder() { void OmxVideoDecoder::Initialize(DemuxerStream* demuxer_stream, FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask( + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &OmxVideoDecoder::Initialize, @@ -40,7 +42,7 @@ void OmxVideoDecoder::Initialize(DemuxerStream* demuxer_stream, return; } - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(message_loop_, MessageLoop::current()); DCHECK(!demuxer_stream_); DCHECK(!initialize_callback_.get()); @@ -88,11 +90,11 @@ void OmxVideoDecoder::Initialize(DemuxerStream* demuxer_stream, config.opaque_context = NULL; config.width = width_; config.height = height_; - decode_engine_->Initialize(message_loop(), this, NULL, config); + decode_engine_->Initialize(message_loop_, this, NULL, config); } void OmxVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(initialize_callback_.get()); info_ = info; // Save a copy. @@ -115,15 +117,15 @@ void OmxVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { } void OmxVideoDecoder::Stop(FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask(FROM_HERE, + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &OmxVideoDecoder::Stop, callback)); return; } - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(!uninitialize_callback_.get()); uninitialize_callback_.reset(callback); @@ -131,7 +133,7 @@ void OmxVideoDecoder::Stop(FilterCallback* callback) { } void OmxVideoDecoder::OnUninitializeComplete() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(uninitialize_callback_.get()); AutoCallbackRunner done_runner(uninitialize_callback_.release()); @@ -140,15 +142,15 @@ void OmxVideoDecoder::OnUninitializeComplete() { } void OmxVideoDecoder::Flush(FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask(FROM_HERE, + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &OmxVideoDecoder::Flush, callback)); return; } - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(!flush_callback_.get()); flush_callback_.reset(callback); @@ -165,8 +167,8 @@ void OmxVideoDecoder::OnFlushComplete() { void OmxVideoDecoder::Seek(base::TimeDelta time, FilterCallback* callback) { - if (MessageLoop::current() != message_loop()) { - message_loop()->PostTask(FROM_HERE, + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &OmxVideoDecoder::Seek, time, @@ -174,7 +176,7 @@ void OmxVideoDecoder::Seek(base::TimeDelta time, return; } - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(!seek_callback_.get()); seek_callback_.reset(callback); @@ -182,7 +184,7 @@ void OmxVideoDecoder::Seek(base::TimeDelta time, } void OmxVideoDecoder::OnSeekComplete() { - DCHECK_EQ(MessageLoop::current(), message_loop()); + DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(seek_callback_.get()); AutoCallbackRunner done_runner(seek_callback_.release()); @@ -196,20 +198,20 @@ void OmxVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) { } void OmxVideoDecoder::ProduceVideoSample(scoped_refptr<Buffer> buffer) { - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(message_loop_, MessageLoop::current()); // Issue more demux. demuxer_stream_->Read(NewCallback(this, &OmxVideoDecoder::DemuxCompleteTask)); } void OmxVideoDecoder::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { - DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(message_loop_, MessageLoop::current()); VideoFrameReady(frame); } void OmxVideoDecoder::ProduceVideoFrame(scoped_refptr<VideoFrame> frame) { DCHECK(decode_engine_.get()); - message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(decode_engine_.get(), &VideoDecodeEngine::ProduceVideoFrame, frame)); @@ -228,7 +230,7 @@ void OmxVideoDecoder::DemuxCompleteTask(Buffer* buffer) { // We simply delicate the buffer to the right message loop. scoped_refptr<Buffer> ref_buffer = buffer; DCHECK(decode_engine_.get()); - message_loop()->PostTask( + message_loop_->PostTask( FROM_HERE, NewRunnableMethod(decode_engine_.get(), &VideoDecodeEngine::ConsumeVideoSample, ref_buffer)); diff --git a/media/filters/omx_video_decoder.h b/media/filters/omx_video_decoder.h index 7eb8504..ddec99f 100644 --- a/media/filters/omx_video_decoder.h +++ b/media/filters/omx_video_decoder.h @@ -23,7 +23,8 @@ class VideoFrame; class OmxVideoDecoder : public VideoDecoder, public VideoDecodeEngine::EventHandler { public: - explicit OmxVideoDecoder(VideoDecodeContext* decode_context); + OmxVideoDecoder(MessageLoop* message_loop, + VideoDecodeContext* decode_context); virtual ~OmxVideoDecoder(); // Filter implementations. @@ -50,6 +51,8 @@ class OmxVideoDecoder : public VideoDecoder, // scoped_refptr. void DemuxCompleteTask(Buffer* buffer); + MessageLoop* message_loop_; + // Pointer to the demuxer stream that will feed us compressed buffers. scoped_refptr<DemuxerStream> demuxer_stream_; scoped_ptr<VideoDecodeEngine> decode_engine_; diff --git a/media/media.gyp b/media/media.gyp index 259a7a1..660898b 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -94,6 +94,10 @@ 'base/media_switches.cc', 'base/media_switches.h', 'base/media_win.cc', + 'base/message_loop_factory.cc', + 'base/message_loop_factory.h', + 'base/message_loop_factory_impl.cc', + 'base/message_loop_factory_impl.h', 'base/pipeline.h', 'base/pipeline_impl.cc', 'base/pipeline_impl.h', diff --git a/media/tools/player_wtl/movie.cc b/media/tools/player_wtl/movie.cc index 2efd715..fe73490 100644 --- a/media/tools/player_wtl/movie.cc +++ b/media/tools/player_wtl/movie.cc @@ -8,6 +8,7 @@ #include "base/threading/platform_thread.h" #include "base/utf_string_conversions.h" #include "media/base/filter_collection.h" +#include "media/base/message_loop_factory_impl.h" #include "media/base/pipeline_impl.h" #include "media/filters/audio_renderer_impl.h" #include "media/filters/ffmpeg_audio_decoder.h" @@ -60,12 +61,17 @@ bool Movie::Open(const wchar_t* url, WtlVideoRenderer* video_renderer) { Close(); } + message_loop_factory_.reset(new media::MessageLoopFactoryImpl()); + // Create filter collection. scoped_ptr<FilterCollection> collection(new FilterCollection()); collection->AddDataSource(new FileDataSource()); - collection->AddAudioDecoder(new FFmpegAudioDecoder()); - collection->AddDemuxer(new FFmpegDemuxer()); - collection->AddVideoDecoder(new FFmpegVideoDecoder(NULL)); + collection->AddAudioDecoder(new FFmpegAudioDecoder( + message_loop_factory_->GetMessageLoop("AudioDecoderThread"))); + collection->AddDemuxer(new FFmpegDemuxer( + message_loop_factory_->GetMessageLoop("DemuxThread"))); + collection->AddVideoDecoder(new FFmpegVideoDecoder( + message_loop_factory_->GetMessageLoop("VideoDecoderThread"), NULL)); if (enable_audio_) { collection->AddAudioRenderer(new AudioRendererImpl()); @@ -74,9 +80,8 @@ bool Movie::Open(const wchar_t* url, WtlVideoRenderer* video_renderer) { } collection->AddVideoRenderer(video_renderer); - thread_.reset(new base::Thread("PipelineThread")); - thread_->Start(); - pipeline_ = new PipelineImpl(thread_->message_loop()); + pipeline_ = new PipelineImpl( + message_loop_factory_->GetMessageLoop("PipelineThread")); // Create and start our pipeline. pipeline_->Start(collection.release(), WideToUTF8(std::wstring(url)), NULL); @@ -168,10 +173,10 @@ bool Movie::GetDumpYuvFileEnable() { void Movie::Close() { if (pipeline_) { pipeline_->Stop(NULL); - thread_->Stop(); pipeline_ = NULL; - thread_.reset(); } + + message_loop_factory_.reset(); } } // namespace media diff --git a/media/tools/player_wtl/movie.h b/media/tools/player_wtl/movie.h index ea81b09..00708f9 100644 --- a/media/tools/player_wtl/movie.h +++ b/media/tools/player_wtl/movie.h @@ -11,7 +11,7 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" -#include "base/threading/thread.h" +#include "media/base/message_loop_factory.h" template <typename T> struct DefaultSingletonTraits; class WtlVideoRenderer; @@ -83,7 +83,7 @@ class Movie { virtual ~Movie(); scoped_refptr<PipelineImpl> pipeline_; - scoped_ptr<base::Thread> thread_; + scoped_ptr<media::MessageLoopFactory> message_loop_factory_; bool enable_audio_; bool enable_draw_; diff --git a/media/tools/player_wtl/view.h b/media/tools/player_wtl/view.h index cbb0a48..5273cd5 100644 --- a/media/tools/player_wtl/view.h +++ b/media/tools/player_wtl/view.h @@ -9,6 +9,7 @@ #include <process.h> #include <string.h> +#include "base/logging.h" #include "media/base/video_frame.h" #include "media/base/yuv_convert.h" #include "media/tools/player_wtl/movie.h" diff --git a/media/tools/player_x11/player_x11.cc b/media/tools/player_x11/player_x11.cc index df9bd619..2e75994 100644 --- a/media/tools/player_x11/player_x11.cc +++ b/media/tools/player_x11/player_x11.cc @@ -17,6 +17,7 @@ #include "media/base/filter_collection.h" #include "media/base/media.h" #include "media/base/media_switches.h" +#include "media/base/message_loop_factory_impl.h" #include "media/base/pipeline_impl.h" #include "media/filters/audio_renderer_impl.h" #include "media/filters/ffmpeg_audio_decoder.h" @@ -83,7 +84,8 @@ bool InitX11() { bool InitPipeline(MessageLoop* message_loop, const char* filename, bool enable_audio, scoped_refptr<media::PipelineImpl>* pipeline, - MessageLoop* paint_message_loop) { + MessageLoop* paint_message_loop, + media::MessageLoopFactory* message_loop_factory) { // Initialize OpenMAX. if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableOpenMax) && @@ -102,13 +104,19 @@ bool InitPipeline(MessageLoop* message_loop, scoped_ptr<media::FilterCollection> collection( new media::FilterCollection()); collection->AddDataSource(new media::FileDataSource()); - collection->AddDemuxer(new media::FFmpegDemuxer()); - collection->AddAudioDecoder(new media::FFmpegAudioDecoder()); + collection->AddDemuxer(new media::FFmpegDemuxer( + message_loop_factory->GetMessageLoop("DemuxThread"))); + collection->AddAudioDecoder(new media::FFmpegAudioDecoder( + message_loop_factory->GetMessageLoop("AudioDecoderThread"))); if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableOpenMax)) { - collection->AddVideoDecoder(new media::OmxVideoDecoder(NULL)); + collection->AddVideoDecoder(new media::OmxVideoDecoder( + message_loop_factory->GetMessageLoop("VideoDecoderThread"), + NULL)); } else { - collection->AddVideoDecoder(new media::FFmpegVideoDecoder(NULL)); + collection->AddVideoDecoder(new media::FFmpegVideoDecoder( + message_loop_factory->GetMessageLoop("VideoDecoderThread"), + NULL)); } collection->AddVideoRenderer(new Renderer(g_display, g_window, @@ -244,13 +252,16 @@ int main(int argc, char** argv) { // Initialize the pipeline thread and the pipeline. base::AtExitManager at_exit; + scoped_ptr<media::MessageLoopFactory> message_loop_factory( + new media::MessageLoopFactoryImpl()); scoped_ptr<base::Thread> thread; scoped_refptr<media::PipelineImpl> pipeline; MessageLoop message_loop; thread.reset(new base::Thread("PipelineThread")); thread->Start(); if (InitPipeline(thread->message_loop(), filename.c_str(), - enable_audio, &pipeline, &message_loop)) { + enable_audio, &pipeline, &message_loop, + message_loop_factory.get())) { // Main loop of the application. g_running = true; @@ -266,6 +277,8 @@ int main(int argc, char** argv) { } // Cleanup tasks. + message_loop_factory.reset(); + thread->Stop(); XDestroyWindow(g_display, g_window); XCloseDisplay(g_display); diff --git a/media/tools/player_x11/x11_video_renderer.h b/media/tools/player_x11/x11_video_renderer.h index 0129b60..fd5c12e 100644 --- a/media/tools/player_x11/x11_video_renderer.h +++ b/media/tools/player_x11/x11_video_renderer.h @@ -11,6 +11,8 @@ #include "media/base/filters.h" #include "media/filters/video_renderer_base.h" +class MessageLoop; + class X11VideoRenderer : public media::VideoRendererBase { public: X11VideoRenderer(Display* display, Window window, MessageLoop* message_loop); diff --git a/webkit/glue/webmediaplayer_impl.cc b/webkit/glue/webmediaplayer_impl.cc index 005c7cf..3bfb6a9 100644 --- a/webkit/glue/webmediaplayer_impl.cc +++ b/webkit/glue/webmediaplayer_impl.cc @@ -225,13 +225,14 @@ void WebMediaPlayerImpl::Proxy::PutCurrentFrame( WebMediaPlayerImpl::WebMediaPlayerImpl( WebKit::WebMediaPlayerClient* client, - media::FilterCollection* collection) + media::FilterCollection* collection, + media::MessageLoopFactory* message_loop_factory) : network_state_(WebKit::WebMediaPlayer::Empty), ready_state_(WebKit::WebMediaPlayer::HaveNothing), main_loop_(NULL), filter_collection_(collection), pipeline_(NULL), - pipeline_thread_("PipelineThread"), + message_loop_factory_(message_loop_factory), paused_(true), seeking_(false), playback_rate_(0.0f), @@ -247,13 +248,14 @@ bool WebMediaPlayerImpl::Initialize( WebKit::WebFrame* frame, bool use_simple_data_source, scoped_refptr<WebVideoRenderer> web_video_renderer) { - // Create the pipeline and its thread. - if (!pipeline_thread_.Start()) { + MessageLoop* pipeline_message_loop = + message_loop_factory_->GetMessageLoop("PipelineThread"); + if (!pipeline_message_loop) { NOTREACHED() << "Could not start PipelineThread"; return false; } - pipeline_ = new media::PipelineImpl(pipeline_thread_.message_loop()); + pipeline_ = new media::PipelineImpl(pipeline_message_loop); // Also we want to be notified of |main_loop_| destruction. main_loop_->AddDestructionObserver(this); @@ -290,9 +292,12 @@ bool WebMediaPlayerImpl::Initialize( } // Add in the default filter factories. - filter_collection_->AddDemuxer(new media::FFmpegDemuxer()); - filter_collection_->AddAudioDecoder(new media::FFmpegAudioDecoder()); - filter_collection_->AddVideoDecoder(new media::FFmpegVideoDecoder(NULL)); + filter_collection_->AddDemuxer(new media::FFmpegDemuxer( + message_loop_factory_->GetMessageLoop("DemuxThread"))); + filter_collection_->AddAudioDecoder(new media::FFmpegAudioDecoder( + message_loop_factory_->GetMessageLoop("AudioDecoderThread"))); + filter_collection_->AddVideoDecoder(new media::FFmpegVideoDecoder( + message_loop_factory_->GetMessageLoop("VideoDecoderThread"), NULL)); filter_collection_->AddAudioRenderer(new media::NullAudioRenderer()); return true; @@ -794,9 +799,10 @@ void WebMediaPlayerImpl::Destroy() { pipeline_->Stop(NewCallback(this, &WebMediaPlayerImpl::PipelineStoppedCallback)); pipeline_stopped_.Wait(); - pipeline_thread_.Stop(); } + message_loop_factory_.reset(); + // And then detach the proxy, it may live on the render thread for a little // longer until all the tasks are finished. if (proxy_) { diff --git a/webkit/glue/webmediaplayer_impl.h b/webkit/glue/webmediaplayer_impl.h index abb1c60..9f2db64 100644 --- a/webkit/glue/webmediaplayer_impl.h +++ b/webkit/glue/webmediaplayer_impl.h @@ -62,6 +62,7 @@ #include "gfx/rect.h" #include "gfx/size.h" #include "media/base/filters.h" +#include "media/base/message_loop_factory.h" #include "media/base/pipeline.h" #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/WebKit/chromium/public/WebMediaPlayer.h" @@ -175,7 +176,8 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer, // // Callers must call |Initialize()| before they can use the object. WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client, - media::FilterCollection* collection); + media::FilterCollection* collection, + media::MessageLoopFactory* message_loop_factory); virtual ~WebMediaPlayerImpl(); // Finalizes initialization of the object. @@ -288,7 +290,8 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer, // The actual pipeline and the thread it runs on. scoped_refptr<media::Pipeline> pipeline_; - base::Thread pipeline_thread_; + + scoped_ptr<media::MessageLoopFactory> message_loop_factory_; // Playback state. // diff --git a/webkit/support/webkit_support.cc b/webkit/support/webkit_support.cc index 8a76c1f..f043c82 100644 --- a/webkit/support/webkit_support.cc +++ b/webkit/support/webkit_support.cc @@ -26,6 +26,7 @@ #include "base/weak_ptr.h" #include "grit/webkit_chromium_resources.h" #include "media/base/filter_collection.h" +#include "media/base/message_loop_factory_impl.h" #include "net/base/escape.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" @@ -266,6 +267,9 @@ WebPlugin* CreateWebPlugin(WebFrame* frame, WebKit::WebMediaPlayer* CreateMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client) { + scoped_ptr<media::MessageLoopFactory> message_loop_factory( + new media::MessageLoopFactoryImpl()); + scoped_ptr<media::FilterCollection> collection( new media::FilterCollection()); @@ -274,7 +278,9 @@ WebKit::WebMediaPlayer* CreateMediaPlayer(WebFrame* frame, collection->AddVideoRenderer(video_renderer); scoped_ptr<webkit_glue::WebMediaPlayerImpl> result( - new webkit_glue::WebMediaPlayerImpl(client, collection.release())); + new webkit_glue::WebMediaPlayerImpl(client, + collection.release(), + message_loop_factory.release())); if (!result->Initialize(frame, false, video_renderer)) { return NULL; } diff --git a/webkit/tools/test_shell/test_webview_delegate.cc b/webkit/tools/test_shell/test_webview_delegate.cc index 305fa1f..0d61350 100644 --- a/webkit/tools/test_shell/test_webview_delegate.cc +++ b/webkit/tools/test_shell/test_webview_delegate.cc @@ -19,6 +19,7 @@ #include "gfx/native_widget_types.h" #include "gfx/point.h" #include "media/base/filter_collection.h" +#include "media/base/message_loop_factory_impl.h" #include "net/base/net_errors.h" #include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityObject.h" #include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h" @@ -732,6 +733,9 @@ WebWorker* TestWebViewDelegate::createWorker(WebFrame* frame, WebMediaPlayer* TestWebViewDelegate::createMediaPlayer( WebFrame* frame, WebMediaPlayerClient* client) { + scoped_ptr<media::MessageLoopFactory> message_loop_factory( + new media::MessageLoopFactoryImpl()); + scoped_ptr<media::FilterCollection> collection( new media::FilterCollection()); @@ -740,7 +744,9 @@ WebMediaPlayer* TestWebViewDelegate::createMediaPlayer( collection->AddVideoRenderer(video_renderer); scoped_ptr<webkit_glue::WebMediaPlayerImpl> result( - new webkit_glue::WebMediaPlayerImpl(client, collection.release())); + new webkit_glue::WebMediaPlayerImpl(client, + collection.release(), + message_loop_factory.release())); if (!result->Initialize(frame, false, video_renderer)) { return NULL; } |