OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/base/pipeline.h" | 5 #include "media/base/pipeline.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
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/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
15 #include "base/single_thread_task_runner.h" | 15 #include "base/single_thread_task_runner.h" |
16 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
18 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
19 #include "base/synchronization/condition_variable.h" | 19 #include "base/synchronization/condition_variable.h" |
20 #include "media/base/audio_decoder.h" | 20 #include "media/base/audio_decoder.h" |
21 #include "media/base/audio_renderer.h" | 21 #include "media/base/audio_renderer.h" |
22 #include "media/base/clock.h" | |
23 #include "media/base/filter_collection.h" | 22 #include "media/base/filter_collection.h" |
24 #include "media/base/media_log.h" | 23 #include "media/base/media_log.h" |
25 #include "media/base/text_renderer.h" | 24 #include "media/base/text_renderer.h" |
26 #include "media/base/text_track_config.h" | 25 #include "media/base/text_track_config.h" |
26 #include "media/base/time_delta_interpolator.h" | |
27 #include "media/base/video_decoder.h" | 27 #include "media/base/video_decoder.h" |
28 #include "media/base/video_decoder_config.h" | 28 #include "media/base/video_decoder_config.h" |
29 #include "media/base/video_renderer.h" | 29 #include "media/base/video_renderer.h" |
30 | 30 |
31 using base::TimeDelta; | 31 using base::TimeDelta; |
32 | 32 |
33 namespace media { | 33 namespace media { |
34 | 34 |
35 Pipeline::Pipeline( | 35 Pipeline::Pipeline( |
36 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 36 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
37 MediaLog* media_log) | 37 MediaLog* media_log) |
38 : task_runner_(task_runner), | 38 : task_runner_(task_runner), |
39 media_log_(media_log), | 39 media_log_(media_log), |
40 running_(false), | 40 running_(false), |
41 did_loading_progress_(false), | 41 did_loading_progress_(false), |
42 volume_(1.0f), | 42 volume_(1.0f), |
43 playback_rate_(0.0f), | 43 playback_rate_(0.0f), |
44 clock_(new Clock(&default_tick_clock_)), | 44 interpolator_(new TimeDeltaInterpolator(&default_tick_clock_)), |
45 clock_state_(CLOCK_PAUSED), | 45 interpolation_state_(INTERPOLATION_STOPPED), |
46 status_(PIPELINE_OK), | 46 status_(PIPELINE_OK), |
47 state_(kCreated), | 47 state_(kCreated), |
48 audio_ended_(false), | 48 audio_ended_(false), |
49 video_ended_(false), | 49 video_ended_(false), |
50 text_ended_(false), | 50 text_ended_(false), |
51 audio_buffering_state_(BUFFERING_HAVE_NOTHING), | 51 audio_buffering_state_(BUFFERING_HAVE_NOTHING), |
52 video_buffering_state_(BUFFERING_HAVE_NOTHING), | 52 video_buffering_state_(BUFFERING_HAVE_NOTHING), |
53 demuxer_(NULL), | 53 demuxer_(NULL), |
54 underflow_disabled_for_testing_(false) { | 54 underflow_disabled_for_testing_(false) { |
55 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 55 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
149 base::AutoLock auto_lock(lock_); | 149 base::AutoLock auto_lock(lock_); |
150 volume_ = volume; | 150 volume_ = volume; |
151 if (running_) { | 151 if (running_) { |
152 task_runner_->PostTask(FROM_HERE, base::Bind( | 152 task_runner_->PostTask(FROM_HERE, base::Bind( |
153 &Pipeline::VolumeChangedTask, base::Unretained(this), volume)); | 153 &Pipeline::VolumeChangedTask, base::Unretained(this), volume)); |
154 } | 154 } |
155 } | 155 } |
156 | 156 |
157 TimeDelta Pipeline::GetMediaTime() const { | 157 TimeDelta Pipeline::GetMediaTime() const { |
158 base::AutoLock auto_lock(lock_); | 158 base::AutoLock auto_lock(lock_); |
159 return std::min(clock_->Elapsed(), duration_); | 159 return std::min(interpolator_->GetInterpolatedTime(), duration_); |
160 } | 160 } |
161 | 161 |
162 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { | 162 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { |
163 base::AutoLock auto_lock(lock_); | 163 base::AutoLock auto_lock(lock_); |
164 return buffered_time_ranges_; | 164 return buffered_time_ranges_; |
165 } | 165 } |
166 | 166 |
167 TimeDelta Pipeline::GetMediaDuration() const { | 167 TimeDelta Pipeline::GetMediaDuration() const { |
168 base::AutoLock auto_lock(lock_); | 168 base::AutoLock auto_lock(lock_); |
169 return duration_; | 169 return duration_; |
170 } | 170 } |
171 | 171 |
172 bool Pipeline::DidLoadingProgress() { | 172 bool Pipeline::DidLoadingProgress() { |
173 base::AutoLock auto_lock(lock_); | 173 base::AutoLock auto_lock(lock_); |
174 bool ret = did_loading_progress_; | 174 bool ret = did_loading_progress_; |
175 did_loading_progress_ = false; | 175 did_loading_progress_ = false; |
176 return ret; | 176 return ret; |
177 } | 177 } |
178 | 178 |
179 PipelineStatistics Pipeline::GetStatistics() const { | 179 PipelineStatistics Pipeline::GetStatistics() const { |
180 base::AutoLock auto_lock(lock_); | 180 base::AutoLock auto_lock(lock_); |
181 return statistics_; | 181 return statistics_; |
182 } | 182 } |
183 | 183 |
184 void Pipeline::SetClockForTesting(Clock* clock) { | 184 void Pipeline::SetTimeDeltaInterpolatorForTesting( |
185 clock_.reset(clock); | 185 TimeDeltaInterpolator* interpolator) { |
186 interpolator_.reset(interpolator); | |
186 } | 187 } |
187 | 188 |
188 void Pipeline::SetErrorForTesting(PipelineStatus status) { | 189 void Pipeline::SetErrorForTesting(PipelineStatus status) { |
189 SetError(status); | 190 SetError(status); |
190 } | 191 } |
191 | 192 |
192 void Pipeline::SetState(State next_state) { | 193 void Pipeline::SetState(State next_state) { |
193 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); | 194 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); |
194 | 195 |
195 state_ = next_state; | 196 state_ = next_state; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
283 &Pipeline::ErrorChangedTask, base::Unretained(this), error)); | 284 &Pipeline::ErrorChangedTask, base::Unretained(this), error)); |
284 | 285 |
285 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); | 286 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); |
286 } | 287 } |
287 | 288 |
288 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { | 289 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { |
289 DCHECK(task_runner_->BelongsToCurrentThread()); | 290 DCHECK(task_runner_->BelongsToCurrentThread()); |
290 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); | 291 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); |
291 base::AutoLock auto_lock(lock_); | 292 base::AutoLock auto_lock(lock_); |
292 | 293 |
293 if (clock_state_ == CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE && | 294 if (interpolation_state_ == INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE && |
294 time < clock_->Elapsed()) { | 295 time < interpolator_->GetInterpolatedTime()) { |
295 return; | 296 return; |
296 } | 297 } |
297 | 298 |
298 if (state_ == kSeeking) | 299 if (state_ == kSeeking) |
299 return; | 300 return; |
300 | 301 |
301 clock_->SetTime(time, max_time); | 302 interpolator_->SetTime(time, max_time); |
302 StartClockIfWaitingForTimeUpdate_Locked(); | 303 StartClockIfWaitingForTimeUpdate_Locked(); |
303 } | 304 } |
304 | 305 |
305 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { | 306 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { |
306 DCHECK(task_runner_->BelongsToCurrentThread()); | 307 DCHECK(task_runner_->BelongsToCurrentThread()); |
307 | 308 |
308 if (audio_renderer_) | 309 if (audio_renderer_) |
309 return; | 310 return; |
310 | 311 |
311 if (state_ == kSeeking) | 312 if (state_ == kSeeking) |
312 return; | 313 return; |
313 | 314 |
314 base::AutoLock auto_lock(lock_); | 315 base::AutoLock auto_lock(lock_); |
315 DCHECK_NE(clock_state_, CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE); | 316 DCHECK_NE(interpolation_state_, INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE); |
316 clock_->SetMaxTime(max_time); | 317 interpolator_->SetMaxTime(max_time); |
317 } | 318 } |
318 | 319 |
319 void Pipeline::SetDuration(TimeDelta duration) { | 320 void Pipeline::SetDuration(TimeDelta duration) { |
320 DCHECK(IsRunning()); | 321 DCHECK(IsRunning()); |
321 media_log_->AddEvent( | 322 media_log_->AddEvent( |
322 media_log_->CreateTimeEvent( | 323 media_log_->CreateTimeEvent( |
323 MediaLogEvent::DURATION_SET, "duration", duration)); | 324 MediaLogEvent::DURATION_SET, "duration", duration)); |
324 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 325 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
325 | 326 |
326 base::AutoLock auto_lock(lock_); | 327 base::AutoLock auto_lock(lock_); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
371 | 372 |
372 case kInitVideoRenderer: | 373 case kInitVideoRenderer: |
373 return InitializeVideoRenderer(done_cb); | 374 return InitializeVideoRenderer(done_cb); |
374 | 375 |
375 case kInitPrerolling: | 376 case kInitPrerolling: |
376 filter_collection_.reset(); | 377 filter_collection_.reset(); |
377 { | 378 { |
378 base::AutoLock l(lock_); | 379 base::AutoLock l(lock_); |
379 // We do not want to start the clock running. We only want to set the | 380 // We do not want to start the clock running. We only want to set the |
380 // base media time so our timestamp calculations will be correct. | 381 // base media time so our timestamp calculations will be correct. |
381 clock_->SetTime(base::TimeDelta(), base::TimeDelta()); | 382 interpolator_->SetTime(base::TimeDelta(), base::TimeDelta()); |
382 } | 383 } |
383 if (!audio_renderer_ && !video_renderer_) { | 384 if (!audio_renderer_ && !video_renderer_) { |
384 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); | 385 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); |
385 return; | 386 return; |
386 } | 387 } |
387 | 388 |
388 { | 389 { |
389 PipelineMetadata metadata; | 390 PipelineMetadata metadata; |
390 metadata.has_audio = audio_renderer_; | 391 metadata.has_audio = audio_renderer_; |
391 metadata.has_video = video_renderer_; | 392 metadata.has_video = video_renderer_; |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
633 | 634 |
634 void Pipeline::PlaybackRateChangedTask(float playback_rate) { | 635 void Pipeline::PlaybackRateChangedTask(float playback_rate) { |
635 DCHECK(task_runner_->BelongsToCurrentThread()); | 636 DCHECK(task_runner_->BelongsToCurrentThread()); |
636 | 637 |
637 // Playback rate changes are only carried out while playing. | 638 // Playback rate changes are only carried out while playing. |
638 if (state_ != kPlaying) | 639 if (state_ != kPlaying) |
639 return; | 640 return; |
640 | 641 |
641 { | 642 { |
642 base::AutoLock auto_lock(lock_); | 643 base::AutoLock auto_lock(lock_); |
643 clock_->SetPlaybackRate(playback_rate); | 644 interpolator_->SetPlaybackRate(playback_rate); |
644 } | 645 } |
645 | 646 |
646 if (audio_renderer_) | 647 if (audio_renderer_) |
647 audio_renderer_->SetPlaybackRate(playback_rate_); | 648 audio_renderer_->SetPlaybackRate(playback_rate_); |
648 if (video_renderer_) | 649 if (video_renderer_) |
649 video_renderer_->SetPlaybackRate(playback_rate_); | 650 video_renderer_->SetPlaybackRate(playback_rate_); |
650 } | 651 } |
651 | 652 |
652 void Pipeline::VolumeChangedTask(float volume) { | 653 void Pipeline::VolumeChangedTask(float volume) { |
653 DCHECK(task_runner_->BelongsToCurrentThread()); | 654 DCHECK(task_runner_->BelongsToCurrentThread()); |
(...skipping 28 matching lines...) Expand all Loading... | |
682 seek_cb_ = seek_cb; | 683 seek_cb_ = seek_cb; |
683 audio_ended_ = false; | 684 audio_ended_ = false; |
684 video_ended_ = false; | 685 video_ended_ = false; |
685 text_ended_ = false; | 686 text_ended_ = false; |
686 start_timestamp_ = time; | 687 start_timestamp_ = time; |
687 | 688 |
688 // Kick off seeking! | 689 // Kick off seeking! |
689 { | 690 { |
690 base::AutoLock auto_lock(lock_); | 691 base::AutoLock auto_lock(lock_); |
691 PauseClockAndStopRendering_Locked(); | 692 PauseClockAndStopRendering_Locked(); |
692 clock_->SetTime(time, time); | 693 interpolator_->SetTime(time, time); |
acolwell GONE FROM CHROMIUM
2014/07/09 00:42:46
This form appears to be used in a bunch of places.
scherkus (not reviewing)
2014/07/09 01:54:31
I'm going to the keep the API roughly intact for t
| |
693 } | 694 } |
694 DoSeek(time, base::Bind( | 695 DoSeek(time, base::Bind( |
695 &Pipeline::OnStateTransition, base::Unretained(this))); | 696 &Pipeline::OnStateTransition, base::Unretained(this))); |
696 } | 697 } |
697 | 698 |
698 void Pipeline::DoAudioRendererEnded() { | 699 void Pipeline::DoAudioRendererEnded() { |
699 DCHECK(task_runner_->BelongsToCurrentThread()); | 700 DCHECK(task_runner_->BelongsToCurrentThread()); |
700 | 701 |
701 if (state_ != kPlaying) | 702 if (state_ != kPlaying) |
702 return; | 703 return; |
703 | 704 |
704 DCHECK(!audio_ended_); | 705 DCHECK(!audio_ended_); |
705 audio_ended_ = true; | 706 audio_ended_ = true; |
706 | 707 |
707 // Start clock since there is no more audio to trigger clock updates. | 708 // Start clock since there is no more audio to trigger clock updates. |
708 { | 709 { |
709 base::AutoLock auto_lock(lock_); | 710 base::AutoLock auto_lock(lock_); |
710 clock_->SetMaxTime(duration_); | 711 interpolator_->SetMaxTime(duration_); |
711 StartClockIfWaitingForTimeUpdate_Locked(); | 712 StartClockIfWaitingForTimeUpdate_Locked(); |
712 } | 713 } |
713 | 714 |
714 RunEndedCallbackIfNeeded(); | 715 RunEndedCallbackIfNeeded(); |
715 } | 716 } |
716 | 717 |
717 void Pipeline::DoVideoRendererEnded() { | 718 void Pipeline::DoVideoRendererEnded() { |
718 DCHECK(task_runner_->BelongsToCurrentThread()); | 719 DCHECK(task_runner_->BelongsToCurrentThread()); |
719 | 720 |
720 if (state_ != kPlaying) | 721 if (state_ != kPlaying) |
(...skipping 25 matching lines...) Expand all Loading... | |
746 | 747 |
747 if (video_renderer_ && !video_ended_) | 748 if (video_renderer_ && !video_ended_) |
748 return; | 749 return; |
749 | 750 |
750 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) | 751 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) |
751 return; | 752 return; |
752 | 753 |
753 { | 754 { |
754 base::AutoLock auto_lock(lock_); | 755 base::AutoLock auto_lock(lock_); |
755 PauseClockAndStopRendering_Locked(); | 756 PauseClockAndStopRendering_Locked(); |
756 clock_->SetTime(duration_, duration_); | 757 interpolator_->SetTime(duration_, duration_); |
757 } | 758 } |
758 | 759 |
759 DCHECK_EQ(status_, PIPELINE_OK); | 760 DCHECK_EQ(status_, PIPELINE_OK); |
760 ended_cb_.Run(); | 761 ended_cb_.Run(); |
761 } | 762 } |
762 | 763 |
763 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, | 764 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, |
764 const TextTrackConfig& config) { | 765 const TextTrackConfig& config) { |
765 DCHECK(task_runner_->BelongsToCurrentThread()); | 766 DCHECK(task_runner_->BelongsToCurrentThread()); |
766 // TODO(matthewjheaney): fix up text_ended_ when text stream | 767 // TODO(matthewjheaney): fix up text_ended_ when text stream |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
863 DCHECK(WaitingForEnoughData()); | 864 DCHECK(WaitingForEnoughData()); |
864 DCHECK(task_runner_->BelongsToCurrentThread()); | 865 DCHECK(task_runner_->BelongsToCurrentThread()); |
865 | 866 |
866 base::AutoLock auto_lock(lock_); | 867 base::AutoLock auto_lock(lock_); |
867 PauseClockAndStopRendering_Locked(); | 868 PauseClockAndStopRendering_Locked(); |
868 } | 869 } |
869 | 870 |
870 void Pipeline::StartPlayback() { | 871 void Pipeline::StartPlayback() { |
871 DVLOG(1) << __FUNCTION__; | 872 DVLOG(1) << __FUNCTION__; |
872 DCHECK_EQ(state_, kPlaying); | 873 DCHECK_EQ(state_, kPlaying); |
873 DCHECK_EQ(clock_state_, CLOCK_PAUSED); | 874 DCHECK_EQ(interpolation_state_, INTERPOLATION_STOPPED); |
874 DCHECK(!WaitingForEnoughData()); | 875 DCHECK(!WaitingForEnoughData()); |
875 DCHECK(task_runner_->BelongsToCurrentThread()); | 876 DCHECK(task_runner_->BelongsToCurrentThread()); |
876 | 877 |
877 if (audio_renderer_) { | 878 if (audio_renderer_) { |
878 // We use audio stream to update the clock. So if there is such a | 879 // We use audio stream to update the clock. So if there is such a |
879 // stream, we pause the clock until we receive a valid timestamp. | 880 // stream, we pause the clock until we receive a valid timestamp. |
880 base::AutoLock auto_lock(lock_); | 881 base::AutoLock auto_lock(lock_); |
881 clock_state_ = CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE; | 882 interpolation_state_ = INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE; |
882 audio_renderer_->StartRendering(); | 883 audio_renderer_->StartRendering(); |
883 } else { | 884 } else { |
884 base::AutoLock auto_lock(lock_); | 885 base::AutoLock auto_lock(lock_); |
885 clock_state_ = CLOCK_PLAYING; | 886 interpolation_state_ = INTERPOLATION_STARTED; |
886 clock_->SetMaxTime(duration_); | 887 interpolator_->SetMaxTime(duration_); |
acolwell GONE FROM CHROMIUM
2014/07/09 00:42:46
Yeah.. this stuff should be in the interpolator_
scherkus (not reviewing)
2014/07/09 01:54:31
Ditto.
| |
887 clock_->Play(); | 888 interpolator_->StartInterpolating(); |
888 } | 889 } |
889 } | 890 } |
890 | 891 |
891 void Pipeline::PauseClockAndStopRendering_Locked() { | 892 void Pipeline::PauseClockAndStopRendering_Locked() { |
892 lock_.AssertAcquired(); | 893 lock_.AssertAcquired(); |
893 switch (clock_state_) { | 894 switch (interpolation_state_) { |
894 case CLOCK_PAUSED: | 895 case INTERPOLATION_STOPPED: |
895 return; | 896 return; |
896 | 897 |
897 case CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE: | 898 case INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE: |
898 audio_renderer_->StopRendering(); | 899 audio_renderer_->StopRendering(); |
899 break; | 900 break; |
900 | 901 |
901 case CLOCK_PLAYING: | 902 case INTERPOLATION_STARTED: |
902 if (audio_renderer_) | 903 if (audio_renderer_) |
903 audio_renderer_->StopRendering(); | 904 audio_renderer_->StopRendering(); |
904 clock_->Pause(); | 905 interpolator_->StopInterpolating(); |
905 break; | 906 break; |
906 } | 907 } |
907 | 908 |
908 clock_state_ = CLOCK_PAUSED; | 909 interpolation_state_ = INTERPOLATION_STOPPED; |
909 } | 910 } |
910 | 911 |
911 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 912 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
912 lock_.AssertAcquired(); | 913 lock_.AssertAcquired(); |
913 if (clock_state_ != CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE) | 914 if (interpolation_state_ != INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE) |
914 return; | 915 return; |
915 | 916 |
916 clock_state_ = CLOCK_PLAYING; | 917 interpolation_state_ = INTERPOLATION_STARTED; |
917 clock_->Play(); | 918 interpolator_->StartInterpolating(); |
918 } | 919 } |
919 | 920 |
920 } // namespace media | 921 } // namespace media |
OLD | NEW |