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/filter_collection.h" | 22 #include "media/base/filter_collection.h" |
23 #include "media/base/media_log.h" | 23 #include "media/base/media_log.h" |
24 #include "media/base/text_renderer.h" | 24 #include "media/base/text_renderer.h" |
25 #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" | 26 #include "media/base/video_decoder.h" |
28 #include "media/base/video_decoder_config.h" | 27 #include "media/base/video_decoder_config.h" |
29 #include "media/base/video_renderer.h" | 28 #include "media/base/video_renderer.h" |
29 #include "media/base/wall_clock_time_source.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 interpolator_(new TimeDeltaInterpolator(&default_tick_clock_)), | |
45 interpolation_state_(INTERPOLATION_STOPPED), | |
46 status_(PIPELINE_OK), | 44 status_(PIPELINE_OK), |
47 state_(kCreated), | 45 state_(kCreated), |
48 audio_ended_(false), | 46 audio_ended_(false), |
49 video_ended_(false), | 47 video_ended_(false), |
50 text_ended_(false), | 48 text_ended_(false), |
51 audio_buffering_state_(BUFFERING_HAVE_NOTHING), | 49 audio_buffering_state_(BUFFERING_HAVE_NOTHING), |
52 video_buffering_state_(BUFFERING_HAVE_NOTHING), | 50 video_buffering_state_(BUFFERING_HAVE_NOTHING), |
53 demuxer_(NULL), | 51 demuxer_(NULL), |
52 time_source_(NULL), | |
54 underflow_disabled_for_testing_(false) { | 53 underflow_disabled_for_testing_(false) { |
55 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 54 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
56 media_log_->AddEvent( | 55 media_log_->AddEvent( |
57 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); | 56 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); |
58 interpolator_->SetBounds(base::TimeDelta(), base::TimeDelta()); | |
59 } | 57 } |
60 | 58 |
61 Pipeline::~Pipeline() { | 59 Pipeline::~Pipeline() { |
62 DCHECK(thread_checker_.CalledOnValidThread()) | 60 DCHECK(thread_checker_.CalledOnValidThread()) |
63 << "Pipeline must be destroyed on same thread that created it"; | 61 << "Pipeline must be destroyed on same thread that created it"; |
64 DCHECK(!running_) << "Stop() must complete before destroying object"; | 62 DCHECK(!running_) << "Stop() must complete before destroying object"; |
65 DCHECK(stop_cb_.is_null()); | 63 DCHECK(stop_cb_.is_null()); |
66 DCHECK(seek_cb_.is_null()); | 64 DCHECK(seek_cb_.is_null()); |
67 | 65 |
68 media_log_->AddEvent( | 66 media_log_->AddEvent( |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
150 base::AutoLock auto_lock(lock_); | 148 base::AutoLock auto_lock(lock_); |
151 volume_ = volume; | 149 volume_ = volume; |
152 if (running_) { | 150 if (running_) { |
153 task_runner_->PostTask(FROM_HERE, base::Bind( | 151 task_runner_->PostTask(FROM_HERE, base::Bind( |
154 &Pipeline::VolumeChangedTask, base::Unretained(this), volume)); | 152 &Pipeline::VolumeChangedTask, base::Unretained(this), volume)); |
155 } | 153 } |
156 } | 154 } |
157 | 155 |
158 TimeDelta Pipeline::GetMediaTime() const { | 156 TimeDelta Pipeline::GetMediaTime() const { |
159 base::AutoLock auto_lock(lock_); | 157 base::AutoLock auto_lock(lock_); |
160 return std::min(interpolator_->GetInterpolatedTime(), duration_); | 158 return time_source_->CurrentMediaTimestamp(); |
xhwang
2014/07/12 06:36:44
Other use of time_source_ in this file is not prot
| |
161 } | 159 } |
162 | 160 |
163 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { | 161 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { |
164 base::AutoLock auto_lock(lock_); | 162 base::AutoLock auto_lock(lock_); |
165 return buffered_time_ranges_; | 163 return buffered_time_ranges_; |
166 } | 164 } |
167 | 165 |
168 TimeDelta Pipeline::GetMediaDuration() const { | 166 TimeDelta Pipeline::GetMediaDuration() const { |
169 base::AutoLock auto_lock(lock_); | 167 base::AutoLock auto_lock(lock_); |
170 return duration_; | 168 return duration_; |
171 } | 169 } |
172 | 170 |
173 bool Pipeline::DidLoadingProgress() { | 171 bool Pipeline::DidLoadingProgress() { |
174 base::AutoLock auto_lock(lock_); | 172 base::AutoLock auto_lock(lock_); |
175 bool ret = did_loading_progress_; | 173 bool ret = did_loading_progress_; |
176 did_loading_progress_ = false; | 174 did_loading_progress_ = false; |
177 return ret; | 175 return ret; |
178 } | 176 } |
179 | 177 |
180 PipelineStatistics Pipeline::GetStatistics() const { | 178 PipelineStatistics Pipeline::GetStatistics() const { |
181 base::AutoLock auto_lock(lock_); | 179 base::AutoLock auto_lock(lock_); |
182 return statistics_; | 180 return statistics_; |
183 } | 181 } |
184 | 182 |
185 void Pipeline::SetTimeDeltaInterpolatorForTesting( | |
186 TimeDeltaInterpolator* interpolator) { | |
187 interpolator_.reset(interpolator); | |
188 } | |
189 | |
190 void Pipeline::SetErrorForTesting(PipelineStatus status) { | 183 void Pipeline::SetErrorForTesting(PipelineStatus status) { |
191 SetError(status); | 184 SetError(status); |
192 } | 185 } |
193 | 186 |
194 void Pipeline::SetState(State next_state) { | 187 void Pipeline::SetState(State next_state) { |
195 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); | 188 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); |
196 | 189 |
197 state_ = next_state; | 190 state_ = next_state; |
198 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); | 191 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); |
199 } | 192 } |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 DCHECK(IsRunning()); | 269 DCHECK(IsRunning()); |
277 DCHECK_NE(PIPELINE_OK, error); | 270 DCHECK_NE(PIPELINE_OK, error); |
278 VLOG(1) << "Media pipeline error: " << error; | 271 VLOG(1) << "Media pipeline error: " << error; |
279 | 272 |
280 task_runner_->PostTask(FROM_HERE, base::Bind( | 273 task_runner_->PostTask(FROM_HERE, base::Bind( |
281 &Pipeline::ErrorChangedTask, base::Unretained(this), error)); | 274 &Pipeline::ErrorChangedTask, base::Unretained(this), error)); |
282 | 275 |
283 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); | 276 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); |
284 } | 277 } |
285 | 278 |
286 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { | |
287 DCHECK(task_runner_->BelongsToCurrentThread()); | |
288 DCHECK_LE(time.InMicroseconds(), max_time.InMicroseconds()); | |
289 base::AutoLock auto_lock(lock_); | |
290 | |
291 if (interpolation_state_ == INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE && | |
292 time < interpolator_->GetInterpolatedTime()) { | |
293 return; | |
294 } | |
295 | |
296 if (state_ == kSeeking) | |
297 return; | |
298 | |
299 interpolator_->SetBounds(time, max_time); | |
300 StartClockIfWaitingForTimeUpdate_Locked(); | |
301 } | |
302 | |
303 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { | |
304 DCHECK(task_runner_->BelongsToCurrentThread()); | |
305 | |
306 if (audio_renderer_) | |
307 return; | |
308 | |
309 if (state_ == kSeeking) | |
310 return; | |
311 | |
312 base::AutoLock auto_lock(lock_); | |
313 DCHECK_NE(interpolation_state_, INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE); | |
314 interpolator_->SetUpperBound(max_time); | |
315 } | |
316 | |
317 void Pipeline::SetDuration(TimeDelta duration) { | 279 void Pipeline::SetDuration(TimeDelta duration) { |
318 DCHECK(IsRunning()); | 280 DCHECK(IsRunning()); |
319 media_log_->AddEvent( | 281 media_log_->AddEvent( |
320 media_log_->CreateTimeEvent( | 282 media_log_->CreateTimeEvent( |
321 MediaLogEvent::DURATION_SET, "duration", duration)); | 283 MediaLogEvent::DURATION_SET, "duration", duration)); |
322 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 284 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
323 | 285 |
324 base::AutoLock auto_lock(lock_); | 286 base::AutoLock auto_lock(lock_); |
325 duration_ = duration; | 287 duration_ = duration; |
326 if (!duration_change_cb_.is_null()) | 288 if (!duration_change_cb_.is_null()) |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
385 metadata.has_audio = audio_renderer_; | 347 metadata.has_audio = audio_renderer_; |
386 metadata.has_video = video_renderer_; | 348 metadata.has_video = video_renderer_; |
387 metadata.timeline_offset = demuxer_->GetTimelineOffset(); | 349 metadata.timeline_offset = demuxer_->GetTimelineOffset(); |
388 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); | 350 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
389 if (stream) { | 351 if (stream) { |
390 metadata.natural_size = | 352 metadata.natural_size = |
391 stream->video_decoder_config().natural_size(); | 353 stream->video_decoder_config().natural_size(); |
392 metadata.video_rotation = stream->video_rotation(); | 354 metadata.video_rotation = stream->video_rotation(); |
393 } | 355 } |
394 metadata_cb_.Run(metadata); | 356 metadata_cb_.Run(metadata); |
357 | |
358 if (audio_renderer_) { | |
359 time_source_ = audio_renderer_.get(); | |
360 } else { | |
361 wall_clock_time_source_.reset(new WallClockTimeSource()); | |
362 time_source_ = wall_clock_time_source_.get(); | |
363 } | |
395 } | 364 } |
396 } | 365 } |
397 | 366 |
398 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | 367 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
399 | 368 |
400 { | 369 time_source_->SetMediaTimestamp(start_timestamp_); |
401 base::AutoLock auto_lock(lock_); | |
402 interpolator_->SetBounds(start_timestamp_, start_timestamp_); | |
403 } | |
404 | 370 |
405 if (audio_renderer_) | 371 if (audio_renderer_) |
406 audio_renderer_->StartPlayingFrom(start_timestamp_); | 372 audio_renderer_->StartPlaying(); |
407 if (video_renderer_) | 373 if (video_renderer_) |
408 video_renderer_->StartPlayingFrom(start_timestamp_); | 374 video_renderer_->StartPlaying(); |
409 if (text_renderer_) | 375 if (text_renderer_) |
410 text_renderer_->StartPlaying(); | 376 text_renderer_->StartPlaying(); |
411 | 377 |
412 PlaybackRateChangedTask(GetPlaybackRate()); | 378 PlaybackRateChangedTask(GetPlaybackRate()); |
413 VolumeChangedTask(GetVolume()); | 379 VolumeChangedTask(GetVolume()); |
414 return; | 380 return; |
415 | 381 |
416 case kStopping: | 382 case kStopping: |
417 case kStopped: | 383 case kStopped: |
418 case kCreated: | 384 case kCreated: |
(...skipping 19 matching lines...) Expand all Loading... | |
438 #endif | 404 #endif |
439 | 405 |
440 void Pipeline::DoSeek( | 406 void Pipeline::DoSeek( |
441 base::TimeDelta seek_timestamp, | 407 base::TimeDelta seek_timestamp, |
442 const PipelineStatusCB& done_cb) { | 408 const PipelineStatusCB& done_cb) { |
443 DCHECK(task_runner_->BelongsToCurrentThread()); | 409 DCHECK(task_runner_->BelongsToCurrentThread()); |
444 DCHECK(!pending_callbacks_.get()); | 410 DCHECK(!pending_callbacks_.get()); |
445 SerialRunner::Queue bound_fns; | 411 SerialRunner::Queue bound_fns; |
446 { | 412 { |
447 base::AutoLock auto_lock(lock_); | 413 base::AutoLock auto_lock(lock_); |
448 PauseClockAndStopRendering_Locked(); | 414 PausePlayback(); |
449 } | 415 } |
450 | 416 |
451 // Pause. | 417 // Pause. |
452 if (text_renderer_) { | 418 if (text_renderer_) { |
453 bound_fns.Push(base::Bind( | 419 bound_fns.Push(base::Bind( |
454 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); | 420 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); |
455 } | 421 } |
456 | 422 |
457 // Flush. | 423 // Flush. |
458 if (audio_renderer_) { | 424 if (audio_renderer_) { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
635 DoStop(base::Bind(&Pipeline::OnStopCompleted, base::Unretained(this))); | 601 DoStop(base::Bind(&Pipeline::OnStopCompleted, base::Unretained(this))); |
636 } | 602 } |
637 | 603 |
638 void Pipeline::PlaybackRateChangedTask(float playback_rate) { | 604 void Pipeline::PlaybackRateChangedTask(float playback_rate) { |
639 DCHECK(task_runner_->BelongsToCurrentThread()); | 605 DCHECK(task_runner_->BelongsToCurrentThread()); |
640 | 606 |
641 // Playback rate changes are only carried out while playing. | 607 // Playback rate changes are only carried out while playing. |
642 if (state_ != kPlaying) | 608 if (state_ != kPlaying) |
643 return; | 609 return; |
644 | 610 |
645 { | 611 time_source_->SetPlaybackRate(playback_rate_); |
646 base::AutoLock auto_lock(lock_); | |
647 interpolator_->SetPlaybackRate(playback_rate); | |
648 } | |
649 | |
650 if (audio_renderer_) | |
651 audio_renderer_->SetPlaybackRate(playback_rate_); | |
652 } | 612 } |
653 | 613 |
654 void Pipeline::VolumeChangedTask(float volume) { | 614 void Pipeline::VolumeChangedTask(float volume) { |
655 DCHECK(task_runner_->BelongsToCurrentThread()); | 615 DCHECK(task_runner_->BelongsToCurrentThread()); |
656 | 616 |
657 // Volume changes are only carried out while playing. | 617 // Volume changes are only carried out while playing. |
658 if (state_ != kPlaying) | 618 if (state_ != kPlaying) |
659 return; | 619 return; |
660 | 620 |
661 if (audio_renderer_) | 621 if (audio_renderer_) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
693 | 653 |
694 void Pipeline::DoAudioRendererEnded() { | 654 void Pipeline::DoAudioRendererEnded() { |
695 DCHECK(task_runner_->BelongsToCurrentThread()); | 655 DCHECK(task_runner_->BelongsToCurrentThread()); |
696 | 656 |
697 if (state_ != kPlaying) | 657 if (state_ != kPlaying) |
698 return; | 658 return; |
699 | 659 |
700 DCHECK(!audio_ended_); | 660 DCHECK(!audio_ended_); |
701 audio_ended_ = true; | 661 audio_ended_ = true; |
702 | 662 |
703 // Start clock since there is no more audio to trigger clock updates. | |
704 { | |
705 base::AutoLock auto_lock(lock_); | |
706 interpolator_->SetUpperBound(duration_); | |
707 StartClockIfWaitingForTimeUpdate_Locked(); | |
708 } | |
709 | |
710 RunEndedCallbackIfNeeded(); | 663 RunEndedCallbackIfNeeded(); |
711 } | 664 } |
712 | 665 |
713 void Pipeline::DoVideoRendererEnded() { | 666 void Pipeline::DoVideoRendererEnded() { |
714 DCHECK(task_runner_->BelongsToCurrentThread()); | 667 DCHECK(task_runner_->BelongsToCurrentThread()); |
715 | 668 |
716 if (state_ != kPlaying) | 669 if (state_ != kPlaying) |
717 return; | 670 return; |
718 | 671 |
719 DCHECK(!video_ended_); | 672 DCHECK(!video_ended_); |
(...skipping 19 matching lines...) Expand all Loading... | |
739 | 692 |
740 if (audio_renderer_ && !audio_ended_) | 693 if (audio_renderer_ && !audio_ended_) |
741 return; | 694 return; |
742 | 695 |
743 if (video_renderer_ && !video_ended_) | 696 if (video_renderer_ && !video_ended_) |
744 return; | 697 return; |
745 | 698 |
746 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) | 699 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) |
747 return; | 700 return; |
748 | 701 |
749 { | 702 PausePlayback(); |
750 base::AutoLock auto_lock(lock_); | |
751 PauseClockAndStopRendering_Locked(); | |
752 interpolator_->SetBounds(duration_, duration_); | |
753 } | |
754 | 703 |
755 DCHECK_EQ(status_, PIPELINE_OK); | 704 DCHECK_EQ(status_, PIPELINE_OK); |
756 ended_cb_.Run(); | 705 ended_cb_.Run(); |
757 } | 706 } |
758 | 707 |
759 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, | 708 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, |
760 const TextTrackConfig& config) { | 709 const TextTrackConfig& config) { |
761 DCHECK(task_runner_->BelongsToCurrentThread()); | 710 DCHECK(task_runner_->BelongsToCurrentThread()); |
762 // TODO(matthewjheaney): fix up text_ended_ when text stream | 711 // TODO(matthewjheaney): fix up text_ended_ when text stream |
763 // is added (http://crbug.com/321446). | 712 // is added (http://crbug.com/321446). |
(...skipping 13 matching lines...) Expand all Loading... | |
777 } | 726 } |
778 | 727 |
779 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { | 728 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { |
780 DCHECK(task_runner_->BelongsToCurrentThread()); | 729 DCHECK(task_runner_->BelongsToCurrentThread()); |
781 | 730 |
782 audio_renderer_ = filter_collection_->GetAudioRenderer(); | 731 audio_renderer_ = filter_collection_->GetAudioRenderer(); |
783 audio_renderer_->Initialize( | 732 audio_renderer_->Initialize( |
784 demuxer_->GetStream(DemuxerStream::AUDIO), | 733 demuxer_->GetStream(DemuxerStream::AUDIO), |
785 done_cb, | 734 done_cb, |
786 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), | 735 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), |
787 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), | |
788 base::Bind(&Pipeline::BufferingStateChanged, base::Unretained(this), | 736 base::Bind(&Pipeline::BufferingStateChanged, base::Unretained(this), |
789 &audio_buffering_state_), | 737 &audio_buffering_state_), |
790 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), | 738 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), |
791 base::Bind(&Pipeline::SetError, base::Unretained(this))); | 739 base::Bind(&Pipeline::SetError, base::Unretained(this))); |
792 } | 740 } |
793 | 741 |
794 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { | 742 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { |
795 DCHECK(task_runner_->BelongsToCurrentThread()); | 743 DCHECK(task_runner_->BelongsToCurrentThread()); |
796 | 744 |
797 video_renderer_ = filter_collection_->GetVideoRenderer(); | 745 video_renderer_ = filter_collection_->GetVideoRenderer(); |
798 video_renderer_->Initialize( | 746 video_renderer_->Initialize( |
799 demuxer_->GetStream(DemuxerStream::VIDEO), | 747 demuxer_->GetStream(DemuxerStream::VIDEO), |
800 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, | 748 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, |
801 done_cb, | 749 done_cb, |
802 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), | 750 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), |
803 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), | |
804 base::Bind(&Pipeline::BufferingStateChanged, base::Unretained(this), | 751 base::Bind(&Pipeline::BufferingStateChanged, base::Unretained(this), |
805 &video_buffering_state_), | 752 &video_buffering_state_), |
806 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), | 753 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), |
807 base::Bind(&Pipeline::SetError, base::Unretained(this)), | 754 base::Bind(&Pipeline::SetError, base::Unretained(this)), |
808 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), | 755 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), |
809 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); | 756 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); |
810 } | 757 } |
811 | 758 |
812 void Pipeline::BufferingStateChanged(BufferingState* buffering_state, | 759 void Pipeline::BufferingStateChanged(BufferingState* buffering_state, |
813 BufferingState new_buffering_state) { | 760 BufferingState new_buffering_state) { |
814 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 761 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " |
815 << " " << new_buffering_state << ") " | 762 << " " << new_buffering_state << ") " |
816 << (buffering_state == &audio_buffering_state_ ? "audio" : "video"); | 763 << (buffering_state == &audio_buffering_state_ ? "audio" : "video"); |
817 DCHECK(task_runner_->BelongsToCurrentThread()); | 764 DCHECK(task_runner_->BelongsToCurrentThread()); |
818 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 765 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
819 | 766 |
820 *buffering_state = new_buffering_state; | 767 *buffering_state = new_buffering_state; |
821 | 768 |
769 #if 0 | |
822 // Disable underflow by ignoring updates that renderers have ran out of data | 770 // Disable underflow by ignoring updates that renderers have ran out of data |
823 // after we have started the clock. | 771 // after we have started the clock. |
824 if (state_ == kPlaying && underflow_disabled_for_testing_ && | 772 if (state_ == kPlaying && underflow_disabled_for_testing_ && |
825 interpolation_state_ != INTERPOLATION_STOPPED) { | 773 interpolation_state_ != INTERPOLATION_STOPPED) { |
826 return; | 774 return; |
827 } | 775 } |
776 #endif | |
828 | 777 |
829 // Renderer underflowed. | 778 // Renderer underflowed. |
830 if (!was_waiting_for_enough_data && WaitingForEnoughData()) { | 779 if (!was_waiting_for_enough_data && WaitingForEnoughData()) { |
831 PausePlayback(); | 780 PausePlayback(); |
832 | 781 |
833 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of | 782 // TODO(scherkus): Fire BUFFERING_HAVE_NOTHING callback to alert clients of |
834 // underflow state http://crbug.com/144683 | 783 // underflow state http://crbug.com/144683 |
835 return; | 784 return; |
836 } | 785 } |
837 | 786 |
(...skipping 15 matching lines...) Expand all Loading... | |
853 return true; | 802 return true; |
854 return false; | 803 return false; |
855 } | 804 } |
856 | 805 |
857 void Pipeline::PausePlayback() { | 806 void Pipeline::PausePlayback() { |
858 DVLOG(1) << __FUNCTION__; | 807 DVLOG(1) << __FUNCTION__; |
859 DCHECK_EQ(state_, kPlaying); | 808 DCHECK_EQ(state_, kPlaying); |
860 DCHECK(WaitingForEnoughData()); | 809 DCHECK(WaitingForEnoughData()); |
861 DCHECK(task_runner_->BelongsToCurrentThread()); | 810 DCHECK(task_runner_->BelongsToCurrentThread()); |
862 | 811 |
863 base::AutoLock auto_lock(lock_); | 812 time_source_->StopTicking(); |
864 PauseClockAndStopRendering_Locked(); | |
865 } | 813 } |
866 | 814 |
867 void Pipeline::StartPlayback() { | 815 void Pipeline::StartPlayback() { |
868 DVLOG(1) << __FUNCTION__; | 816 DVLOG(1) << __FUNCTION__; |
869 DCHECK_EQ(state_, kPlaying); | 817 DCHECK_EQ(state_, kPlaying); |
870 DCHECK_EQ(interpolation_state_, INTERPOLATION_STOPPED); | |
871 DCHECK(!WaitingForEnoughData()); | 818 DCHECK(!WaitingForEnoughData()); |
872 DCHECK(task_runner_->BelongsToCurrentThread()); | 819 DCHECK(task_runner_->BelongsToCurrentThread()); |
873 | 820 |
874 if (audio_renderer_) { | 821 time_source_->StartTicking(); |
875 // We use audio stream to update the clock. So if there is such a | |
876 // stream, we pause the clock until we receive a valid timestamp. | |
877 base::AutoLock auto_lock(lock_); | |
878 interpolation_state_ = INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE; | |
879 audio_renderer_->StartRendering(); | |
880 } else { | |
881 base::AutoLock auto_lock(lock_); | |
882 interpolation_state_ = INTERPOLATION_STARTED; | |
883 interpolator_->SetUpperBound(duration_); | |
884 interpolator_->StartInterpolating(); | |
885 } | |
886 } | |
887 | |
888 void Pipeline::PauseClockAndStopRendering_Locked() { | |
889 lock_.AssertAcquired(); | |
890 switch (interpolation_state_) { | |
891 case INTERPOLATION_STOPPED: | |
892 return; | |
893 | |
894 case INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE: | |
895 audio_renderer_->StopRendering(); | |
896 break; | |
897 | |
898 case INTERPOLATION_STARTED: | |
899 if (audio_renderer_) | |
900 audio_renderer_->StopRendering(); | |
901 interpolator_->StopInterpolating(); | |
902 break; | |
903 } | |
904 | |
905 interpolation_state_ = INTERPOLATION_STOPPED; | |
906 } | |
907 | |
908 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | |
909 lock_.AssertAcquired(); | |
910 if (interpolation_state_ != INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE) | |
911 return; | |
912 | |
913 interpolation_state_ = INTERPOLATION_STARTED; | |
914 interpolator_->StartInterpolating(); | |
915 } | 822 } |
916 | 823 |
917 } // namespace media | 824 } // namespace media |
OLD | NEW |