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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
194 } | 194 } |
195 | 195 |
196 time_source_->SetMediaTime(time); | 196 time_source_->SetMediaTime(time); |
197 | 197 |
198 if (audio_renderer_) | 198 if (audio_renderer_) |
199 audio_renderer_->StartPlaying(); | 199 audio_renderer_->StartPlaying(); |
200 if (video_renderer_) | 200 if (video_renderer_) |
201 video_renderer_->StartPlayingFrom(time); | 201 video_renderer_->StartPlayingFrom(time); |
202 } | 202 } |
203 | 203 |
204 void RendererImpl::RestartStreamPlayback(DemuxerStream* stream, | |
205 base::TimeDelta time) { | |
206 DVLOG(1) << __FUNCTION__ << " stream=" << stream | |
207 << " time=" << time.InSecondsF(); | |
208 DCHECK(task_runner_->BelongsToCurrentThread()); | |
209 if (stream->type() == DemuxerStream::VIDEO) { | |
210 DCHECK(video_renderer_); | |
211 DCHECK(video_ended_); | |
212 video_ended_ = false; | |
213 restarting_video_ = true; | |
214 video_renderer_->Flush(base::Bind( | |
215 &RendererImpl::OnVideoRendererFlushDone_ForRestart, weak_this_, time)); | |
216 } else if (stream->type() == DemuxerStream::AUDIO) { | |
217 DCHECK(audio_renderer_); | |
218 DCHECK(time_source_); | |
219 DCHECK(audio_ended_); | |
220 audio_ended_ = false; | |
221 restarting_audio_ = true; | |
222 // Stop ticking (transition into paused state) in audio renderer before | |
223 // calling Flush, since after Flush we are going to restart playback by | |
224 // calling audio renderer StartPlaying which would fail in playing state. | |
225 time_ticking_ = false; | |
226 time_source_->StopTicking(); | |
227 audio_renderer_->Flush(base::Bind( | |
228 &RendererImpl::OnAudioRendererFlushDone_ForRestart, weak_this_, time)); | |
229 } | |
230 } | |
231 | |
232 void RendererImpl::OnVideoRendererFlushDone_ForRestart(base::TimeDelta time) { | |
233 DCHECK(task_runner_->BelongsToCurrentThread()); | |
234 if (state_ == STATE_PLAYING) { | |
235 DCHECK(video_renderer_); | |
236 video_renderer_->StartPlayingFrom(time); | |
237 } | |
238 } | |
239 | |
240 void RendererImpl::OnAudioRendererFlushDone_ForRestart(base::TimeDelta time) { | |
241 DCHECK(task_runner_->BelongsToCurrentThread()); | |
242 if (state_ == STATE_PLAYING) { | |
243 DCHECK(time_source_); | |
244 DCHECK(audio_renderer_); | |
245 audio_renderer_->StartPlaying(); | |
246 } | |
247 } | |
248 | |
204 void RendererImpl::SetPlaybackRate(double playback_rate) { | 249 void RendererImpl::SetPlaybackRate(double playback_rate) { |
205 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 250 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
206 DCHECK(task_runner_->BelongsToCurrentThread()); | 251 DCHECK(task_runner_->BelongsToCurrentThread()); |
207 | 252 |
208 // Playback rate changes are only carried out while playing. | 253 // Playback rate changes are only carried out while playing. |
209 if (state_ != STATE_PLAYING) | 254 if (state_ != STATE_PLAYING) |
210 return; | 255 return; |
211 | 256 |
212 time_source_->SetPlaybackRate(playback_rate); | 257 time_source_->SetPlaybackRate(playback_rate); |
213 | 258 |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 ? &audio_buffering_state_ | 540 ? &audio_buffering_state_ |
496 : &video_buffering_state_; | 541 : &video_buffering_state_; |
497 | 542 |
498 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 543 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " |
499 << new_buffering_state << ") " | 544 << new_buffering_state << ") " |
500 << (type == DemuxerStream::AUDIO ? "audio" : "video"); | 545 << (type == DemuxerStream::AUDIO ? "audio" : "video"); |
501 DCHECK(task_runner_->BelongsToCurrentThread()); | 546 DCHECK(task_runner_->BelongsToCurrentThread()); |
502 | 547 |
503 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 548 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
504 | 549 |
550 // When restarting video stream playback we want to ignore the | |
551 // BUFFERING_HAVE_NOTHING notification so that audio keeps playing while | |
552 // video decoder is catching up. | |
553 if (type == DemuxerStream::VIDEO && restarting_video_) { | |
554 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { | |
555 DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for video " | |
556 "stream which is being restarted."; | |
557 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { | |
chcunningham
2016/06/03 01:38:49
What if the new buffering state never reaches HAVE
servolk
2016/06/03 02:53:15
If MSE apps decide to not bother appending video t
chcunningham
2016/06/03 20:54:59
I don't think its a matter of worrying just to hel
| |
558 DVLOG(1) | |
559 << __FUNCTION__ | |
560 << " Got BUFFERING_HAVE_ENOUGH for video stream, resuming playback."; | |
561 restarting_video_ = false; | |
562 if (playback_rate_ > 0) | |
563 video_renderer_->OnTimeStateChanged(true); | |
chcunningham
2016/06/03 01:38:49
Not really related to this line, but it triggered
servolk
2016/06/03 02:53:15
Yes, it sounds reasonable to me. I'm not sure why
| |
564 } | |
565 return; | |
566 } | |
567 | |
568 if (type == DemuxerStream::AUDIO && restarting_audio_) { | |
569 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { | |
570 DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for " | |
571 << (type == DemuxerStream::AUDIO ? "audio" : "video") | |
572 << " stream"; | |
573 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { | |
574 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for " | |
575 << (type == DemuxerStream::AUDIO ? "audio" : "video") | |
576 << " stream"; | |
577 | |
578 restarting_audio_ = false; | |
579 | |
580 // Now that we have decoded enough audio, pause and unpause playback | |
581 // momentarily to ensure video renderer is synchronised with audio. | |
582 double curr_playback_rate = playback_rate_; | |
583 SetPlaybackRate(0); | |
chcunningham
2016/06/03 01:38:49
Why does this help sync? I think you're already pa
chcunningham
2016/06/03 20:55:37
(reminder about this one in case you missed it)
| |
584 SetPlaybackRate(curr_playback_rate); | |
585 | |
586 time_ticking_ = true; | |
587 time_source_->StartTicking(); | |
588 } | |
589 return; | |
590 } | |
591 | |
505 // When audio is present and has enough data, defer video underflow callbacks | 592 // When audio is present and has enough data, defer video underflow callbacks |
506 // for some time to avoid unnecessary glitches in audio; see | 593 // for some time to avoid unnecessary glitches in audio; see |
507 // http://crbug.com/144683#c53. | 594 // http://crbug.com/144683#c53. |
508 if (audio_renderer_ && type == DemuxerStream::VIDEO && | 595 if (audio_renderer_ && type == DemuxerStream::VIDEO && |
509 state_ == STATE_PLAYING) { | 596 state_ == STATE_PLAYING) { |
510 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 597 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
511 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 598 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
512 new_buffering_state == BUFFERING_HAVE_NOTHING && | 599 new_buffering_state == BUFFERING_HAVE_NOTHING && |
513 deferred_underflow_cb_.IsCancelled()) { | 600 deferred_underflow_cb_.IsCancelled()) { |
514 deferred_underflow_cb_.Reset( | 601 deferred_underflow_cb_.Reset( |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
605 DCHECK(!time_ticking_); | 692 DCHECK(!time_ticking_); |
606 DCHECK(!WaitingForEnoughData()); | 693 DCHECK(!WaitingForEnoughData()); |
607 | 694 |
608 time_ticking_ = true; | 695 time_ticking_ = true; |
609 time_source_->StartTicking(); | 696 time_source_->StartTicking(); |
610 if (playback_rate_ > 0 && video_renderer_) | 697 if (playback_rate_ > 0 && video_renderer_) |
611 video_renderer_->OnTimeStateChanged(true); | 698 video_renderer_->OnTimeStateChanged(true); |
612 } | 699 } |
613 | 700 |
614 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { | 701 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { |
615 DVLOG(1) << __FUNCTION__; | 702 DVLOG(1) << __FUNCTION__ |
703 << (type == DemuxerStream::AUDIO ? " audio" : " video"); | |
616 DCHECK(task_runner_->BelongsToCurrentThread()); | 704 DCHECK(task_runner_->BelongsToCurrentThread()); |
617 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 705 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
618 | 706 |
619 if (state_ != STATE_PLAYING) | 707 if (state_ != STATE_PLAYING) |
620 return; | 708 return; |
621 | 709 |
622 if (type == DemuxerStream::AUDIO) { | 710 if (type == DemuxerStream::AUDIO) { |
623 DCHECK(!audio_ended_); | 711 DCHECK(!audio_ended_); |
624 audio_ended_ = true; | 712 audio_ended_ = true; |
625 } else { | 713 } else { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
691 DCHECK(task_runner_->BelongsToCurrentThread()); | 779 DCHECK(task_runner_->BelongsToCurrentThread()); |
692 client_->OnVideoNaturalSizeChange(size); | 780 client_->OnVideoNaturalSizeChange(size); |
693 } | 781 } |
694 | 782 |
695 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 783 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
696 DCHECK(task_runner_->BelongsToCurrentThread()); | 784 DCHECK(task_runner_->BelongsToCurrentThread()); |
697 client_->OnVideoOpacityChange(opaque); | 785 client_->OnVideoOpacityChange(opaque); |
698 } | 786 } |
699 | 787 |
700 } // namespace media | 788 } // namespace media |
OLD | NEW |