Index: media/base/pipeline.cc |
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc |
index 2b26541a75109c87feafa993501dfc3d2699ba23..10007478ba276fdafb649265f4e355c27e63336e 100644 |
--- a/media/base/pipeline.cc |
+++ b/media/base/pipeline.cc |
@@ -17,6 +17,7 @@ |
#include "base/synchronization/condition_variable.h" |
#include "media/base/audio_decoder.h" |
#include "media/base/audio_renderer.h" |
+#include "media/base/callback_util.h" |
#include "media/base/clock.h" |
#include "media/base/composite_filter.h" |
#include "media/base/filter_collection.h" |
@@ -64,7 +65,6 @@ media::PipelineStatus PipelineStatusNotification::status() { |
struct Pipeline::PipelineInitState { |
scoped_refptr<AudioDecoder> audio_decoder; |
scoped_refptr<VideoDecoder> video_decoder; |
- scoped_refptr<AudioRenderer> audio_renderer; |
scoped_refptr<VideoRenderer> video_renderer; |
scoped_refptr<CompositeFilter> composite; |
}; |
@@ -317,6 +317,7 @@ bool Pipeline::IsPipelineSeeking() { |
} |
void Pipeline::ReportStatus(const PipelineStatusCB& cb, PipelineStatus status) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
if (cb.is_null()) |
return; |
cb.Run(status); |
@@ -390,6 +391,14 @@ TimeDelta Pipeline::GetDuration() const { |
return GetMediaDuration(); |
} |
+void Pipeline::OnAudioDisabled() { |
+ DCHECK(IsRunning()); |
+ message_loop_->PostTask(FROM_HERE, base::Bind( |
+ &Pipeline::AudioDisabledTask, this)); |
+ media_log_->AddEvent( |
+ media_log_->CreateEvent(MediaLogEvent::AUDIO_RENDERER_DISABLED)); |
+} |
+ |
void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { |
DCHECK(time <= max_time); |
DCHECK(IsRunning()); |
@@ -460,6 +469,61 @@ TimeDelta Pipeline::TimeForByteOffset_Locked(int64 byte_offset) const { |
return time_offset; |
} |
+void Pipeline::DoPause(const base::Closure& done_cb) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
+ |
+ if (audio_renderer_) |
+ closures->push(base::Bind(&AudioRenderer::Pause, audio_renderer_)); |
+ |
+ if (pipeline_filter_) |
+ closures->push(base::Bind(&Filter::Pause, pipeline_filter_)); |
+ |
+ RunInSeries(closures.Pass(), done_cb); |
+} |
+ |
+void Pipeline::DoFlush(const base::Closure& done_cb) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
+ |
+ if (audio_renderer_) |
+ closures->push(base::Bind(&AudioRenderer::Flush, audio_renderer_)); |
+ |
+ if (pipeline_filter_) |
+ closures->push(base::Bind(&Filter::Flush, pipeline_filter_)); |
+ |
+ RunInParallel(closures.Pass(), done_cb); |
+} |
+ |
+void Pipeline::DoPlay(const base::Closure& done_cb) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
+ |
+ if (audio_renderer_) |
+ closures->push(base::Bind(&AudioRenderer::Play, audio_renderer_)); |
+ |
+ if (pipeline_filter_) |
+ closures->push(base::Bind(&Filter::Play, pipeline_filter_)); |
+ |
+ RunInSeries(closures.Pass(), done_cb); |
+} |
+ |
+void Pipeline::DoStop(const base::Closure& done_cb) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
+ |
+ if (demuxer_) |
+ closures->push(base::Bind(&Demuxer::Stop, demuxer_)); |
+ |
+ if (audio_renderer_) |
+ closures->push(base::Bind(&AudioRenderer::Stop, audio_renderer_)); |
+ |
+ if (pipeline_filter_) |
+ closures->push(base::Bind(&Filter::Stop, pipeline_filter_)); |
+ |
+ RunInSeries(closures.Pass(), done_cb); |
+} |
+ |
void Pipeline::AddBufferedByteRange(int64 start, int64 end) { |
DCHECK(IsRunning()); |
base::AutoLock auto_lock(lock_); |
@@ -491,16 +555,6 @@ void Pipeline::NotifyEnded() { |
media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); |
} |
-void Pipeline::DisableAudioRenderer() { |
- DCHECK(IsRunning()); |
- |
- // Disable renderer on the message loop. |
- message_loop_->PostTask(FROM_HERE, base::Bind( |
- &Pipeline::DisableAudioRendererTask, this)); |
- media_log_->AddEvent( |
- media_log_->CreateEvent(MediaLogEvent::AUDIO_RENDERER_DISABLED)); |
-} |
- |
// Called from any thread. |
void Pipeline::OnFilterInitialize(PipelineStatus status) { |
// Continue the initialize task by proceeding to the next stage. |
@@ -658,12 +712,13 @@ void Pipeline::InitializeTask(PipelineStatus last_stage_status) { |
PlaybackRateChangedTask(GetPlaybackRate()); |
VolumeChangedTask(GetVolume()); |
- // Fire a seek request to get the renderers to preroll. We don't need to |
- // tell the demuxer to seek since it should already be at the start. |
+ // Fire a seek request to get the renderers to preroll. We can skip a seek |
+ // here as the demuxer should be at the start of the stream. |
seek_pending_ = true; |
SetState(kSeeking); |
seek_timestamp_ = demuxer_->GetStartTime(); |
- OnDemuxerSeekDone(seek_timestamp_, PIPELINE_OK); |
+ DoSeek(seek_timestamp_, true, |
+ base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this)); |
} |
} |
@@ -752,9 +807,11 @@ void Pipeline::PlaybackRateChangedTask(float playback_rate) { |
// hasn't completed yet, the playback rate will be set when initialization |
// completes. |
if (pipeline_filter_) { |
- DCHECK(demuxer_); |
demuxer_->SetPlaybackRate(playback_rate); |
pipeline_filter_->SetPlaybackRate(playback_rate); |
+ |
+ if (audio_renderer_) |
+ audio_renderer_->SetPlaybackRate(playback_rate_); |
} |
} |
@@ -800,8 +857,7 @@ void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
if (clock_->IsPlaying()) |
clock_->Pause(); |
} |
- pipeline_filter_->Pause( |
- base::Bind(&Pipeline::OnFilterStateTransition, this)); |
+ DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
} |
void Pipeline::NotifyEndedTask() { |
@@ -841,7 +897,7 @@ void Pipeline::NotifyEndedTask() { |
ReportStatus(ended_cb_, status_); |
} |
-void Pipeline::DisableAudioRendererTask() { |
+void Pipeline::AudioDisabledTask() { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
base::AutoLock auto_lock(lock_); |
@@ -888,16 +944,14 @@ void Pipeline::FilterStateTransitionTask() { |
// Carry out the action for the current state. |
if (TransientState(state_)) { |
if (state_ == kPausing) { |
- pipeline_filter_->Pause( |
- base::Bind(&Pipeline::OnFilterStateTransition, this)); |
+ DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
} else if (state_ == kFlushing) { |
- pipeline_filter_->Flush( |
- base::Bind(&Pipeline::OnFilterStateTransition, this)); |
+ DoFlush(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
} else if (state_ == kSeeking) { |
- DoSeek(seek_timestamp_); |
+ DoSeek(seek_timestamp_, false, |
+ base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this)); |
} else if (state_ == kStarting) { |
- pipeline_filter_->Play( |
- base::Bind(&Pipeline::OnFilterStateTransition, this)); |
+ DoPlay(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
} else if (state_ == kStopping) { |
DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
} else { |
@@ -943,8 +997,7 @@ void Pipeline::TeardownStateTransitionTask() { |
break; |
case kPausing: |
SetState(kFlushing); |
- pipeline_filter_->Flush( |
- base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
+ DoFlush(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
break; |
case kFlushing: |
SetState(kStopping); |
@@ -1092,23 +1145,20 @@ bool Pipeline::InitializeAudioRenderer( |
if (!decoder) |
return false; |
- filter_collection_->SelectAudioRenderer( |
- &pipeline_init_state_->audio_renderer); |
- if (!pipeline_init_state_->audio_renderer) { |
+ filter_collection_->SelectAudioRenderer(&audio_renderer_); |
+ if (!audio_renderer_) { |
SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); |
return false; |
} |
- pipeline_init_state_->composite->AddFilter( |
- pipeline_init_state_->audio_renderer); |
- |
- pipeline_init_state_->audio_renderer->Initialize( |
+ audio_renderer_->Initialize( |
decoder, |
base::Bind(&Pipeline::OnFilterInitialize, this), |
base::Bind(&Pipeline::OnAudioUnderflow, this), |
- base::Bind(&Pipeline::OnAudioTimeUpdate, this)); |
- |
- audio_renderer_ = pipeline_init_state_->audio_renderer; |
+ base::Bind(&Pipeline::OnAudioTimeUpdate, this), |
+ base::Bind(&Pipeline::NotifyEnded, this), |
+ base::Bind(&Pipeline::OnAudioDisabled, this), |
+ base::Bind(&Pipeline::SetError, this)); |
return true; |
} |
@@ -1194,8 +1244,7 @@ void Pipeline::TearDownPipeline() { |
case kStarted: |
case kEnded: |
SetState(kPausing); |
- pipeline_filter_->Pause( |
- base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
+ DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
break; |
case kStopping: |
@@ -1207,53 +1256,26 @@ void Pipeline::TearDownPipeline() { |
}; |
} |
-void Pipeline::DoStop(const base::Closure& callback) { |
- if (demuxer_) { |
- demuxer_->Stop(base::Bind( |
- &Pipeline::OnDemuxerStopDone, this, callback)); |
- return; |
- } |
- |
- OnDemuxerStopDone(callback); |
-} |
- |
-void Pipeline::OnDemuxerStopDone(const base::Closure& callback) { |
- if (!message_loop_->BelongsToCurrentThread()) { |
- message_loop_->PostTask(FROM_HERE, base::Bind( |
- &Pipeline::OnDemuxerStopDone, this, callback)); |
- return; |
- } |
- |
- if (pipeline_filter_) { |
- pipeline_filter_->Stop(callback); |
- return; |
- } |
- |
- callback.Run(); |
-} |
- |
-void Pipeline::DoSeek(TimeDelta seek_timestamp) { |
- demuxer_->Seek(seek_timestamp, base::Bind( |
- &Pipeline::OnDemuxerSeekDone, this, seek_timestamp)); |
-} |
+void Pipeline::DoSeek(base::TimeDelta seek_timestamp, |
+ bool skip_demuxer_seek, |
+ const PipelineStatusCB& done_cb) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( |
+ new std::queue<PipelineStatusCBFunc>()); |
-void Pipeline::OnDemuxerSeekDone(TimeDelta seek_timestamp, |
- PipelineStatus status) { |
- if (!message_loop_->BelongsToCurrentThread()) { |
- message_loop_->PostTask(FROM_HERE, base::Bind( |
- &Pipeline::OnDemuxerSeekDone, this, seek_timestamp, status)); |
- return; |
- } |
+ if (!skip_demuxer_seek) |
+ status_cbs->push(base::Bind(&Demuxer::Seek, demuxer_, seek_timestamp)); |
- PipelineStatusCB done_cb = |
- base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this); |
+ if (audio_renderer_) |
+ status_cbs->push(base::Bind( |
+ &AudioRenderer::Seek, audio_renderer_, seek_timestamp)); |
- if (status == PIPELINE_OK && pipeline_filter_) { |
- pipeline_filter_->Seek(seek_timestamp, done_cb); |
- return; |
- } |
+ if (pipeline_filter_) |
+ status_cbs->push(base::Bind( |
+ &Filter::Seek, pipeline_filter_, seek_timestamp)); |
- ReportStatus(done_cb, status); |
+ RunInSeriesWithStatus(status_cbs.Pass(), base::Bind( |
+ &Pipeline::ReportStatus, this, done_cb)); |
} |
void Pipeline::OnAudioUnderflow() { |