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 12 matching lines...) Expand all Loading... |
23 #include "media/base/time_source.h" | 23 #include "media/base/time_source.h" |
24 #include "media/base/video_decoder_config.h" | 24 #include "media/base/video_decoder_config.h" |
25 #include "media/base/video_renderer.h" | 25 #include "media/base/video_renderer.h" |
26 #include "media/base/wall_clock_time_source.h" | 26 #include "media/base/wall_clock_time_source.h" |
27 | 27 |
28 namespace media { | 28 namespace media { |
29 | 29 |
30 // See |video_underflow_threshold_|. | 30 // See |video_underflow_threshold_|. |
31 static const int kDefaultVideoUnderflowThresholdMs = 3000; | 31 static const int kDefaultVideoUnderflowThresholdMs = 3000; |
32 | 32 |
| 33 static const int kAudioRestartUnderflowThresholdMs = 2000; |
| 34 |
33 class RendererImpl::RendererClientInternal : public RendererClient { | 35 class RendererImpl::RendererClientInternal : public RendererClient { |
34 public: | 36 public: |
35 RendererClientInternal(DemuxerStream::Type type, RendererImpl* renderer) | 37 RendererClientInternal(DemuxerStream::Type type, RendererImpl* renderer) |
36 : type_(type), renderer_(renderer) { | 38 : type_(type), renderer_(renderer) { |
37 DCHECK((type_ == DemuxerStream::AUDIO) || (type_ == DemuxerStream::VIDEO)); | 39 DCHECK((type_ == DemuxerStream::AUDIO) || (type_ == DemuxerStream::VIDEO)); |
38 } | 40 } |
39 | 41 |
40 void OnError(PipelineStatus error) override { renderer_->OnError(error); } | 42 void OnError(PipelineStatus error) override { renderer_->OnError(error); } |
41 void OnEnded() override { renderer_->OnRendererEnded(type_); } | 43 void OnEnded() override { renderer_->OnRendererEnded(type_); } |
42 void OnStatisticsUpdate(const PipelineStatistics& stats) override { | 44 void OnStatisticsUpdate(const PipelineStatistics& stats) override { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 DCHECK_EQ(state_, STATE_UNINITIALIZED); | 124 DCHECK_EQ(state_, STATE_UNINITIALIZED); |
123 DCHECK(!init_cb.is_null()); | 125 DCHECK(!init_cb.is_null()); |
124 DCHECK(client); | 126 DCHECK(client); |
125 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || | 127 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || |
126 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO)); | 128 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO)); |
127 | 129 |
128 client_ = client; | 130 client_ = client; |
129 demuxer_stream_provider_ = demuxer_stream_provider; | 131 demuxer_stream_provider_ = demuxer_stream_provider; |
130 init_cb_ = init_cb; | 132 init_cb_ = init_cb; |
131 | 133 |
| 134 DemuxerStream* audio_stream = |
| 135 demuxer_stream_provider->GetStream(DemuxerStream::AUDIO); |
| 136 if (audio_stream) |
| 137 audio_stream->SetStreamRestartedCB( |
| 138 base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_)); |
| 139 DemuxerStream* video_stream = |
| 140 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO); |
| 141 if (video_stream) |
| 142 video_stream->SetStreamRestartedCB( |
| 143 base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_)); |
| 144 |
132 if (HasEncryptedStream() && !cdm_context_) { | 145 if (HasEncryptedStream() && !cdm_context_) { |
133 state_ = STATE_INIT_PENDING_CDM; | 146 state_ = STATE_INIT_PENDING_CDM; |
134 return; | 147 return; |
135 } | 148 } |
136 | 149 |
137 state_ = STATE_INITIALIZING; | 150 state_ = STATE_INITIALIZING; |
138 InitializeAudioRenderer(); | 151 InitializeAudioRenderer(); |
139 } | 152 } |
140 | 153 |
141 void RendererImpl::SetCdm(CdmContext* cdm_context, | 154 void RendererImpl::SetCdm(CdmContext* cdm_context, |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 } | 207 } |
195 | 208 |
196 time_source_->SetMediaTime(time); | 209 time_source_->SetMediaTime(time); |
197 | 210 |
198 if (audio_renderer_) | 211 if (audio_renderer_) |
199 audio_renderer_->StartPlaying(); | 212 audio_renderer_->StartPlaying(); |
200 if (video_renderer_) | 213 if (video_renderer_) |
201 video_renderer_->StartPlayingFrom(time); | 214 video_renderer_->StartPlayingFrom(time); |
202 } | 215 } |
203 | 216 |
| 217 void RendererImpl::RestartStreamPlayback(DemuxerStream* stream, |
| 218 base::TimeDelta time) { |
| 219 DVLOG(1) << __FUNCTION__ << " stream=" << stream |
| 220 << " time=" << time.InSecondsF(); |
| 221 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 222 if (state_ != STATE_PLAYING) |
| 223 return; |
| 224 if (stream->type() == DemuxerStream::VIDEO) { |
| 225 DCHECK(video_renderer_); |
| 226 if (restarting_video_) |
| 227 return; |
| 228 restarting_video_ = true; |
| 229 video_renderer_->Flush( |
| 230 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); |
| 231 } else if (stream->type() == DemuxerStream::AUDIO) { |
| 232 DCHECK(audio_renderer_); |
| 233 DCHECK(time_source_); |
| 234 if (restarting_audio_) |
| 235 return; |
| 236 restarting_audio_ = true; |
| 237 // Stop ticking (transition into paused state) in audio renderer before |
| 238 // calling Flush, since after Flush we are going to restart playback by |
| 239 // calling audio renderer StartPlaying which would fail in playing state. |
| 240 if (time_ticking_) { |
| 241 time_ticking_ = false; |
| 242 time_source_->StopTicking(); |
| 243 } |
| 244 audio_renderer_->Flush( |
| 245 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); |
| 246 } |
| 247 } |
| 248 |
| 249 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { |
| 250 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 251 DVLOG(2) << __FUNCTION__; |
| 252 video_ended_ = false; |
| 253 if (state_ == STATE_PLAYING) { |
| 254 DCHECK(video_renderer_); |
| 255 video_renderer_->StartPlayingFrom(time); |
| 256 } |
| 257 } |
| 258 |
| 259 void RendererImpl::RestartAudioRenderer(base::TimeDelta time) { |
| 260 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 261 DVLOG(2) << __FUNCTION__; |
| 262 audio_ended_ = false; |
| 263 if (state_ == STATE_PLAYING) { |
| 264 DCHECK(time_source_); |
| 265 DCHECK(audio_renderer_); |
| 266 audio_renderer_->StartPlaying(); |
| 267 } |
| 268 } |
| 269 |
204 void RendererImpl::SetPlaybackRate(double playback_rate) { | 270 void RendererImpl::SetPlaybackRate(double playback_rate) { |
205 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 271 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
206 DCHECK(task_runner_->BelongsToCurrentThread()); | 272 DCHECK(task_runner_->BelongsToCurrentThread()); |
207 | 273 |
208 // Playback rate changes are only carried out while playing. | 274 // Playback rate changes are only carried out while playing. |
209 if (state_ != STATE_PLAYING) | 275 if (state_ != STATE_PLAYING) |
210 return; | 276 return; |
211 | 277 |
212 time_source_->SetPlaybackRate(playback_rate); | 278 time_source_->SetPlaybackRate(playback_rate); |
213 | 279 |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 if (state_ == STATE_ERROR) { | 502 if (state_ == STATE_ERROR) { |
437 DCHECK(flush_cb_.is_null()); | 503 DCHECK(flush_cb_.is_null()); |
438 return; | 504 return; |
439 } | 505 } |
440 | 506 |
441 DCHECK_EQ(state_, STATE_FLUSHING); | 507 DCHECK_EQ(state_, STATE_FLUSHING); |
442 DCHECK(!flush_cb_.is_null()); | 508 DCHECK(!flush_cb_.is_null()); |
443 | 509 |
444 // If we had a deferred video renderer underflow prior to the flush, it should | 510 // If we had a deferred video renderer underflow prior to the flush, it should |
445 // have been cleared by the audio renderer changing to BUFFERING_HAVE_NOTHING. | 511 // have been cleared by the audio renderer changing to BUFFERING_HAVE_NOTHING. |
446 DCHECK(deferred_underflow_cb_.IsCancelled()); | 512 DCHECK(deferred_video_underflow_cb_.IsCancelled()); |
447 | 513 |
448 DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING); | 514 DCHECK_EQ(audio_buffering_state_, BUFFERING_HAVE_NOTHING); |
449 audio_ended_ = false; | 515 audio_ended_ = false; |
450 FlushVideoRenderer(); | 516 FlushVideoRenderer(); |
451 } | 517 } |
452 | 518 |
453 void RendererImpl::FlushVideoRenderer() { | 519 void RendererImpl::FlushVideoRenderer() { |
454 DVLOG(1) << __FUNCTION__; | 520 DVLOG(1) << __FUNCTION__; |
455 DCHECK(task_runner_->BelongsToCurrentThread()); | 521 DCHECK(task_runner_->BelongsToCurrentThread()); |
456 DCHECK_EQ(state_, STATE_FLUSHING); | 522 DCHECK_EQ(state_, STATE_FLUSHING); |
(...skipping 24 matching lines...) Expand all Loading... |
481 video_ended_ = false; | 547 video_ended_ = false; |
482 state_ = STATE_PLAYING; | 548 state_ = STATE_PLAYING; |
483 base::ResetAndReturn(&flush_cb_).Run(); | 549 base::ResetAndReturn(&flush_cb_).Run(); |
484 } | 550 } |
485 | 551 |
486 void RendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) { | 552 void RendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) { |
487 DCHECK(task_runner_->BelongsToCurrentThread()); | 553 DCHECK(task_runner_->BelongsToCurrentThread()); |
488 client_->OnStatisticsUpdate(stats); | 554 client_->OnStatisticsUpdate(stats); |
489 } | 555 } |
490 | 556 |
| 557 namespace { |
| 558 |
| 559 const char* BufferingStateStr(BufferingState state) { |
| 560 switch (state) { |
| 561 case BUFFERING_HAVE_NOTHING: |
| 562 return "HAVE_NOTHING"; |
| 563 case BUFFERING_HAVE_ENOUGH: |
| 564 return "HAVE_ENOUGH"; |
| 565 } |
| 566 NOTREACHED(); |
| 567 return ""; |
| 568 } |
| 569 } |
| 570 |
| 571 bool RendererImpl::HandleRestartedStreamBufferingChanges( |
| 572 DemuxerStream::Type type, |
| 573 BufferingState new_buffering_state) { |
| 574 // When restarting playback we want to defer the BUFFERING_HAVE_NOTHING for |
| 575 // the stream being restarted, to allow continuing uninterrupted playback on |
| 576 // the other stream. |
| 577 if (type == DemuxerStream::VIDEO && restarting_video_) { |
| 578 if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
| 579 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for video stream," |
| 580 " resuming playback."; |
| 581 restarting_video_ = false; |
| 582 if (state_ == STATE_PLAYING && |
| 583 !deferred_video_underflow_cb_.IsCancelled()) { |
| 584 // If deferred_video_underflow_cb_ wasn't triggered, then audio should |
| 585 // still be playing, we only need to unpause the video stream. |
| 586 DVLOG(4) << "deferred_video_underflow_cb_.Cancel()"; |
| 587 deferred_video_underflow_cb_.Cancel(); |
| 588 video_buffering_state_ = new_buffering_state; |
| 589 if (playback_rate_ > 0) |
| 590 video_renderer_->OnTimeStateChanged(true); |
| 591 return true; |
| 592 } |
| 593 } |
| 594 // We don't handle the BUFFERING_HAVE_NOTHING case explicitly here, since |
| 595 // the existing logic for deferring video underflow reporting in |
| 596 // OnBufferingStateChange is exactly what we need. So fall through to the |
| 597 // regular video underflow handling path in OnBufferingStateChange. |
| 598 } |
| 599 |
| 600 if (type == DemuxerStream::AUDIO && restarting_audio_) { |
| 601 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { |
| 602 if (deferred_video_underflow_cb_.IsCancelled() && |
| 603 deferred_audio_restart_underflow_cb_.IsCancelled()) { |
| 604 DVLOG(1) << __FUNCTION__ << " Deferring BUFFERING_HAVE_NOTHING for " |
| 605 "audio stream which is being restarted."; |
| 606 audio_buffering_state_ = new_buffering_state; |
| 607 deferred_audio_restart_underflow_cb_.Reset( |
| 608 base::Bind(&RendererImpl::OnBufferingStateChange, weak_this_, type, |
| 609 new_buffering_state)); |
| 610 task_runner_->PostDelayedTask( |
| 611 FROM_HERE, deferred_audio_restart_underflow_cb_.callback(), |
| 612 base::TimeDelta::FromMilliseconds( |
| 613 kAudioRestartUnderflowThresholdMs)); |
| 614 return true; |
| 615 } |
| 616 // Cancel the deferred callback and report the underflow immediately. |
| 617 DVLOG(4) << "deferred_audio_restart_underflow_cb_.Cancel()"; |
| 618 deferred_audio_restart_underflow_cb_.Cancel(); |
| 619 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
| 620 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for audio stream," |
| 621 " resuming playback."; |
| 622 deferred_audio_restart_underflow_cb_.Cancel(); |
| 623 // Now that we have decoded enough audio, pause playback momentarily to |
| 624 // ensure video renderer is synchronised with audio. |
| 625 PausePlayback(); |
| 626 restarting_audio_ = false; |
| 627 } |
| 628 } |
| 629 return false; |
| 630 } |
| 631 |
491 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type, | 632 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type, |
492 BufferingState new_buffering_state) { | 633 BufferingState new_buffering_state) { |
493 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 634 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
494 BufferingState* buffering_state = type == DemuxerStream::AUDIO | 635 BufferingState* buffering_state = type == DemuxerStream::AUDIO |
495 ? &audio_buffering_state_ | 636 ? &audio_buffering_state_ |
496 : &video_buffering_state_; | 637 : &video_buffering_state_; |
497 | 638 |
498 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 639 DVLOG(1) << __FUNCTION__ |
499 << new_buffering_state << ") " | 640 << (type == DemuxerStream::AUDIO ? " audio " : " video ") |
500 << (type == DemuxerStream::AUDIO ? "audio" : "video"); | 641 << BufferingStateStr(*buffering_state) << " -> " |
| 642 << BufferingStateStr(new_buffering_state); |
501 DCHECK(task_runner_->BelongsToCurrentThread()); | 643 DCHECK(task_runner_->BelongsToCurrentThread()); |
502 | 644 |
503 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 645 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
504 | 646 |
| 647 if (restarting_audio_ || restarting_video_) { |
| 648 if (HandleRestartedStreamBufferingChanges(type, new_buffering_state)) |
| 649 return; |
| 650 } |
| 651 |
505 // When audio is present and has enough data, defer video underflow callbacks | 652 // When audio is present and has enough data, defer video underflow callbacks |
506 // for some time to avoid unnecessary glitches in audio; see | 653 // for some time to avoid unnecessary glitches in audio; see |
507 // http://crbug.com/144683#c53. | 654 // http://crbug.com/144683#c53. |
508 if (audio_renderer_ && type == DemuxerStream::VIDEO && | 655 if (audio_renderer_ && type == DemuxerStream::VIDEO && |
509 state_ == STATE_PLAYING) { | 656 state_ == STATE_PLAYING) { |
510 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 657 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
511 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 658 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
512 new_buffering_state == BUFFERING_HAVE_NOTHING && | 659 new_buffering_state == BUFFERING_HAVE_NOTHING && |
513 deferred_underflow_cb_.IsCancelled()) { | 660 deferred_video_underflow_cb_.IsCancelled()) { |
514 deferred_underflow_cb_.Reset( | 661 DVLOG(4) << __FUNCTION__ << " Deferring HAVE_NOTHING for video stream."; |
| 662 deferred_video_underflow_cb_.Reset( |
515 base::Bind(&RendererImpl::OnBufferingStateChange, | 663 base::Bind(&RendererImpl::OnBufferingStateChange, |
516 weak_factory_.GetWeakPtr(), type, new_buffering_state)); | 664 weak_factory_.GetWeakPtr(), type, new_buffering_state)); |
517 task_runner_->PostDelayedTask(FROM_HERE, | 665 task_runner_->PostDelayedTask(FROM_HERE, |
518 deferred_underflow_cb_.callback(), | 666 deferred_video_underflow_cb_.callback(), |
519 video_underflow_threshold_); | 667 video_underflow_threshold_); |
520 return; | 668 return; |
521 } | 669 } |
522 | 670 |
523 deferred_underflow_cb_.Cancel(); | 671 DVLOG(4) << "deferred_video_underflow_cb_.Cancel()"; |
524 } else if (!deferred_underflow_cb_.IsCancelled() && | 672 deferred_video_underflow_cb_.Cancel(); |
| 673 } else if (!deferred_video_underflow_cb_.IsCancelled() && |
525 type == DemuxerStream::AUDIO && | 674 type == DemuxerStream::AUDIO && |
526 new_buffering_state == BUFFERING_HAVE_NOTHING) { | 675 new_buffering_state == BUFFERING_HAVE_NOTHING) { |
527 // If audio underflows while we have a deferred video underflow in progress | 676 // If audio underflows while we have a deferred video underflow in progress |
528 // we want to mark video as underflowed immediately and cancel the deferral. | 677 // we want to mark video as underflowed immediately and cancel the deferral. |
529 deferred_underflow_cb_.Cancel(); | 678 deferred_video_underflow_cb_.Cancel(); |
530 video_buffering_state_ = BUFFERING_HAVE_NOTHING; | 679 video_buffering_state_ = BUFFERING_HAVE_NOTHING; |
531 } | 680 } |
532 | 681 |
533 *buffering_state = new_buffering_state; | 682 *buffering_state = new_buffering_state; |
534 | 683 |
535 // Disable underflow by ignoring updates that renderers have ran out of data. | 684 // Disable underflow by ignoring updates that renderers have ran out of data. |
536 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ && | 685 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ && |
537 time_ticking_) { | 686 time_ticking_) { |
538 DVLOG(1) << "Update ignored because underflow is disabled for testing."; | 687 DVLOG(1) << "Update ignored because underflow is disabled for testing."; |
539 return; | 688 return; |
(...skipping 23 matching lines...) Expand all Loading... |
563 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) | 712 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) |
564 return true; | 713 return true; |
565 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) | 714 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) |
566 return true; | 715 return true; |
567 return false; | 716 return false; |
568 } | 717 } |
569 | 718 |
570 void RendererImpl::PausePlayback() { | 719 void RendererImpl::PausePlayback() { |
571 DVLOG(1) << __FUNCTION__; | 720 DVLOG(1) << __FUNCTION__; |
572 DCHECK(task_runner_->BelongsToCurrentThread()); | 721 DCHECK(task_runner_->BelongsToCurrentThread()); |
573 DCHECK(time_ticking_); | |
574 switch (state_) { | 722 switch (state_) { |
575 case STATE_PLAYING: | 723 case STATE_PLAYING: |
576 DCHECK(PlaybackHasEnded() || WaitingForEnoughData()) | 724 DCHECK(PlaybackHasEnded() || WaitingForEnoughData() || restarting_audio_) |
577 << "Playback should only pause due to ending or underflowing"; | 725 << "Playback should only pause due to ending or underflowing or" |
| 726 " when restarting audio stream"; |
| 727 |
578 break; | 728 break; |
579 | 729 |
580 case STATE_FLUSHING: | 730 case STATE_FLUSHING: |
581 // It's OK to pause playback when flushing. | 731 // It's OK to pause playback when flushing. |
582 break; | 732 break; |
583 | 733 |
584 case STATE_UNINITIALIZED: | 734 case STATE_UNINITIALIZED: |
585 case STATE_INIT_PENDING_CDM: | 735 case STATE_INIT_PENDING_CDM: |
586 case STATE_INITIALIZING: | 736 case STATE_INITIALIZING: |
587 NOTREACHED() << "Invalid state: " << state_; | 737 NOTREACHED() << "Invalid state: " << state_; |
588 break; | 738 break; |
589 | 739 |
590 case STATE_ERROR: | 740 case STATE_ERROR: |
591 // An error state may occur at any time. | 741 // An error state may occur at any time. |
592 break; | 742 break; |
593 } | 743 } |
594 | 744 |
595 time_ticking_ = false; | 745 if (time_ticking_) { |
596 time_source_->StopTicking(); | 746 time_ticking_ = false; |
| 747 time_source_->StopTicking(); |
| 748 } |
597 if (playback_rate_ > 0 && video_renderer_) | 749 if (playback_rate_ > 0 && video_renderer_) |
598 video_renderer_->OnTimeStateChanged(false); | 750 video_renderer_->OnTimeStateChanged(false); |
599 } | 751 } |
600 | 752 |
601 void RendererImpl::StartPlayback() { | 753 void RendererImpl::StartPlayback() { |
602 DVLOG(1) << __FUNCTION__; | 754 DVLOG(1) << __FUNCTION__; |
603 DCHECK(task_runner_->BelongsToCurrentThread()); | 755 DCHECK(task_runner_->BelongsToCurrentThread()); |
604 DCHECK_EQ(state_, STATE_PLAYING); | 756 DCHECK_EQ(state_, STATE_PLAYING); |
605 DCHECK(!time_ticking_); | 757 DCHECK(!time_ticking_); |
606 DCHECK(!WaitingForEnoughData()); | 758 DCHECK(!WaitingForEnoughData()); |
607 | 759 |
608 time_ticking_ = true; | 760 time_ticking_ = true; |
609 time_source_->StartTicking(); | 761 time_source_->StartTicking(); |
610 if (playback_rate_ > 0 && video_renderer_) | 762 if (playback_rate_ > 0 && video_renderer_) |
611 video_renderer_->OnTimeStateChanged(true); | 763 video_renderer_->OnTimeStateChanged(true); |
612 } | 764 } |
613 | 765 |
614 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { | 766 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { |
615 DVLOG(1) << __FUNCTION__; | 767 DVLOG(1) << __FUNCTION__ |
| 768 << (type == DemuxerStream::AUDIO ? " audio" : " video"); |
616 DCHECK(task_runner_->BelongsToCurrentThread()); | 769 DCHECK(task_runner_->BelongsToCurrentThread()); |
617 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 770 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
618 | 771 |
619 if (state_ != STATE_PLAYING) | 772 if (state_ != STATE_PLAYING) |
620 return; | 773 return; |
621 | 774 |
622 if (type == DemuxerStream::AUDIO) { | 775 if (type == DemuxerStream::AUDIO) { |
623 DCHECK(!audio_ended_); | 776 DCHECK(!audio_ended_); |
624 audio_ended_ = true; | 777 audio_ended_ = true; |
625 } else { | 778 } else { |
626 DCHECK(!video_ended_); | 779 DCHECK(!video_ended_); |
627 video_ended_ = true; | 780 video_ended_ = true; |
| 781 DCHECK(video_renderer_); |
| 782 video_renderer_->OnTimeStateChanged(false); |
628 } | 783 } |
629 | 784 |
630 RunEndedCallbackIfNeeded(); | 785 RunEndedCallbackIfNeeded(); |
631 } | 786 } |
632 | 787 |
633 bool RendererImpl::PlaybackHasEnded() const { | 788 bool RendererImpl::PlaybackHasEnded() const { |
634 DVLOG(1) << __FUNCTION__; | |
635 DCHECK(task_runner_->BelongsToCurrentThread()); | 789 DCHECK(task_runner_->BelongsToCurrentThread()); |
636 | 790 |
637 if (audio_renderer_ && !audio_ended_) | 791 if (audio_renderer_ && !audio_ended_) |
638 return false; | 792 return false; |
639 | 793 |
640 if (video_renderer_ && !video_ended_) | 794 if (video_renderer_ && !video_ended_) |
641 return false; | 795 return false; |
642 | 796 |
643 return true; | 797 return true; |
644 } | 798 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 DCHECK(task_runner_->BelongsToCurrentThread()); | 845 DCHECK(task_runner_->BelongsToCurrentThread()); |
692 client_->OnVideoNaturalSizeChange(size); | 846 client_->OnVideoNaturalSizeChange(size); |
693 } | 847 } |
694 | 848 |
695 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 849 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
696 DCHECK(task_runner_->BelongsToCurrentThread()); | 850 DCHECK(task_runner_->BelongsToCurrentThread()); |
697 client_->OnVideoOpacityChange(opaque); | 851 client_->OnVideoOpacityChange(opaque); |
698 } | 852 } |
699 | 853 |
700 } // namespace media | 854 } // namespace media |
OLD | NEW |