Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: media/base/pipeline.cc

Issue 284763002: Update AudioRenderer API to fire changes in BufferingState. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/bind_to_current_loop.h"
22 #include "media/base/clock.h" 23 #include "media/base/clock.h"
23 #include "media/base/filter_collection.h" 24 #include "media/base/filter_collection.h"
24 #include "media/base/media_log.h" 25 #include "media/base/media_log.h"
25 #include "media/base/text_renderer.h" 26 #include "media/base/text_renderer.h"
26 #include "media/base/text_track_config.h" 27 #include "media/base/text_track_config.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;
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 metadata.natural_size = stream->video_decoder_config().natural_size(); 406 metadata.natural_size = stream->video_decoder_config().natural_size();
406 metadata_cb_.Run(metadata); 407 metadata_cb_.Run(metadata);
407 } 408 }
408 409
409 return DoInitialPreroll(done_cb); 410 return DoInitialPreroll(done_cb);
410 411
411 case kPlaying: 412 case kPlaying:
412 PlaybackRateChangedTask(GetPlaybackRate()); 413 PlaybackRateChangedTask(GetPlaybackRate());
413 VolumeChangedTask(GetVolume()); 414 VolumeChangedTask(GetVolume());
414 415
416 // Handle renderers that immediately signal they have enough data.
417 if (!WaitingForEnoughData())
418 TransitionToNonWaiting();
419
415 // We enter this state from either kInitPrerolling or kSeeking. As of now 420 // 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 421 // both those states call Preroll(), which means by time we enter this
417 // state we've already buffered enough data. Forcefully update the 422 // state we've already buffered enough data. Forcefully update the
418 // buffering state, which start the clock and renderers and transition 423 // buffering state, which start the clock and renderers and transition
419 // into kPlaying state. 424 // into kPlaying state.
420 // 425 //
421 // TODO(scherkus): Remove after renderers are taught to fire buffering 426 // TODO(scherkus): Remove after renderers are taught to fire buffering
422 // state callbacks http://crbug.com/144683 427 // state callbacks http://crbug.com/144683
423 DCHECK(WaitingForEnoughData()); 428 if (video_renderer_) {
424 if (audio_renderer_) 429 DCHECK(WaitingForEnoughData());
425 BufferingStateChanged(&audio_buffering_state_, BUFFERING_HAVE_ENOUGH);
426 if (video_renderer_)
427 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH); 430 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH);
431 }
428 return; 432 return;
429 433
430 case kStopping: 434 case kStopping:
431 case kStopped: 435 case kStopped:
432 case kCreated: 436 case kCreated:
433 case kSeeking: 437 case kSeeking:
434 NOTREACHED() << "State has no transition: " << state_; 438 NOTREACHED() << "State has no transition: " << state_;
435 return; 439 return;
436 } 440 }
437 } 441 }
438 442
439 // Note that the usage of base::Unretained() with the audio/video renderers 443 // 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 444 // in the following DoXXX() functions is considered safe as they are owned by
441 // |pending_callbacks_| and share the same lifetime. 445 // |pending_callbacks_| and share the same lifetime.
442 // 446 //
443 // That being said, deleting the renderers while keeping |pending_callbacks_| 447 // That being said, deleting the renderers while keeping |pending_callbacks_|
444 // running on the media thread would result in crashes. 448 // running on the media thread would result in crashes.
445 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) { 449 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) {
446 DCHECK(task_runner_->BelongsToCurrentThread()); 450 DCHECK(task_runner_->BelongsToCurrentThread());
447 DCHECK(!pending_callbacks_.get()); 451 DCHECK(!pending_callbacks_.get());
448 SerialRunner::Queue bound_fns; 452 SerialRunner::Queue bound_fns;
449 453
450 base::TimeDelta seek_timestamp = demuxer_->GetStartTime(); 454 base::TimeDelta seek_timestamp = demuxer_->GetStartTime();
451 455
452 // Preroll renderers. 456 // Preroll renderers.
453 if (audio_renderer_) { 457 if (audio_renderer_) {
454 bound_fns.Push(base::Bind( 458 bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom,
455 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), 459 base::Unretained(audio_renderer_.get()),
456 seek_timestamp)); 460 seek_timestamp));
457 } 461 }
458 462
459 if (video_renderer_) { 463 if (video_renderer_) {
460 bound_fns.Push(base::Bind( 464 bound_fns.Push(base::Bind(
461 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), 465 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()),
462 seek_timestamp)); 466 seek_timestamp));
463 467
464 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering 468 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering
465 // state callbacks http://crbug.com/144683 469 // state callbacks http://crbug.com/144683
466 bound_fns.Push(base::Bind(&VideoRenderer::Play, 470 bound_fns.Push(base::Bind(&VideoRenderer::Play,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 bound_fns.Push(base::Bind( 519 bound_fns.Push(base::Bind(
516 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); 520 &TextRenderer::Flush, base::Unretained(text_renderer_.get())));
517 } 521 }
518 522
519 // Seek demuxer. 523 // Seek demuxer.
520 bound_fns.Push(base::Bind( 524 bound_fns.Push(base::Bind(
521 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); 525 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
522 526
523 // Preroll renderers. 527 // Preroll renderers.
524 if (audio_renderer_) { 528 if (audio_renderer_) {
525 bound_fns.Push(base::Bind( 529 bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom,
526 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), 530 base::Unretained(audio_renderer_.get()),
527 seek_timestamp)); 531 seek_timestamp));
528 } 532 }
529 533
530 if (video_renderer_) { 534 if (video_renderer_) {
531 bound_fns.Push(base::Bind( 535 bound_fns.Push(base::Bind(
532 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), 536 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()),
533 seek_timestamp)); 537 seek_timestamp));
534 538
535 // TODO(scherkus): Remove after renderers are taught to fire buffering 539 // TODO(scherkus): Remove after renderers are taught to fire buffering
536 // state callbacks http://crbug.com/144683 540 // state callbacks http://crbug.com/144683
537 bound_fns.Push(base::Bind(&VideoRenderer::Play, 541 bound_fns.Push(base::Bind(&VideoRenderer::Play,
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 } 854 }
851 855
852 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { 856 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) {
853 DCHECK(task_runner_->BelongsToCurrentThread()); 857 DCHECK(task_runner_->BelongsToCurrentThread());
854 858
855 audio_renderer_ = filter_collection_->GetAudioRenderer(); 859 audio_renderer_ = filter_collection_->GetAudioRenderer();
856 audio_renderer_->Initialize( 860 audio_renderer_->Initialize(
857 demuxer_->GetStream(DemuxerStream::AUDIO), 861 demuxer_->GetStream(DemuxerStream::AUDIO),
858 done_cb, 862 done_cb,
859 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), 863 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)),
860 base::Bind(&Pipeline::OnAudioUnderflow, base::Unretained(this)),
861 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), 864 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)),
865 // TODO(scherkus): Enforce AudioRendererImpl to call on right thread.
866 BindToCurrentLoop(base::Bind(&Pipeline::BufferingStateChanged,
acolwell GONE FROM CHROMIUM 2014/05/13 20:44:27 nit: Shouldn't we hide this wrapping in the AudioR
scherkus (not reviewing) 2014/05/15 23:28:43 Done.
867 base::Unretained(this),
868 &audio_buffering_state_)),
862 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), 869 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)),
863 base::Bind(&Pipeline::SetError, base::Unretained(this))); 870 base::Bind(&Pipeline::SetError, base::Unretained(this)));
864 } 871 }
865 872
866 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { 873 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) {
867 DCHECK(task_runner_->BelongsToCurrentThread()); 874 DCHECK(task_runner_->BelongsToCurrentThread());
868 875
869 video_renderer_ = filter_collection_->GetVideoRenderer(); 876 video_renderer_ = filter_collection_->GetVideoRenderer();
870 video_renderer_->Initialize( 877 video_renderer_->Initialize(
871 demuxer_->GetStream(DemuxerStream::VIDEO), 878 demuxer_->GetStream(DemuxerStream::VIDEO),
872 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, 879 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE,
873 done_cb, 880 done_cb,
874 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), 881 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)),
875 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), 882 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)),
876 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), 883 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)),
877 base::Bind(&Pipeline::SetError, base::Unretained(this)), 884 base::Bind(&Pipeline::SetError, base::Unretained(this)),
878 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), 885 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)),
879 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); 886 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this)));
880 } 887 }
881 888
882 void Pipeline::OnAudioUnderflow() {
883 if (!task_runner_->BelongsToCurrentThread()) {
acolwell GONE FROM CHROMIUM 2014/05/13 20:44:27 \o/ I'm happy to see this method die. It lived WAY
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, 889 void Pipeline::BufferingStateChanged(BufferingState* buffering_state,
897 BufferingState new_buffering_state) { 890 BufferingState new_buffering_state) {
898 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " 891 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", "
899 << " " << new_buffering_state << ") " 892 << " " << new_buffering_state << ") "
900 << (buffering_state == &audio_buffering_state_ ? "audio" : "video"); 893 << (buffering_state == &audio_buffering_state_ ? "audio" : "video");
901 DCHECK(task_runner_->BelongsToCurrentThread()); 894 DCHECK(task_runner_->BelongsToCurrentThread());
902 bool was_waiting_for_enough_data = WaitingForEnoughData(); 895 bool was_waiting_for_enough_data = WaitingForEnoughData();
903 *buffering_state = new_buffering_state; 896 *buffering_state = new_buffering_state;
904 897
905 // Renderer underflowed. 898 // Renderer underflowed.
906 if (!was_waiting_for_enough_data && WaitingForEnoughData()) { 899 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
907 StartWaitingForEnoughData(); 900 TransitionToWaiting();
908 return; 901 return;
909 } 902 }
910 903
911 // Renderer prerolled. 904 // Renderer prerolled.
912 if (was_waiting_for_enough_data && !WaitingForEnoughData()) { 905 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
913 StartPlayback(); 906 TransitionToNonWaiting();
914 return; 907 return;
915 } 908 }
916 } 909 }
917 910
918 bool Pipeline::WaitingForEnoughData() const { 911 bool Pipeline::WaitingForEnoughData() const {
919 DCHECK(task_runner_->BelongsToCurrentThread()); 912 DCHECK(task_runner_->BelongsToCurrentThread());
920 if (state_ != kPlaying) 913 if (state_ != kPlaying)
921 return false; 914 return false;
922 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) 915 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
923 return true; 916 return true;
924 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) 917 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
925 return true; 918 return true;
926 return false; 919 return false;
927 } 920 }
928 921
929 void Pipeline::StartWaitingForEnoughData() { 922 void Pipeline::TransitionToWaiting() {
930 DVLOG(1) << __FUNCTION__; 923 DVLOG(1) << __FUNCTION__;
931 DCHECK_EQ(state_, kPlaying); 924 DCHECK_EQ(state_, kPlaying);
932 DCHECK(WaitingForEnoughData()); 925 DCHECK(WaitingForEnoughData());
926 task_runner_->PostTask(
927 FROM_HERE, base::Bind(&Pipeline::PausePlayback, base::Unretained(this)));
928 }
929
930 void Pipeline::TransitionToNonWaiting() {
931 DVLOG(1) << __FUNCTION__;
932 DCHECK_EQ(state_, kPlaying);
933 DCHECK(!WaitingForEnoughData());
934 task_runner_->PostTask(
acolwell GONE FROM CHROMIUM 2014/05/13 20:44:27 Why do you need to PostTask() here and above now?
scherkus (not reviewing) 2014/05/15 23:28:43 it's to avoid reentrancy into renderers ... but I
935 FROM_HERE, base::Bind(&Pipeline::StartPlayback, base::Unretained(this)));
936 }
937
938 void Pipeline::PausePlayback() {
939 DVLOG(1) << __FUNCTION__;
940 DCHECK(task_runner_->BelongsToCurrentThread());
933 941
934 if (audio_renderer_) 942 if (audio_renderer_)
935 audio_renderer_->StopRendering(); 943 audio_renderer_->StopRendering();
936 944
937 base::AutoLock auto_lock(lock_); 945 base::AutoLock auto_lock(lock_);
938 clock_->Pause(); 946 clock_->Pause();
939 } 947 }
940 948
941 void Pipeline::StartPlayback() { 949 void Pipeline::StartPlayback() {
942 DVLOG(1) << __FUNCTION__; 950 DVLOG(1) << __FUNCTION__;
943 DCHECK_EQ(state_, kPlaying); 951 DCHECK(task_runner_->BelongsToCurrentThread());
944 DCHECK(!WaitingForEnoughData());
945 952
946 if (audio_renderer_) { 953 if (audio_renderer_) {
947 // We use audio stream to update the clock. So if there is such a 954 // 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. 955 // stream, we pause the clock until we receive a valid timestamp.
949 base::AutoLock auto_lock(lock_); 956 base::AutoLock auto_lock(lock_);
950 waiting_for_clock_update_ = true; 957 waiting_for_clock_update_ = true;
951 audio_renderer_->StartRendering(); 958 audio_renderer_->StartRendering();
952 } else { 959 } else {
953 base::AutoLock auto_lock(lock_); 960 base::AutoLock auto_lock(lock_);
954 DCHECK(!waiting_for_clock_update_); 961 DCHECK(!waiting_for_clock_update_);
955 clock_->SetMaxTime(clock_->Duration()); 962 clock_->SetMaxTime(clock_->Duration());
956 clock_->Play(); 963 clock_->Play();
957 } 964 }
958 965
959 preroll_completed_cb_.Run(); 966 preroll_completed_cb_.Run();
960 if (!seek_cb_.is_null()) 967 if (!seek_cb_.is_null())
961 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 968 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
962 } 969 }
963 970
964 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { 971 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() {
965 lock_.AssertAcquired(); 972 lock_.AssertAcquired();
966 if (!waiting_for_clock_update_) 973 if (!waiting_for_clock_update_)
967 return; 974 return;
968 975
969 waiting_for_clock_update_ = false; 976 waiting_for_clock_update_ = false;
970 clock_->Play(); 977 clock_->Play();
971 } 978 }
972 979
973 } // namespace media 980 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698