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" |
11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
14 #include "base/location.h" | 14 #include "base/location.h" |
15 #include "base/metrics/histogram_macros.h" | |
15 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
16 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
17 #include "media/base/audio_decoder_config.h" | 18 #include "media/base/audio_decoder_config.h" |
18 #include "media/base/audio_renderer.h" | 19 #include "media/base/audio_renderer.h" |
19 #include "media/base/bind_to_current_loop.h" | 20 #include "media/base/bind_to_current_loop.h" |
20 #include "media/base/demuxer_stream_provider.h" | 21 #include "media/base/demuxer_stream_provider.h" |
21 #include "media/base/media_switches.h" | 22 #include "media/base/media_switches.h" |
22 #include "media/base/renderer_client.h" | 23 #include "media/base/renderer_client.h" |
23 #include "media/base/time_source.h" | 24 #include "media/base/time_source.h" |
24 #include "media/base/video_decoder_config.h" | 25 #include "media/base/video_decoder_config.h" |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
58 DCHECK(type_ == DemuxerStream::VIDEO); | 59 DCHECK(type_ == DemuxerStream::VIDEO); |
59 renderer_->OnVideoOpacityChange(opaque); | 60 renderer_->OnVideoOpacityChange(opaque); |
60 } | 61 } |
61 void OnDurationChange(base::TimeDelta duration) override { | 62 void OnDurationChange(base::TimeDelta duration) override { |
62 // RendererClients should only be notified of duration changes in certain | 63 // RendererClients should only be notified of duration changes in certain |
63 // scenarios, none of which should arise for RendererClientInternal. | 64 // scenarios, none of which should arise for RendererClientInternal. |
64 // Duration changes should be sent to the pipeline by the DemuxerStream, via | 65 // Duration changes should be sent to the pipeline by the DemuxerStream, via |
65 // the DemuxerHost interface. | 66 // the DemuxerHost interface. |
66 NOTREACHED(); | 67 NOTREACHED(); |
67 } | 68 } |
69 void OnFirstFrameRender() override { renderer_->OnFirstFrameRender(type_); } | |
68 | 70 |
69 private: | 71 private: |
70 DemuxerStream::Type type_; | 72 DemuxerStream::Type type_; |
71 RendererImpl* renderer_; | 73 RendererImpl* renderer_; |
72 }; | 74 }; |
73 | 75 |
74 RendererImpl::RendererImpl( | 76 RendererImpl::RendererImpl( |
75 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 77 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
76 std::unique_ptr<AudioRenderer> audio_renderer, | 78 std::unique_ptr<AudioRenderer> audio_renderer, |
77 std::unique_ptr<VideoRenderer> video_renderer) | 79 std::unique_ptr<VideoRenderer> video_renderer) |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
229 bool video = (stream->type() == DemuxerStream::VIDEO); | 231 bool video = (stream->type() == DemuxerStream::VIDEO); |
230 DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream | 232 DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream |
231 << " enabled=" << stream->enabled() << " time=" << time.InSecondsF(); | 233 << " enabled=" << stream->enabled() << " time=" << time.InSecondsF(); |
232 if ((state_ != STATE_PLAYING) || (audio_ended_ && video_ended_)) | 234 if ((state_ != STATE_PLAYING) || (audio_ended_ && video_ended_)) |
233 return; | 235 return; |
234 if (stream->type() == DemuxerStream::VIDEO) { | 236 if (stream->type() == DemuxerStream::VIDEO) { |
235 DCHECK(video_renderer_); | 237 DCHECK(video_renderer_); |
236 if (restarting_video_) | 238 if (restarting_video_) |
237 return; | 239 return; |
238 restarting_video_ = true; | 240 restarting_video_ = true; |
241 | |
242 if (stream->enabled() && video_preroll_start_time_.is_null()) | |
243 video_preroll_start_time_ = base::TimeTicks::Now(); | |
244 | |
239 video_renderer_->Flush( | 245 video_renderer_->Flush( |
240 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); | 246 base::Bind(&RendererImpl::RestartVideoRenderer, weak_this_, time)); |
241 } else if (stream->type() == DemuxerStream::AUDIO) { | 247 } else if (stream->type() == DemuxerStream::AUDIO) { |
242 DCHECK(audio_renderer_); | 248 DCHECK(audio_renderer_); |
243 DCHECK(time_source_); | 249 DCHECK(time_source_); |
244 if (restarting_audio_) | 250 if (restarting_audio_) |
245 return; | 251 return; |
246 restarting_audio_ = true; | 252 restarting_audio_ = true; |
253 | |
254 if (stream->enabled() && audio_preroll_start_time_.is_null()) | |
255 audio_preroll_start_time_ = base::TimeTicks::Now(); | |
256 | |
247 // Stop ticking (transition into paused state) in audio renderer before | 257 // Stop ticking (transition into paused state) in audio renderer before |
248 // calling Flush, since after Flush we are going to restart playback by | 258 // calling Flush, since after Flush we are going to restart playback by |
249 // calling audio renderer StartPlaying which would fail in playing state. | 259 // calling audio renderer StartPlaying which would fail in playing state. |
250 if (time_ticking_) { | 260 if (time_ticking_) { |
251 time_ticking_ = false; | 261 time_ticking_ = false; |
252 time_source_->StopTicking(); | 262 time_source_->StopTicking(); |
253 } | 263 } |
254 audio_renderer_->Flush( | 264 audio_renderer_->Flush( |
255 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); | 265 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); |
256 } | 266 } |
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
635 : &video_buffering_state_; | 645 : &video_buffering_state_; |
636 | 646 |
637 DVLOG(1) << __func__ << (type == DemuxerStream::AUDIO ? " audio " : " video ") | 647 DVLOG(1) << __func__ << (type == DemuxerStream::AUDIO ? " audio " : " video ") |
638 << BufferingStateStr(*buffering_state) << " -> " | 648 << BufferingStateStr(*buffering_state) << " -> " |
639 << BufferingStateStr(new_buffering_state); | 649 << BufferingStateStr(new_buffering_state); |
640 DCHECK(task_runner_->BelongsToCurrentThread()); | 650 DCHECK(task_runner_->BelongsToCurrentThread()); |
641 | 651 |
642 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 652 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
643 | 653 |
644 if (restarting_audio_ || restarting_video_) { | 654 if (restarting_audio_ || restarting_video_) { |
645 if (HandleRestartedStreamBufferingChanges(type, new_buffering_state)) | 655 if (HandleRestartedStreamBufferingChanges(type, new_buffering_state)) { |
646 return; | 656 return; |
657 } | |
647 } | 658 } |
648 | 659 |
649 // When audio is present and has enough data, defer video underflow callbacks | 660 // When audio is present and has enough data, defer video underflow callbacks |
650 // for some time to avoid unnecessary glitches in audio; see | 661 // for some time to avoid unnecessary glitches in audio; see |
651 // http://crbug.com/144683#c53. | 662 // http://crbug.com/144683#c53. |
652 if (audio_renderer_ && type == DemuxerStream::VIDEO && | 663 if (audio_renderer_ && type == DemuxerStream::VIDEO && |
653 state_ == STATE_PLAYING) { | 664 state_ == STATE_PLAYING) { |
654 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 665 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
655 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && | 666 audio_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
656 new_buffering_state == BUFFERING_HAVE_NOTHING && | 667 new_buffering_state == BUFFERING_HAVE_NOTHING && |
657 deferred_video_underflow_cb_.IsCancelled()) { | 668 deferred_video_underflow_cb_.IsCancelled()) { |
658 DVLOG(4) << __func__ << " Deferring HAVE_NOTHING for video stream."; | 669 DVLOG(1) << __func__ << " Deferring HAVE_NOTHING for video stream."; |
servolk
2016/12/13 19:46:28
Nit: why? this could be noisy in logs. Let's keep
whywhat
2016/12/13 21:44:10
Oops, uploaded accidental change after debug loggi
| |
659 deferred_video_underflow_cb_.Reset( | 670 deferred_video_underflow_cb_.Reset( |
660 base::Bind(&RendererImpl::OnBufferingStateChange, | 671 base::Bind(&RendererImpl::OnBufferingStateChange, |
661 weak_factory_.GetWeakPtr(), type, new_buffering_state)); | 672 weak_factory_.GetWeakPtr(), type, new_buffering_state)); |
662 task_runner_->PostDelayedTask(FROM_HERE, | 673 task_runner_->PostDelayedTask(FROM_HERE, |
663 deferred_video_underflow_cb_.callback(), | 674 deferred_video_underflow_cb_.callback(), |
664 video_underflow_threshold_); | 675 video_underflow_threshold_); |
665 return; | 676 return; |
666 } | 677 } |
667 | 678 |
668 DVLOG(4) << "deferred_video_underflow_cb_.Cancel()"; | |
servolk
2016/12/13 19:46:28
Also: why?
whywhat
2016/12/13 21:44:10
ditto
| |
669 deferred_video_underflow_cb_.Cancel(); | 679 deferred_video_underflow_cb_.Cancel(); |
670 } else if (!deferred_video_underflow_cb_.IsCancelled() && | 680 } else if (!deferred_video_underflow_cb_.IsCancelled() && |
671 type == DemuxerStream::AUDIO && | 681 type == DemuxerStream::AUDIO && |
672 new_buffering_state == BUFFERING_HAVE_NOTHING) { | 682 new_buffering_state == BUFFERING_HAVE_NOTHING) { |
673 // If audio underflows while we have a deferred video underflow in progress | 683 // If audio underflows while we have a deferred video underflow in progress |
674 // we want to mark video as underflowed immediately and cancel the deferral. | 684 // we want to mark video as underflowed immediately and cancel the deferral. |
675 deferred_video_underflow_cb_.Cancel(); | 685 deferred_video_underflow_cb_.Cancel(); |
676 video_buffering_state_ = BUFFERING_HAVE_NOTHING; | 686 video_buffering_state_ = BUFFERING_HAVE_NOTHING; |
677 } | 687 } |
678 | 688 |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
838 void RendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { | 848 void RendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { |
839 DCHECK(task_runner_->BelongsToCurrentThread()); | 849 DCHECK(task_runner_->BelongsToCurrentThread()); |
840 client_->OnVideoNaturalSizeChange(size); | 850 client_->OnVideoNaturalSizeChange(size); |
841 } | 851 } |
842 | 852 |
843 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 853 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
844 DCHECK(task_runner_->BelongsToCurrentThread()); | 854 DCHECK(task_runner_->BelongsToCurrentThread()); |
845 client_->OnVideoOpacityChange(opaque); | 855 client_->OnVideoOpacityChange(opaque); |
846 } | 856 } |
847 | 857 |
858 void RendererImpl::OnFirstFrameRender(DemuxerStream::Type type) { | |
859 DCHECK(task_runner_->BelongsToCurrentThread()); | |
860 if (type == DemuxerStream::AUDIO && !audio_preroll_start_time_.is_null()) { | |
861 UMA_HISTOGRAM_MEDIUM_TIMES( | |
862 "Media.Audio.PrerollTime", | |
863 base::TimeTicks::Now() - audio_preroll_start_time_); | |
864 audio_preroll_start_time_ = base::TimeTicks(); | |
865 } else if (type == DemuxerStream::VIDEO && | |
866 !video_preroll_start_time_.is_null()) { | |
867 UMA_HISTOGRAM_MEDIUM_TIMES( | |
868 "Media.Video.PrerollTime", | |
869 base::TimeTicks::Now() - video_preroll_start_time_); | |
870 video_preroll_start_time_ = base::TimeTicks(); | |
871 } | |
872 } | |
873 | |
848 } // namespace media | 874 } // namespace media |
OLD | NEW |