| 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 (stream->type() == DemuxerStream::VIDEO) { |
| 223 DCHECK(video_renderer_); |
| 224 if (restarting_video_) |
| 225 return; |
| 226 restarting_video_ = true; |
| 227 video_renderer_->Flush( |
| 228 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); |
| 229 } else if (stream->type() == DemuxerStream::AUDIO) { |
| 230 DCHECK(audio_renderer_); |
| 231 DCHECK(time_source_); |
| 232 if (restarting_audio_) |
| 233 return; |
| 234 restarting_audio_ = true; |
| 235 // Stop ticking (transition into paused state) in audio renderer before |
| 236 // calling Flush, since after Flush we are going to restart playback by |
| 237 // calling audio renderer StartPlaying which would fail in playing state. |
| 238 if (time_ticking_) { |
| 239 time_ticking_ = false; |
| 240 time_source_->StopTicking(); |
| 241 } |
| 242 audio_renderer_->Flush( |
| 243 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); |
| 244 } |
| 245 } |
| 246 |
| 247 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { |
| 248 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 249 DVLOG(2) << __FUNCTION__; |
| 250 video_ended_ = false; |
| 251 if (state_ == STATE_PLAYING) { |
| 252 DCHECK(video_renderer_); |
| 253 video_renderer_->StartPlayingFrom(time); |
| 254 } |
| 255 } |
| 256 |
| 257 void RendererImpl::RestartAudioRenderer(base::TimeDelta time) { |
| 258 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 259 DVLOG(2) << __FUNCTION__; |
| 260 audio_ended_ = false; |
| 261 if (state_ == STATE_PLAYING) { |
| 262 DCHECK(time_source_); |
| 263 DCHECK(audio_renderer_); |
| 264 audio_renderer_->StartPlaying(); |
| 265 } |
| 266 } |
| 267 |
| 204 void RendererImpl::SetPlaybackRate(double playback_rate) { | 268 void RendererImpl::SetPlaybackRate(double playback_rate) { |
| 205 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 269 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
| 206 DCHECK(task_runner_->BelongsToCurrentThread()); | 270 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 207 | 271 |
| 208 // Playback rate changes are only carried out while playing. | 272 // Playback rate changes are only carried out while playing. |
| 209 if (state_ != STATE_PLAYING) | 273 if (state_ != STATE_PLAYING) |
| 210 return; | 274 return; |
| 211 | 275 |
| 212 time_source_->SetPlaybackRate(playback_rate); | 276 time_source_->SetPlaybackRate(playback_rate); |
| 213 | 277 |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 video_ended_ = false; | 545 video_ended_ = false; |
| 482 state_ = STATE_PLAYING; | 546 state_ = STATE_PLAYING; |
| 483 base::ResetAndReturn(&flush_cb_).Run(); | 547 base::ResetAndReturn(&flush_cb_).Run(); |
| 484 } | 548 } |
| 485 | 549 |
| 486 void RendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) { | 550 void RendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) { |
| 487 DCHECK(task_runner_->BelongsToCurrentThread()); | 551 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 488 client_->OnStatisticsUpdate(stats); | 552 client_->OnStatisticsUpdate(stats); |
| 489 } | 553 } |
| 490 | 554 |
| 555 namespace { |
| 556 |
| 557 const char* BufferingStateStr(BufferingState state) { |
| 558 switch (state) { |
| 559 case BUFFERING_HAVE_NOTHING: |
| 560 return "HAVE_NOTHING"; |
| 561 case BUFFERING_HAVE_ENOUGH: |
| 562 return "HAVE_ENOUGH"; |
| 563 } |
| 564 NOTREACHED(); |
| 565 return ""; |
| 566 } |
| 567 } |
| 568 |
| 491 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type, | 569 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type, |
| 492 BufferingState new_buffering_state) { | 570 BufferingState new_buffering_state) { |
| 493 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 571 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
| 494 BufferingState* buffering_state = type == DemuxerStream::AUDIO | 572 BufferingState* buffering_state = type == DemuxerStream::AUDIO |
| 495 ? &audio_buffering_state_ | 573 ? &audio_buffering_state_ |
| 496 : &video_buffering_state_; | 574 : &video_buffering_state_; |
| 497 | 575 |
| 498 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 576 DVLOG(1) << __FUNCTION__ |
| 499 << new_buffering_state << ") " | 577 << (type == DemuxerStream::AUDIO ? " audio " : " video ") |
| 500 << (type == DemuxerStream::AUDIO ? "audio" : "video"); | 578 << BufferingStateStr(*buffering_state) << " -> " |
| 579 << BufferingStateStr(new_buffering_state); |
| 501 DCHECK(task_runner_->BelongsToCurrentThread()); | 580 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 502 | 581 |
| 503 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 582 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
| 504 | 583 |
| 584 // When restarting playback we want to defer the BUFFERING_HAVE_NOTHING for |
| 585 // the stream being restarted, to allow continuing uninterrupted playback on |
| 586 // the other stream. |
| 587 if (type == DemuxerStream::VIDEO && restarting_video_) { |
| 588 if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
| 589 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for video stream," |
| 590 " resuming playback."; |
| 591 restarting_video_ = false; |
| 592 if (state_ == STATE_PLAYING && !deferred_underflow_cb_.IsCancelled()) { |
| 593 // If deferred_underflow_cb_ wasn't triggered, then audio should still |
| 594 // be playing, we only need to unpause the video stream. |
| 595 deferred_underflow_cb_.Cancel(); |
| 596 video_buffering_state_ = new_buffering_state; |
| 597 if (playback_rate_ > 0) |
| 598 video_renderer_->OnTimeStateChanged(true); |
| 599 return; |
| 600 } |
| 601 } |
| 602 // Fall through to the regular video underflow handling path. |
| 603 } |
| 604 |
| 605 if (type == DemuxerStream::AUDIO && restarting_audio_) { |
| 606 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { |
| 607 if (deferred_underflow_cb_.IsCancelled() && |
| 608 deferred_audio_restart_underflow_cb_.IsCancelled()) { |
| 609 DVLOG(1) << __FUNCTION__ << " Deferring BUFFERING_HAVE_NOTHING for " |
| 610 "audio stream which is being restarted."; |
| 611 audio_buffering_state_ = new_buffering_state; |
| 612 deferred_audio_restart_underflow_cb_.Reset( |
| 613 base::Bind(&RendererImpl::OnBufferingStateChange, weak_this_, type, |
| 614 new_buffering_state)); |
| 615 task_runner_->PostDelayedTask( |
| 616 FROM_HERE, deferred_audio_restart_underflow_cb_.callback(), |
| 617 base::TimeDelta::FromMilliseconds( |
| 618 kAudioRestartUnderflowThresholdMs)); |
| 619 return; |
| 620 } |
| 621 // Cancel the deferred callback and report an underflow immediately. |
| 622 DVLOG(4) << "deferred_audio_restart_underflow_cb_.Cancel()"; |
| 623 deferred_audio_restart_underflow_cb_.Cancel(); |
| 624 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
| 625 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for audio stream," |
| 626 " resuming playback."; |
| 627 deferred_audio_restart_underflow_cb_.Cancel(); |
| 628 // Now that we have decoded enough audio, pause playback momentarily to |
| 629 // ensure video renderer is synchronised with audio. |
| 630 PausePlayback(); |
| 631 restarting_audio_ = false; |
| 632 // Ensure that StartPlayback gets invoked below. |
| 633 was_waiting_for_enough_data = true; |
| 634 } |
| 635 } |
| 636 |
| 505 // When audio is present and has enough data, defer video underflow callbacks | 637 // When audio is present and has enough data, defer video underflow callbacks |
| 506 // for some time to avoid unnecessary glitches in audio; see | 638 // for some time to avoid unnecessary glitches in audio; see |
| 507 // http://crbug.com/144683#c53. | 639 // http://crbug.com/144683#c53. |
| 508 if (audio_renderer_ && type == DemuxerStream::VIDEO && | 640 if (audio_renderer_ && type == DemuxerStream::VIDEO && |
| 509 state_ == STATE_PLAYING) { | 641 state_ == STATE_PLAYING) { |
| 510 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 642 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
| 511 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 643 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
| 512 new_buffering_state == BUFFERING_HAVE_NOTHING && | 644 new_buffering_state == BUFFERING_HAVE_NOTHING && |
| 513 deferred_underflow_cb_.IsCancelled()) { | 645 deferred_underflow_cb_.IsCancelled()) { |
| 646 DVLOG(2) << __FUNCTION__ << " Deferring HAVE_NOTHING for video stream."; |
| 514 deferred_underflow_cb_.Reset( | 647 deferred_underflow_cb_.Reset( |
| 515 base::Bind(&RendererImpl::OnBufferingStateChange, | 648 base::Bind(&RendererImpl::OnBufferingStateChange, |
| 516 weak_factory_.GetWeakPtr(), type, new_buffering_state)); | 649 weak_factory_.GetWeakPtr(), type, new_buffering_state)); |
| 517 task_runner_->PostDelayedTask(FROM_HERE, | 650 task_runner_->PostDelayedTask(FROM_HERE, |
| 518 deferred_underflow_cb_.callback(), | 651 deferred_underflow_cb_.callback(), |
| 519 video_underflow_threshold_); | 652 video_underflow_threshold_); |
| 520 return; | 653 return; |
| 521 } | 654 } |
| 522 | 655 |
| 656 DVLOG(4) << "deferred_underflow_cb_.Cancel()"; |
| 523 deferred_underflow_cb_.Cancel(); | 657 deferred_underflow_cb_.Cancel(); |
| 524 } else if (!deferred_underflow_cb_.IsCancelled() && | 658 } else if (!deferred_underflow_cb_.IsCancelled() && |
| 525 type == DemuxerStream::AUDIO && | 659 type == DemuxerStream::AUDIO && |
| 526 new_buffering_state == BUFFERING_HAVE_NOTHING) { | 660 new_buffering_state == BUFFERING_HAVE_NOTHING) { |
| 527 // If audio underflows while we have a deferred video underflow in progress | 661 // 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. | 662 // we want to mark video as underflowed immediately and cancel the deferral. |
| 529 deferred_underflow_cb_.Cancel(); | 663 deferred_underflow_cb_.Cancel(); |
| 530 video_buffering_state_ = BUFFERING_HAVE_NOTHING; | 664 video_buffering_state_ = BUFFERING_HAVE_NOTHING; |
| 531 } | 665 } |
| 532 | 666 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 563 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) | 697 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) |
| 564 return true; | 698 return true; |
| 565 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) | 699 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) |
| 566 return true; | 700 return true; |
| 567 return false; | 701 return false; |
| 568 } | 702 } |
| 569 | 703 |
| 570 void RendererImpl::PausePlayback() { | 704 void RendererImpl::PausePlayback() { |
| 571 DVLOG(1) << __FUNCTION__; | 705 DVLOG(1) << __FUNCTION__; |
| 572 DCHECK(task_runner_->BelongsToCurrentThread()); | 706 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 573 DCHECK(time_ticking_); | |
| 574 switch (state_) { | 707 switch (state_) { |
| 575 case STATE_PLAYING: | 708 case STATE_PLAYING: |
| 576 DCHECK(PlaybackHasEnded() || WaitingForEnoughData()) | 709 DCHECK(PlaybackHasEnded() || WaitingForEnoughData() || restarting_audio_) |
| 577 << "Playback should only pause due to ending or underflowing"; | 710 << "Playback should only pause due to ending or underflowing or" |
| 711 " when restarting audio stream"; |
| 712 |
| 578 break; | 713 break; |
| 579 | 714 |
| 580 case STATE_FLUSHING: | 715 case STATE_FLUSHING: |
| 581 // It's OK to pause playback when flushing. | 716 // It's OK to pause playback when flushing. |
| 582 break; | 717 break; |
| 583 | 718 |
| 584 case STATE_UNINITIALIZED: | 719 case STATE_UNINITIALIZED: |
| 585 case STATE_INIT_PENDING_CDM: | 720 case STATE_INIT_PENDING_CDM: |
| 586 case STATE_INITIALIZING: | 721 case STATE_INITIALIZING: |
| 587 NOTREACHED() << "Invalid state: " << state_; | 722 NOTREACHED() << "Invalid state: " << state_; |
| 588 break; | 723 break; |
| 589 | 724 |
| 590 case STATE_ERROR: | 725 case STATE_ERROR: |
| 591 // An error state may occur at any time. | 726 // An error state may occur at any time. |
| 592 break; | 727 break; |
| 593 } | 728 } |
| 594 | 729 |
| 595 time_ticking_ = false; | 730 if (time_ticking_) { |
| 596 time_source_->StopTicking(); | 731 time_ticking_ = false; |
| 732 time_source_->StopTicking(); |
| 733 } |
| 597 if (playback_rate_ > 0 && video_renderer_) | 734 if (playback_rate_ > 0 && video_renderer_) |
| 598 video_renderer_->OnTimeStateChanged(false); | 735 video_renderer_->OnTimeStateChanged(false); |
| 599 } | 736 } |
| 600 | 737 |
| 601 void RendererImpl::StartPlayback() { | 738 void RendererImpl::StartPlayback() { |
| 602 DVLOG(1) << __FUNCTION__; | 739 DVLOG(1) << __FUNCTION__; |
| 603 DCHECK(task_runner_->BelongsToCurrentThread()); | 740 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 604 DCHECK_EQ(state_, STATE_PLAYING); | 741 DCHECK_EQ(state_, STATE_PLAYING); |
| 605 DCHECK(!time_ticking_); | 742 DCHECK(!time_ticking_); |
| 606 DCHECK(!WaitingForEnoughData()); | 743 DCHECK(!WaitingForEnoughData()); |
| 607 | 744 |
| 608 time_ticking_ = true; | 745 time_ticking_ = true; |
| 609 time_source_->StartTicking(); | 746 time_source_->StartTicking(); |
| 610 if (playback_rate_ > 0 && video_renderer_) | 747 if (playback_rate_ > 0 && video_renderer_) |
| 611 video_renderer_->OnTimeStateChanged(true); | 748 video_renderer_->OnTimeStateChanged(true); |
| 612 } | 749 } |
| 613 | 750 |
| 614 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { | 751 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { |
| 615 DVLOG(1) << __FUNCTION__; | 752 DVLOG(1) << __FUNCTION__ |
| 753 << (type == DemuxerStream::AUDIO ? " audio" : " video"); |
| 616 DCHECK(task_runner_->BelongsToCurrentThread()); | 754 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 617 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 755 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
| 618 | 756 |
| 619 if (state_ != STATE_PLAYING) | 757 if (state_ != STATE_PLAYING) |
| 620 return; | 758 return; |
| 621 | 759 |
| 622 if (type == DemuxerStream::AUDIO) { | 760 if (type == DemuxerStream::AUDIO) { |
| 623 DCHECK(!audio_ended_); | 761 DCHECK(!audio_ended_); |
| 624 audio_ended_ = true; | 762 audio_ended_ = true; |
| 625 } else { | 763 } else { |
| 626 DCHECK(!video_ended_); | 764 DCHECK(!video_ended_); |
| 627 video_ended_ = true; | 765 video_ended_ = true; |
| 766 DCHECK(video_renderer_); |
| 767 video_renderer_->OnTimeStateChanged(false); |
| 628 } | 768 } |
| 629 | 769 |
| 630 RunEndedCallbackIfNeeded(); | 770 RunEndedCallbackIfNeeded(); |
| 631 } | 771 } |
| 632 | 772 |
| 633 bool RendererImpl::PlaybackHasEnded() const { | 773 bool RendererImpl::PlaybackHasEnded() const { |
| 634 DVLOG(1) << __FUNCTION__; | |
| 635 DCHECK(task_runner_->BelongsToCurrentThread()); | 774 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 636 | 775 |
| 637 if (audio_renderer_ && !audio_ended_) | 776 if (audio_renderer_ && !audio_ended_) |
| 638 return false; | 777 return false; |
| 639 | 778 |
| 640 if (video_renderer_ && !video_ended_) | 779 if (video_renderer_ && !video_ended_) |
| 641 return false; | 780 return false; |
| 642 | 781 |
| 643 return true; | 782 return true; |
| 644 } | 783 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 DCHECK(task_runner_->BelongsToCurrentThread()); | 830 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 692 client_->OnVideoNaturalSizeChange(size); | 831 client_->OnVideoNaturalSizeChange(size); |
| 693 } | 832 } |
| 694 | 833 |
| 695 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 834 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
| 696 DCHECK(task_runner_->BelongsToCurrentThread()); | 835 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 697 client_->OnVideoOpacityChange(opaque); | 836 client_->OnVideoOpacityChange(opaque); |
| 698 } | 837 } |
| 699 | 838 |
| 700 } // namespace media | 839 } // namespace media |
| OLD | NEW |