Chromium Code Reviews| 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" |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 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 clock_(new Clock(&default_tick_clock_)), |
| 45 waiting_for_clock_update_(false), | 45 clock_state_(CLOCK_PAUSED), |
| 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 creation_time_(default_tick_clock_.NowTicks()) { | 54 creation_time_(default_tick_clock_.NowTicks()) { |
| 55 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 55 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 &Pipeline::ErrorChangedTask, base::Unretained(this), error)); | 290 &Pipeline::ErrorChangedTask, base::Unretained(this), error)); |
| 291 | 291 |
| 292 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); | 292 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); |
| 293 } | 293 } |
| 294 | 294 |
| 295 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { | 295 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { |
| 296 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); | 296 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); |
| 297 DCHECK(IsRunning()); | 297 DCHECK(IsRunning()); |
| 298 base::AutoLock auto_lock(lock_); | 298 base::AutoLock auto_lock(lock_); |
| 299 | 299 |
| 300 if (waiting_for_clock_update_ && time < clock_->Elapsed()) | 300 if (clock_state_ == CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE && |
| 301 time < clock_->Elapsed()) { | |
| 301 return; | 302 return; |
| 303 } | |
| 302 | 304 |
| 303 // TODO(scherkus): |state_| should only be accessed on pipeline thread, see | 305 // TODO(scherkus): |state_| should only be accessed on pipeline thread, see |
| 304 // http://crbug.com/137973 | 306 // http://crbug.com/137973 |
| 305 if (state_ == kSeeking) | 307 if (state_ == kSeeking) |
| 306 return; | 308 return; |
| 307 | 309 |
| 308 clock_->SetTime(time, max_time); | 310 clock_->SetTime(time, max_time); |
| 309 StartClockIfWaitingForTimeUpdate_Locked(); | 311 StartClockIfWaitingForTimeUpdate_Locked(); |
| 310 } | 312 } |
| 311 | 313 |
| 312 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { | 314 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { |
| 313 DCHECK(IsRunning()); | 315 DCHECK(IsRunning()); |
| 314 base::AutoLock auto_lock(lock_); | 316 base::AutoLock auto_lock(lock_); |
| 315 | 317 |
| 316 if (audio_renderer_) | 318 if (audio_renderer_) |
| 317 return; | 319 return; |
| 318 | 320 |
| 319 // TODO(scherkus): |state_| should only be accessed on pipeline thread, see | 321 // TODO(scherkus): |state_| should only be accessed on pipeline thread, see |
| 320 // http://crbug.com/137973 | 322 // http://crbug.com/137973 |
| 321 if (state_ == kSeeking) | 323 if (state_ == kSeeking) |
| 322 return; | 324 return; |
| 323 | 325 |
| 324 DCHECK(!waiting_for_clock_update_); | 326 DCHECK_NE(clock_state_, CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE); |
| 325 clock_->SetMaxTime(max_time); | 327 clock_->SetMaxTime(max_time); |
| 326 } | 328 } |
| 327 | 329 |
| 328 void Pipeline::SetDuration(TimeDelta duration) { | 330 void Pipeline::SetDuration(TimeDelta duration) { |
| 329 DCHECK(IsRunning()); | 331 DCHECK(IsRunning()); |
| 330 media_log_->AddEvent( | 332 media_log_->AddEvent( |
| 331 media_log_->CreateTimeEvent( | 333 media_log_->CreateTimeEvent( |
| 332 MediaLogEvent::DURATION_SET, "duration", duration)); | 334 MediaLogEvent::DURATION_SET, "duration", duration)); |
| 333 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 335 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
| 334 | 336 |
| (...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 746 | 748 |
| 747 SetState(kSeeking); | 749 SetState(kSeeking); |
| 748 base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime()); | 750 base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime()); |
| 749 seek_cb_ = seek_cb; | 751 seek_cb_ = seek_cb; |
| 750 audio_ended_ = false; | 752 audio_ended_ = false; |
| 751 video_ended_ = false; | 753 video_ended_ = false; |
| 752 text_ended_ = false; | 754 text_ended_ = false; |
| 753 | 755 |
| 754 // Kick off seeking! | 756 // Kick off seeking! |
| 755 { | 757 { |
| 756 if (audio_renderer_) | |
| 757 audio_renderer_->StopRendering(); | |
| 758 | |
| 759 base::AutoLock auto_lock(lock_); | 758 base::AutoLock auto_lock(lock_); |
| 760 if (clock_->IsPlaying()) | 759 PauseClockAndStopRendering_Locked(); |
| 761 clock_->Pause(); | |
| 762 clock_->SetTime(seek_timestamp, seek_timestamp); | 760 clock_->SetTime(seek_timestamp, seek_timestamp); |
| 763 } | 761 } |
| 764 DoSeek(seek_timestamp, base::Bind( | 762 DoSeek(seek_timestamp, base::Bind( |
| 765 &Pipeline::OnStateTransition, base::Unretained(this))); | 763 &Pipeline::OnStateTransition, base::Unretained(this))); |
| 766 } | 764 } |
| 767 | 765 |
| 768 void Pipeline::DoAudioRendererEnded() { | 766 void Pipeline::DoAudioRendererEnded() { |
| 769 DCHECK(task_runner_->BelongsToCurrentThread()); | 767 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 770 | 768 |
| 771 if (state_ != kPlaying) | 769 if (state_ != kPlaying) |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 815 return; | 813 return; |
| 816 | 814 |
| 817 if (video_renderer_ && !video_ended_) | 815 if (video_renderer_ && !video_ended_) |
| 818 return; | 816 return; |
| 819 | 817 |
| 820 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) | 818 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) |
| 821 return; | 819 return; |
| 822 | 820 |
| 823 { | 821 { |
| 824 base::AutoLock auto_lock(lock_); | 822 base::AutoLock auto_lock(lock_); |
| 825 clock_->EndOfStream(); | 823 PauseClockAndStopRendering_Locked(); |
| 824 clock_->SetTime(clock_->Duration(), clock_->Duration()); | |
| 826 } | 825 } |
| 827 | 826 |
| 828 DCHECK_EQ(status_, PIPELINE_OK); | 827 DCHECK_EQ(status_, PIPELINE_OK); |
| 829 ended_cb_.Run(); | 828 ended_cb_.Run(); |
| 830 } | 829 } |
| 831 | 830 |
| 832 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, | 831 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, |
| 833 const TextTrackConfig& config) { | 832 const TextTrackConfig& config) { |
| 834 DCHECK(task_runner_->BelongsToCurrentThread()); | 833 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 835 // TODO(matthewjheaney): fix up text_ended_ when text stream | 834 // TODO(matthewjheaney): fix up text_ended_ when text stream |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 924 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) | 923 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) |
| 925 return true; | 924 return true; |
| 926 return false; | 925 return false; |
| 927 } | 926 } |
| 928 | 927 |
| 929 void Pipeline::StartWaitingForEnoughData() { | 928 void Pipeline::StartWaitingForEnoughData() { |
| 930 DVLOG(1) << __FUNCTION__; | 929 DVLOG(1) << __FUNCTION__; |
| 931 DCHECK_EQ(state_, kPlaying); | 930 DCHECK_EQ(state_, kPlaying); |
| 932 DCHECK(WaitingForEnoughData()); | 931 DCHECK(WaitingForEnoughData()); |
| 933 | 932 |
| 934 if (audio_renderer_) | |
| 935 audio_renderer_->StopRendering(); | |
| 936 | |
| 937 base::AutoLock auto_lock(lock_); | 933 base::AutoLock auto_lock(lock_); |
| 938 clock_->Pause(); | 934 PauseClockAndStopRendering_Locked(); |
| 939 } | 935 } |
| 940 | 936 |
| 941 void Pipeline::StartPlayback() { | 937 void Pipeline::StartPlayback() { |
| 942 DVLOG(1) << __FUNCTION__; | 938 DVLOG(1) << __FUNCTION__; |
| 943 DCHECK_EQ(state_, kPlaying); | 939 DCHECK_EQ(state_, kPlaying); |
| 940 DCHECK_EQ(clock_state_, CLOCK_PAUSED); | |
| 944 DCHECK(!WaitingForEnoughData()); | 941 DCHECK(!WaitingForEnoughData()); |
| 945 | 942 |
| 946 if (audio_renderer_) { | 943 if (audio_renderer_) { |
| 947 // We use audio stream to update the clock. So if there is such a | 944 // We use audio stream to update the clock. So if there is such a |
| 948 // stream, we pause the clock until we receive a valid timestamp. | 945 // stream, we pause the clock until we receive a valid timestamp. |
| 949 base::AutoLock auto_lock(lock_); | 946 base::AutoLock auto_lock(lock_); |
| 950 waiting_for_clock_update_ = true; | 947 clock_state_ = CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE; |
| 951 audio_renderer_->StartRendering(); | 948 audio_renderer_->StartRendering(); |
| 952 } else { | 949 } else { |
| 953 base::AutoLock auto_lock(lock_); | 950 base::AutoLock auto_lock(lock_); |
| 954 DCHECK(!waiting_for_clock_update_); | 951 clock_state_ = CLOCK_PLAYING; |
| 955 clock_->SetMaxTime(clock_->Duration()); | 952 clock_->SetMaxTime(clock_->Duration()); |
| 956 clock_->Play(); | 953 clock_->Play(); |
| 957 } | 954 } |
| 958 | 955 |
| 959 preroll_completed_cb_.Run(); | 956 preroll_completed_cb_.Run(); |
| 960 if (!seek_cb_.is_null()) | 957 if (!seek_cb_.is_null()) |
| 961 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | 958 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
| 962 } | 959 } |
| 963 | 960 |
| 961 void Pipeline::PauseClockAndStopRendering_Locked() { | |
| 962 lock_.AssertAcquired(); | |
| 963 switch (clock_state_) { | |
| 964 case CLOCK_PAUSED: | |
| 965 break; | |
|
acolwell GONE FROM CHROMIUM
2014/05/22 01:28:21
nit: return instead?
scherkus (not reviewing)
2014/05/22 17:23:40
Done.
| |
| 966 | |
| 967 case CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE: | |
| 968 audio_renderer_->StopRendering(); | |
| 969 break; | |
| 970 | |
| 971 case CLOCK_PLAYING: | |
| 972 if (audio_renderer_) | |
| 973 audio_renderer_->StopRendering(); | |
| 974 clock_->Pause(); | |
| 975 break; | |
| 976 } | |
| 977 | |
| 978 clock_state_ = CLOCK_PAUSED; | |
| 979 } | |
| 980 | |
| 964 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 981 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
| 965 lock_.AssertAcquired(); | 982 lock_.AssertAcquired(); |
| 966 if (!waiting_for_clock_update_) | 983 if (clock_state_ != CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE) |
| 967 return; | 984 return; |
| 968 | 985 |
| 969 waiting_for_clock_update_ = false; | 986 clock_state_ = CLOCK_PLAYING; |
| 970 clock_->Play(); | 987 clock_->Play(); |
| 971 } | 988 } |
| 972 | 989 |
| 973 } // namespace media | 990 } // namespace media |
| OLD | NEW |