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" |
| 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 |