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

Side by Side Diff: media/base/android/media_codec_player.cc

Issue 1254293003: MediaCodecPlayer implementation (stage 4 - preroll) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mtplayer-browserseek
Patch Set: Rebased Created 5 years, 4 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/android/media_codec_player.h" 5 #include "media/base/android/media_codec_player.h"
6 6
7 #include "base/barrier_closure.h" 7 #include "base/barrier_closure.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 } 475 }
476 476
477 void MediaCodecPlayer::OnDemuxerDurationChanged( 477 void MediaCodecPlayer::OnDemuxerDurationChanged(
478 base::TimeDelta duration) { 478 base::TimeDelta duration) {
479 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 479 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
480 DVLOG(1) << __FUNCTION__ << " duration:" << duration; 480 DVLOG(1) << __FUNCTION__ << " duration:" << duration;
481 481
482 duration_ = duration; 482 duration_ = duration;
483 } 483 }
484 484
485 void MediaCodecPlayer::SetDecodersTimeCallbackForTests(
486 DecodersTimeCallback cb) {
487 DCHECK(ui_task_runner_->BelongsToCurrentThread());
488 decoders_time_cb_ = cb;
489 }
490
491 bool MediaCodecPlayer::IsPrerollingForTests(DemuxerStream::Type type) const {
492 DCHECK(ui_task_runner_->BelongsToCurrentThread());
493 DCHECK(audio_decoder_ && video_decoder_);
494
495 if (type == DemuxerStream::AUDIO)
496 return audio_decoder_->IsPrerollingForTests();
497 else if (type == DemuxerStream::VIDEO)
498 return video_decoder_->IsPrerollingForTests();
499 else
500 return false;
501 }
502
485 // Events from Player, called on UI thread 503 // Events from Player, called on UI thread
486 504
487 void MediaCodecPlayer::OnMediaMetadataChanged(base::TimeDelta duration, 505 void MediaCodecPlayer::OnMediaMetadataChanged(base::TimeDelta duration,
488 const gfx::Size& video_size) { 506 const gfx::Size& video_size) {
489 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 507 DCHECK(ui_task_runner_->BelongsToCurrentThread());
490 508
491 if (duration != kNoTimestamp()) 509 if (duration != kNoTimestamp())
492 metadata_cache_.duration = duration; 510 metadata_cache_.duration = duration;
493 511
494 if (!video_size.IsEmpty()) 512 if (!video_size.IsEmpty())
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 566
549 if (HasVideo() && !video_decoder_->HasVideoSurface()) { 567 if (HasVideo() && !video_decoder_->HasVideoSurface()) {
550 SetState(kStateWaitingForSurface); 568 SetState(kStateWaitingForSurface);
551 return; 569 return;
552 } 570 }
553 571
554 SetState(kStatePlaying); 572 SetState(kStatePlaying);
555 StartPlaybackOrBrowserSeek(); 573 StartPlaybackOrBrowserSeek();
556 } 574 }
557 575
576 void MediaCodecPlayer::OnPrerollDone() {
577 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
578 DVLOG(1) << __FUNCTION__;
579
580 DCHECK(interpolator_.interpolating());
581
582 StartStatus status = StartDecoders(interpolator_.GetInterpolatedTime());
583 if (status != kStartOk)
584 GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_);
585 }
586
558 void MediaCodecPlayer::OnStopDone() { 587 void MediaCodecPlayer::OnStopDone() {
559 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 588 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
560 DVLOG(1) << __FUNCTION__; 589 DVLOG(1) << __FUNCTION__;
561 590
562 if (!(audio_decoder_->IsStopped() && video_decoder_->IsStopped())) 591 if (!(audio_decoder_->IsStopped() && video_decoder_->IsStopped())) {
592 DVLOG(1) << __FUNCTION__ << " both audio and video has to be stopped"
593 << ", ignoring";
563 return; // Wait until other stream is stopped 594 return; // Wait until other stream is stopped
595 }
564 596
565 // At this point decoder threads should not be running 597 // At this point decoder threads should not be running
566 if (interpolator_.interpolating()) 598 if (interpolator_.interpolating())
567 interpolator_.StopInterpolating(); 599 interpolator_.StopInterpolating();
568 600
569 base::TimeDelta seek_time; 601 base::TimeDelta seek_time;
570 switch (state_) { 602 switch (state_) {
571 case kStateStopping: { 603 case kStateStopping: {
572 base::TimeDelta seek_time = GetPendingSeek(); 604 base::TimeDelta seek_time = GetPendingSeek();
573 if (seek_time != kNoTimestamp()) { 605 if (seek_time != kNoTimestamp()) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 } 661 }
630 662
631 void MediaCodecPlayer::OnTimeIntervalUpdate(DemuxerStream::Type type, 663 void MediaCodecPlayer::OnTimeIntervalUpdate(DemuxerStream::Type type,
632 base::TimeDelta now_playing, 664 base::TimeDelta now_playing,
633 base::TimeDelta last_buffered) { 665 base::TimeDelta last_buffered) {
634 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 666 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
635 667
636 DVLOG(2) << __FUNCTION__ << ": stream type:" << type << " [" << now_playing 668 DVLOG(2) << __FUNCTION__ << ": stream type:" << type << " [" << now_playing
637 << "," << last_buffered << "]"; 669 << "," << last_buffered << "]";
638 670
671 // For testing only: report time interval as we receive it from decoders
672 // as an indication of what is being rendered.
673 if (!decoders_time_cb_.is_null()) {
674 ui_task_runner_->PostTask(
675 FROM_HERE,
676 base::Bind(decoders_time_cb_, type, now_playing, last_buffered));
677 }
678
639 // I assume that audio stream cannot be added after we get configs by 679 // I assume that audio stream cannot be added after we get configs by
640 // OnDemuxerConfigsAvailable(), but that audio can finish early. 680 // OnDemuxerConfigsAvailable(), but that audio can finish early.
641 681
642 if (type == DemuxerStream::VIDEO) { 682 if (type == DemuxerStream::VIDEO) {
643 // Ignore video PTS if there is audio stream or if it's behind current 683 // Ignore video PTS if there is audio stream or if it's behind current
644 // time as set by audio stream. 684 // time as set by audio stream.
645 if (!AudioFinished() || now_playing < interpolator_.GetInterpolatedTime()) 685 if (!AudioFinished() ||
686 (HasAudio() && now_playing < interpolator_.GetInterpolatedTime()))
646 return; 687 return;
647 } 688 }
648 689
649 interpolator_.SetBounds(now_playing, last_buffered); 690 interpolator_.SetBounds(now_playing, last_buffered);
650 691
651 // Post to UI thread 692 // Post to UI thread
652 ui_task_runner_->PostTask(FROM_HERE, 693 ui_task_runner_->PostTask(FROM_HERE,
653 base::Bind(time_update_cb_, GetInterpolatedTime(), 694 base::Bind(time_update_cb_, GetInterpolatedTime(),
654 base::TimeTicks::Now())); 695 base::TimeTicks::Now()));
655 } 696 }
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 break; 826 break;
786 case kStartOk: 827 case kStartOk:
787 break; 828 break;
788 } 829 }
789 } 830 }
790 831
791 MediaCodecPlayer::StartStatus MediaCodecPlayer::StartPlaybackDecoders() { 832 MediaCodecPlayer::StartStatus MediaCodecPlayer::StartPlaybackDecoders() {
792 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 833 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
793 DVLOG(1) << __FUNCTION__; 834 DVLOG(1) << __FUNCTION__;
794 835
795 bool do_audio = !AudioFinished(); 836 // Configure all streams before the start since we may discover that browser
796 bool do_video = !VideoFinished(); 837 // seek is required.
838 MediaCodecPlayer::StartStatus status = ConfigureDecoders();
839 if (status != kStartOk)
840 return status;
841
842 // At this point decoder threads should not be running.
843 if (!interpolator_.interpolating())
844 interpolator_.StartInterpolating();
845
846 base::TimeDelta current_time = GetInterpolatedTime();
847
848 bool preroll_required = false;
849 status = MaybePrerollDecoders(current_time, &preroll_required);
850 if (preroll_required)
851 return status;
852
853 return StartDecoders(current_time);
854 }
855
856 MediaCodecPlayer::StartStatus MediaCodecPlayer::ConfigureDecoders() {
857 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
858 DVLOG(1) << __FUNCTION__;
859
860 const bool do_audio = !AudioFinished();
861 const bool do_video = !VideoFinished();
797 862
798 // If there is nothing to play, the state machine should determine this at the 863 // If there is nothing to play, the state machine should determine this at the
799 // prefetch state and never call this method. 864 // prefetch state and never call this method.
800 DCHECK(do_audio || do_video); 865 DCHECK(do_audio || do_video);
801 866
802 // Configure all streams before the start since we may discover that browser 867 // Start with video: if browser seek is required it would
803 // seek is required. Start with video: if browser seek is required it would
804 // not make sense to configure audio. 868 // not make sense to configure audio.
805 869
806 if (do_video) { 870 if (do_video) {
807 MediaCodecDecoder::ConfigStatus status = video_decoder_->Configure(); 871 MediaCodecDecoder::ConfigStatus status = video_decoder_->Configure();
808 switch (status) { 872 switch (status) {
809 case MediaCodecDecoder::kConfigOk: 873 case MediaCodecDecoder::kConfigOk:
810 break; 874 break;
811 case MediaCodecDecoder::kConfigKeyFrameRequired: 875 case MediaCodecDecoder::kConfigKeyFrameRequired:
812 // TODO(timav): post a task or return the status? 876 // TODO(timav): post a task or return the status?
813 return kStartBrowserSeekRequired; 877 return kStartBrowserSeekRequired;
814 case MediaCodecDecoder::kConfigFailure: 878 case MediaCodecDecoder::kConfigFailure:
815 return kStartFailed; 879 return kStartFailed;
816 } 880 }
817 } 881 }
818 882
819 if (do_audio) { 883 if (do_audio) {
820 MediaCodecDecoder::ConfigStatus status = audio_decoder_->Configure(); 884 MediaCodecDecoder::ConfigStatus status = audio_decoder_->Configure();
821 if (status != MediaCodecDecoder::kConfigOk) { 885 if (status != MediaCodecDecoder::kConfigOk) {
822 return kStartFailed; 886 return kStartFailed;
823 } 887 }
824 } 888 }
825 889
826 // At this point decoder threads should not be running. 890 return kStartOk;
827 if (!interpolator_.interpolating()) 891 }
828 interpolator_.StartInterpolating();
829 892
830 base::TimeDelta current_time = GetInterpolatedTime(); 893 MediaCodecPlayer::StartStatus MediaCodecPlayer::MaybePrerollDecoders(
894 base::TimeDelta current_time,
895 bool* preroll_required) {
896 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
897 DVLOG(1) << __FUNCTION__ << " current_time:" << current_time;
831 898
832 if (do_audio) { 899 // If requested, preroll is always done in the beginning of the playback,
833 if (!audio_decoder_->Start(current_time)) { 900 // after prefetch. The request might not happen at all though, in which case
901 // we won't have prerolling phase. We need the prerolling when we (re)create
902 // the decoder, because its configuration and initialization (getting input,
903 // but not making output) can take time, and after the seek because there
904 // could be some data to be skipped and there is again initialization after
905 // the flush.
906
907 int count = 0;
908 const bool do_audio_preroll = audio_decoder_->NotCompletedAndNeedsPreroll();
909 if (do_audio_preroll)
910 ++count;
911
912 const bool do_video_preroll = video_decoder_->NotCompletedAndNeedsPreroll();
913 if (do_video_preroll)
914 ++count;
915
916 if (count == 0) {
917 DVLOG(1) << __FUNCTION__ << ": preroll is not required, skipping";
918 *preroll_required = false;
919 return kStartOk;
920 }
921
922 *preroll_required = true;
923
924 DCHECK(count > 0);
925 DCHECK(do_audio_preroll || do_video_preroll);
926
927 DVLOG(1) << __FUNCTION__ << ": preroll for " << count << " stream(s)";
928
929 base::Closure preroll_cb = base::BarrierClosure(
930 count, base::Bind(&MediaCodecPlayer::OnPrerollDone, media_weak_this_));
931
932 if (do_audio_preroll) {
933 if (!audio_decoder_->Preroll(current_time, preroll_cb))
834 return kStartFailed; 934 return kStartFailed;
835 } 935 }
936
937 if (do_video_preroll) {
938 if (!video_decoder_->Preroll(current_time, preroll_cb))
939 return kStartFailed;
940 }
941
942 return kStartOk;
943 }
944
945 MediaCodecPlayer::StartStatus MediaCodecPlayer::StartDecoders(
946 base::TimeDelta current_time) {
947 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
948 DVLOG(1) << __FUNCTION__ << " current_time:" << current_time;
949
950 if (!AudioFinished()) {
951 if (!audio_decoder_->Start(current_time))
952 return kStartFailed;
836 953
837 // Attach listener on UI thread 954 // Attach listener on UI thread
838 ui_task_runner_->PostTask(FROM_HERE, attach_listener_cb_); 955 ui_task_runner_->PostTask(FROM_HERE, attach_listener_cb_);
839 } 956 }
840 957
841 if (do_video) { 958 if (!VideoFinished()) {
842 if (!video_decoder_->Start(current_time)) { 959 if (!video_decoder_->Start(current_time))
843 return kStartFailed; 960 return kStartFailed;
844 }
845 } 961 }
846 962
847 return kStartOk; 963 return kStartOk;
848 } 964 }
849 965
850 void MediaCodecPlayer::StopDecoders() { 966 void MediaCodecPlayer::StopDecoders() {
851 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 967 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
852 DVLOG(1) << __FUNCTION__; 968 DVLOG(1) << __FUNCTION__;
853 969
854 video_decoder_->SyncStop(); 970 video_decoder_->SyncStop();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 RETURN_STRING(kStateWaitingForSurface); 1086 RETURN_STRING(kStateWaitingForSurface);
971 RETURN_STRING(kStateWaitingForSeek); 1087 RETURN_STRING(kStateWaitingForSeek);
972 RETURN_STRING(kStateError); 1088 RETURN_STRING(kStateError);
973 } 1089 }
974 return nullptr; // crash early 1090 return nullptr; // crash early
975 } 1091 }
976 1092
977 #undef RETURN_STRING 1093 #undef RETURN_STRING
978 1094
979 } // namespace media 1095 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_codec_player.h ('k') | media/base/android/media_codec_player_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698