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

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: rebase 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
« no previous file with comments | « media/base/pipeline.h ('k') | media/base/pipeline_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 metadata.natural_size = stream->video_decoder_config().natural_size(); 407 metadata.natural_size = stream->video_decoder_config().natural_size();
408 metadata_cb_.Run(metadata); 408 metadata_cb_.Run(metadata);
409 } 409 }
410 410
411 return DoInitialPreroll(done_cb); 411 return DoInitialPreroll(done_cb);
412 412
413 case kPlaying: 413 case kPlaying:
414 PlaybackRateChangedTask(GetPlaybackRate()); 414 PlaybackRateChangedTask(GetPlaybackRate());
415 VolumeChangedTask(GetVolume()); 415 VolumeChangedTask(GetVolume());
416 416
417 // Handle renderers that immediately signal they have enough data.
418 if (!WaitingForEnoughData())
419 StartPlayback();
420
417 // We enter this state from either kInitPrerolling or kSeeking. As of now 421 // We enter this state from either kInitPrerolling or kSeeking. As of now
418 // both those states call Preroll(), which means by time we enter this 422 // both those states call Preroll(), which means by time we enter this
419 // state we've already buffered enough data. Forcefully update the 423 // state we've already buffered enough data. Forcefully update the
420 // buffering state, which start the clock and renderers and transition 424 // buffering state, which start the clock and renderers and transition
421 // into kPlaying state. 425 // into kPlaying state.
422 // 426 //
423 // TODO(scherkus): Remove after renderers are taught to fire buffering 427 // TODO(scherkus): Remove after renderers are taught to fire buffering
424 // state callbacks http://crbug.com/144683 428 // state callbacks http://crbug.com/144683
425 DCHECK(WaitingForEnoughData()); 429 if (video_renderer_) {
426 if (audio_renderer_) 430 DCHECK(WaitingForEnoughData());
427 BufferingStateChanged(&audio_buffering_state_, BUFFERING_HAVE_ENOUGH);
428 if (video_renderer_)
429 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH); 431 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH);
432 }
430 return; 433 return;
431 434
432 case kStopping: 435 case kStopping:
433 case kStopped: 436 case kStopped:
434 case kCreated: 437 case kCreated:
435 case kSeeking: 438 case kSeeking:
436 NOTREACHED() << "State has no transition: " << state_; 439 NOTREACHED() << "State has no transition: " << state_;
437 return; 440 return;
438 } 441 }
439 } 442 }
440 443
441 // Note that the usage of base::Unretained() with the audio/video renderers 444 // Note that the usage of base::Unretained() with the audio/video renderers
442 // in the following DoXXX() functions is considered safe as they are owned by 445 // in the following DoXXX() functions is considered safe as they are owned by
443 // |pending_callbacks_| and share the same lifetime. 446 // |pending_callbacks_| and share the same lifetime.
444 // 447 //
445 // That being said, deleting the renderers while keeping |pending_callbacks_| 448 // That being said, deleting the renderers while keeping |pending_callbacks_|
446 // running on the media thread would result in crashes. 449 // running on the media thread would result in crashes.
447 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) { 450 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) {
448 DCHECK(task_runner_->BelongsToCurrentThread()); 451 DCHECK(task_runner_->BelongsToCurrentThread());
449 DCHECK(!pending_callbacks_.get()); 452 DCHECK(!pending_callbacks_.get());
450 SerialRunner::Queue bound_fns; 453 SerialRunner::Queue bound_fns;
451 454
452 base::TimeDelta seek_timestamp = demuxer_->GetStartTime(); 455 base::TimeDelta seek_timestamp = demuxer_->GetStartTime();
453 456
454 // Preroll renderers. 457 // Preroll renderers.
455 if (audio_renderer_) { 458 if (audio_renderer_) {
456 bound_fns.Push(base::Bind( 459 bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom,
457 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), 460 base::Unretained(audio_renderer_.get()),
458 seek_timestamp)); 461 seek_timestamp));
459 } 462 }
460 463
461 if (video_renderer_) { 464 if (video_renderer_) {
462 bound_fns.Push(base::Bind( 465 bound_fns.Push(base::Bind(
463 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), 466 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()),
464 seek_timestamp)); 467 seek_timestamp));
465 468
466 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering 469 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering
467 // state callbacks http://crbug.com/144683 470 // state callbacks http://crbug.com/144683
468 bound_fns.Push(base::Bind(&VideoRenderer::Play, 471 bound_fns.Push(base::Bind(&VideoRenderer::Play,
469 base::Unretained(video_renderer_.get()))); 472 base::Unretained(video_renderer_.get())));
470 } 473 }
471 474
472 if (text_renderer_) { 475 if (text_renderer_) {
473 bound_fns.Push(base::Bind( 476 bound_fns.Push(base::Bind(
474 &TextRenderer::Play, base::Unretained(text_renderer_.get()))); 477 &TextRenderer::Play, base::Unretained(text_renderer_.get())));
475 } 478 }
476 479
477 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 480 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
478 } 481 }
479 482
483 #if DCHECK_IS_ON
484 static void VerifyBufferingStates(BufferingState* audio_buffering_state,
485 BufferingState* video_buffering_state) {
486 DCHECK_EQ(*audio_buffering_state, BUFFERING_HAVE_NOTHING);
487 DCHECK_EQ(*video_buffering_state, BUFFERING_HAVE_NOTHING);
488 }
489 #endif
490
480 void Pipeline::DoSeek( 491 void Pipeline::DoSeek(
481 base::TimeDelta seek_timestamp, 492 base::TimeDelta seek_timestamp,
482 const PipelineStatusCB& done_cb) { 493 const PipelineStatusCB& done_cb) {
483 DCHECK(task_runner_->BelongsToCurrentThread()); 494 DCHECK(task_runner_->BelongsToCurrentThread());
484 DCHECK(!pending_callbacks_.get()); 495 DCHECK(!pending_callbacks_.get());
485 SerialRunner::Queue bound_fns; 496 SerialRunner::Queue bound_fns;
486 497
487 // Pause. 498 // Pause.
488 if (text_renderer_) { 499 if (text_renderer_) {
489 bound_fns.Push(base::Bind( 500 bound_fns.Push(base::Bind(
490 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); 501 &TextRenderer::Pause, base::Unretained(text_renderer_.get())));
491 } 502 }
492 503
493 // Flush. 504 // Flush.
494 if (audio_renderer_) { 505 if (audio_renderer_) {
495 bound_fns.Push(base::Bind( 506 bound_fns.Push(base::Bind(
496 &AudioRenderer::Flush, base::Unretained(audio_renderer_.get()))); 507 &AudioRenderer::Flush, base::Unretained(audio_renderer_.get())));
508 }
497 509
498 // TODO(scherkus): Remove after AudioRenderer is taught to fire buffering
499 // state callbacks http://crbug.com/144683
500 bound_fns.Push(base::Bind(&Pipeline::BufferingStateChanged,
501 base::Unretained(this),
502 &audio_buffering_state_,
503 BUFFERING_HAVE_NOTHING));
504 }
505 if (video_renderer_) { 510 if (video_renderer_) {
506 bound_fns.Push(base::Bind( 511 bound_fns.Push(base::Bind(
507 &VideoRenderer::Flush, base::Unretained(video_renderer_.get()))); 512 &VideoRenderer::Flush, base::Unretained(video_renderer_.get())));
508 513
509 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering 514 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering
510 // state callbacks http://crbug.com/144683 515 // state callbacks http://crbug.com/144683
511 bound_fns.Push(base::Bind(&Pipeline::BufferingStateChanged, 516 bound_fns.Push(base::Bind(&Pipeline::BufferingStateChanged,
512 base::Unretained(this), 517 base::Unretained(this),
513 &video_buffering_state_, 518 &video_buffering_state_,
514 BUFFERING_HAVE_NOTHING)); 519 BUFFERING_HAVE_NOTHING));
515 } 520 }
521
522 #if DCHECK_IS_ON
523 // Verify renderers reset their buffering states.
524 bound_fns.Push(base::Bind(&VerifyBufferingStates,
525 &audio_buffering_state_,
526 &video_buffering_state_));
527 #endif
528
516 if (text_renderer_) { 529 if (text_renderer_) {
517 bound_fns.Push(base::Bind( 530 bound_fns.Push(base::Bind(
518 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); 531 &TextRenderer::Flush, base::Unretained(text_renderer_.get())));
519 } 532 }
520 533
521 // Seek demuxer. 534 // Seek demuxer.
522 bound_fns.Push(base::Bind( 535 bound_fns.Push(base::Bind(
523 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); 536 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
524 537
525 // Preroll renderers. 538 // Preroll renderers.
526 if (audio_renderer_) { 539 if (audio_renderer_) {
527 bound_fns.Push(base::Bind( 540 bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom,
528 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), 541 base::Unretained(audio_renderer_.get()),
529 seek_timestamp)); 542 seek_timestamp));
530 } 543 }
531 544
532 if (video_renderer_) { 545 if (video_renderer_) {
533 bound_fns.Push(base::Bind( 546 bound_fns.Push(base::Bind(
534 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), 547 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()),
535 seek_timestamp)); 548 seek_timestamp));
536 549
537 // TODO(scherkus): Remove after renderers are taught to fire buffering 550 // TODO(scherkus): Remove after renderers are taught to fire buffering
538 // state callbacks http://crbug.com/144683 551 // state callbacks http://crbug.com/144683
539 bound_fns.Push(base::Bind(&VideoRenderer::Play, 552 bound_fns.Push(base::Bind(&VideoRenderer::Play,
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 } 862 }
850 863
851 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { 864 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) {
852 DCHECK(task_runner_->BelongsToCurrentThread()); 865 DCHECK(task_runner_->BelongsToCurrentThread());
853 866
854 audio_renderer_ = filter_collection_->GetAudioRenderer(); 867 audio_renderer_ = filter_collection_->GetAudioRenderer();
855 audio_renderer_->Initialize( 868 audio_renderer_->Initialize(
856 demuxer_->GetStream(DemuxerStream::AUDIO), 869 demuxer_->GetStream(DemuxerStream::AUDIO),
857 done_cb, 870 done_cb,
858 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), 871 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)),
859 base::Bind(&Pipeline::OnAudioUnderflow, base::Unretained(this)),
860 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), 872 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)),
873 base::Bind(&Pipeline::BufferingStateChanged, base::Unretained(this),
874 &audio_buffering_state_),
861 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), 875 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)),
862 base::Bind(&Pipeline::SetError, base::Unretained(this))); 876 base::Bind(&Pipeline::SetError, base::Unretained(this)));
863 } 877 }
864 878
865 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { 879 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) {
866 DCHECK(task_runner_->BelongsToCurrentThread()); 880 DCHECK(task_runner_->BelongsToCurrentThread());
867 881
868 video_renderer_ = filter_collection_->GetVideoRenderer(); 882 video_renderer_ = filter_collection_->GetVideoRenderer();
869 video_renderer_->Initialize( 883 video_renderer_->Initialize(
870 demuxer_->GetStream(DemuxerStream::VIDEO), 884 demuxer_->GetStream(DemuxerStream::VIDEO),
871 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, 885 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE,
872 done_cb, 886 done_cb,
873 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), 887 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)),
874 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), 888 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)),
875 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), 889 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)),
876 base::Bind(&Pipeline::SetError, base::Unretained(this)), 890 base::Bind(&Pipeline::SetError, base::Unretained(this)),
877 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), 891 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)),
878 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); 892 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this)));
879 } 893 }
880 894
881 void Pipeline::OnAudioUnderflow() {
882 if (!task_runner_->BelongsToCurrentThread()) {
883 task_runner_->PostTask(FROM_HERE, base::Bind(
884 &Pipeline::OnAudioUnderflow, base::Unretained(this)));
885 return;
886 }
887
888 if (state_ != kPlaying)
889 return;
890
891 if (audio_renderer_)
892 audio_renderer_->ResumeAfterUnderflow();
893 }
894
895 void Pipeline::BufferingStateChanged(BufferingState* buffering_state, 895 void Pipeline::BufferingStateChanged(BufferingState* buffering_state,
896 BufferingState new_buffering_state) { 896 BufferingState new_buffering_state) {
897 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " 897 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", "
898 << " " << new_buffering_state << ") " 898 << " " << new_buffering_state << ") "
899 << (buffering_state == &audio_buffering_state_ ? "audio" : "video"); 899 << (buffering_state == &audio_buffering_state_ ? "audio" : "video");
900 DCHECK(task_runner_->BelongsToCurrentThread()); 900 DCHECK(task_runner_->BelongsToCurrentThread());
901 bool was_waiting_for_enough_data = WaitingForEnoughData(); 901 bool was_waiting_for_enough_data = WaitingForEnoughData();
902 *buffering_state = new_buffering_state; 902 *buffering_state = new_buffering_state;
903 903
904 // Renderer underflowed. 904 // Renderer underflowed.
905 if (!was_waiting_for_enough_data && WaitingForEnoughData()) { 905 if (!was_waiting_for_enough_data && WaitingForEnoughData()) {
906 StartWaitingForEnoughData(); 906 PausePlayback();
907 return; 907 return;
908 } 908 }
909 909
910 // Renderer prerolled. 910 // Renderer prerolled.
911 if (was_waiting_for_enough_data && !WaitingForEnoughData()) { 911 if (was_waiting_for_enough_data && !WaitingForEnoughData()) {
912 StartPlayback(); 912 StartPlayback();
913 return; 913 return;
914 } 914 }
915 } 915 }
916 916
917 bool Pipeline::WaitingForEnoughData() const { 917 bool Pipeline::WaitingForEnoughData() const {
918 DCHECK(task_runner_->BelongsToCurrentThread()); 918 DCHECK(task_runner_->BelongsToCurrentThread());
919 if (state_ != kPlaying) 919 if (state_ != kPlaying)
920 return false; 920 return false;
921 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH) 921 if (audio_renderer_ && audio_buffering_state_ != BUFFERING_HAVE_ENOUGH)
922 return true; 922 return true;
923 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH) 923 if (video_renderer_ && video_buffering_state_ != BUFFERING_HAVE_ENOUGH)
924 return true; 924 return true;
925 return false; 925 return false;
926 } 926 }
927 927
928 void Pipeline::StartWaitingForEnoughData() { 928 void Pipeline::PausePlayback() {
929 DVLOG(1) << __FUNCTION__; 929 DVLOG(1) << __FUNCTION__;
930 DCHECK_EQ(state_, kPlaying); 930 DCHECK_EQ(state_, kPlaying);
931 DCHECK(WaitingForEnoughData()); 931 DCHECK(WaitingForEnoughData());
932 DCHECK(task_runner_->BelongsToCurrentThread());
932 933
933 base::AutoLock auto_lock(lock_); 934 base::AutoLock auto_lock(lock_);
934 PauseClockAndStopRendering_Locked(); 935 PauseClockAndStopRendering_Locked();
935 } 936 }
936 937
937 void Pipeline::StartPlayback() { 938 void Pipeline::StartPlayback() {
938 DVLOG(1) << __FUNCTION__; 939 DVLOG(1) << __FUNCTION__;
939 DCHECK_EQ(state_, kPlaying); 940 DCHECK_EQ(state_, kPlaying);
940 DCHECK_EQ(clock_state_, CLOCK_PAUSED); 941 DCHECK_EQ(clock_state_, CLOCK_PAUSED);
941 DCHECK(!WaitingForEnoughData()); 942 DCHECK(!WaitingForEnoughData());
943 DCHECK(task_runner_->BelongsToCurrentThread());
942 944
943 if (audio_renderer_) { 945 if (audio_renderer_) {
944 // We use audio stream to update the clock. So if there is such a 946 // We use audio stream to update the clock. So if there is such a
945 // stream, we pause the clock until we receive a valid timestamp. 947 // stream, we pause the clock until we receive a valid timestamp.
946 base::AutoLock auto_lock(lock_); 948 base::AutoLock auto_lock(lock_);
947 clock_state_ = CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE; 949 clock_state_ = CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE;
948 audio_renderer_->StartRendering(); 950 audio_renderer_->StartRendering();
949 } else { 951 } else {
950 base::AutoLock auto_lock(lock_); 952 base::AutoLock auto_lock(lock_);
951 clock_state_ = CLOCK_PLAYING; 953 clock_state_ = CLOCK_PLAYING;
(...skipping 29 matching lines...) Expand all
981 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { 983 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() {
982 lock_.AssertAcquired(); 984 lock_.AssertAcquired();
983 if (clock_state_ != CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE) 985 if (clock_state_ != CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE)
984 return; 986 return;
985 987
986 clock_state_ = CLOCK_PLAYING; 988 clock_state_ = CLOCK_PLAYING;
987 clock_->Play(); 989 clock_->Play();
988 } 990 }
989 991
990 } // namespace media 992 } // namespace media
OLDNEW
« no previous file with comments | « media/base/pipeline.h ('k') | media/base/pipeline_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698