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" | 26 #include "media/base/time_delta_interpolator.h" |
27 #include "media/base/time_source.h" | |
27 #include "media/base/video_decoder.h" | 28 #include "media/base/video_decoder.h" |
28 #include "media/base/video_decoder_config.h" | 29 #include "media/base/video_decoder_config.h" |
29 #include "media/base/video_renderer.h" | 30 #include "media/base/video_renderer.h" |
30 | 31 |
31 using base::TimeDelta; | 32 using base::TimeDelta; |
32 | 33 |
33 namespace media { | 34 namespace media { |
34 | 35 |
35 Pipeline::Pipeline( | 36 Pipeline::Pipeline( |
36 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 37 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
37 MediaLog* media_log) | 38 MediaLog* media_log) |
38 : task_runner_(task_runner), | 39 : task_runner_(task_runner), |
39 media_log_(media_log), | 40 media_log_(media_log), |
40 running_(false), | 41 running_(false), |
41 did_loading_progress_(false), | 42 did_loading_progress_(false), |
42 volume_(1.0f), | 43 volume_(1.0f), |
43 playback_rate_(0.0f), | 44 playback_rate_(0.0f), |
44 interpolator_(new TimeDeltaInterpolator(&default_tick_clock_)), | 45 interpolator_(new TimeDeltaInterpolator(&default_tick_clock_)), |
45 interpolation_state_(INTERPOLATION_STOPPED), | 46 interpolation_state_(INTERPOLATION_STOPPED), |
46 status_(PIPELINE_OK), | 47 status_(PIPELINE_OK), |
47 state_(kCreated), | 48 state_(kCreated), |
48 audio_ended_(false), | 49 audio_ended_(false), |
49 video_ended_(false), | 50 video_ended_(false), |
50 text_ended_(false), | 51 text_ended_(false), |
51 audio_buffering_state_(BUFFERING_HAVE_NOTHING), | 52 audio_buffering_state_(BUFFERING_HAVE_NOTHING), |
52 video_buffering_state_(BUFFERING_HAVE_NOTHING), | 53 video_buffering_state_(BUFFERING_HAVE_NOTHING), |
53 demuxer_(NULL), | 54 demuxer_(NULL), |
55 time_source_(NULL), | |
54 underflow_disabled_for_testing_(false) { | 56 underflow_disabled_for_testing_(false) { |
55 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 57 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
56 media_log_->AddEvent( | 58 media_log_->AddEvent( |
57 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); | 59 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); |
58 interpolator_->SetBounds(base::TimeDelta(), base::TimeDelta()); | 60 interpolator_->SetBounds(base::TimeDelta(), base::TimeDelta()); |
59 } | 61 } |
60 | 62 |
61 Pipeline::~Pipeline() { | 63 Pipeline::~Pipeline() { |
62 DCHECK(thread_checker_.CalledOnValidThread()) | 64 DCHECK(thread_checker_.CalledOnValidThread()) |
63 << "Pipeline must be destroyed on same thread that created it"; | 65 << "Pipeline must be destroyed on same thread that created it"; |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
373 case kPlaying: | 375 case kPlaying: |
374 // Finish initial start sequence the first time we enter the playing | 376 // Finish initial start sequence the first time we enter the playing |
375 // state. | 377 // state. |
376 if (filter_collection_) { | 378 if (filter_collection_) { |
377 filter_collection_.reset(); | 379 filter_collection_.reset(); |
378 if (!audio_renderer_ && !video_renderer_) { | 380 if (!audio_renderer_ && !video_renderer_) { |
379 ErrorChangedTask(PIPELINE_ERROR_COULD_NOT_RENDER); | 381 ErrorChangedTask(PIPELINE_ERROR_COULD_NOT_RENDER); |
380 return; | 382 return; |
381 } | 383 } |
382 | 384 |
385 if (audio_renderer_) | |
386 time_source_ = audio_renderer_->GetTimeSource(); | |
387 | |
383 { | 388 { |
384 PipelineMetadata metadata; | 389 PipelineMetadata metadata; |
385 metadata.has_audio = audio_renderer_; | 390 metadata.has_audio = audio_renderer_; |
386 metadata.has_video = video_renderer_; | 391 metadata.has_video = video_renderer_; |
387 metadata.timeline_offset = demuxer_->GetTimelineOffset(); | 392 metadata.timeline_offset = demuxer_->GetTimelineOffset(); |
388 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); | 393 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
389 if (stream) { | 394 if (stream) { |
390 metadata.natural_size = | 395 metadata.natural_size = |
391 stream->video_decoder_config().natural_size(); | 396 stream->video_decoder_config().natural_size(); |
392 metadata.video_rotation = stream->video_rotation(); | 397 metadata.video_rotation = stream->video_rotation(); |
393 } | 398 } |
394 metadata_cb_.Run(metadata); | 399 metadata_cb_.Run(metadata); |
395 } | 400 } |
396 } | 401 } |
397 | 402 |
398 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | 403 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
399 | 404 |
400 { | 405 { |
401 base::AutoLock auto_lock(lock_); | 406 base::AutoLock auto_lock(lock_); |
402 interpolator_->SetBounds(start_timestamp_, start_timestamp_); | 407 interpolator_->SetBounds(start_timestamp_, start_timestamp_); |
403 } | 408 } |
404 | 409 |
405 if (audio_renderer_) { | 410 if (time_source_) |
xhwang
2014/07/22 00:29:28
Once we use WallClockTimeSource, we should be able
scherkus (not reviewing)
2014/07/22 00:30:59
correct! all condition checking for time_source_ w
| |
406 audio_renderer_->SetMediaTime(start_timestamp_); | 411 time_source_->SetMediaTime(start_timestamp_); |
412 if (audio_renderer_) | |
407 audio_renderer_->StartPlaying(); | 413 audio_renderer_->StartPlaying(); |
408 } | |
409 if (video_renderer_) | 414 if (video_renderer_) |
410 video_renderer_->StartPlaying(); | 415 video_renderer_->StartPlaying(); |
411 if (text_renderer_) | 416 if (text_renderer_) |
412 text_renderer_->StartPlaying(); | 417 text_renderer_->StartPlaying(); |
413 | 418 |
414 PlaybackRateChangedTask(GetPlaybackRate()); | 419 PlaybackRateChangedTask(GetPlaybackRate()); |
415 VolumeChangedTask(GetVolume()); | 420 VolumeChangedTask(GetVolume()); |
416 return; | 421 return; |
417 | 422 |
418 case kStopping: | 423 case kStopping: |
(...skipping 21 matching lines...) Expand all Loading... | |
440 #endif | 445 #endif |
441 | 446 |
442 void Pipeline::DoSeek( | 447 void Pipeline::DoSeek( |
443 base::TimeDelta seek_timestamp, | 448 base::TimeDelta seek_timestamp, |
444 const PipelineStatusCB& done_cb) { | 449 const PipelineStatusCB& done_cb) { |
445 DCHECK(task_runner_->BelongsToCurrentThread()); | 450 DCHECK(task_runner_->BelongsToCurrentThread()); |
446 DCHECK(!pending_callbacks_.get()); | 451 DCHECK(!pending_callbacks_.get()); |
447 SerialRunner::Queue bound_fns; | 452 SerialRunner::Queue bound_fns; |
448 { | 453 { |
449 base::AutoLock auto_lock(lock_); | 454 base::AutoLock auto_lock(lock_); |
450 PauseClockAndStopRendering_Locked(); | 455 PauseClockAndStopTicking_Locked(); |
451 } | 456 } |
452 | 457 |
453 // Pause. | 458 // Pause. |
454 if (text_renderer_) { | 459 if (text_renderer_) { |
455 bound_fns.Push(base::Bind( | 460 bound_fns.Push(base::Bind( |
456 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); | 461 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); |
457 } | 462 } |
458 | 463 |
459 // Flush. | 464 // Flush. |
460 if (audio_renderer_) { | 465 if (audio_renderer_) { |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
642 | 647 |
643 // Playback rate changes are only carried out while playing. | 648 // Playback rate changes are only carried out while playing. |
644 if (state_ != kPlaying) | 649 if (state_ != kPlaying) |
645 return; | 650 return; |
646 | 651 |
647 { | 652 { |
648 base::AutoLock auto_lock(lock_); | 653 base::AutoLock auto_lock(lock_); |
649 interpolator_->SetPlaybackRate(playback_rate); | 654 interpolator_->SetPlaybackRate(playback_rate); |
650 } | 655 } |
651 | 656 |
652 if (audio_renderer_) | 657 if (time_source_) |
653 audio_renderer_->SetPlaybackRate(playback_rate_); | 658 time_source_->SetPlaybackRate(playback_rate_); |
654 } | 659 } |
655 | 660 |
656 void Pipeline::VolumeChangedTask(float volume) { | 661 void Pipeline::VolumeChangedTask(float volume) { |
657 DCHECK(task_runner_->BelongsToCurrentThread()); | 662 DCHECK(task_runner_->BelongsToCurrentThread()); |
658 | 663 |
659 // Volume changes are only carried out while playing. | 664 // Volume changes are only carried out while playing. |
660 if (state_ != kPlaying) | 665 if (state_ != kPlaying) |
661 return; | 666 return; |
662 | 667 |
663 if (audio_renderer_) | 668 if (audio_renderer_) |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
743 return; | 748 return; |
744 | 749 |
745 if (video_renderer_ && !video_ended_) | 750 if (video_renderer_ && !video_ended_) |
746 return; | 751 return; |
747 | 752 |
748 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) | 753 if (text_renderer_ && text_renderer_->HasTracks() && !text_ended_) |
749 return; | 754 return; |
750 | 755 |
751 { | 756 { |
752 base::AutoLock auto_lock(lock_); | 757 base::AutoLock auto_lock(lock_); |
753 PauseClockAndStopRendering_Locked(); | 758 PauseClockAndStopTicking_Locked(); |
754 interpolator_->SetBounds(duration_, duration_); | 759 interpolator_->SetBounds(duration_, duration_); |
755 } | 760 } |
756 | 761 |
757 DCHECK_EQ(status_, PIPELINE_OK); | 762 DCHECK_EQ(status_, PIPELINE_OK); |
758 ended_cb_.Run(); | 763 ended_cb_.Run(); |
759 } | 764 } |
760 | 765 |
761 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, | 766 void Pipeline::AddTextStreamTask(DemuxerStream* text_stream, |
762 const TextTrackConfig& config) { | 767 const TextTrackConfig& config) { |
763 DCHECK(task_runner_->BelongsToCurrentThread()); | 768 DCHECK(task_runner_->BelongsToCurrentThread()); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
856 return false; | 861 return false; |
857 } | 862 } |
858 | 863 |
859 void Pipeline::PausePlayback() { | 864 void Pipeline::PausePlayback() { |
860 DVLOG(1) << __FUNCTION__; | 865 DVLOG(1) << __FUNCTION__; |
861 DCHECK_EQ(state_, kPlaying); | 866 DCHECK_EQ(state_, kPlaying); |
862 DCHECK(WaitingForEnoughData()); | 867 DCHECK(WaitingForEnoughData()); |
863 DCHECK(task_runner_->BelongsToCurrentThread()); | 868 DCHECK(task_runner_->BelongsToCurrentThread()); |
864 | 869 |
865 base::AutoLock auto_lock(lock_); | 870 base::AutoLock auto_lock(lock_); |
866 PauseClockAndStopRendering_Locked(); | 871 PauseClockAndStopTicking_Locked(); |
867 } | 872 } |
868 | 873 |
869 void Pipeline::StartPlayback() { | 874 void Pipeline::StartPlayback() { |
870 DVLOG(1) << __FUNCTION__; | 875 DVLOG(1) << __FUNCTION__; |
871 DCHECK_EQ(state_, kPlaying); | 876 DCHECK_EQ(state_, kPlaying); |
872 DCHECK_EQ(interpolation_state_, INTERPOLATION_STOPPED); | 877 DCHECK_EQ(interpolation_state_, INTERPOLATION_STOPPED); |
873 DCHECK(!WaitingForEnoughData()); | 878 DCHECK(!WaitingForEnoughData()); |
874 DCHECK(task_runner_->BelongsToCurrentThread()); | 879 DCHECK(task_runner_->BelongsToCurrentThread()); |
875 | 880 |
876 if (audio_renderer_) { | 881 if (time_source_) { |
877 // We use audio stream to update the clock. So if there is such a | 882 // We use audio stream to update the clock. So if there is such a |
878 // stream, we pause the clock until we receive a valid timestamp. | 883 // stream, we pause the clock until we receive a valid timestamp. |
879 base::AutoLock auto_lock(lock_); | 884 base::AutoLock auto_lock(lock_); |
880 interpolation_state_ = INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE; | 885 interpolation_state_ = INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE; |
881 audio_renderer_->StartRendering(); | 886 time_source_->StartTicking(); |
882 } else { | 887 } else { |
883 base::AutoLock auto_lock(lock_); | 888 base::AutoLock auto_lock(lock_); |
884 interpolation_state_ = INTERPOLATION_STARTED; | 889 interpolation_state_ = INTERPOLATION_STARTED; |
885 interpolator_->SetUpperBound(duration_); | 890 interpolator_->SetUpperBound(duration_); |
886 interpolator_->StartInterpolating(); | 891 interpolator_->StartInterpolating(); |
887 } | 892 } |
888 } | 893 } |
889 | 894 |
890 void Pipeline::PauseClockAndStopRendering_Locked() { | 895 void Pipeline::PauseClockAndStopTicking_Locked() { |
891 lock_.AssertAcquired(); | 896 lock_.AssertAcquired(); |
892 switch (interpolation_state_) { | 897 switch (interpolation_state_) { |
893 case INTERPOLATION_STOPPED: | 898 case INTERPOLATION_STOPPED: |
894 return; | 899 return; |
895 | 900 |
896 case INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE: | 901 case INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE: |
897 audio_renderer_->StopRendering(); | 902 time_source_->StopTicking(); |
xhwang
2014/07/22 00:29:28
This is a bit odd here. Maybe time_source_ should
scherkus (not reviewing)
2014/07/22 00:30:59
yeah it'll get cleaned up
| |
898 break; | 903 break; |
899 | 904 |
900 case INTERPOLATION_STARTED: | 905 case INTERPOLATION_STARTED: |
901 if (audio_renderer_) | 906 if (time_source_) |
902 audio_renderer_->StopRendering(); | 907 time_source_->StopTicking(); |
903 interpolator_->StopInterpolating(); | 908 interpolator_->StopInterpolating(); |
904 break; | 909 break; |
905 } | 910 } |
906 | 911 |
907 interpolation_state_ = INTERPOLATION_STOPPED; | 912 interpolation_state_ = INTERPOLATION_STOPPED; |
908 } | 913 } |
909 | 914 |
910 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 915 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
911 lock_.AssertAcquired(); | 916 lock_.AssertAcquired(); |
912 if (interpolation_state_ != INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE) | 917 if (interpolation_state_ != INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE) |
913 return; | 918 return; |
914 | 919 |
915 interpolation_state_ = INTERPOLATION_STARTED; | 920 interpolation_state_ = INTERPOLATION_STARTED; |
916 interpolator_->StartInterpolating(); | 921 interpolator_->StartInterpolating(); |
917 } | 922 } |
918 | 923 |
919 } // namespace media | 924 } // namespace media |
OLD | NEW |