| 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() {
|
|
|