Chromium Code Reviews| 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 |