Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(521)

Unified Diff: media/renderers/renderer_impl.cc

Issue 2684103005: Allow media track switching. (Closed)
Patch Set: Fixed comments Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/renderers/renderer_impl.h ('k') | media/renderers/renderer_impl_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/renderers/renderer_impl.cc
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc
index cc1504529eee3f0dbef0eef70fb56a63306f9e05..eb5710d2eea5f40c4f634d063a62e29f9547c162 100644
--- a/media/renderers/renderer_impl.cc
+++ b/media/renderers/renderer_impl.cc
@@ -80,6 +80,8 @@ RendererImpl::RendererImpl(
task_runner_(task_runner),
audio_renderer_(std::move(audio_renderer)),
video_renderer_(std::move(video_renderer)),
+ current_audio_stream_(nullptr),
+ current_video_stream_(nullptr),
time_source_(NULL),
time_ticking_(false),
playback_rate_(0.0),
@@ -197,10 +199,19 @@ void RendererImpl::Flush(const base::Closure& flush_cb) {
flush_cb_ = flush_cb;
state_ = STATE_FLUSHING;
- if (time_ticking_)
- PausePlayback();
+ // If we are currently handling a media stream status change, then postpone
+ // Flush until after that's done (because stream status changes also flush
+ // audio_renderer_/video_renderer_ and they need to be restarted before they
+ // can be flushed again). OnStreamRestartCompleted will resume Flush
+ // processing after audio/video restart has completed and there are no other
+ // pending stream status changes.
+ if (restarting_audio_ || restarting_video_) {
+ pending_actions_.push_back(
+ base::Bind(&RendererImpl::FlushInternal, weak_this_));
+ return;
+ }
- FlushAudioRenderer();
+ FlushInternal();
}
void RendererImpl::StartPlayingFrom(base::TimeDelta time) {
@@ -221,64 +232,6 @@ void RendererImpl::StartPlayingFrom(base::TimeDelta time) {
video_renderer_->StartPlayingFrom(time);
}
-void RendererImpl::OnStreamStatusChanged(DemuxerStream* stream,
- bool enabled,
- base::TimeDelta time) {
- DCHECK(task_runner_->BelongsToCurrentThread());
- DCHECK(stream);
- bool video = (stream->type() == DemuxerStream::VIDEO);
- DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream
- << " enabled=" << enabled << " time=" << time.InSecondsF();
- if ((state_ != STATE_PLAYING) || (audio_ended_ && video_ended_))
- return;
- if (restarting_audio_ || restarting_video_) {
- DVLOG(3) << __func__ << ": postponed stream " << stream
- << " status change handling.";
- pending_stream_status_notifications_.push_back(
- base::Bind(&RendererImpl::OnStreamStatusChanged, weak_this_, stream,
- enabled, time));
- return;
- }
- if (stream->type() == DemuxerStream::VIDEO) {
- DCHECK(video_renderer_);
- restarting_video_ = true;
- video_renderer_->Flush(
- base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time));
- } else if (stream->type() == DemuxerStream::AUDIO) {
- DCHECK(audio_renderer_);
- DCHECK(time_source_);
- restarting_audio_ = true;
- // Stop ticking (transition into paused state) in audio renderer before
- // calling Flush, since after Flush we are going to restart playback by
- // calling audio renderer StartPlaying which would fail in playing state.
- if (time_ticking_) {
- time_ticking_ = false;
- time_source_->StopTicking();
- }
- audio_renderer_->Flush(
- base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time));
- }
-}
-
-void RendererImpl::RestartVideoRenderer(base::TimeDelta time) {
- DVLOG(3) << __func__;
- DCHECK(task_runner_->BelongsToCurrentThread());
- DCHECK(video_renderer_);
- DCHECK_EQ(state_, STATE_PLAYING);
- video_ended_ = false;
- video_renderer_->StartPlayingFrom(time);
-}
-
-void RendererImpl::RestartAudioRenderer(base::TimeDelta time) {
- DVLOG(3) << __func__;
- DCHECK(task_runner_->BelongsToCurrentThread());
- DCHECK_EQ(state_, STATE_PLAYING);
- DCHECK(time_source_);
- DCHECK(audio_renderer_);
- audio_ended_ = false;
- audio_renderer_->StartPlaying();
-}
-
void RendererImpl::SetPlaybackRate(double playback_rate) {
DVLOG(1) << __func__ << "(" << playback_rate << ")";
DCHECK(task_runner_->BelongsToCurrentThread());
@@ -400,6 +353,8 @@ void RendererImpl::InitializeAudioRenderer() {
return;
}
+ current_audio_stream_ = audio_stream;
+
audio_renderer_client_.reset(
new RendererClientInternal(DemuxerStream::AUDIO, this));
// Note: After the initialization of a renderer, error events from it may
@@ -448,6 +403,8 @@ void RendererImpl::InitializeVideoRenderer() {
return;
}
+ current_video_stream_ = video_stream;
+
video_renderer_client_.reset(
new RendererClientInternal(DemuxerStream::VIDEO, this));
video_renderer_->Initialize(
@@ -493,6 +450,18 @@ void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
FinishInitialization(PIPELINE_OK);
}
+void RendererImpl::FlushInternal() {
+ DVLOG(1) << __func__;
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK_EQ(state_, STATE_FLUSHING);
+ DCHECK(!flush_cb_.is_null());
+
+ if (time_ticking_)
+ PausePlayback();
+
+ FlushAudioRenderer();
+}
+
void RendererImpl::FlushAudioRenderer() {
DVLOG(1) << __func__;
DCHECK(task_runner_->BelongsToCurrentThread());
@@ -560,6 +529,168 @@ void RendererImpl::OnVideoRendererFlushDone() {
video_ended_ = false;
state_ = STATE_FLUSHED;
base::ResetAndReturn(&flush_cb_).Run();
+
+ if (!pending_actions_.empty()) {
+ base::Closure closure = pending_actions_.front();
+ pending_actions_.pop_front();
+ closure.Run();
+ }
+}
+
+void RendererImpl::OnStreamStatusChanged(DemuxerStream* stream,
+ bool enabled,
+ base::TimeDelta time) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK(stream);
+ bool video = (stream->type() == DemuxerStream::VIDEO);
+ DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream
+ << " enabled=" << enabled << " time=" << time.InSecondsF();
+
+ if ((state_ != STATE_PLAYING && state_ != STATE_FLUSHING &&
+ state_ != STATE_FLUSHED) ||
+ (audio_ended_ && video_ended_))
+ return;
+
+ if (restarting_audio_ || restarting_video_ || state_ == STATE_FLUSHING) {
+ DVLOG(3) << __func__ << ": postponed stream " << stream
+ << " status change handling.";
+ pending_actions_.push_back(base::Bind(&RendererImpl::OnStreamStatusChanged,
+ weak_this_, stream, enabled, time));
+ return;
+ }
+
+ DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHED);
+ if (stream->type() == DemuxerStream::VIDEO) {
+ DCHECK(video_renderer_);
+ restarting_video_ = true;
+ base::Closure handle_track_status_cb =
+ base::Bind(stream == current_video_stream_
+ ? &RendererImpl::RestartVideoRenderer
+ : &RendererImpl::ReinitializeVideoRenderer,
+ weak_this_, stream, time);
+ if (state_ == STATE_FLUSHED)
+ handle_track_status_cb.Run();
+ else
+ video_renderer_->Flush(handle_track_status_cb);
+ } else if (stream->type() == DemuxerStream::AUDIO) {
+ DCHECK(audio_renderer_);
+ DCHECK(time_source_);
+ restarting_audio_ = true;
+ base::Closure handle_track_status_cb =
+ base::Bind(stream == current_audio_stream_
+ ? &RendererImpl::RestartAudioRenderer
+ : &RendererImpl::ReinitializeAudioRenderer,
+ weak_this_, stream, time);
+ if (state_ == STATE_FLUSHED) {
+ handle_track_status_cb.Run();
+ return;
+ }
+ // Stop ticking (transition into paused state) in audio renderer before
+ // calling Flush, since after Flush we are going to restart playback by
+ // calling audio renderer StartPlaying which would fail in playing state.
+ if (time_ticking_) {
+ time_ticking_ = false;
+ time_source_->StopTicking();
+ }
+ audio_renderer_->Flush(handle_track_status_cb);
+ }
+}
+
+void RendererImpl::ReinitializeAudioRenderer(DemuxerStream* stream,
+ base::TimeDelta time) {
+ DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK_NE(stream, current_audio_stream_);
+
+ current_audio_stream_ = stream;
+ audio_renderer_->Initialize(
+ stream, cdm_context_, audio_renderer_client_.get(),
+ base::Bind(&RendererImpl::OnAudioRendererReinitialized, weak_this_,
+ stream, time));
+}
+
+void RendererImpl::OnAudioRendererReinitialized(DemuxerStream* stream,
+ base::TimeDelta time,
+ PipelineStatus status) {
+ DVLOG(2) << __func__ << ": status=" << status;
+ DCHECK_EQ(stream, current_audio_stream_);
+
+ if (status != PIPELINE_OK) {
+ OnError(status);
+ return;
+ }
+ RestartAudioRenderer(stream, time);
+}
+
+void RendererImpl::ReinitializeVideoRenderer(DemuxerStream* stream,
+ base::TimeDelta time) {
+ DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK_NE(stream, current_video_stream_);
+
+ current_video_stream_ = stream;
+ video_renderer_->OnTimeStopped();
+ video_renderer_->Initialize(
+ stream, cdm_context_, video_renderer_client_.get(),
+ base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)),
+ base::Bind(&RendererImpl::OnVideoRendererReinitialized, weak_this_,
+ stream, time));
+}
+
+void RendererImpl::OnVideoRendererReinitialized(DemuxerStream* stream,
+ base::TimeDelta time,
+ PipelineStatus status) {
+ DVLOG(2) << __func__ << ": status=" << status;
+ DCHECK_EQ(stream, current_video_stream_);
+
+ if (status != PIPELINE_OK) {
+ OnError(status);
+ return;
+ }
+ RestartVideoRenderer(stream, time);
+}
+
+void RendererImpl::RestartAudioRenderer(DemuxerStream* stream,
+ base::TimeDelta time) {
+ DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHED ||
+ state_ == STATE_FLUSHING);
+ DCHECK(time_source_);
+ DCHECK(audio_renderer_);
+ DCHECK_EQ(stream, current_audio_stream_);
+
+ audio_ended_ = false;
+ if (state_ == STATE_FLUSHED) {
+ // If we are in the FLUSHED state, then we are done. The audio renderer will
+ // be restarted by a subsequent RendererImpl::StartPlayingFrom call.
+ OnStreamRestartCompleted();
+ } else {
+ // Stream restart will be completed when the audio renderer decodes enough
+ // data and reports HAVE_ENOUGH to HandleRestartedStreamBufferingChanges.
+ audio_renderer_->StartPlaying();
+ }
+}
+
+void RendererImpl::RestartVideoRenderer(DemuxerStream* stream,
+ base::TimeDelta time) {
+ DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK(video_renderer_);
+ DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHED ||
+ state_ == STATE_FLUSHING);
+ DCHECK_EQ(stream, current_video_stream_);
+
+ video_ended_ = false;
+ if (state_ == STATE_FLUSHED) {
+ // If we are in the FLUSHED state, then we are done. The video renderer will
+ // be restarted by a subsequent RendererImpl::StartPlayingFrom call.
+ OnStreamRestartCompleted();
+ } else {
+ // Stream restart will be completed when the video renderer decodes enough
+ // data and reports HAVE_ENOUGH to HandleRestartedStreamBufferingChanges.
+ video_renderer_->StartPlayingFrom(time);
+ }
}
void RendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) {
@@ -634,12 +765,16 @@ bool RendererImpl::HandleRestartedStreamBufferingChanges(
}
void RendererImpl::OnStreamRestartCompleted() {
+ DVLOG(3) << __func__ << " restarting_audio_=" << restarting_audio_
+ << " restarting_video_=" << restarting_video_;
+ DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(restarting_audio_ || restarting_video_);
restarting_audio_ = false;
restarting_video_ = false;
- if (!pending_stream_status_notifications_.empty()) {
- pending_stream_status_notifications_.front().Run();
- pending_stream_status_notifications_.pop_front();
+ if (!pending_actions_.empty()) {
+ base::Closure closure = pending_actions_.front();
+ pending_actions_.pop_front();
+ closure.Run();
}
}
« no previous file with comments | « media/renderers/renderer_impl.h ('k') | media/renderers/renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698