Index: media/renderers/renderer_impl.cc |
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc |
index 6de238c68ce39ea96f3a74813e535b21bb177605..53c08e52506f7d3f63334af8c35ee5429634c77d 100644 |
--- a/media/renderers/renderer_impl.cc |
+++ b/media/renderers/renderer_impl.cc |
@@ -129,6 +129,17 @@ void RendererImpl::Initialize(DemuxerStreamProvider* demuxer_stream_provider, |
demuxer_stream_provider_ = demuxer_stream_provider; |
init_cb_ = init_cb; |
+ DemuxerStream* audio_stream = |
+ demuxer_stream_provider->GetStream(DemuxerStream::AUDIO); |
+ if (audio_stream) |
+ audio_stream->SetStreamRestartedCB( |
+ base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_)); |
+ DemuxerStream* video_stream = |
+ demuxer_stream_provider->GetStream(DemuxerStream::VIDEO); |
+ if (video_stream) |
+ video_stream->SetStreamRestartedCB( |
+ base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_)); |
+ |
if (HasEncryptedStream() && !cdm_context_) { |
state_ = STATE_INIT_PENDING_CDM; |
return; |
@@ -201,6 +212,51 @@ void RendererImpl::StartPlayingFrom(base::TimeDelta time) { |
video_renderer_->StartPlayingFrom(time); |
} |
+void RendererImpl::RestartStreamPlayback(DemuxerStream* stream, |
+ base::TimeDelta time) { |
+ DVLOG(1) << __FUNCTION__ << " stream=" << stream |
+ << " time=" << time.InSecondsF(); |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
+ if (stream->type() == DemuxerStream::VIDEO) { |
+ DCHECK(video_renderer_); |
+ DCHECK(video_ended_); |
+ video_ended_ = false; |
+ 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_); |
+ DCHECK(audio_ended_); |
+ audio_ended_ = false; |
+ 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. |
+ time_ticking_ = false; |
+ time_source_->StopTicking(); |
+ audio_renderer_->Flush( |
+ base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); |
+ } |
+} |
+ |
+void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
+ if (state_ == STATE_PLAYING) { |
+ DCHECK(video_renderer_); |
+ video_renderer_->StartPlayingFrom(time); |
+ } |
+} |
+ |
+void RendererImpl::RestartAudioRenderer(base::TimeDelta time) { |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
+ if (state_ == STATE_PLAYING) { |
+ DCHECK(time_source_); |
+ DCHECK(audio_renderer_); |
+ audio_renderer_->StartPlaying(); |
+ } |
+} |
+ |
void RendererImpl::SetPlaybackRate(double playback_rate) { |
DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
DCHECK(task_runner_->BelongsToCurrentThread()); |
@@ -502,6 +558,48 @@ void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type, |
bool was_waiting_for_enough_data = WaitingForEnoughData(); |
+ // When restarting video stream playback we want to ignore the |
+ // BUFFERING_HAVE_NOTHING notification so that audio keeps playing while |
+ // video decoder is catching up. |
+ if (type == DemuxerStream::VIDEO && restarting_video_) { |
+ if (new_buffering_state == BUFFERING_HAVE_NOTHING) { |
+ DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for video " |
+ "stream which is being restarted."; |
+ } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
+ DVLOG(1) |
+ << __FUNCTION__ |
+ << " Got BUFFERING_HAVE_ENOUGH for video stream, resuming playback."; |
+ restarting_video_ = false; |
+ if (playback_rate_ > 0) |
+ video_renderer_->OnTimeStateChanged(true); |
+ } |
+ return; |
+ } |
+ |
+ if (type == DemuxerStream::AUDIO && restarting_audio_) { |
+ if (new_buffering_state == BUFFERING_HAVE_NOTHING) { |
+ DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for " |
+ << (type == DemuxerStream::AUDIO ? "audio" : "video") |
+ << " stream"; |
+ } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
+ DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for " |
+ << (type == DemuxerStream::AUDIO ? "audio" : "video") |
+ << " stream"; |
+ |
+ restarting_audio_ = false; |
+ |
+ // Now that we have decoded enough audio, pause and unpause playback |
+ // momentarily to ensure video renderer is synchronised with audio. |
+ double curr_playback_rate = playback_rate_; |
+ SetPlaybackRate(0); |
+ SetPlaybackRate(curr_playback_rate); |
+ |
+ time_ticking_ = true; |
+ time_source_->StartTicking(); |
+ } |
+ return; |
+ } |
+ |
// When audio is present and has enough data, defer video underflow callbacks |
// for some time to avoid unnecessary glitches in audio; see |
// http://crbug.com/144683#c53. |
@@ -612,7 +710,8 @@ void RendererImpl::StartPlayback() { |
} |
void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { |
- DVLOG(1) << __FUNCTION__; |
+ DVLOG(1) << __FUNCTION__ |
+ << (type == DemuxerStream::AUDIO ? " audio" : " video"); |
DCHECK(task_runner_->BelongsToCurrentThread()); |
DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |