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 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 } | 201 } |
202 | 202 |
203 time_source_->SetMediaTime(time); | 203 time_source_->SetMediaTime(time); |
204 | 204 |
205 if (audio_renderer_) | 205 if (audio_renderer_) |
206 audio_renderer_->StartPlaying(); | 206 audio_renderer_->StartPlaying(); |
207 if (video_renderer_) | 207 if (video_renderer_) |
208 video_renderer_->StartPlayingFrom(time); | 208 video_renderer_->StartPlayingFrom(time); |
209 } | 209 } |
210 | 210 |
211 void RendererImpl::RestartStreamPlayback(DemuxerStream* stream, | 211 void RendererImpl::OnStreamStatusChanged(DemuxerStream* stream, |
212 bool enabled, | 212 bool enabled, |
213 base::TimeDelta time) { | 213 base::TimeDelta time) { |
214 DCHECK(task_runner_->BelongsToCurrentThread()); | 214 DCHECK(task_runner_->BelongsToCurrentThread()); |
215 DCHECK(stream); | 215 DCHECK(stream); |
216 bool video = (stream->type() == DemuxerStream::VIDEO); | 216 bool video = (stream->type() == DemuxerStream::VIDEO); |
217 DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream | 217 DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream |
218 << " enabled=" << stream->enabled() << " time=" << time.InSecondsF(); | 218 << " enabled=" << enabled << " time=" << time.InSecondsF(); |
219 if ((state_ != STATE_PLAYING) || (audio_ended_ && video_ended_)) | 219 if ((state_ != STATE_PLAYING) || (audio_ended_ && video_ended_)) |
220 return; | 220 return; |
| 221 if (restarting_audio_ || restarting_video_) { |
| 222 DVLOG(3) << __func__ << ": postponed stream " << stream |
| 223 << " status change handling."; |
| 224 pending_stream_status_notifications_.push_back( |
| 225 base::Bind(&RendererImpl::OnStreamStatusChanged, weak_this_, stream, |
| 226 enabled, time)); |
| 227 return; |
| 228 } |
221 if (stream->type() == DemuxerStream::VIDEO) { | 229 if (stream->type() == DemuxerStream::VIDEO) { |
222 DCHECK(video_renderer_); | 230 DCHECK(video_renderer_); |
223 if (restarting_video_) | |
224 return; | |
225 restarting_video_ = true; | 231 restarting_video_ = true; |
226 video_renderer_->Flush( | 232 video_renderer_->Flush( |
227 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); | 233 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); |
228 } else if (stream->type() == DemuxerStream::AUDIO) { | 234 } else if (stream->type() == DemuxerStream::AUDIO) { |
229 DCHECK(audio_renderer_); | 235 DCHECK(audio_renderer_); |
230 DCHECK(time_source_); | 236 DCHECK(time_source_); |
231 if (restarting_audio_) | |
232 return; | |
233 restarting_audio_ = true; | 237 restarting_audio_ = true; |
234 // Stop ticking (transition into paused state) in audio renderer before | 238 // Stop ticking (transition into paused state) in audio renderer before |
235 // calling Flush, since after Flush we are going to restart playback by | 239 // calling Flush, since after Flush we are going to restart playback by |
236 // calling audio renderer StartPlaying which would fail in playing state. | 240 // calling audio renderer StartPlaying which would fail in playing state. |
237 if (time_ticking_) { | 241 if (time_ticking_) { |
238 time_ticking_ = false; | 242 time_ticking_ = false; |
239 time_source_->StopTicking(); | 243 time_source_->StopTicking(); |
240 } | 244 } |
241 audio_renderer_->Flush( | 245 audio_renderer_->Flush( |
242 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); | 246 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 | 377 |
374 DemuxerStream* audio_stream = | 378 DemuxerStream* audio_stream = |
375 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); | 379 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); |
376 if (!audio_stream) { | 380 if (!audio_stream) { |
377 audio_renderer_.reset(); | 381 audio_renderer_.reset(); |
378 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 382 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); |
379 return; | 383 return; |
380 } | 384 } |
381 | 385 |
382 audio_stream->SetStreamStatusChangeCB(base::Bind( | 386 audio_stream->SetStreamStatusChangeCB(base::Bind( |
383 &RendererImpl::RestartStreamPlayback, weak_this_, audio_stream)); | 387 &RendererImpl::OnStreamStatusChanged, weak_this_, audio_stream)); |
384 | 388 |
385 audio_renderer_client_.reset( | 389 audio_renderer_client_.reset( |
386 new RendererClientInternal(DemuxerStream::AUDIO, this)); | 390 new RendererClientInternal(DemuxerStream::AUDIO, this)); |
387 // Note: After the initialization of a renderer, error events from it may | 391 // Note: After the initialization of a renderer, error events from it may |
388 // happen at any time and all future calls must guard against STATE_ERROR. | 392 // happen at any time and all future calls must guard against STATE_ERROR. |
389 audio_renderer_->Initialize(audio_stream, cdm_context_, | 393 audio_renderer_->Initialize(audio_stream, cdm_context_, |
390 audio_renderer_client_.get(), done_cb); | 394 audio_renderer_client_.get(), done_cb); |
391 } | 395 } |
392 | 396 |
393 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { | 397 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { |
(...skipping 28 matching lines...) Expand all Loading... |
422 | 426 |
423 DemuxerStream* video_stream = | 427 DemuxerStream* video_stream = |
424 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); | 428 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); |
425 if (!video_stream) { | 429 if (!video_stream) { |
426 video_renderer_.reset(); | 430 video_renderer_.reset(); |
427 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 431 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); |
428 return; | 432 return; |
429 } | 433 } |
430 | 434 |
431 video_stream->SetStreamStatusChangeCB(base::Bind( | 435 video_stream->SetStreamStatusChangeCB(base::Bind( |
432 &RendererImpl::RestartStreamPlayback, weak_this_, video_stream)); | 436 &RendererImpl::OnStreamStatusChanged, weak_this_, video_stream)); |
433 | 437 |
434 video_renderer_client_.reset( | 438 video_renderer_client_.reset( |
435 new RendererClientInternal(DemuxerStream::VIDEO, this)); | 439 new RendererClientInternal(DemuxerStream::VIDEO, this)); |
436 video_renderer_->Initialize( | 440 video_renderer_->Initialize( |
437 video_stream, cdm_context_, video_renderer_client_.get(), | 441 video_stream, cdm_context_, video_renderer_client_.get(), |
438 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)), | 442 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)), |
439 done_cb); | 443 done_cb); |
440 } | 444 } |
441 | 445 |
442 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) { | 446 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) { |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 return "HAVE_ENOUGH"; | 561 return "HAVE_ENOUGH"; |
558 } | 562 } |
559 NOTREACHED(); | 563 NOTREACHED(); |
560 return ""; | 564 return ""; |
561 } | 565 } |
562 } | 566 } |
563 | 567 |
564 bool RendererImpl::HandleRestartedStreamBufferingChanges( | 568 bool RendererImpl::HandleRestartedStreamBufferingChanges( |
565 DemuxerStream::Type type, | 569 DemuxerStream::Type type, |
566 BufferingState new_buffering_state) { | 570 BufferingState new_buffering_state) { |
| 571 DCHECK(task_runner_->BelongsToCurrentThread()); |
567 // When restarting playback we want to defer the BUFFERING_HAVE_NOTHING for | 572 // When restarting playback we want to defer the BUFFERING_HAVE_NOTHING for |
568 // the stream being restarted, to allow continuing uninterrupted playback on | 573 // the stream being restarted, to allow continuing uninterrupted playback on |
569 // the other stream. | 574 // the other stream. |
570 if (type == DemuxerStream::VIDEO && restarting_video_) { | 575 if (type == DemuxerStream::VIDEO && restarting_video_) { |
571 if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { | 576 if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
572 DVLOG(1) << __func__ << " Got BUFFERING_HAVE_ENOUGH for video stream," | 577 DVLOG(1) << __func__ << " Got BUFFERING_HAVE_ENOUGH for video stream," |
573 " resuming playback."; | 578 " resuming playback."; |
574 restarting_video_ = false; | 579 task_runner_->PostTask( |
| 580 FROM_HERE, |
| 581 base::Bind(&RendererImpl::OnStreamRestartCompleted, weak_this_)); |
575 if (state_ == STATE_PLAYING && | 582 if (state_ == STATE_PLAYING && |
576 !deferred_video_underflow_cb_.IsCancelled()) { | 583 !deferred_video_underflow_cb_.IsCancelled()) { |
577 // If deferred_video_underflow_cb_ wasn't triggered, then audio should | 584 // If deferred_video_underflow_cb_ wasn't triggered, then audio should |
578 // still be playing, we only need to unpause the video stream. | 585 // still be playing, we only need to unpause the video stream. |
579 DVLOG(4) << "deferred_video_underflow_cb_.Cancel()"; | 586 DVLOG(4) << "deferred_video_underflow_cb_.Cancel()"; |
580 deferred_video_underflow_cb_.Cancel(); | 587 deferred_video_underflow_cb_.Cancel(); |
581 video_buffering_state_ = new_buffering_state; | 588 video_buffering_state_ = new_buffering_state; |
582 if (playback_rate_ > 0) | 589 if (playback_rate_ > 0) |
583 video_renderer_->OnTimeProgressing(); | 590 video_renderer_->OnTimeProgressing(); |
584 return true; | 591 return true; |
(...skipping 24 matching lines...) Expand all Loading... |
609 // Cancel the deferred callback and report the underflow immediately. | 616 // Cancel the deferred callback and report the underflow immediately. |
610 DVLOG(4) << "deferred_audio_restart_underflow_cb_.Cancel()"; | 617 DVLOG(4) << "deferred_audio_restart_underflow_cb_.Cancel()"; |
611 deferred_audio_restart_underflow_cb_.Cancel(); | 618 deferred_audio_restart_underflow_cb_.Cancel(); |
612 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { | 619 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { |
613 DVLOG(1) << __func__ << " Got BUFFERING_HAVE_ENOUGH for audio stream," | 620 DVLOG(1) << __func__ << " Got BUFFERING_HAVE_ENOUGH for audio stream," |
614 " resuming playback."; | 621 " resuming playback."; |
615 deferred_audio_restart_underflow_cb_.Cancel(); | 622 deferred_audio_restart_underflow_cb_.Cancel(); |
616 // Now that we have decoded enough audio, pause playback momentarily to | 623 // Now that we have decoded enough audio, pause playback momentarily to |
617 // ensure video renderer is synchronised with audio. | 624 // ensure video renderer is synchronised with audio. |
618 PausePlayback(); | 625 PausePlayback(); |
619 restarting_audio_ = false; | 626 task_runner_->PostTask( |
| 627 FROM_HERE, |
| 628 base::Bind(&RendererImpl::OnStreamRestartCompleted, weak_this_)); |
620 } | 629 } |
621 } | 630 } |
622 return false; | 631 return false; |
623 } | 632 } |
624 | 633 |
| 634 void RendererImpl::OnStreamRestartCompleted() { |
| 635 DCHECK(restarting_audio_ || restarting_video_); |
| 636 restarting_audio_ = false; |
| 637 restarting_video_ = false; |
| 638 if (!pending_stream_status_notifications_.empty()) { |
| 639 pending_stream_status_notifications_.front().Run(); |
| 640 pending_stream_status_notifications_.pop_front(); |
| 641 } |
| 642 } |
| 643 |
625 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type, | 644 void RendererImpl::OnBufferingStateChange(DemuxerStream::Type type, |
626 BufferingState new_buffering_state) { | 645 BufferingState new_buffering_state) { |
627 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 646 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
628 BufferingState* buffering_state = type == DemuxerStream::AUDIO | 647 BufferingState* buffering_state = type == DemuxerStream::AUDIO |
629 ? &audio_buffering_state_ | 648 ? &audio_buffering_state_ |
630 : &video_buffering_state_; | 649 : &video_buffering_state_; |
631 | 650 |
632 DVLOG(1) << __func__ << (type == DemuxerStream::AUDIO ? " audio " : " video ") | 651 DVLOG(1) << __func__ << (type == DemuxerStream::AUDIO ? " audio " : " video ") |
633 << BufferingStateStr(*buffering_state) << " -> " | 652 << BufferingStateStr(*buffering_state) << " -> " |
634 << BufferingStateStr(new_buffering_state); | 653 << BufferingStateStr(new_buffering_state); |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
834 DCHECK(task_runner_->BelongsToCurrentThread()); | 853 DCHECK(task_runner_->BelongsToCurrentThread()); |
835 client_->OnVideoNaturalSizeChange(size); | 854 client_->OnVideoNaturalSizeChange(size); |
836 } | 855 } |
837 | 856 |
838 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 857 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
839 DCHECK(task_runner_->BelongsToCurrentThread()); | 858 DCHECK(task_runner_->BelongsToCurrentThread()); |
840 client_->OnVideoOpacityChange(opaque); | 859 client_->OnVideoOpacityChange(opaque); |
841 } | 860 } |
842 | 861 |
843 } // namespace media | 862 } // namespace media |
OLD | NEW |