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..e1268a533e105ff240225ad12f9c153ea8b20947 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), |
+ audio_finished_(false), |
+ video_finished_(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); |
} |
+ audio_finished_ = false; |
+ video_finished_ = 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,29 @@ 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_ || AudioFinishedOrNoAudio()); |
+ DCHECK(video_decoder_job_ || VideoFinishedOrNoVideo()); |
+ |
+ int count = ((AudioFinishedOrNoAudio()) ? 0 : 1) + |
+ ((VideoFinishedOrNoVideo()) ? 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 (!AudioFinishedOrNoAudio()) |
audio_decoder_job_->Prefetch(barrier); |
- if (video_decoder_job_) |
+ if (!VideoFinishedOrNoVideo()) |
video_decoder_job_->Prefetch(barrier); |
- SetPendingEvent(PREFETCH_DONE_EVENT_PENDING); |
- ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
return; |
} |
@@ -590,13 +601,23 @@ 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) { |
- PlaybackCompleted(is_audio); |
+ PlaybackCompleted(is_audio); // Includes ProcessPendingEvents() if needed. |
acolwell GONE FROM CHROMIUM
2013/12/06 18:28:30
nit: Why don't you just let this fall through to t
wolenetz
2013/12/09 22:58:27
A little tweaking is also required to ensure that
|
+ return; |
+ } |
+ |
+ if (pending_event_ != NO_EVENT_PENDING) { |
+ ProcessPendingEvents(); |
return; |
} |
@@ -643,6 +664,7 @@ void MediaSourcePlayer::MediaDecoderCallback( |
void MediaSourcePlayer::DecodeMoreAudio() { |
DVLOG(1) << __FUNCTION__; |
DCHECK(!audio_decoder_job_->is_decoding()); |
+ DCHECK(!AudioFinishedOrNoAudio()); |
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(!VideoFinishedOrNoVideo()); |
if (video_decoder_job_->Decode( |
start_time_ticks_, start_presentation_timestamp_, base::Bind( |
@@ -710,12 +733,15 @@ void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { |
else |
video_finished_ = true; |
- if ((!HasAudio() || audio_finished_) && (!HasVideo() || video_finished_)) { |
+ if (AudioFinishedOrNoAudio() && VideoFinishedOrNoVideo()) { |
playing_ = false; |
clock_.Pause(); |
start_time_ticks_ = base::TimeTicks(); |
manager()->OnPlaybackComplete(player_id()); |
} |
+ |
+ if (pending_event_ != NO_EVENT_PENDING) |
+ ProcessPendingEvents(); |
} |
void MediaSourcePlayer::ClearDecodingData() { |
@@ -735,6 +761,14 @@ bool MediaSourcePlayer::HasAudio() { |
return kUnknownAudioCodec != audio_codec_; |
} |
+bool MediaSourcePlayer::AudioFinishedOrNoAudio() { |
acolwell GONE FROM CHROMIUM
2013/12/06 18:28:30
nit: I think the OrNoAudio() just confuses things
wolenetz
2013/12/09 22:58:27
This makes sense with the current *_finished_ flag
|
+ return audio_finished_ || !HasAudio(); |
+} |
+ |
+bool MediaSourcePlayer::VideoFinishedOrNoVideo() { |
acolwell GONE FROM CHROMIUM
2013/12/06 18:28:30
ditto
wolenetz
2013/12/09 22:58:27
Done.
|
+ return video_finished_ || !HasVideo(); |
+} |
+ |
void MediaSourcePlayer::ConfigureAudioDecoderJob() { |
if (!HasAudio()) { |
audio_decoder_job_.reset(); |
@@ -916,10 +950,15 @@ void MediaSourcePlayer::OnPrefetchDone() { |
if (!clock_.IsPlaying()) |
clock_.Play(); |
- if (audio_decoder_job_) |
+ if (!AudioFinishedOrNoAudio()) { |
+ DCHECK(audio_decoder_job_); |
acolwell GONE FROM CHROMIUM
2013/12/06 18:28:30
nit: This seems redundant since DecodeMoreAudio()
wolenetz
2013/12/09 22:58:27
Done.
|
DecodeMoreAudio(); |
- if (video_decoder_job_) |
+ } |
+ |
+ if (!VideoFinishedOrNoVideo()) { |
+ DCHECK(video_decoder_job_); |
acolwell GONE FROM CHROMIUM
2013/12/06 18:28:30
ditto
wolenetz
2013/12/09 22:58:27
Done.
|
DecodeMoreVideo(); |
+ } |
} |
const char* MediaSourcePlayer::GetEventName(PendingEventFlags event) { |