Index: media/base/android/media_source_player.cc |
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc |
index 4c6cb9c1215602e934600f547b83d2470eb53928..e5b518e22c0e64930311496a95c4e3c72ce219f0 100644 |
--- a/media/base/android/media_source_player.cc |
+++ b/media/base/android/media_source_player.cc |
@@ -73,8 +73,8 @@ MediaSourcePlayer::MediaSourcePlayer( |
video_codec_(kUnknownVideoCodec), |
num_channels_(0), |
sampling_rate_(0), |
- audio_finished_(true), |
- video_finished_(true), |
+ reached_audio_eos_(false), |
+ reached_video_eos_(false), |
playing_(false), |
is_audio_encrypted_(false), |
is_video_encrypted_(false), |
@@ -318,8 +318,6 @@ void MediaSourcePlayer::StartInternal() { |
return; |
} |
- audio_finished_ = false; |
- video_finished_ = false; |
SetPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
ProcessPendingEvents(); |
} |
@@ -451,6 +449,9 @@ void MediaSourcePlayer::OnDemuxerSeekDone( |
audio_timestamp_helper_->SetBaseTimestamp(actual_browser_seek_time); |
} |
+ reached_audio_eos_ = false; |
+ reached_video_eos_ = false; |
+ |
base::TimeDelta current_time = GetCurrentTime(); |
// TODO(qinmin): Simplify the logic by using |start_presentation_timestamp_| |
// to preroll media decoder jobs. Currently |start_presentation_timestamp_| |
@@ -530,19 +531,28 @@ void MediaSourcePlayer::ProcessPendingEvents() { |
if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) { |
DVLOG(1) << __FUNCTION__ << " : Handling PREFETCH_REQUEST_EVENT."; |
- int count = (audio_decoder_job_ ? 1 : 0) + (video_decoder_job_ ? 1 : 0); |
+ DCHECK(audio_decoder_job_ || AudioFinished()); |
+ DCHECK(video_decoder_job_ || VideoFinished()); |
+ |
+ int count = (AudioFinished() ? 0 : 1) + (VideoFinished() ? 0 : 1); |
+ |
+ // It is possible that all streams have finished decode, yet starvation |
+ // occurred during the last stream's EOS decode. In this case, prefetch is a |
+ // no-op. |
+ ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
+ if (count == 0) |
+ return; |
+ SetPendingEvent(PREFETCH_DONE_EVENT_PENDING); |
base::Closure barrier = BarrierClosure(count, base::Bind( |
&MediaSourcePlayer::OnPrefetchDone, weak_this_.GetWeakPtr())); |
- if (audio_decoder_job_) |
+ if (!AudioFinished()) |
audio_decoder_job_->Prefetch(barrier); |
- if (video_decoder_job_) |
+ if (!VideoFinished()) |
video_decoder_job_->Prefetch(barrier); |
- SetPendingEvent(PREFETCH_DONE_EVENT_PENDING); |
- ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
return; |
} |
@@ -590,16 +600,27 @@ void MediaSourcePlayer::MediaDecoderCallback( |
return; |
} |
- if (pending_event_ != NO_EVENT_PENDING) { |
+ DCHECK(!IsEventPending(PREFETCH_DONE_EVENT_PENDING)); |
+ |
+ // Let |SEEK_EVENT_PENDING| (the highest priority event outside of |
+ // |PREFETCH_DONE_EVENT_PENDING|) preempt output EOS detection here. Process |
+ // any other pending events only after handling EOS detection. |
+ if (IsEventPending(SEEK_EVENT_PENDING)) { |
ProcessPendingEvents(); |
return; |
} |
- if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) { |
+ if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) |
PlaybackCompleted(is_audio); |
+ |
+ if (pending_event_ != NO_EVENT_PENDING) { |
+ ProcessPendingEvents(); |
return; |
} |
+ if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) |
+ return; |
+ |
if (status == MEDIA_CODEC_OK && is_clock_manager && |
presentation_timestamp != kNoTimestamp()) { |
UpdateTimestamps(presentation_timestamp, audio_output_bytes); |
@@ -643,6 +664,7 @@ void MediaSourcePlayer::MediaDecoderCallback( |
void MediaSourcePlayer::DecodeMoreAudio() { |
DVLOG(1) << __FUNCTION__; |
DCHECK(!audio_decoder_job_->is_decoding()); |
+ DCHECK(!AudioFinished()); |
if (audio_decoder_job_->Decode( |
start_time_ticks_, start_presentation_timestamp_, base::Bind( |
@@ -672,6 +694,7 @@ void MediaSourcePlayer::DecodeMoreAudio() { |
void MediaSourcePlayer::DecodeMoreVideo() { |
DVLOG(1) << __FUNCTION__; |
DCHECK(!video_decoder_job_->is_decoding()); |
+ DCHECK(!VideoFinished()); |
if (video_decoder_job_->Decode( |
start_time_ticks_, start_presentation_timestamp_, base::Bind( |
@@ -706,11 +729,11 @@ void MediaSourcePlayer::DecodeMoreVideo() { |
void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { |
DVLOG(1) << __FUNCTION__ << "(" << is_audio << ")"; |
if (is_audio) |
- audio_finished_ = true; |
+ reached_audio_eos_ = true; |
else |
- video_finished_ = true; |
+ reached_video_eos_ = true; |
- if ((!HasAudio() || audio_finished_) && (!HasVideo() || video_finished_)) { |
+ if (AudioFinished() && VideoFinished()) { |
playing_ = false; |
clock_.Pause(); |
start_time_ticks_ = base::TimeTicks(); |
@@ -735,6 +758,14 @@ bool MediaSourcePlayer::HasAudio() { |
return kUnknownAudioCodec != audio_codec_; |
} |
+bool MediaSourcePlayer::AudioFinished() { |
+ return reached_audio_eos_ || !HasAudio(); |
+} |
+ |
+bool MediaSourcePlayer::VideoFinished() { |
+ return reached_video_eos_ || !HasVideo(); |
+} |
+ |
void MediaSourcePlayer::ConfigureAudioDecoderJob() { |
if (!HasAudio()) { |
audio_decoder_job_.reset(); |
@@ -916,9 +947,10 @@ void MediaSourcePlayer::OnPrefetchDone() { |
if (!clock_.IsPlaying()) |
clock_.Play(); |
- if (audio_decoder_job_) |
+ if (!AudioFinished()) |
DecodeMoreAudio(); |
- if (video_decoder_job_) |
+ |
+ if (!VideoFinished()) |
DecodeMoreVideo(); |
} |