Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: media/base/pipeline.cc

Issue 376013003: Rename media::Clock to media::TimeDeltaInterpolator and update API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698