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 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 metadata.natural_size = stream->video_decoder_config().natural_size(); | 405 metadata.natural_size = stream->video_decoder_config().natural_size(); |
406 metadata_cb_.Run(metadata); | 406 metadata_cb_.Run(metadata); |
407 } | 407 } |
408 | 408 |
409 return DoInitialPreroll(done_cb); | 409 return DoInitialPreroll(done_cb); |
410 | 410 |
411 case kPlaying: | 411 case kPlaying: |
412 PlaybackRateChangedTask(GetPlaybackRate()); | 412 PlaybackRateChangedTask(GetPlaybackRate()); |
413 VolumeChangedTask(GetVolume()); | 413 VolumeChangedTask(GetVolume()); |
414 | 414 |
| 415 // Handle renderers that immediately signal they have enough data. |
| 416 if (!WaitingForEnoughData()) |
| 417 StartPlayback(); |
| 418 |
415 // We enter this state from either kInitPrerolling or kSeeking. As of now | 419 // We enter this state from either kInitPrerolling or kSeeking. As of now |
416 // both those states call Preroll(), which means by time we enter this | 420 // both those states call Preroll(), which means by time we enter this |
417 // state we've already buffered enough data. Forcefully update the | 421 // state we've already buffered enough data. Forcefully update the |
418 // buffering state, which start the clock and renderers and transition | 422 // buffering state, which start the clock and renderers and transition |
419 // into kPlaying state. | 423 // into kPlaying state. |
420 // | 424 // |
421 // TODO(scherkus): Remove after renderers are taught to fire buffering | 425 // TODO(scherkus): Remove after renderers are taught to fire buffering |
422 // state callbacks http://crbug.com/144683 | 426 // state callbacks http://crbug.com/144683 |
423 DCHECK(WaitingForEnoughData()); | 427 if (video_renderer_) { |
424 if (audio_renderer_) | 428 DCHECK(WaitingForEnoughData()); |
425 BufferingStateChanged(&audio_buffering_state_, BUFFERING_HAVE_ENOUGH); | |
426 if (video_renderer_) | |
427 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH); | 429 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH); |
| 430 } |
428 return; | 431 return; |
429 | 432 |
430 case kStopping: | 433 case kStopping: |
431 case kStopped: | 434 case kStopped: |
432 case kCreated: | 435 case kCreated: |
433 case kSeeking: | 436 case kSeeking: |
434 NOTREACHED() << "State has no transition: " << state_; | 437 NOTREACHED() << "State has no transition: " << state_; |
435 return; | 438 return; |
436 } | 439 } |
437 } | 440 } |
438 | 441 |
439 // Note that the usage of base::Unretained() with the audio/video renderers | 442 // Note that the usage of base::Unretained() with the audio/video renderers |
440 // in the following DoXXX() functions is considered safe as they are owned by | 443 // in the following DoXXX() functions is considered safe as they are owned by |
441 // |pending_callbacks_| and share the same lifetime. | 444 // |pending_callbacks_| and share the same lifetime. |
442 // | 445 // |
443 // That being said, deleting the renderers while keeping |pending_callbacks_| | 446 // That being said, deleting the renderers while keeping |pending_callbacks_| |
444 // running on the media thread would result in crashes. | 447 // running on the media thread would result in crashes. |
445 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) { | 448 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) { |
446 DCHECK(task_runner_->BelongsToCurrentThread()); | 449 DCHECK(task_runner_->BelongsToCurrentThread()); |
447 DCHECK(!pending_callbacks_.get()); | 450 DCHECK(!pending_callbacks_.get()); |
448 SerialRunner::Queue bound_fns; | 451 SerialRunner::Queue bound_fns; |
449 | 452 |
450 base::TimeDelta seek_timestamp = demuxer_->GetStartTime(); | 453 base::TimeDelta seek_timestamp = demuxer_->GetStartTime(); |
451 | 454 |
452 // Preroll renderers. | 455 // Preroll renderers. |
453 if (audio_renderer_) { | 456 if (audio_renderer_) { |
454 bound_fns.Push(base::Bind( | 457 bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom, |
455 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), | 458 base::Unretained(audio_renderer_.get()), |
456 seek_timestamp)); | 459 seek_timestamp)); |
457 } | 460 } |
458 | 461 |
459 if (video_renderer_) { | 462 if (video_renderer_) { |
460 bound_fns.Push(base::Bind( | 463 bound_fns.Push(base::Bind( |
461 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), | 464 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), |
462 seek_timestamp)); | 465 seek_timestamp)); |
463 | 466 |
464 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering | 467 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering |
465 // state callbacks http://crbug.com/144683 | 468 // state callbacks http://crbug.com/144683 |
466 bound_fns.Push(base::Bind(&VideoRenderer::Play, | 469 bound_fns.Push(base::Bind(&VideoRenderer::Play, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
515 bound_fns.Push(base::Bind( | 518 bound_fns.Push(base::Bind( |
516 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); | 519 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); |
517 } | 520 } |
518 | 521 |
519 // Seek demuxer. | 522 // Seek demuxer. |
520 bound_fns.Push(base::Bind( | 523 bound_fns.Push(base::Bind( |
521 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); | 524 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); |
522 | 525 |
523 // Preroll renderers. | 526 // Preroll renderers. |
524 if (audio_renderer_) { | 527 if (audio_renderer_) { |
525 bound_fns.Push(base::Bind( | 528 bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom, |
526 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), | 529 base::Unretained(audio_renderer_.get()), |
527 seek_timestamp)); | 530 seek_timestamp)); |
528 } | 531 } |
529 | 532 |
530 if (video_renderer_) { | 533 if (video_renderer_) { |
531 bound_fns.Push(base::Bind( | 534 bound_fns.Push(base::Bind( |
532 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), | 535 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), |
533 seek_timestamp)); | 536 seek_timestamp)); |
534 | 537 |
535 // TODO(scherkus): Remove after renderers are taught to fire buffering | 538 // TODO(scherkus): Remove after renderers are taught to fire buffering |
536 // state callbacks http://crbug.com/144683 | 539 // state callbacks http://crbug.com/144683 |
537 bound_fns.Push(base::Bind(&VideoRenderer::Play, | 540 bound_fns.Push(base::Bind(&VideoRenderer::Play, |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 } | 853 } |
851 | 854 |
852 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { | 855 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { |
853 DCHECK(task_runner_->BelongsToCurrentThread()); | 856 DCHECK(task_runner_->BelongsToCurrentThread()); |
854 | 857 |
855 audio_renderer_ = filter_collection_->GetAudioRenderer(); | 858 audio_renderer_ = filter_collection_->GetAudioRenderer(); |
856 audio_renderer_->Initialize( | 859 audio_renderer_->Initialize( |
857 demuxer_->GetStream(DemuxerStream::AUDIO), | 860 demuxer_->GetStream(DemuxerStream::AUDIO), |
858 done_cb, | 861 done_cb, |
859 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), | 862 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), |
860 base::Bind(&Pipeline::OnAudioUnderflow, base::Unretained(this)), | |
861 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), | 863 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), |
| 864 base::Bind(&Pipeline::BufferingStateChanged, base::Unretained(this), |
| 865 &audio_buffering_state_), |
862 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), | 866 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), |
863 base::Bind(&Pipeline::SetError, base::Unretained(this))); | 867 base::Bind(&Pipeline::SetError, base::Unretained(this))); |
864 } | 868 } |
865 | 869 |
866 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { | 870 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { |
867 DCHECK(task_runner_->BelongsToCurrentThread()); | 871 DCHECK(task_runner_->BelongsToCurrentThread()); |
868 | 872 |
869 video_renderer_ = filter_collection_->GetVideoRenderer(); | 873 video_renderer_ = filter_collection_->GetVideoRenderer(); |
870 video_renderer_->Initialize( | 874 video_renderer_->Initialize( |
871 demuxer_->GetStream(DemuxerStream::VIDEO), | 875 demuxer_->GetStream(DemuxerStream::VIDEO), |
872 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, | 876 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, |
873 done_cb, | 877 done_cb, |
874 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), | 878 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), |
875 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), | 879 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), |
876 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), | 880 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), |
877 base::Bind(&Pipeline::SetError, base::Unretained(this)), | 881 base::Bind(&Pipeline::SetError, base::Unretained(this)), |
878 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), | 882 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), |
879 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); | 883 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); |
880 } | 884 } |
881 | 885 |
882 void Pipeline::OnAudioUnderflow() { | |
883 if (!task_runner_->BelongsToCurrentThread()) { | |
884 task_runner_->PostTask(FROM_HERE, base::Bind( | |
885 &Pipeline::OnAudioUnderflow, base::Unretained(this))); | |
886 return; | |
887 } | |
888 | |
889 if (state_ != kPlaying) | |
890 return; | |
891 | |
892 if (audio_renderer_) | |
893 audio_renderer_->ResumeAfterUnderflow(); | |
894 } | |
895 | |
896 void Pipeline::BufferingStateChanged(BufferingState* buffering_state, | 886 void Pipeline::BufferingStateChanged(BufferingState* buffering_state, |
897 BufferingState new_buffering_state) { | 887 BufferingState new_buffering_state) { |
898 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 888 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " |
899 << " " << new_buffering_state << ") " | 889 << " " << new_buffering_state << ") " |
900 << (buffering_state == &audio_buffering_state_ ? "audio" : "video"); | 890 << (buffering_state == &audio_buffering_state_ ? "audio" : "video"); |
901 DCHECK(task_runner_->BelongsToCurrentThread()); | 891 DCHECK(task_runner_->BelongsToCurrentThread()); |
902 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 892 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
903 *buffering_state = new_buffering_state; | 893 *buffering_state = new_buffering_state; |
904 | 894 |
905 // Renderer underflowed. | 895 // Renderer underflowed. |
906 if (!was_waiting_for_enough_data && WaitingForEnoughData()) { | 896 if (!was_waiting_for_enough_data && WaitingForEnoughData()) { |
907 StartWaitingForEnoughData(); | 897 PausePlayback(); |
908 return; | 898 return; |
909 } | 899 } |
910 | 900 |
911 // Renderer prerolled. | 901 // Renderer prerolled. |
912 if (was_waiting_for_enough_data && !WaitingForEnoughData()) { | 902 if (was_waiting_for_enough_data && !WaitingForEnoughData()) { |
913 StartPlayback(); | 903 StartPlayback(); |
914 return; | 904 return; |
915 } | 905 } |
916 } | 906 } |
917 | 907 |
918 bool Pipeline::WaitingForEnoughData() const { | 908 bool Pipeline::WaitingForEnoughData() const { |
919 DCHECK(task_runner_->BelongsToCurrentThread()); | 909 DCHECK(task_runner_->BelongsToCurrentThread()); |
920 if (state_ != kPlaying) | 910 if (state_ != kPlaying) |
921 return false; | 911 return false; |
922 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) | 912 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) |
923 return true; | 913 return true; |
924 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) | 914 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) |
925 return true; | 915 return true; |
926 return false; | 916 return false; |
927 } | 917 } |
928 | 918 |
929 void Pipeline::StartWaitingForEnoughData() { | 919 void Pipeline::PausePlayback() { |
930 DVLOG(1) << __FUNCTION__; | 920 DVLOG(1) << __FUNCTION__; |
931 DCHECK_EQ(state_, kPlaying); | 921 DCHECK_EQ(state_, kPlaying); |
932 DCHECK(WaitingForEnoughData()); | 922 DCHECK(WaitingForEnoughData()); |
| 923 DCHECK(task_runner_->BelongsToCurrentThread()); |
933 | 924 |
934 if (audio_renderer_) | 925 if (audio_renderer_) |
935 audio_renderer_->StopRendering(); | 926 audio_renderer_->StopRendering(); |
936 | 927 |
937 base::AutoLock auto_lock(lock_); | 928 base::AutoLock auto_lock(lock_); |
938 clock_->Pause(); | 929 clock_->Pause(); |
939 } | 930 } |
940 | 931 |
941 void Pipeline::StartPlayback() { | 932 void Pipeline::StartPlayback() { |
942 DVLOG(1) << __FUNCTION__; | 933 DVLOG(1) << __FUNCTION__; |
943 DCHECK_EQ(state_, kPlaying); | 934 DCHECK_EQ(state_, kPlaying); |
944 DCHECK(!WaitingForEnoughData()); | 935 DCHECK(!WaitingForEnoughData()); |
| 936 DCHECK(task_runner_->BelongsToCurrentThread()); |
945 | 937 |
946 if (audio_renderer_) { | 938 if (audio_renderer_) { |
947 // We use audio stream to update the clock. So if there is such a | 939 // 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. | 940 // stream, we pause the clock until we receive a valid timestamp. |
949 base::AutoLock auto_lock(lock_); | 941 base::AutoLock auto_lock(lock_); |
950 waiting_for_clock_update_ = true; | 942 waiting_for_clock_update_ = true; |
951 audio_renderer_->StartRendering(); | 943 audio_renderer_->StartRendering(); |
952 } else { | 944 } else { |
953 base::AutoLock auto_lock(lock_); | 945 base::AutoLock auto_lock(lock_); |
954 DCHECK(!waiting_for_clock_update_); | 946 DCHECK(!waiting_for_clock_update_); |
955 clock_->SetMaxTime(clock_->Duration()); | 947 clock_->SetMaxTime(clock_->Duration()); |
956 clock_->Play(); | 948 clock_->Play(); |
957 } | 949 } |
958 | 950 |
959 preroll_completed_cb_.Run(); | 951 preroll_completed_cb_.Run(); |
960 if (!seek_cb_.is_null()) | 952 if (!seek_cb_.is_null()) |
961 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | 953 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
962 } | 954 } |
963 | 955 |
964 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 956 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
965 lock_.AssertAcquired(); | 957 lock_.AssertAcquired(); |
966 if (!waiting_for_clock_update_) | 958 if (!waiting_for_clock_update_) |
967 return; | 959 return; |
968 | 960 |
969 waiting_for_clock_update_ = false; | 961 waiting_for_clock_update_ = false; |
970 clock_->Play(); | 962 clock_->Play(); |
971 } | 963 } |
972 | 964 |
973 } // namespace media | 965 } // namespace media |
OLD | NEW |