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 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 181 pending_cdm_attached_cb_ = cdm_attached_cb; | 181 pending_cdm_attached_cb_ = cdm_attached_cb; |
| 182 | 182 |
| 183 InitializeAudioRenderer(); | 183 InitializeAudioRenderer(); |
| 184 } | 184 } |
| 185 | 185 |
| 186 void RendererImpl::Flush(const base::Closure& flush_cb) { | 186 void RendererImpl::Flush(const base::Closure& flush_cb) { |
| 187 DVLOG(1) << __func__; | 187 DVLOG(1) << __func__; |
| 188 DCHECK(task_runner_->BelongsToCurrentThread()); | 188 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 189 DCHECK(flush_cb_.is_null()); | 189 DCHECK(flush_cb_.is_null()); |
| 190 | 190 |
| 191 if (state_ == STATE_FLUSHED) { | |
| 192 flush_cb.Run(); | |
|
xhwang
2017/04/06 05:20:28
Directly run the callback could cause reentrancy i
servolk
2017/04/06 17:11:47
Yes, I agree, PostTask should be safer here. Fixed
| |
| 193 return; | |
| 194 } | |
| 195 | |
| 191 if (state_ != STATE_PLAYING) { | 196 if (state_ != STATE_PLAYING) { |
| 192 DCHECK_EQ(state_, STATE_ERROR); | 197 DCHECK_EQ(state_, STATE_ERROR); |
| 193 return; | 198 return; |
| 194 } | 199 } |
| 195 | 200 |
| 196 // If we are currently handling a media stream status change, then postpone | 201 // If we are currently handling a media stream status change, then postpone |
| 197 // Flush until after that's done (because stream status changes also flush | 202 // Flush until after that's done (because stream status changes also flush |
| 198 // audio_renderer_/video_renderer_ and they need to be restarted before they | 203 // audio_renderer_/video_renderer_ and they need to be restarted before they |
| 199 // can be flushed again). OnStreamRestartCompleted will resume Flush | 204 // can be flushed again). OnStreamRestartCompleted will resume Flush |
| 200 // processing after audio/video restart has completed and there are no other | 205 // processing after audio/video restart has completed and there are no other |
| 201 // pending stream status changes. | 206 // pending stream status changes. |
| 202 if (restarting_audio_ || restarting_video_) { | 207 if (restarting_audio_ || restarting_video_) { |
| 203 DCHECK(!pending_flush_cb_); | 208 DCHECK(!pending_flush_cb_); |
| 204 pending_flush_cb_ = flush_cb; | 209 pending_flush_cb_ = flush_cb; |
| 205 pending_actions_.push_back( | 210 pending_actions_.push_back( |
| 206 base::Bind(&RendererImpl::Flush, weak_this_, pending_flush_cb_)); | 211 base::Bind(&RendererImpl::Flush, weak_this_, pending_flush_cb_)); |
|
xhwang
2017/04/06 05:20:28
oh, this is based on your other CL? I thought you
servolk
2017/04/06 17:11:47
I have initially create it based on my other CL, t
| |
| 207 return; | 212 return; |
| 208 } | 213 } |
| 209 | 214 |
| 210 if (pending_flush_cb_) { | 215 if (pending_flush_cb_) { |
| 211 DCHECK(flush_cb.Equals(pending_flush_cb_)); | 216 DCHECK(flush_cb.Equals(pending_flush_cb_)); |
| 212 base::ResetAndReturn(&pending_flush_cb_); | 217 base::ResetAndReturn(&pending_flush_cb_); |
| 213 } | 218 } |
| 214 | 219 |
| 215 flush_cb_ = flush_cb; | 220 flush_cb_ = flush_cb; |
| 216 state_ = STATE_FLUSHING; | 221 state_ = STATE_FLUSHING; |
| 217 | 222 |
| 218 if (time_ticking_) | 223 if (time_ticking_) |
| 219 PausePlayback(); | 224 PausePlayback(); |
| 220 | 225 |
| 221 FlushAudioRenderer(); | 226 FlushAudioRenderer(); |
| 222 } | 227 } |
| 223 | 228 |
| 224 void RendererImpl::StartPlayingFrom(base::TimeDelta time) { | 229 void RendererImpl::StartPlayingFrom(base::TimeDelta time) { |
| 225 DVLOG(1) << __func__; | 230 DVLOG(1) << __func__; |
| 226 DCHECK(task_runner_->BelongsToCurrentThread()); | 231 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 227 | 232 |
| 228 if (state_ != STATE_PLAYING) { | 233 if (state_ != STATE_FLUSHED) { |
| 229 DCHECK_EQ(state_, STATE_ERROR); | 234 DCHECK_EQ(state_, STATE_ERROR); |
| 230 return; | 235 return; |
| 231 } | 236 } |
| 232 | 237 |
| 233 time_source_->SetMediaTime(time); | 238 time_source_->SetMediaTime(time); |
| 234 | 239 |
| 240 state_ = STATE_PLAYING; | |
| 235 if (audio_renderer_) | 241 if (audio_renderer_) |
| 236 audio_renderer_->StartPlaying(); | 242 audio_renderer_->StartPlaying(); |
| 237 if (video_renderer_) | 243 if (video_renderer_) |
| 238 video_renderer_->StartPlayingFrom(time); | 244 video_renderer_->StartPlayingFrom(time); |
| 239 } | 245 } |
| 240 | 246 |
| 241 void RendererImpl::SetPlaybackRate(double playback_rate) { | 247 void RendererImpl::SetPlaybackRate(double playback_rate) { |
| 242 DVLOG(1) << __func__ << "(" << playback_rate << ")"; | 248 DVLOG(1) << __func__ << "(" << playback_rate << ")"; |
| 243 DCHECK(task_runner_->BelongsToCurrentThread()); | 249 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 244 | 250 |
| 245 // Playback rate changes are only carried out while playing. | 251 // Playback rate changes are only carried out while playing. |
| 246 if (state_ != STATE_PLAYING) | 252 if (state_ != STATE_PLAYING && state_ != STATE_FLUSHED) |
| 247 return; | 253 return; |
| 248 | 254 |
| 249 time_source_->SetPlaybackRate(playback_rate); | 255 time_source_->SetPlaybackRate(playback_rate); |
| 250 | 256 |
| 251 const double old_rate = playback_rate_; | 257 const double old_rate = playback_rate_; |
| 252 playback_rate_ = playback_rate; | 258 playback_rate_ = playback_rate; |
| 253 if (!time_ticking_ || !video_renderer_) | 259 if (!time_ticking_ || !video_renderer_) |
| 254 return; | 260 return; |
| 255 | 261 |
| 256 if (old_rate == 0 && playback_rate > 0) | 262 if (old_rate == 0 && playback_rate > 0) |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 442 media_resource_->SetStreamStatusChangeCB( | 448 media_resource_->SetStreamStatusChangeCB( |
| 443 base::Bind(&RendererImpl::OnStreamStatusChanged, weak_this_)); | 449 base::Bind(&RendererImpl::OnStreamStatusChanged, weak_this_)); |
| 444 | 450 |
| 445 if (audio_renderer_) { | 451 if (audio_renderer_) { |
| 446 time_source_ = audio_renderer_->GetTimeSource(); | 452 time_source_ = audio_renderer_->GetTimeSource(); |
| 447 } else if (!time_source_) { | 453 } else if (!time_source_) { |
| 448 wall_clock_time_source_.reset(new WallClockTimeSource()); | 454 wall_clock_time_source_.reset(new WallClockTimeSource()); |
| 449 time_source_ = wall_clock_time_source_.get(); | 455 time_source_ = wall_clock_time_source_.get(); |
| 450 } | 456 } |
| 451 | 457 |
| 452 state_ = STATE_PLAYING; | 458 state_ = STATE_FLUSHED; |
| 453 DCHECK(time_source_); | 459 DCHECK(time_source_); |
| 454 DCHECK(audio_renderer_ || video_renderer_); | 460 DCHECK(audio_renderer_ || video_renderer_); |
| 455 | 461 |
| 456 FinishInitialization(PIPELINE_OK); | 462 FinishInitialization(PIPELINE_OK); |
| 457 } | 463 } |
| 458 | 464 |
| 459 void RendererImpl::FlushAudioRenderer() { | 465 void RendererImpl::FlushAudioRenderer() { |
| 460 DVLOG(1) << __func__; | 466 DVLOG(1) << __func__; |
| 461 DCHECK(task_runner_->BelongsToCurrentThread()); | 467 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 462 DCHECK_EQ(state_, STATE_FLUSHING); | 468 DCHECK_EQ(state_, STATE_FLUSHING); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 if (state_ == STATE_ERROR) { | 520 if (state_ == STATE_ERROR) { |
| 515 DCHECK(flush_cb_.is_null()); | 521 DCHECK(flush_cb_.is_null()); |
| 516 return; | 522 return; |
| 517 } | 523 } |
| 518 | 524 |
| 519 DCHECK_EQ(state_, STATE_FLUSHING); | 525 DCHECK_EQ(state_, STATE_FLUSHING); |
| 520 DCHECK(!flush_cb_.is_null()); | 526 DCHECK(!flush_cb_.is_null()); |
| 521 | 527 |
| 522 DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING); | 528 DCHECK_EQ(video_buffering_state_, BUFFERING_HAVE_NOTHING); |
| 523 video_ended_ = false; | 529 video_ended_ = false; |
| 524 state_ = STATE_PLAYING; | 530 state_ = STATE_FLUSHED; |
| 525 base::ResetAndReturn(&flush_cb_).Run(); | 531 base::ResetAndReturn(&flush_cb_).Run(); |
| 526 | 532 |
| 527 if (!pending_actions_.empty()) { | 533 if (!pending_actions_.empty()) { |
| 528 base::Closure closure = pending_actions_.front(); | 534 base::Closure closure = pending_actions_.front(); |
| 529 pending_actions_.pop_front(); | 535 pending_actions_.pop_front(); |
| 530 closure.Run(); | 536 closure.Run(); |
| 531 } | 537 } |
| 532 } | 538 } |
| 533 | 539 |
| 534 void RendererImpl::OnStreamStatusChanged(DemuxerStream* stream, | 540 void RendererImpl::OnStreamStatusChanged(DemuxerStream* stream, |
| 535 bool enabled, | 541 bool enabled, |
| 536 base::TimeDelta time) { | 542 base::TimeDelta time) { |
| 537 DCHECK(task_runner_->BelongsToCurrentThread()); | 543 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 538 DCHECK(stream); | 544 DCHECK(stream); |
| 539 bool video = (stream->type() == DemuxerStream::VIDEO); | 545 bool video = (stream->type() == DemuxerStream::VIDEO); |
| 540 DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream | 546 DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream |
| 541 << " enabled=" << enabled << " time=" << time.InSecondsF(); | 547 << " enabled=" << enabled << " time=" << time.InSecondsF(); |
| 542 if ((state_ != STATE_PLAYING && state_ != STATE_FLUSHING) || | 548 |
| 549 if ((state_ != STATE_PLAYING && state_ != STATE_FLUSHING && | |
| 550 state_ != STATE_FLUSHED) || | |
| 543 (audio_ended_ && video_ended_)) | 551 (audio_ended_ && video_ended_)) |
| 544 return; | 552 return; |
| 545 if (restarting_audio_ || restarting_video_ || flush_cb_) { | 553 if (restarting_audio_ || restarting_video_ || flush_cb_) { |
| 546 DVLOG(3) << __func__ << ": postponed stream " << stream | 554 DVLOG(3) << __func__ << ": postponed stream " << stream |
| 547 << " status change handling."; | 555 << " status change handling."; |
| 548 pending_actions_.push_back(base::Bind(&RendererImpl::OnStreamStatusChanged, | 556 pending_actions_.push_back(base::Bind(&RendererImpl::OnStreamStatusChanged, |
| 549 weak_this_, stream, enabled, time)); | 557 weak_this_, stream, enabled, time)); |
| 550 return; | 558 return; |
| 551 } | 559 } |
| 552 if (stream->type() == DemuxerStream::VIDEO) { | 560 if (stream->type() == DemuxerStream::VIDEO) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 627 OnError(status); | 635 OnError(status); |
| 628 return; | 636 return; |
| 629 } | 637 } |
| 630 RestartVideoRenderer(stream, time); | 638 RestartVideoRenderer(stream, time); |
| 631 } | 639 } |
| 632 | 640 |
| 633 void RendererImpl::RestartAudioRenderer(DemuxerStream* stream, | 641 void RendererImpl::RestartAudioRenderer(DemuxerStream* stream, |
| 634 base::TimeDelta time) { | 642 base::TimeDelta time) { |
| 635 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF(); | 643 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF(); |
| 636 DCHECK(task_runner_->BelongsToCurrentThread()); | 644 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 637 DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHING); | 645 DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHED); |
| 638 DCHECK(time_source_); | 646 DCHECK(time_source_); |
| 639 DCHECK(audio_renderer_); | 647 DCHECK(audio_renderer_); |
| 640 DCHECK_EQ(stream, current_audio_stream_); | 648 DCHECK_EQ(stream, current_audio_stream_); |
| 641 | 649 |
| 642 audio_ended_ = false; | 650 audio_ended_ = false; |
| 643 audio_renderer_->StartPlaying(); | 651 audio_renderer_->StartPlaying(); |
| 644 } | 652 } |
| 645 | 653 |
| 646 void RendererImpl::RestartVideoRenderer(DemuxerStream* stream, | 654 void RendererImpl::RestartVideoRenderer(DemuxerStream* stream, |
| 647 base::TimeDelta time) { | 655 base::TimeDelta time) { |
| 648 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF(); | 656 DVLOG(2) << __func__ << " stream=" << stream << " time=" << time.InSecondsF(); |
| 649 DCHECK(task_runner_->BelongsToCurrentThread()); | 657 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 650 DCHECK(video_renderer_); | 658 DCHECK(video_renderer_); |
| 651 DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHING); | 659 DCHECK(state_ == STATE_PLAYING || state_ == STATE_FLUSHED); |
| 652 DCHECK_EQ(stream, current_video_stream_); | 660 DCHECK_EQ(stream, current_video_stream_); |
| 653 | 661 |
| 654 video_ended_ = false; | 662 video_ended_ = false; |
| 655 video_renderer_->StartPlayingFrom(time); | 663 video_renderer_->StartPlayingFrom(time); |
| 656 } | 664 } |
| 657 | 665 |
| 658 void RendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) { | 666 void RendererImpl::OnStatisticsUpdate(const PipelineStatistics& stats) { |
| 659 DCHECK(task_runner_->BelongsToCurrentThread()); | 667 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 660 client_->OnStatisticsUpdate(stats); | 668 client_->OnStatisticsUpdate(stats); |
| 661 } | 669 } |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 828 DCHECK(task_runner_->BelongsToCurrentThread()); | 836 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 829 switch (state_) { | 837 switch (state_) { |
| 830 case STATE_PLAYING: | 838 case STATE_PLAYING: |
| 831 DCHECK(PlaybackHasEnded() || WaitingForEnoughData() || restarting_audio_) | 839 DCHECK(PlaybackHasEnded() || WaitingForEnoughData() || restarting_audio_) |
| 832 << "Playback should only pause due to ending or underflowing or" | 840 << "Playback should only pause due to ending or underflowing or" |
| 833 " when restarting audio stream"; | 841 " when restarting audio stream"; |
| 834 | 842 |
| 835 break; | 843 break; |
| 836 | 844 |
| 837 case STATE_FLUSHING: | 845 case STATE_FLUSHING: |
| 846 case STATE_FLUSHED: | |
| 838 // It's OK to pause playback when flushing. | 847 // It's OK to pause playback when flushing. |
| 839 break; | 848 break; |
| 840 | 849 |
| 841 case STATE_UNINITIALIZED: | 850 case STATE_UNINITIALIZED: |
| 842 case STATE_INIT_PENDING_CDM: | 851 case STATE_INIT_PENDING_CDM: |
| 843 case STATE_INITIALIZING: | 852 case STATE_INITIALIZING: |
| 844 NOTREACHED() << "Invalid state: " << state_; | 853 NOTREACHED() << "Invalid state: " << state_; |
| 845 break; | 854 break; |
| 846 | 855 |
| 847 case STATE_ERROR: | 856 case STATE_ERROR: |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 951 DCHECK(task_runner_->BelongsToCurrentThread()); | 960 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 952 client_->OnVideoNaturalSizeChange(size); | 961 client_->OnVideoNaturalSizeChange(size); |
| 953 } | 962 } |
| 954 | 963 |
| 955 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 964 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
| 956 DCHECK(task_runner_->BelongsToCurrentThread()); | 965 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 957 client_->OnVideoOpacityChange(opaque); | 966 client_->OnVideoOpacityChange(opaque); |
| 958 } | 967 } |
| 959 | 968 |
| 960 } // namespace media | 969 } // namespace media |
| OLD | NEW |