OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |