OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/renderers/renderer_impl.h" | 5 #include "media/renderers/renderer_impl.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 DCHECK_EQ(state_, STATE_UNINITIALIZED); | 122 DCHECK_EQ(state_, STATE_UNINITIALIZED); |
123 DCHECK(!init_cb.is_null()); | 123 DCHECK(!init_cb.is_null()); |
124 DCHECK(client); | 124 DCHECK(client); |
125 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || | 125 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || |
126 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO)); | 126 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO)); |
127 | 127 |
128 client_ = client; | 128 client_ = client; |
129 demuxer_stream_provider_ = demuxer_stream_provider; | 129 demuxer_stream_provider_ = demuxer_stream_provider; |
130 init_cb_ = init_cb; | 130 init_cb_ = init_cb; |
131 | 131 |
| 132 DemuxerStream* audio_stream = |
| 133 demuxer_stream_provider->GetStream(DemuxerStream::AUDIO); |
| 134 if (audio_stream) |
| 135 audio_stream->SetStreamRestartedCB( |
| 136 base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_)); |
| 137 DemuxerStream* video_stream = |
| 138 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO); |
| 139 if (video_stream) |
| 140 video_stream->SetStreamRestartedCB( |
| 141 base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_)); |
| 142 |
132 if (HasEncryptedStream() && !cdm_context_) { | 143 if (HasEncryptedStream() && !cdm_context_) { |
133 state_ = STATE_INIT_PENDING_CDM; | 144 state_ = STATE_INIT_PENDING_CDM; |
134 return; | 145 return; |
135 } | 146 } |
136 | 147 |
137 state_ = STATE_INITIALIZING; | 148 state_ = STATE_INITIALIZING; |
138 InitializeAudioRenderer(); | 149 InitializeAudioRenderer(); |
139 } | 150 } |
140 | 151 |
141 void RendererImpl::SetCdm(CdmContext* cdm_context, | 152 void RendererImpl::SetCdm(CdmContext* cdm_context, |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 } | 205 } |
195 | 206 |
196 time_source_->SetMediaTime(time); | 207 time_source_->SetMediaTime(time); |
197 | 208 |
198 if (audio_renderer_) | 209 if (audio_renderer_) |
199 audio_renderer_->StartPlaying(); | 210 audio_renderer_->StartPlaying(); |
200 if (video_renderer_) | 211 if (video_renderer_) |
201 video_renderer_->StartPlayingFrom(time); | 212 video_renderer_->StartPlayingFrom(time); |
202 } | 213 } |
203 | 214 |
| 215 void RendererImpl::RestartStreamPlayback(DemuxerStream* stream, |
| 216 base::TimeDelta time) { |
| 217 DVLOG(1) << __FUNCTION__ << " stream=" << stream |
| 218 << " time=" << time.InSecondsF(); |
| 219 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 220 if (stream->type() == DemuxerStream::VIDEO) { |
| 221 DCHECK(video_renderer_); |
| 222 DCHECK(video_ended_); |
| 223 video_ended_ = false; |
| 224 restarting_video_ = true; |
| 225 video_renderer_->Flush( |
| 226 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); |
| 227 } else if (stream->type() == DemuxerStream::AUDIO) { |
| 228 DCHECK(audio_renderer_); |
| 229 DCHECK(time_source_); |
| 230 DCHECK(audio_ended_); |
| 231 audio_ended_ = false; |
| 232 restarting_audio_ = true; |
| 233 // Stop ticking (transition into paused state) in audio renderer before |
| 234 // calling Flush, since after Flush we are going to restart playback by |
| 235 // calling audio renderer StartPlaying which would fail in playing state. |
| 236 time_ticking_ = false; |
| 237 time_source_->StopTicking(); |
| 238 audio_renderer_->Flush( |
| 239 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); |
| 240 } |
| 241 } |
| 242 |
| 243 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { |
| 244 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 245 if (state_ == STATE_PLAYING) { |
| 246 DCHECK(video_renderer_); |
| 247 video_renderer_->StartPlayingFrom(time); |
| 248 } |
| 249 } |
| 250 |
| 251 void RendererImpl::RestartAudioRenderer(base::TimeDelta time) { |
| 252 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 253 if (state_ == STATE_PLAYING) { |
| 254 DCHECK(time_source_); |
| 255 DCHECK(audio_renderer_); |
| 256 audio_renderer_->StartPlaying(); |
| 257 } |
| 258 } |
| 259 |
204 void RendererImpl::SetPlaybackRate(double playback_rate) { | 260 void RendererImpl::SetPlaybackRate(double playback_rate) { |
205 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 261 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
206 DCHECK(task_runner_->BelongsToCurrentThread()); | 262 DCHECK(task_runner_->BelongsToCurrentThread()); |
207 | 263 |
208 // Playback rate changes are only carried out while playing. | 264 // Playback rate changes are only carried out while playing. |
209 if (state_ != STATE_PLAYING) | 265 if (state_ != STATE_PLAYING) |
210 return; | 266 return; |
211 | 267 |
212 time_source_->SetPlaybackRate(playback_rate); | 268 time_source_->SetPlaybackRate(playback_rate); |
213 | 269 |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 ? &audio_buffering_state_ | 551 ? &audio_buffering_state_ |
496 : &video_buffering_state_; | 552 : &video_buffering_state_; |
497 | 553 |
498 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 554 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " |
499 << new_buffering_state << ") " | 555 << new_buffering_state << ") " |
500 << (type == DemuxerStream::AUDIO ? "audio" : "video"); | 556 << (type == DemuxerStream::AUDIO ? "audio" : "video"); |
501 DCHECK(task_runner_->BelongsToCurrentThread()); | 557 DCHECK(task_runner_->BelongsToCurrentThread()); |
502 | 558 |
503 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 559 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
504 | 560 |
| 561 // When restarting video stream playback we want to ignore the |
| 562 // BUFFERING_HAVE_NOTHING notification so that audio keeps playing while |
| 563 // video decoder is catching up. |
| 564 if (type == DemuxerStream::VIDEO && restarting_video_) { |
| 565 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { |
| 566 DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for video " |
| 567 "stream which is being restarted."; |
| 568 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
| 569 DVLOG(1) |
| 570 << __FUNCTION__ |
| 571 << " Got BUFFERING_HAVE_ENOUGH for video stream, resuming playback."; |
| 572 restarting_video_ = false; |
| 573 if (playback_rate_ > 0) |
| 574 video_renderer_->OnTimeStateChanged(true); |
| 575 } |
| 576 return; |
| 577 } |
| 578 |
| 579 if (type == DemuxerStream::AUDIO && restarting_audio_) { |
| 580 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { |
| 581 DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for " |
| 582 << (type == DemuxerStream::AUDIO ? "audio" : "video") |
| 583 << " stream"; |
| 584 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
| 585 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for " |
| 586 << (type == DemuxerStream::AUDIO ? "audio" : "video") |
| 587 << " stream"; |
| 588 |
| 589 restarting_audio_ = false; |
| 590 |
| 591 // Now that we have decoded enough audio, pause and unpause playback |
| 592 // momentarily to ensure video renderer is synchronised with audio. |
| 593 double curr_playback_rate = playback_rate_; |
| 594 SetPlaybackRate(0); |
| 595 SetPlaybackRate(curr_playback_rate); |
| 596 |
| 597 time_ticking_ = true; |
| 598 time_source_->StartTicking(); |
| 599 } |
| 600 return; |
| 601 } |
| 602 |
505 // When audio is present and has enough data, defer video underflow callbacks | 603 // When audio is present and has enough data, defer video underflow callbacks |
506 // for some time to avoid unnecessary glitches in audio; see | 604 // for some time to avoid unnecessary glitches in audio; see |
507 // http://crbug.com/144683#c53. | 605 // http://crbug.com/144683#c53. |
508 if (audio_renderer_ && type == DemuxerStream::VIDEO && | 606 if (audio_renderer_ && type == DemuxerStream::VIDEO && |
509 state_ == STATE_PLAYING) { | 607 state_ == STATE_PLAYING) { |
510 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 608 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
511 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 609 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
512 new_buffering_state == BUFFERING_HAVE_NOTHING && | 610 new_buffering_state == BUFFERING_HAVE_NOTHING && |
513 deferred_underflow_cb_.IsCancelled()) { | 611 deferred_underflow_cb_.IsCancelled()) { |
514 deferred_underflow_cb_.Reset( | 612 deferred_underflow_cb_.Reset( |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 DCHECK(!time_ticking_); | 703 DCHECK(!time_ticking_); |
606 DCHECK(!WaitingForEnoughData()); | 704 DCHECK(!WaitingForEnoughData()); |
607 | 705 |
608 time_ticking_ = true; | 706 time_ticking_ = true; |
609 time_source_->StartTicking(); | 707 time_source_->StartTicking(); |
610 if (playback_rate_ > 0 && video_renderer_) | 708 if (playback_rate_ > 0 && video_renderer_) |
611 video_renderer_->OnTimeStateChanged(true); | 709 video_renderer_->OnTimeStateChanged(true); |
612 } | 710 } |
613 | 711 |
614 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { | 712 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { |
615 DVLOG(1) << __FUNCTION__; | 713 DVLOG(1) << __FUNCTION__ |
| 714 << (type == DemuxerStream::AUDIO ? " audio" : " video"); |
616 DCHECK(task_runner_->BelongsToCurrentThread()); | 715 DCHECK(task_runner_->BelongsToCurrentThread()); |
617 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 716 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
618 | 717 |
619 if (state_ != STATE_PLAYING) | 718 if (state_ != STATE_PLAYING) |
620 return; | 719 return; |
621 | 720 |
622 if (type == DemuxerStream::AUDIO) { | 721 if (type == DemuxerStream::AUDIO) { |
623 DCHECK(!audio_ended_); | 722 DCHECK(!audio_ended_); |
624 audio_ended_ = true; | 723 audio_ended_ = true; |
625 } else { | 724 } else { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 DCHECK(task_runner_->BelongsToCurrentThread()); | 790 DCHECK(task_runner_->BelongsToCurrentThread()); |
692 client_->OnVideoNaturalSizeChange(size); | 791 client_->OnVideoNaturalSizeChange(size); |
693 } | 792 } |
694 | 793 |
695 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 794 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
696 DCHECK(task_runner_->BelongsToCurrentThread()); | 795 DCHECK(task_runner_->BelongsToCurrentThread()); |
697 client_->OnVideoOpacityChange(opaque); | 796 client_->OnVideoOpacityChange(opaque); |
698 } | 797 } |
699 | 798 |
700 } // namespace media | 799 } // namespace media |
OLD | NEW |