| Index: media/filters/renderer_impl.cc
|
| diff --git a/media/filters/renderer_impl.cc b/media/filters/renderer_impl.cc
|
| deleted file mode 100644
|
| index b8005d409d8218f725cced19056b8d8c4b696b04..0000000000000000000000000000000000000000
|
| --- a/media/filters/renderer_impl.cc
|
| +++ /dev/null
|
| @@ -1,576 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "media/filters/renderer_impl.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/callback.h"
|
| -#include "base/callback_helpers.h"
|
| -#include "base/compiler_specific.h"
|
| -#include "base/location.h"
|
| -#include "base/single_thread_task_runner.h"
|
| -#include "media/base/audio_renderer.h"
|
| -#include "media/base/bind_to_current_loop.h"
|
| -#include "media/base/demuxer_stream_provider.h"
|
| -#include "media/base/time_source.h"
|
| -#include "media/base/video_renderer.h"
|
| -#include "media/base/wall_clock_time_source.h"
|
| -
|
| -namespace media {
|
| -
|
| -RendererImpl::RendererImpl(
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
|
| - scoped_ptr<AudioRenderer> audio_renderer,
|
| - scoped_ptr<VideoRenderer> video_renderer)
|
| - : state_(STATE_UNINITIALIZED),
|
| - task_runner_(task_runner),
|
| - audio_renderer_(audio_renderer.Pass()),
|
| - video_renderer_(video_renderer.Pass()),
|
| - time_source_(NULL),
|
| - time_ticking_(false),
|
| - audio_buffering_state_(BUFFERING_HAVE_NOTHING),
|
| - video_buffering_state_(BUFFERING_HAVE_NOTHING),
|
| - audio_ended_(false),
|
| - video_ended_(false),
|
| - cdm_context_(nullptr),
|
| - underflow_disabled_for_testing_(false),
|
| - clockless_video_playback_enabled_for_testing_(false),
|
| - weak_factory_(this) {
|
| - weak_this_ = weak_factory_.GetWeakPtr();
|
| - DVLOG(1) << __FUNCTION__;
|
| -}
|
| -
|
| -RendererImpl::~RendererImpl() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - // Tear down in opposite order of construction as |video_renderer_| can still
|
| - // need |time_source_| (which can be |audio_renderer_|) to be alive.
|
| - video_renderer_.reset();
|
| - audio_renderer_.reset();
|
| -
|
| - if (!init_cb_.is_null())
|
| - base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
|
| - else if (!flush_cb_.is_null())
|
| - base::ResetAndReturn(&flush_cb_).Run();
|
| -}
|
| -
|
| -void RendererImpl::Initialize(DemuxerStreamProvider* demuxer_stream_provider,
|
| - const PipelineStatusCB& init_cb,
|
| - const StatisticsCB& statistics_cb,
|
| - const BufferingStateCB& buffering_state_cb,
|
| - const PaintCB& paint_cb,
|
| - const base::Closure& ended_cb,
|
| - const PipelineStatusCB& error_cb) {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_EQ(state_, STATE_UNINITIALIZED);
|
| - DCHECK(!init_cb.is_null());
|
| - DCHECK(!statistics_cb.is_null());
|
| - DCHECK(!buffering_state_cb.is_null());
|
| - DCHECK(!paint_cb.is_null());
|
| - DCHECK(!ended_cb.is_null());
|
| - DCHECK(!error_cb.is_null());
|
| - DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) ||
|
| - demuxer_stream_provider->GetStream(DemuxerStream::VIDEO));
|
| -
|
| - demuxer_stream_provider_ = demuxer_stream_provider;
|
| - statistics_cb_ = statistics_cb;
|
| - buffering_state_cb_ = buffering_state_cb;
|
| - paint_cb_ = paint_cb;
|
| - ended_cb_ = ended_cb;
|
| - error_cb_ = error_cb;
|
| - init_cb_ = init_cb;
|
| -
|
| - state_ = STATE_INITIALIZING;
|
| - InitializeAudioRenderer();
|
| -}
|
| -
|
| -void RendererImpl::SetCdm(CdmContext* cdm_context,
|
| - const CdmAttachedCB& cdm_attached_cb) {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK(cdm_context);
|
| -
|
| - if (cdm_context_) {
|
| - DVLOG(1) << "Switching CDM not supported.";
|
| - cdm_attached_cb.Run(false);
|
| - return;
|
| - }
|
| -
|
| - cdm_context_ = cdm_context;
|
| -
|
| - if (decryptor_ready_cb_.is_null()) {
|
| - cdm_attached_cb.Run(true);
|
| - return;
|
| - }
|
| -
|
| - base::ResetAndReturn(&decryptor_ready_cb_)
|
| - .Run(cdm_context->GetDecryptor(), cdm_attached_cb);
|
| -}
|
| -
|
| -void RendererImpl::Flush(const base::Closure& flush_cb) {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK(flush_cb_.is_null());
|
| -
|
| - if (state_ != STATE_PLAYING) {
|
| - DCHECK_EQ(state_, STATE_ERROR);
|
| - return;
|
| - }
|
| -
|
| - flush_cb_ = flush_cb;
|
| - state_ = STATE_FLUSHING;
|
| -
|
| - if (time_ticking_)
|
| - PausePlayback();
|
| -
|
| - FlushAudioRenderer();
|
| -}
|
| -
|
| -void RendererImpl::StartPlayingFrom(base::TimeDelta time) {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (state_ != STATE_PLAYING) {
|
| - DCHECK_EQ(state_, STATE_ERROR);
|
| - return;
|
| - }
|
| -
|
| - time_source_->SetMediaTime(time);
|
| -
|
| - if (audio_renderer_)
|
| - audio_renderer_->StartPlaying();
|
| - if (video_renderer_)
|
| - video_renderer_->StartPlayingFrom(time);
|
| -}
|
| -
|
| -void RendererImpl::SetPlaybackRate(float playback_rate) {
|
| - DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")";
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - // Playback rate changes are only carried out while playing.
|
| - if (state_ != STATE_PLAYING)
|
| - return;
|
| -
|
| - time_source_->SetPlaybackRate(playback_rate);
|
| -}
|
| -
|
| -void RendererImpl::SetVolume(float volume) {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (audio_renderer_)
|
| - audio_renderer_->SetVolume(volume);
|
| -}
|
| -
|
| -base::TimeDelta RendererImpl::GetMediaTime() {
|
| - // No BelongsToCurrentThread() checking because this can be called from other
|
| - // threads.
|
| - return time_source_->CurrentMediaTime();
|
| -}
|
| -
|
| -bool RendererImpl::HasAudio() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - return audio_renderer_ != NULL;
|
| -}
|
| -
|
| -bool RendererImpl::HasVideo() {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - return video_renderer_ != NULL;
|
| -}
|
| -
|
| -void RendererImpl::DisableUnderflowForTesting() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_EQ(state_, STATE_UNINITIALIZED);
|
| -
|
| - underflow_disabled_for_testing_ = true;
|
| -}
|
| -
|
| -void RendererImpl::EnableClocklessVideoPlaybackForTesting() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_EQ(state_, STATE_UNINITIALIZED);
|
| - DCHECK(underflow_disabled_for_testing_)
|
| - << "Underflow must be disabled for clockless video playback";
|
| -
|
| - clockless_video_playback_enabled_for_testing_ = true;
|
| -}
|
| -
|
| -base::TimeDelta RendererImpl::GetMediaTimeForSyncingVideo() {
|
| - // No BelongsToCurrentThread() checking because this can be called from other
|
| - // threads.
|
| - //
|
| - // TODO(scherkus): Currently called from VideoRendererImpl's internal thread,
|
| - // which should go away at some point http://crbug.com/110814
|
| - if (clockless_video_playback_enabled_for_testing_)
|
| - return base::TimeDelta::Max();
|
| -
|
| - return time_source_->CurrentMediaTimeForSyncingVideo();
|
| -}
|
| -
|
| -void RendererImpl::SetDecryptorReadyCallback(
|
| - const DecryptorReadyCB& decryptor_ready_cb) {
|
| - // Cancels the previous decryptor request.
|
| - if (decryptor_ready_cb.is_null()) {
|
| - if (!decryptor_ready_cb_.is_null()) {
|
| - base::ResetAndReturn(&decryptor_ready_cb_)
|
| - .Run(nullptr, base::Bind(IgnoreCdmAttached));
|
| - }
|
| - return;
|
| - }
|
| -
|
| - // We initialize audio and video decoders in sequence.
|
| - DCHECK(decryptor_ready_cb_.is_null());
|
| -
|
| - if (cdm_context_) {
|
| - decryptor_ready_cb.Run(cdm_context_->GetDecryptor(),
|
| - base::Bind(IgnoreCdmAttached));
|
| - return;
|
| - }
|
| -
|
| - decryptor_ready_cb_ = decryptor_ready_cb;
|
| -}
|
| -
|
| -void RendererImpl::InitializeAudioRenderer() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_EQ(state_, STATE_INITIALIZING);
|
| - DCHECK(!init_cb_.is_null());
|
| -
|
| - PipelineStatusCB done_cb =
|
| - base::Bind(&RendererImpl::OnAudioRendererInitializeDone, weak_this_);
|
| -
|
| - if (!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)) {
|
| - audio_renderer_.reset();
|
| - task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
|
| - return;
|
| - }
|
| -
|
| - // Note: After the initialization of a renderer, error events from it may
|
| - // happen at any time and all future calls must guard against STATE_ERROR.
|
| - audio_renderer_->Initialize(
|
| - demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO), done_cb,
|
| - base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
|
| - base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
|
| - base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
|
| - &audio_buffering_state_),
|
| - base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_),
|
| - base::Bind(&RendererImpl::OnError, weak_this_));
|
| -}
|
| -
|
| -void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) {
|
| - DVLOG(1) << __FUNCTION__ << ": " << status;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - // OnError() may be fired at any time by the renderers, even if they thought
|
| - // they initialized successfully (due to delayed output device setup).
|
| - if (state_ != STATE_INITIALIZING) {
|
| - DCHECK(init_cb_.is_null());
|
| - audio_renderer_.reset();
|
| - return;
|
| - }
|
| -
|
| - if (status != PIPELINE_OK) {
|
| - base::ResetAndReturn(&init_cb_).Run(status);
|
| - return;
|
| - }
|
| -
|
| - DCHECK(!init_cb_.is_null());
|
| - InitializeVideoRenderer();
|
| -}
|
| -
|
| -void RendererImpl::InitializeVideoRenderer() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_EQ(state_, STATE_INITIALIZING);
|
| - DCHECK(!init_cb_.is_null());
|
| -
|
| - PipelineStatusCB done_cb =
|
| - base::Bind(&RendererImpl::OnVideoRendererInitializeDone, weak_this_);
|
| -
|
| - if (!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO)) {
|
| - video_renderer_.reset();
|
| - task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
|
| - return;
|
| - }
|
| -
|
| - video_renderer_->Initialize(
|
| - demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO), done_cb,
|
| - base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
|
| - base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
|
| - base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
|
| - &video_buffering_state_),
|
| - base::ResetAndReturn(&paint_cb_),
|
| - base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_),
|
| - base::Bind(&RendererImpl::OnError, weak_this_),
|
| - base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo,
|
| - base::Unretained(this)));
|
| -}
|
| -
|
| -void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
|
| - DVLOG(1) << __FUNCTION__ << ": " << status;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - // OnError() may be fired at any time by the renderers, even if they thought
|
| - // they initialized successfully (due to delayed output device setup).
|
| - if (state_ != STATE_INITIALIZING) {
|
| - DCHECK(init_cb_.is_null());
|
| - audio_renderer_.reset();
|
| - video_renderer_.reset();
|
| - return;
|
| - }
|
| -
|
| - DCHECK(!init_cb_.is_null());
|
| -
|
| - if (status != PIPELINE_OK) {
|
| - base::ResetAndReturn(&init_cb_).Run(status);
|
| - return;
|
| - }
|
| -
|
| - if (audio_renderer_) {
|
| - time_source_ = audio_renderer_->GetTimeSource();
|
| - } else {
|
| - wall_clock_time_source_.reset(new WallClockTimeSource());
|
| - time_source_ = wall_clock_time_source_.get();
|
| - }
|
| -
|
| - state_ = STATE_PLAYING;
|
| - DCHECK(time_source_);
|
| - DCHECK(audio_renderer_ || video_renderer_);
|
| - base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
|
| -}
|
| -
|
| -void RendererImpl::FlushAudioRenderer() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_EQ(state_, STATE_FLUSHING);
|
| - DCHECK(!flush_cb_.is_null());
|
| -
|
| - if (!audio_renderer_) {
|
| - OnAudioRendererFlushDone();
|
| - return;
|
| - }
|
| -
|
| - audio_renderer_->Flush(
|
| - base::Bind(&RendererImpl::OnAudioRendererFlushDone, weak_this_));
|
| -}
|
| -
|
| -void RendererImpl::OnAudioRendererFlushDone() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (state_ == STATE_ERROR) {
|
| - DCHECK(flush_cb_.is_null());
|
| - return;
|
| - }
|
| -
|
| - DCHECK_EQ(state_, STATE_FLUSHING);
|
| - DCHECK(!flush_cb_.is_null());
|
| -
|
| - DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING);
|
| - audio_ended_ = false;
|
| - FlushVideoRenderer();
|
| -}
|
| -
|
| -void RendererImpl::FlushVideoRenderer() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_EQ(state_, STATE_FLUSHING);
|
| - DCHECK(!flush_cb_.is_null());
|
| -
|
| - if (!video_renderer_) {
|
| - OnVideoRendererFlushDone();
|
| - return;
|
| - }
|
| -
|
| - video_renderer_->Flush(
|
| - base::Bind(&RendererImpl::OnVideoRendererFlushDone, weak_this_));
|
| -}
|
| -
|
| -void RendererImpl::OnVideoRendererFlushDone() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (state_ == STATE_ERROR) {
|
| - DCHECK(flush_cb_.is_null());
|
| - return;
|
| - }
|
| -
|
| - DCHECK_EQ(state_, STATE_FLUSHING);
|
| - DCHECK(!flush_cb_.is_null());
|
| -
|
| - DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING);
|
| - video_ended_ = false;
|
| - state_ = STATE_PLAYING;
|
| - base::ResetAndReturn(&flush_cb_).Run();
|
| -}
|
| -
|
| -void RendererImpl::OnUpdateStatistics(const PipelineStatistics& stats) {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - statistics_cb_.Run(stats);
|
| -}
|
| -
|
| -void RendererImpl::OnBufferingStateChanged(BufferingState* buffering_state,
|
| - BufferingState new_buffering_state) {
|
| - DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", "
|
| - << new_buffering_state << ") "
|
| - << (buffering_state == &audio_buffering_state_ ? "audio" : "video");
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - bool was_waiting_for_enough_data = WaitingForEnoughData();
|
| -
|
| - *buffering_state = new_buffering_state;
|
| -
|
| - // Disable underflow by ignoring updates that renderers have ran out of data.
|
| - if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ &&
|
| - time_ticking_) {
|
| - DVLOG(1) << "Update ignored because underflow is disabled for testing.";
|
| - return;
|
| - }
|
| -
|
| - // Renderer underflowed.
|
| - if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
|
| - PausePlayback();
|
| -
|
| - // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of
|
| - // underflow state http://crbug.com/144683
|
| - return;
|
| - }
|
| -
|
| - // Renderer prerolled.
|
| - if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
|
| - StartPlayback();
|
| - buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH);
|
| - return;
|
| - }
|
| -}
|
| -
|
| -bool RendererImpl::WaitingForEnoughData() const {
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - if (state_ != STATE_PLAYING)
|
| - return false;
|
| - if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
|
| - return true;
|
| - if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
|
| - return true;
|
| - return false;
|
| -}
|
| -
|
| -void RendererImpl::PausePlayback() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK(time_ticking_);
|
| - switch (state_) {
|
| - case STATE_PLAYING:
|
| - DCHECK(PlaybackHasEnded() || WaitingForEnoughData())
|
| - << "Playback should only pause due to ending or underflowing";
|
| - break;
|
| -
|
| - case STATE_FLUSHING:
|
| - // It's OK to pause playback when flushing.
|
| - break;
|
| -
|
| - case STATE_UNINITIALIZED:
|
| - case STATE_INITIALIZING:
|
| - NOTREACHED() << "Invalid state: " << state_;
|
| - break;
|
| -
|
| - case STATE_ERROR:
|
| - // An error state may occur at any time.
|
| - break;
|
| - }
|
| -
|
| - time_ticking_ = false;
|
| - time_source_->StopTicking();
|
| -}
|
| -
|
| -void RendererImpl::StartPlayback() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_EQ(state_, STATE_PLAYING);
|
| - DCHECK(!time_ticking_);
|
| - DCHECK(!WaitingForEnoughData());
|
| -
|
| - time_ticking_ = true;
|
| - time_source_->StartTicking();
|
| -}
|
| -
|
| -void RendererImpl::OnAudioRendererEnded() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (state_ != STATE_PLAYING)
|
| - return;
|
| -
|
| - DCHECK(!audio_ended_);
|
| - audio_ended_ = true;
|
| -
|
| - RunEndedCallbackIfNeeded();
|
| -}
|
| -
|
| -void RendererImpl::OnVideoRendererEnded() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (state_ != STATE_PLAYING)
|
| - return;
|
| -
|
| - DCHECK(!video_ended_);
|
| - video_ended_ = true;
|
| -
|
| - RunEndedCallbackIfNeeded();
|
| -}
|
| -
|
| -bool RendererImpl::PlaybackHasEnded() const {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (audio_renderer_ && !audio_ended_)
|
| - return false;
|
| -
|
| - if (video_renderer_ && !video_ended_)
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void RendererImpl::RunEndedCallbackIfNeeded() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (!PlaybackHasEnded())
|
| - return;
|
| -
|
| - if (time_ticking_)
|
| - PausePlayback();
|
| -
|
| - ended_cb_.Run();
|
| -}
|
| -
|
| -void RendererImpl::OnError(PipelineStatus error) {
|
| - DVLOG(1) << __FUNCTION__ << "(" << error << ")";
|
| - DCHECK(task_runner_->BelongsToCurrentThread());
|
| - DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
|
| -
|
| - // An error has already been delivered.
|
| - if (state_ == STATE_ERROR)
|
| - return;
|
| -
|
| - const State old_state = state_;
|
| - state_ = STATE_ERROR;
|
| -
|
| - if (old_state == STATE_INITIALIZING) {
|
| - base::ResetAndReturn(&init_cb_).Run(error);
|
| - return;
|
| - }
|
| -
|
| - // After OnError() returns, the pipeline may destroy |this|.
|
| - base::ResetAndReturn(&error_cb_).Run(error);
|
| -
|
| - if (!flush_cb_.is_null())
|
| - base::ResetAndReturn(&flush_cb_).Run();
|
| -}
|
| -
|
| -} // namespace media
|
|
|