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 // We need to stop ticking (transition into paused state) before calling | |
223 // Flush, since after Flush we'll need to restart playback by invoking | |
224 // StartPlaying that dchecks we are not in playing state. | |
wolenetz
2016/05/27 20:49:42
nit: we usually don't refer to implementation deta
servolk
2016/06/01 17:36:16
Done.
| |
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 // TODO(servolk): VideoRenderer should ensure that Flush callback is called | |
237 // outside of its internal lock, to allow calling renderer methods directly. | |
238 task_runner_->PostTask( | |
239 FROM_HERE, base::Bind(&VideoRenderer::StartPlayingFrom, | |
240 base::Unretained(video_renderer_.get()), time)); | |
241 } | |
242 } | |
243 | |
244 void RendererImpl::OnAudioRendererFlushDone_ForRestart(base::TimeDelta time) { | |
245 DCHECK(task_runner_->BelongsToCurrentThread()); | |
246 if (state_ == STATE_PLAYING) { | |
247 DCHECK(time_source_); | |
248 DCHECK(audio_renderer_); | |
249 audio_renderer_->StartPlaying(); | |
250 } | |
251 } | |
252 | |
204 void RendererImpl::SetPlaybackRate(double playback_rate) { | 253 void RendererImpl::SetPlaybackRate(double playback_rate) { |
205 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 254 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
206 DCHECK(task_runner_->BelongsToCurrentThread()); | 255 DCHECK(task_runner_->BelongsToCurrentThread()); |
207 | 256 |
208 // Playback rate changes are only carried out while playing. | 257 // Playback rate changes are only carried out while playing. |
209 if (state_ != STATE_PLAYING) | 258 if (state_ != STATE_PLAYING) |
210 return; | 259 return; |
211 | 260 |
212 time_source_->SetPlaybackRate(playback_rate); | 261 time_source_->SetPlaybackRate(playback_rate); |
213 | 262 |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 ? &audio_buffering_state_ | 544 ? &audio_buffering_state_ |
496 : &video_buffering_state_; | 545 : &video_buffering_state_; |
497 | 546 |
498 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 547 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " |
499 << new_buffering_state << ") " | 548 << new_buffering_state << ") " |
500 << (type == DemuxerStream::AUDIO ? "audio" : "video"); | 549 << (type == DemuxerStream::AUDIO ? "audio" : "video"); |
501 DCHECK(task_runner_->BelongsToCurrentThread()); | 550 DCHECK(task_runner_->BelongsToCurrentThread()); |
502 | 551 |
503 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 552 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
504 | 553 |
554 // When restarting video stream playback we want to ignore the | |
555 // BUFFERING_HAVE_NOTHING notification so that audio keeps playing while | |
556 // video decoder is catching up. | |
557 if (type == DemuxerStream::VIDEO && restarting_video_) { | |
558 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { | |
559 DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for video " | |
560 "stream which is being restarted."; | |
561 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { | |
562 DVLOG(1) | |
563 << __FUNCTION__ | |
564 << " Got BUFFERING_HAVE_ENOUGH for video stream, resuming playback."; | |
565 restarting_video_ = false; | |
566 if (playback_rate_ > 0) | |
567 video_renderer_->OnTimeStateChanged(true); | |
568 } | |
569 return; | |
570 } | |
571 | |
572 if (type == DemuxerStream::AUDIO && restarting_audio_) { | |
573 if (new_buffering_state == BUFFERING_HAVE_NOTHING) { | |
574 DVLOG(1) << __FUNCTION__ << " Ignoring BUFFERING_HAVE_NOTHING for " | |
575 << (type == DemuxerStream::AUDIO ? "audio" : "video") | |
576 << " stream"; | |
577 } else if (new_buffering_state == BUFFERING_HAVE_ENOUGH) { | |
578 DVLOG(1) << __FUNCTION__ << " Got BUFFERING_HAVE_ENOUGH for " | |
579 << (type == DemuxerStream::AUDIO ? "audio" : "video") | |
580 << " stream"; | |
581 | |
582 restarting_audio_ = false; | |
583 | |
584 // Now that we have decoded enough audio, pause and unpause playback | |
585 // momentarily to ensure video renderer is synchronised with audio. | |
586 double curr_playback_rate = playback_rate_; | |
587 SetPlaybackRate(0); | |
588 SetPlaybackRate(curr_playback_rate); | |
589 | |
590 time_source_->StartTicking(); | |
591 } | |
592 return; | |
593 } | |
594 | |
505 // When audio is present and has enough data, defer video underflow callbacks | 595 // When audio is present and has enough data, defer video underflow callbacks |
506 // for some time to avoid unnecessary glitches in audio; see | 596 // for some time to avoid unnecessary glitches in audio; see |
507 // http://crbug.com/144683#c53. | 597 // http://crbug.com/144683#c53. |
508 if (audio_renderer_ && type == DemuxerStream::VIDEO && | 598 if (audio_renderer_ && type == DemuxerStream::VIDEO && |
509 state_ == STATE_PLAYING) { | 599 state_ == STATE_PLAYING) { |
510 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 600 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
511 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 601 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
512 new_buffering_state == BUFFERING_HAVE_NOTHING && | 602 new_buffering_state == BUFFERING_HAVE_NOTHING && |
513 deferred_underflow_cb_.IsCancelled()) { | 603 deferred_underflow_cb_.IsCancelled()) { |
514 deferred_underflow_cb_.Reset( | 604 deferred_underflow_cb_.Reset( |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
605 DCHECK(!time_ticking_); | 695 DCHECK(!time_ticking_); |
606 DCHECK(!WaitingForEnoughData()); | 696 DCHECK(!WaitingForEnoughData()); |
607 | 697 |
608 time_ticking_ = true; | 698 time_ticking_ = true; |
609 time_source_->StartTicking(); | 699 time_source_->StartTicking(); |
610 if (playback_rate_ > 0 && video_renderer_) | 700 if (playback_rate_ > 0 && video_renderer_) |
611 video_renderer_->OnTimeStateChanged(true); | 701 video_renderer_->OnTimeStateChanged(true); |
612 } | 702 } |
613 | 703 |
614 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { | 704 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { |
615 DVLOG(1) << __FUNCTION__; | 705 DVLOG(1) << __FUNCTION__ |
706 << (type == DemuxerStream::AUDIO ? " audio" : " video"); | |
616 DCHECK(task_runner_->BelongsToCurrentThread()); | 707 DCHECK(task_runner_->BelongsToCurrentThread()); |
617 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 708 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
618 | 709 |
619 if (state_ != STATE_PLAYING) | 710 if (state_ != STATE_PLAYING) |
620 return; | 711 return; |
621 | 712 |
622 if (type == DemuxerStream::AUDIO) { | 713 if (type == DemuxerStream::AUDIO) { |
623 DCHECK(!audio_ended_); | 714 DCHECK(!audio_ended_); |
624 audio_ended_ = true; | 715 audio_ended_ = true; |
625 } else { | 716 } else { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
691 DCHECK(task_runner_->BelongsToCurrentThread()); | 782 DCHECK(task_runner_->BelongsToCurrentThread()); |
692 client_->OnVideoNaturalSizeChange(size); | 783 client_->OnVideoNaturalSizeChange(size); |
693 } | 784 } |
694 | 785 |
695 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 786 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
696 DCHECK(task_runner_->BelongsToCurrentThread()); | 787 DCHECK(task_runner_->BelongsToCurrentThread()); |
697 client_->OnVideoOpacityChange(opaque); | 788 client_->OnVideoOpacityChange(opaque); |
698 } | 789 } |
699 | 790 |
700 } // namespace media | 791 } // namespace media |
OLD | NEW |