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)); |
} |