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 14 matching lines...) Expand all Loading... |
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; | 33 static const int kAudioRestartUnderflowThresholdMs = 2000; |
34 | 34 |
| 35 static const int kTimeUpdateIntervalMs = 50; |
| 36 |
35 class RendererImpl::RendererClientInternal : public RendererClient { | 37 class RendererImpl::RendererClientInternal : public RendererClient { |
36 public: | 38 public: |
37 RendererClientInternal(DemuxerStream::Type type, RendererImpl* renderer) | 39 RendererClientInternal(DemuxerStream::Type type, RendererImpl* renderer) |
38 : type_(type), renderer_(renderer) { | 40 : type_(type), renderer_(renderer) { |
39 DCHECK((type_ == DemuxerStream::AUDIO) || (type_ == DemuxerStream::VIDEO)); | 41 DCHECK((type_ == DemuxerStream::AUDIO) || (type_ == DemuxerStream::VIDEO)); |
40 } | 42 } |
41 | 43 |
42 void OnError(PipelineStatus error) override { renderer_->OnError(error); } | 44 void OnError(PipelineStatus error) override { renderer_->OnError(error); } |
43 void OnEnded() override { renderer_->OnRendererEnded(type_); } | 45 void OnEnded() override { renderer_->OnRendererEnded(type_); } |
44 void OnStatisticsUpdate(const PipelineStatistics& stats) override { | 46 void OnStatisticsUpdate(const PipelineStatistics& stats) override { |
45 renderer_->OnStatisticsUpdate(stats); | 47 renderer_->OnStatisticsUpdate(stats); |
46 } | 48 } |
47 void OnBufferingStateChange(BufferingState state) override { | 49 void OnBufferingStateChange(BufferingState state) override { |
48 renderer_->OnBufferingStateChange(type_, state); | 50 renderer_->OnBufferingStateChange(type_, state); |
49 } | 51 } |
50 void OnWaitingForDecryptionKey() override { | 52 void OnWaitingForDecryptionKey() override { |
51 renderer_->OnWaitingForDecryptionKey(); | 53 renderer_->OnWaitingForDecryptionKey(); |
52 } | 54 } |
53 void OnVideoNaturalSizeChange(const gfx::Size& size) override { | 55 void OnVideoNaturalSizeChange(const gfx::Size& size) override { |
54 DCHECK(type_ == DemuxerStream::VIDEO); | 56 DCHECK(type_ == DemuxerStream::VIDEO); |
55 renderer_->OnVideoNaturalSizeChange(size); | 57 renderer_->OnVideoNaturalSizeChange(size); |
56 } | 58 } |
57 void OnVideoOpacityChange(bool opaque) override { | 59 void OnVideoOpacityChange(bool opaque) override { |
58 DCHECK(type_ == DemuxerStream::VIDEO); | 60 DCHECK(type_ == DemuxerStream::VIDEO); |
59 renderer_->OnVideoOpacityChange(opaque); | 61 renderer_->OnVideoOpacityChange(opaque); |
60 } | 62 } |
| 63 void OnTimeUpdate(base::TimeDelta curr_time, |
| 64 base::TimeDelta max_time, |
| 65 base::TimeTicks capture_time) override { |
| 66 NOTREACHED(); |
| 67 } |
61 | 68 |
62 private: | 69 private: |
63 DemuxerStream::Type type_; | 70 DemuxerStream::Type type_; |
64 RendererImpl* renderer_; | 71 RendererImpl* renderer_; |
65 }; | 72 }; |
66 | 73 |
67 RendererImpl::RendererImpl( | 74 RendererImpl::RendererImpl( |
68 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 75 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
69 std::unique_ptr<AudioRenderer> audio_renderer, | 76 std::unique_ptr<AudioRenderer> audio_renderer, |
70 std::unique_ptr<VideoRenderer> video_renderer) | 77 std::unique_ptr<VideoRenderer> video_renderer) |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 DCHECK(time_source_); | 243 DCHECK(time_source_); |
237 if (restarting_audio_) | 244 if (restarting_audio_) |
238 return; | 245 return; |
239 restarting_audio_ = true; | 246 restarting_audio_ = true; |
240 // Stop ticking (transition into paused state) in audio renderer before | 247 // Stop ticking (transition into paused state) in audio renderer before |
241 // calling Flush, since after Flush we are going to restart playback by | 248 // calling Flush, since after Flush we are going to restart playback by |
242 // calling audio renderer StartPlaying which would fail in playing state. | 249 // calling audio renderer StartPlaying which would fail in playing state. |
243 if (time_ticking_) { | 250 if (time_ticking_) { |
244 time_ticking_ = false; | 251 time_ticking_ = false; |
245 time_source_->StopTicking(); | 252 time_source_->StopTicking(); |
| 253 CancelPeriodicMediaTimeUpdates(); |
246 } | 254 } |
247 audio_renderer_->Flush( | 255 audio_renderer_->Flush( |
248 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); | 256 base::Bind(&RendererImpl::RestartAudioRenderer, weak_this_, time)); |
249 } | 257 } |
250 } | 258 } |
251 | 259 |
252 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { | 260 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) { |
253 DVLOG(3) << __func__; | 261 DVLOG(3) << __func__; |
254 DCHECK(task_runner_->BelongsToCurrentThread()); | 262 DCHECK(task_runner_->BelongsToCurrentThread()); |
255 DCHECK(video_renderer_); | 263 DCHECK(video_renderer_); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 DVLOG(1) << __func__; | 301 DVLOG(1) << __func__; |
294 DCHECK(task_runner_->BelongsToCurrentThread()); | 302 DCHECK(task_runner_->BelongsToCurrentThread()); |
295 | 303 |
296 if (audio_renderer_) | 304 if (audio_renderer_) |
297 audio_renderer_->SetVolume(volume); | 305 audio_renderer_->SetVolume(volume); |
298 } | 306 } |
299 | 307 |
300 base::TimeDelta RendererImpl::GetMediaTime() { | 308 base::TimeDelta RendererImpl::GetMediaTime() { |
301 // No BelongsToCurrentThread() checking because this can be called from other | 309 // No BelongsToCurrentThread() checking because this can be called from other |
302 // threads. | 310 // threads. |
303 return time_source_->CurrentMediaTime(); | 311 return time_source_->CurrentMediaTime(nullptr); |
304 } | 312 } |
305 | 313 |
306 bool RendererImpl::HasAudio() { | 314 bool RendererImpl::HasAudio() { |
307 DCHECK(task_runner_->BelongsToCurrentThread()); | 315 DCHECK(task_runner_->BelongsToCurrentThread()); |
308 return audio_renderer_ != NULL; | 316 return audio_renderer_ != NULL; |
309 } | 317 } |
310 | 318 |
311 bool RendererImpl::HasVideo() { | 319 bool RendererImpl::HasVideo() { |
312 DCHECK(task_runner_->BelongsToCurrentThread()); | 320 DCHECK(task_runner_->BelongsToCurrentThread()); |
313 return video_renderer_ != NULL; | 321 return video_renderer_ != NULL; |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 break; | 744 break; |
737 | 745 |
738 case STATE_ERROR: | 746 case STATE_ERROR: |
739 // An error state may occur at any time. | 747 // An error state may occur at any time. |
740 break; | 748 break; |
741 } | 749 } |
742 | 750 |
743 if (time_ticking_) { | 751 if (time_ticking_) { |
744 time_ticking_ = false; | 752 time_ticking_ = false; |
745 time_source_->StopTicking(); | 753 time_source_->StopTicking(); |
| 754 CancelPeriodicMediaTimeUpdates(); |
746 } | 755 } |
747 if (playback_rate_ > 0 && video_renderer_) | 756 if (playback_rate_ > 0 && video_renderer_) |
748 video_renderer_->OnTimeStateChanged(false); | 757 video_renderer_->OnTimeStateChanged(false); |
749 } | 758 } |
750 | 759 |
751 void RendererImpl::StartPlayback() { | 760 void RendererImpl::StartPlayback() { |
752 DVLOG(1) << __func__; | 761 DVLOG(1) << __func__; |
753 DCHECK(task_runner_->BelongsToCurrentThread()); | 762 DCHECK(task_runner_->BelongsToCurrentThread()); |
754 DCHECK_EQ(state_, STATE_PLAYING); | 763 DCHECK_EQ(state_, STATE_PLAYING); |
755 DCHECK(!time_ticking_); | 764 DCHECK(!time_ticking_); |
756 DCHECK(!WaitingForEnoughData()); | 765 DCHECK(!WaitingForEnoughData()); |
757 | 766 |
758 time_ticking_ = true; | 767 time_ticking_ = true; |
759 time_source_->StartTicking(); | 768 time_source_->StartTicking(); |
| 769 SchedulePeriodicMediaTimeUpdates(); |
| 770 |
760 if (playback_rate_ > 0 && video_renderer_) | 771 if (playback_rate_ > 0 && video_renderer_) |
761 video_renderer_->OnTimeStateChanged(true); | 772 video_renderer_->OnTimeStateChanged(true); |
762 } | 773 } |
763 | 774 |
764 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { | 775 void RendererImpl::OnRendererEnded(DemuxerStream::Type type) { |
765 DVLOG(1) << __func__ << (type == DemuxerStream::AUDIO ? " audio" : " video"); | 776 DVLOG(1) << __func__ << (type == DemuxerStream::AUDIO ? " audio" : " video"); |
766 DCHECK(task_runner_->BelongsToCurrentThread()); | 777 DCHECK(task_runner_->BelongsToCurrentThread()); |
767 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); | 778 DCHECK((type == DemuxerStream::AUDIO) || (type == DemuxerStream::VIDEO)); |
768 | 779 |
769 if (state_ != STATE_PLAYING) | 780 if (state_ != STATE_PLAYING) |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 void RendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { | 852 void RendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) { |
842 DCHECK(task_runner_->BelongsToCurrentThread()); | 853 DCHECK(task_runner_->BelongsToCurrentThread()); |
843 client_->OnVideoNaturalSizeChange(size); | 854 client_->OnVideoNaturalSizeChange(size); |
844 } | 855 } |
845 | 856 |
846 void RendererImpl::OnVideoOpacityChange(bool opaque) { | 857 void RendererImpl::OnVideoOpacityChange(bool opaque) { |
847 DCHECK(task_runner_->BelongsToCurrentThread()); | 858 DCHECK(task_runner_->BelongsToCurrentThread()); |
848 client_->OnVideoOpacityChange(opaque); | 859 client_->OnVideoOpacityChange(opaque); |
849 } | 860 } |
850 | 861 |
| 862 void RendererImpl::UpdateMediaTime() { |
| 863 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 864 DCHECK(time_ticking_); |
| 865 |
| 866 base::TimeTicks capture_time; |
| 867 base::TimeDelta curr_time = time_source_->CurrentMediaTime(&capture_time); |
| 868 // Allow some slop to account for delays in scheduling time update tasks. |
| 869 base::TimeDelta max_time = |
| 870 curr_time + base::TimeDelta::FromMilliseconds(2 * kTimeUpdateIntervalMs); |
| 871 client_->OnTimeUpdate(curr_time, max_time, capture_time); |
| 872 } |
| 873 |
| 874 void RendererImpl::SchedulePeriodicMediaTimeUpdates() { |
| 875 DVLOG(2) << __func__; |
| 876 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 877 |
| 878 base::TimeTicks capture_time; |
| 879 base::TimeDelta curr_time = time_source_->CurrentMediaTime(&capture_time); |
| 880 client_->OnTimeUpdate(curr_time, curr_time, capture_time); |
| 881 |
| 882 time_update_timer_.Start( |
| 883 FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeUpdateIntervalMs), |
| 884 base::Bind(&RendererImpl::UpdateMediaTime, weak_this_)); |
| 885 } |
| 886 |
| 887 void RendererImpl::CancelPeriodicMediaTimeUpdates() { |
| 888 DVLOG(2) << __func__; |
| 889 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 890 |
| 891 time_update_timer_.Stop(); |
| 892 |
| 893 base::TimeTicks capture_time; |
| 894 base::TimeDelta curr_time = time_source_->CurrentMediaTime(&capture_time); |
| 895 client_->OnTimeUpdate(curr_time, curr_time, capture_time); |
| 896 } |
| 897 |
851 } // namespace media | 898 } // namespace media |
OLD | NEW |