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