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 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 | |
421 // We enter this state from either kInitPrerolling or kSeeking. As of now | 417 // We enter this state from either kInitPrerolling or kSeeking. As of now |
422 // both those states call Preroll(), which means by time we enter this | 418 // both those states call Preroll(), which means by time we enter this |
423 // state we've already buffered enough data. Forcefully update the | 419 // state we've already buffered enough data. Forcefully update the |
424 // buffering state, which start the clock and renderers and transition | 420 // buffering state, which start the clock and renderers and transition |
425 // into kPlaying state. | 421 // into kPlaying state. |
426 // | 422 // |
427 // TODO(scherkus): Remove after renderers are taught to fire buffering | 423 // TODO(scherkus): Remove after renderers are taught to fire buffering |
428 // state callbacks http://crbug.com/144683 | 424 // state callbacks http://crbug.com/144683 |
429 if (video_renderer_) { | 425 DCHECK(WaitingForEnoughData()); |
430 DCHECK(WaitingForEnoughData()); | 426 if (audio_renderer_) |
| 427 BufferingStateChanged(&audio_buffering_state_, BUFFERING_HAVE_ENOUGH); |
| 428 if (video_renderer_) |
431 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH); | 429 BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH); |
432 } | |
433 return; | 430 return; |
434 | 431 |
435 case kStopping: | 432 case kStopping: |
436 case kStopped: | 433 case kStopped: |
437 case kCreated: | 434 case kCreated: |
438 case kSeeking: | 435 case kSeeking: |
439 NOTREACHED() << "State has no transition: " << state_; | 436 NOTREACHED() << "State has no transition: " << state_; |
440 return; | 437 return; |
441 } | 438 } |
442 } | 439 } |
443 | 440 |
444 // Note that the usage of base::Unretained() with the audio/video renderers | 441 // Note that the usage of base::Unretained() with the audio/video renderers |
445 // in the following DoXXX() functions is considered safe as they are owned by | 442 // in the following DoXXX() functions is considered safe as they are owned by |
446 // |pending_callbacks_| and share the same lifetime. | 443 // |pending_callbacks_| and share the same lifetime. |
447 // | 444 // |
448 // That being said, deleting the renderers while keeping |pending_callbacks_| | 445 // That being said, deleting the renderers while keeping |pending_callbacks_| |
449 // running on the media thread would result in crashes. | 446 // running on the media thread would result in crashes. |
450 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) { | 447 void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) { |
451 DCHECK(task_runner_->BelongsToCurrentThread()); | 448 DCHECK(task_runner_->BelongsToCurrentThread()); |
452 DCHECK(!pending_callbacks_.get()); | 449 DCHECK(!pending_callbacks_.get()); |
453 SerialRunner::Queue bound_fns; | 450 SerialRunner::Queue bound_fns; |
454 | 451 |
455 base::TimeDelta seek_timestamp = demuxer_->GetStartTime(); | 452 base::TimeDelta seek_timestamp = demuxer_->GetStartTime(); |
456 | 453 |
457 // Preroll renderers. | 454 // Preroll renderers. |
458 if (audio_renderer_) { | 455 if (audio_renderer_) { |
459 bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom, | 456 bound_fns.Push(base::Bind( |
460 base::Unretained(audio_renderer_.get()), | 457 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), |
461 seek_timestamp)); | 458 seek_timestamp)); |
462 } | 459 } |
463 | 460 |
464 if (video_renderer_) { | 461 if (video_renderer_) { |
465 bound_fns.Push(base::Bind( | 462 bound_fns.Push(base::Bind( |
466 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), | 463 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), |
467 seek_timestamp)); | 464 seek_timestamp)); |
468 | 465 |
469 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering | 466 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering |
470 // state callbacks http://crbug.com/144683 | 467 // state callbacks http://crbug.com/144683 |
471 bound_fns.Push(base::Bind(&VideoRenderer::Play, | 468 bound_fns.Push(base::Bind(&VideoRenderer::Play, |
472 base::Unretained(video_renderer_.get()))); | 469 base::Unretained(video_renderer_.get()))); |
473 } | 470 } |
474 | 471 |
475 if (text_renderer_) { | 472 if (text_renderer_) { |
476 bound_fns.Push(base::Bind( | 473 bound_fns.Push(base::Bind( |
477 &TextRenderer::Play, base::Unretained(text_renderer_.get()))); | 474 &TextRenderer::Play, base::Unretained(text_renderer_.get()))); |
478 } | 475 } |
479 | 476 |
480 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); | 477 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); |
481 } | 478 } |
482 | 479 |
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 | |
491 void Pipeline::DoSeek( | 480 void Pipeline::DoSeek( |
492 base::TimeDelta seek_timestamp, | 481 base::TimeDelta seek_timestamp, |
493 const PipelineStatusCB& done_cb) { | 482 const PipelineStatusCB& done_cb) { |
494 DCHECK(task_runner_->BelongsToCurrentThread()); | 483 DCHECK(task_runner_->BelongsToCurrentThread()); |
495 DCHECK(!pending_callbacks_.get()); | 484 DCHECK(!pending_callbacks_.get()); |
496 SerialRunner::Queue bound_fns; | 485 SerialRunner::Queue bound_fns; |
497 | 486 |
498 // Pause. | 487 // Pause. |
499 if (text_renderer_) { | 488 if (text_renderer_) { |
500 bound_fns.Push(base::Bind( | 489 bound_fns.Push(base::Bind( |
501 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); | 490 &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); |
502 } | 491 } |
503 | 492 |
504 // Flush. | 493 // Flush. |
505 if (audio_renderer_) { | 494 if (audio_renderer_) { |
506 bound_fns.Push(base::Bind( | 495 bound_fns.Push(base::Bind( |
507 &AudioRenderer::Flush, base::Unretained(audio_renderer_.get()))); | 496 &AudioRenderer::Flush, base::Unretained(audio_renderer_.get()))); |
| 497 |
| 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)); |
508 } | 504 } |
509 | |
510 if (video_renderer_) { | 505 if (video_renderer_) { |
511 bound_fns.Push(base::Bind( | 506 bound_fns.Push(base::Bind( |
512 &VideoRenderer::Flush, base::Unretained(video_renderer_.get()))); | 507 &VideoRenderer::Flush, base::Unretained(video_renderer_.get()))); |
513 | 508 |
514 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering | 509 // TODO(scherkus): Remove after VideoRenderer is taught to fire buffering |
515 // state callbacks http://crbug.com/144683 | 510 // state callbacks http://crbug.com/144683 |
516 bound_fns.Push(base::Bind(&Pipeline::BufferingStateChanged, | 511 bound_fns.Push(base::Bind(&Pipeline::BufferingStateChanged, |
517 base::Unretained(this), | 512 base::Unretained(this), |
518 &video_buffering_state_, | 513 &video_buffering_state_, |
519 BUFFERING_HAVE_NOTHING)); | 514 BUFFERING_HAVE_NOTHING)); |
520 } | 515 } |
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 | |
529 if (text_renderer_) { | 516 if (text_renderer_) { |
530 bound_fns.Push(base::Bind( | 517 bound_fns.Push(base::Bind( |
531 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); | 518 &TextRenderer::Flush, base::Unretained(text_renderer_.get()))); |
532 } | 519 } |
533 | 520 |
534 // Seek demuxer. | 521 // Seek demuxer. |
535 bound_fns.Push(base::Bind( | 522 bound_fns.Push(base::Bind( |
536 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); | 523 &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); |
537 | 524 |
538 // Preroll renderers. | 525 // Preroll renderers. |
539 if (audio_renderer_) { | 526 if (audio_renderer_) { |
540 bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom, | 527 bound_fns.Push(base::Bind( |
541 base::Unretained(audio_renderer_.get()), | 528 &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), |
542 seek_timestamp)); | 529 seek_timestamp)); |
543 } | 530 } |
544 | 531 |
545 if (video_renderer_) { | 532 if (video_renderer_) { |
546 bound_fns.Push(base::Bind( | 533 bound_fns.Push(base::Bind( |
547 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), | 534 &VideoRenderer::Preroll, base::Unretained(video_renderer_.get()), |
548 seek_timestamp)); | 535 seek_timestamp)); |
549 | 536 |
550 // TODO(scherkus): Remove after renderers are taught to fire buffering | 537 // TODO(scherkus): Remove after renderers are taught to fire buffering |
551 // state callbacks http://crbug.com/144683 | 538 // state callbacks http://crbug.com/144683 |
552 bound_fns.Push(base::Bind(&VideoRenderer::Play, | 539 bound_fns.Push(base::Bind(&VideoRenderer::Play, |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 } | 849 } |
863 | 850 |
864 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { | 851 void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { |
865 DCHECK(task_runner_->BelongsToCurrentThread()); | 852 DCHECK(task_runner_->BelongsToCurrentThread()); |
866 | 853 |
867 audio_renderer_ = filter_collection_->GetAudioRenderer(); | 854 audio_renderer_ = filter_collection_->GetAudioRenderer(); |
868 audio_renderer_->Initialize( | 855 audio_renderer_->Initialize( |
869 demuxer_->GetStream(DemuxerStream::AUDIO), | 856 demuxer_->GetStream(DemuxerStream::AUDIO), |
870 done_cb, | 857 done_cb, |
871 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), | 858 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), |
| 859 base::Bind(&Pipeline::OnAudioUnderflow, base::Unretained(this)), |
872 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), | 860 base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), |
873 base::Bind(&Pipeline::BufferingStateChanged, base::Unretained(this), | |
874 &audio_buffering_state_), | |
875 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), | 861 base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), |
876 base::Bind(&Pipeline::SetError, base::Unretained(this))); | 862 base::Bind(&Pipeline::SetError, base::Unretained(this))); |
877 } | 863 } |
878 | 864 |
879 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { | 865 void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { |
880 DCHECK(task_runner_->BelongsToCurrentThread()); | 866 DCHECK(task_runner_->BelongsToCurrentThread()); |
881 | 867 |
882 video_renderer_ = filter_collection_->GetVideoRenderer(); | 868 video_renderer_ = filter_collection_->GetVideoRenderer(); |
883 video_renderer_->Initialize( | 869 video_renderer_->Initialize( |
884 demuxer_->GetStream(DemuxerStream::VIDEO), | 870 demuxer_->GetStream(DemuxerStream::VIDEO), |
885 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, | 871 demuxer_->GetLiveness() == Demuxer::LIVENESS_LIVE, |
886 done_cb, | 872 done_cb, |
887 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), | 873 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), |
888 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), | 874 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), |
889 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), | 875 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), |
890 base::Bind(&Pipeline::SetError, base::Unretained(this)), | 876 base::Bind(&Pipeline::SetError, base::Unretained(this)), |
891 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), | 877 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), |
892 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); | 878 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); |
893 } | 879 } |
894 | 880 |
| 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 PausePlayback(); | 906 StartWaitingForEnoughData(); |
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::PausePlayback() { | 928 void Pipeline::StartWaitingForEnoughData() { |
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()); | |
933 | 932 |
934 base::AutoLock auto_lock(lock_); | 933 base::AutoLock auto_lock(lock_); |
935 PauseClockAndStopRendering_Locked(); | 934 PauseClockAndStopRendering_Locked(); |
936 } | 935 } |
937 | 936 |
938 void Pipeline::StartPlayback() { | 937 void Pipeline::StartPlayback() { |
939 DVLOG(1) << __FUNCTION__; | 938 DVLOG(1) << __FUNCTION__; |
940 DCHECK_EQ(state_, kPlaying); | 939 DCHECK_EQ(state_, kPlaying); |
941 DCHECK_EQ(clock_state_, CLOCK_PAUSED); | 940 DCHECK_EQ(clock_state_, CLOCK_PAUSED); |
942 DCHECK(!WaitingForEnoughData()); | 941 DCHECK(!WaitingForEnoughData()); |
943 DCHECK(task_runner_->BelongsToCurrentThread()); | |
944 | 942 |
945 if (audio_renderer_) { | 943 if (audio_renderer_) { |
946 // We use audio stream to update the clock. So if there is such a | 944 // We use audio stream to update the clock. So if there is such a |
947 // stream, we pause the clock until we receive a valid timestamp. | 945 // stream, we pause the clock until we receive a valid timestamp. |
948 base::AutoLock auto_lock(lock_); | 946 base::AutoLock auto_lock(lock_); |
949 clock_state_ = CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE; | 947 clock_state_ = CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE; |
950 audio_renderer_->StartRendering(); | 948 audio_renderer_->StartRendering(); |
951 } else { | 949 } else { |
952 base::AutoLock auto_lock(lock_); | 950 base::AutoLock auto_lock(lock_); |
953 clock_state_ = CLOCK_PLAYING; | 951 clock_state_ = CLOCK_PLAYING; |
(...skipping 29 matching lines...) Expand all Loading... |
983 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 981 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
984 lock_.AssertAcquired(); | 982 lock_.AssertAcquired(); |
985 if (clock_state_ != CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE) | 983 if (clock_state_ != CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE) |
986 return; | 984 return; |
987 | 985 |
988 clock_state_ = CLOCK_PLAYING; | 986 clock_state_ = CLOCK_PLAYING; |
989 clock_->Play(); | 987 clock_->Play(); |
990 } | 988 } |
991 | 989 |
992 } // namespace media | 990 } // namespace media |
OLD | NEW |