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 return; |
| 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 |