Chromium Code Reviews| Index: media/base/pipeline_impl.cc |
| diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc |
| index d295d6b9213ed5ab6a2bdfbae66f1044b85d19f0..b5c0ed431dbbe1ac6929171ce408f4cc6b1b48fb 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,11 +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); |
|
scherkus (not reviewing)
2011/01/05 01:28:38
nit: looks like this file uses { } for one-line if
acolwell GONE FROM CHROMIUM
2011/01/05 16:27:46
Done.
|
| } |
| void PipelineImpl::VolumeChangedTask(float volume) { |
| @@ -745,10 +760,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 +771,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 +804,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 +827,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 +851,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 +900,7 @@ void PipelineImpl::FilterStateTransitionTask() { |
| } else if (IsPipelineStopped()) { |
| FinishDestroyingFiltersTask(); |
| } else { |
| - NOTREACHED(); |
| + NOTREACHED() << "Unexpected state: " << state_; |
| } |
| } |
| @@ -905,24 +908,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 +928,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 +937,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 +1119,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)); |
| } |