diff options
author | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-05 18:44:10 +0000 |
---|---|---|
committer | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-05 18:44:10 +0000 |
commit | 641c9abcde75980f45771240db3d8131c6656fc7 (patch) | |
tree | 251ed8222c95b55352d2ce9bc212a187a3a9e2b4 /media/base/pipeline_impl.cc | |
parent | e7635ea4bb6d3aa207ab64935c177660d850da19 (diff) | |
download | chromium_src-641c9abcde75980f45771240db3d8131c6656fc7.zip chromium_src-641c9abcde75980f45771240db3d8131c6656fc7.tar.gz chromium_src-641c9abcde75980f45771240db3d8131c6656fc7.tar.bz2 |
Refactor PipelineImpl to use CompositeFilter to manage Filter state transitions.
BUG=54110
TEST=media_unittests CompositeFilterTest.*
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=70267
Review URL: http://codereview.chromium.org/5744002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70527 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/base/pipeline_impl.cc')
-rw-r--r-- | media/base/pipeline_impl.cc | 173 |
1 files changed, 73 insertions, 100 deletions
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc index d295d6b..d071d58 100644 --- a/media/base/pipeline_impl.cc +++ b/media/base/pipeline_impl.cc @@ -22,6 +22,7 @@ class PipelineImpl::PipelineInitState { scoped_refptr<Demuxer> demuxer_; scoped_refptr<AudioDecoder> audio_decoder_; scoped_refptr<VideoDecoder> video_decoder_; + scoped_refptr<CompositeFilter> composite_; }; PipelineImpl::PipelineImpl(MessageLoop* message_loop) @@ -29,7 +30,6 @@ PipelineImpl::PipelineImpl(MessageLoop* message_loop) clock_(new ClockImpl(&base::Time::Now)), waiting_for_clock_update_(false), state_(kCreated), - remaining_transitions_(0), current_bytes_(0) { ResetState(); } @@ -317,6 +317,10 @@ void PipelineImpl::ResetState() { rendered_mime_types_.clear(); } +void PipelineImpl::set_state(State next_state) { + state_ = next_state; +} + bool PipelineImpl::IsPipelineOk() { return PIPELINE_OK == GetError(); } @@ -572,22 +576,25 @@ void PipelineImpl::InitializeTask() { // Just created, create data source. if (state_ == kCreated) { - state_ = kInitDataSource; + set_state(kInitDataSource); pipeline_init_state_.reset(new PipelineInitState()); + pipeline_init_state_->composite_ = new CompositeFilter(message_loop_); + pipeline_init_state_->composite_->set_host(this); + InitializeDataSource(); return; } // Data source created, create demuxer. if (state_ == kInitDataSource) { - state_ = kInitDemuxer; + set_state(kInitDemuxer); InitializeDemuxer(pipeline_init_state_->data_source_); return; } // Demuxer created, create audio decoder. if (state_ == kInitDemuxer) { - state_ = kInitAudioDecoder; + set_state(kInitAudioDecoder); // If this method returns false, then there's no audio stream. if (InitializeAudioDecoder(pipeline_init_state_->demuxer_)) return; @@ -595,7 +602,7 @@ void PipelineImpl::InitializeTask() { // Assuming audio decoder was created, create audio renderer. if (state_ == kInitAudioDecoder) { - state_ = kInitAudioRenderer; + set_state(kInitAudioRenderer); // Returns false if there's no audio stream. if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder_)) { InsertRenderedMimeType(mime_type::kMajorTypeAudio); @@ -606,14 +613,14 @@ void PipelineImpl::InitializeTask() { // Assuming audio renderer was created, create video decoder. if (state_ == kInitAudioRenderer) { // Then perform the stage of initialization, i.e. initialize video decoder. - state_ = kInitVideoDecoder; + set_state(kInitVideoDecoder); if (InitializeVideoDecoder(pipeline_init_state_->demuxer_)) return; } // Assuming video decoder was created, create video renderer. if (state_ == kInitVideoDecoder) { - state_ = kInitVideoRenderer; + set_state(kInitVideoRenderer); if (InitializeVideoRenderer(pipeline_init_state_->video_decoder_)) { InsertRenderedMimeType(mime_type::kMajorTypeVideo); return; @@ -629,20 +636,27 @@ void PipelineImpl::InitializeTask() { // Clear the collection of filters. filter_collection_->Clear(); + pipeline_filter_ = pipeline_init_state_->composite_; + // Clear init state since we're done initializing. pipeline_init_state_.reset(); + if (audio_disabled_) { + // Audio was disabled at some point during initialization. Notify + // the pipeline filter now that it has been initialized. + pipeline_filter_->OnAudioRendererDisabled(); + } + // Initialization was successful, we are now considered paused, so it's safe // to set the initial playback rate and volume. PlaybackRateChangedTask(GetPlaybackRate()); VolumeChangedTask(GetVolume()); - // Fire the initial seek request to get the filters to preroll. + // Fire the seek request to get the filters to preroll. seek_pending_ = true; - state_ = kSeeking; - remaining_transitions_ = filters_.size(); + set_state(kSeeking); seek_timestamp_ = base::TimeDelta(); - filters_.front()->Seek(seek_timestamp_, + pipeline_filter_->Seek(seek_timestamp_, NewCallback(this, &PipelineImpl::OnFilterStateTransition)); } } @@ -705,10 +719,12 @@ void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { AutoLock auto_lock(lock_); clock_->SetPlaybackRate(playback_rate); } - for (FilterVector::iterator iter = filters_.begin(); - iter != filters_.end(); - ++iter) { - (*iter)->SetPlaybackRate(playback_rate); + + // Notify |pipeline_filter_| if it has been initialized. If initialization + // hasn't completed yet, the playback rate will be set when initialization + // completes. + if (pipeline_filter_) { + pipeline_filter_->SetPlaybackRate(playback_rate); } } @@ -745,10 +761,9 @@ void PipelineImpl::SeekTask(base::TimeDelta time, // kSeeking (for each filter) // kStarting (for each filter) // kStarted - state_ = kPausing; + set_state(kPausing); seek_timestamp_ = time; seek_callback_.reset(seek_callback); - remaining_transitions_ = filters_.size(); // Kick off seeking! { @@ -757,7 +772,7 @@ void PipelineImpl::SeekTask(base::TimeDelta time, if (!waiting_for_clock_update_) clock_->Pause(); } - filters_.front()->Pause( + pipeline_filter_->Pause( NewCallback(this, &PipelineImpl::OnFilterStateTransition)); } @@ -790,7 +805,7 @@ void PipelineImpl::NotifyEndedTask() { } // Transition to ended, executing the callback if present. - state_ = kEnded; + set_state(kEnded); if (ended_callback_.get()) { ended_callback_->Run(); } @@ -813,11 +828,11 @@ void PipelineImpl::DisableAudioRendererTask() { audio_disabled_ = true; - // Notify all filters of disabled audio renderer. - for (FilterVector::iterator iter = filters_.begin(); - iter != filters_.end(); - ++iter) { - (*iter)->OnAudioRendererDisabled(); + // Notify all filters of disabled audio renderer. If the filter isn't + // initialized yet, OnAudioRendererDisabled() will be called when + // initialization is complete. + if (pipeline_filter_) { + pipeline_filter_->OnAudioRendererDisabled(); } } @@ -837,42 +852,31 @@ void PipelineImpl::FilterStateTransitionTask() { // Decrement the number of remaining transitions, making sure to transition // to the next state if needed. - DCHECK(remaining_transitions_ <= filters_.size()); - DCHECK(remaining_transitions_ > 0u); - if (--remaining_transitions_ == 0) { - state_ = FindNextState(state_); - if (state_ == kSeeking) { - AutoLock auto_lock(lock_); - clock_->SetTime(seek_timestamp_); - } - - if (TransientState(state_)) { - remaining_transitions_ = filters_.size(); - } + set_state(FindNextState(state_)); + if (state_ == kSeeking) { + AutoLock auto_lock(lock_); + clock_->SetTime(seek_timestamp_); } // Carry out the action for the current state. if (TransientState(state_)) { - Filter* filter = filters_[filters_.size() - remaining_transitions_]; if (state_ == kPausing) { - filter->Pause(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); + pipeline_filter_->Pause( + NewCallback(this, &PipelineImpl::OnFilterStateTransition)); } else if (state_ == kFlushing) { - // We had to use parallel flushing all filters. - if (remaining_transitions_ == filters_.size()) { - for (size_t i = 0; i < filters_.size(); i++) { - filters_[i]->Flush( - NewCallback(this, &PipelineImpl::OnFilterStateTransition)); - } - } + pipeline_filter_->Flush( + NewCallback(this, &PipelineImpl::OnFilterStateTransition)); } else if (state_ == kSeeking) { - filter->Seek(seek_timestamp_, + pipeline_filter_->Seek(seek_timestamp_, NewCallback(this, &PipelineImpl::OnFilterStateTransition)); } else if (state_ == kStarting) { - filter->Play(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); + pipeline_filter_->Play( + NewCallback(this,&PipelineImpl::OnFilterStateTransition)); } else if (state_ == kStopping) { - filter->Stop(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); + pipeline_filter_->Stop( + NewCallback(this, &PipelineImpl::OnFilterStateTransition)); } else { - NOTREACHED(); + NOTREACHED() << "Unexpected state: " << state_; } } else if (state_ == kStarted) { FinishInitialization(); @@ -897,7 +901,7 @@ void PipelineImpl::FilterStateTransitionTask() { } else if (IsPipelineStopped()) { FinishDestroyingFiltersTask(); } else { - NOTREACHED(); + NOTREACHED() << "Unexpected state: " << state_; } } @@ -905,24 +909,11 @@ void PipelineImpl::FinishDestroyingFiltersTask() { DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(IsPipelineStopped()); - // Stop every running filter thread. - // - // TODO(scherkus): can we watchdog this section to detect wedged threads? - for (FilterThreadVector::iterator iter = filter_threads_.begin(); - iter != filter_threads_.end(); - ++iter) { - (*iter)->Stop(); - } - // Clear renderer references. audio_renderer_ = NULL; video_renderer_ = NULL; - // Reset the pipeline, which will decrement a reference to this object. - // We will get destroyed as soon as the remaining tasks finish executing. - // To be safe, we'll set our pipeline reference to NULL. - filters_.clear(); - STLDeleteElements(&filter_threads_); + pipeline_filter_ = NULL; stop_pending_ = false; tearing_down_ = false; @@ -938,7 +929,7 @@ void PipelineImpl::FinishDestroyingFiltersTask() { } } else { // Destroying filters due to SetError(). - state_ = kError; + set_state(kError); // If our owner has requested to be notified of an error. if (error_callback_.get()) { error_callback_->Run(); @@ -947,28 +938,12 @@ void PipelineImpl::FinishDestroyingFiltersTask() { } bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - DCHECK(IsPipelineOk()); - - // Create a dedicated thread for this filter if applicable. - if (filter->requires_message_loop()) { - scoped_ptr<base::Thread> thread( - new base::Thread(filter->message_loop_name())); - if (!thread.get() || !thread->Start()) { - NOTREACHED() << "Could not start filter thread"; - SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); - return false; - } + bool ret = pipeline_init_state_->composite_->AddFilter(filter.get()); - filter->set_message_loop(thread->message_loop()); - filter_threads_.push_back(thread.release()); + if (!ret) { + SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); } - - // Register ourselves as the filter's host. - DCHECK(IsPipelineOk()); - filter->set_host(this); - filters_.push_back(make_scoped_refptr(filter.get())); - return true; + return ret; } void PipelineImpl::InitializeDataSource() { @@ -1145,23 +1120,21 @@ void PipelineImpl::TearDownPipeline() { tearing_down_ = true; if (IsPipelineInitializing()) { - // Notify the client that starting did not complete, if necessary. - FinishInitialization(); - } + // Make it look like initialization was successful. + pipeline_filter_ = pipeline_init_state_->composite_; + pipeline_init_state_.reset(); - remaining_transitions_ = filters_.size(); - if (remaining_transitions_ > 0) { - if (IsPipelineInitializing()) { - state_ = kStopping; - filters_.front()->Stop(NewCallback( - this, &PipelineImpl::OnFilterStateTransition)); - } else { - state_ = kPausing; - filters_.front()->Pause(NewCallback( - this, &PipelineImpl::OnFilterStateTransition)); - } + set_state(kStopping); + pipeline_filter_->Stop(NewCallback( + this, &PipelineImpl::OnFilterStateTransition)); + + FinishInitialization(); + } else if (pipeline_filter_.get()) { + set_state(kPausing); + pipeline_filter_->Pause(NewCallback( + this, &PipelineImpl::OnFilterStateTransition)); } else { - state_ = kStopped; + set_state(kStopped); message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); } |