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 8e23a91629331fc6f8df18098a23ee69d37915d2..6827bf0c7c7b0a84c1c31e0b61dcd00201449aaf 100644 |
--- a/media/base/android/media_source_player.cc |
+++ b/media/base/android/media_source_player.cc |
@@ -230,15 +230,46 @@ base::TimeDelta MediaSourcePlayer::GetDuration() { |
void MediaSourcePlayer::Release() { |
DVLOG(1) << __FUNCTION__; |
+ |
+ // Allow SEEK_EVENT_PENDING and CONFIG_CHANGE_EVENT_PENDING to survive the |
+ // Release(). Clear all others. If PREFETCH_DONE_EVENT_PENDING was previously |
+ // pending, or a job was still decoding, then at end of Release() we need to |
+ // ProcessPendingEvents() since seek or config change would not otherwise be |
+ // processed. |
+ // TODO(qinmin/wolenetz): Maintain channel state to not double-request data |
+ // or drop data received across Release()+Start(). See http://crbug.com/306314 |
+ // and http://crbug.com/304234. |
+ bool process_pending_events = false; |
+ if (IsEventPending(SEEK_EVENT_PENDING) || |
qinmin
2013/10/30 23:07:48
No need for this if statement, processPendingEvent
wolenetz
2013/10/31 01:39:11
Excellent point, thank you. Done.
|
+ IsEventPending(CONFIG_CHANGE_EVENT_PENDING)) { |
+ process_pending_events = IsEventPending(PREFETCH_DONE_EVENT_PENDING) || |
+ (audio_decoder_job_ && audio_decoder_job_->is_decoding()) || |
+ (video_decoder_job_ && video_decoder_job_->is_decoding()); |
+ } |
+ if (IsEventPending(SURFACE_CHANGE_EVENT_PENDING)) |
acolwell GONE FROM CHROMIUM
2013/10/30 23:29:53
nit: How about the following instead:
// Clear al
wolenetz
2013/10/31 01:39:11
Done. I was trying to keep the raw pending_event_
|
+ ClearPendingEvent(SURFACE_CHANGE_EVENT_PENDING); |
+ if (IsEventPending(PREFETCH_REQUEST_EVENT_PENDING)) |
+ ClearPendingEvent(PREFETCH_REQUEST_EVENT_PENDING); |
+ if (IsEventPending(PREFETCH_DONE_EVENT_PENDING)) |
+ ClearPendingEvent(PREFETCH_DONE_EVENT_PENDING); |
+ |
audio_decoder_job_.reset(); |
video_decoder_job_.reset(); |
+ |
+ // Prevent job re-creation attempts in OnDemuxerConfigsAvailable() |
reconfig_audio_decoder_ = false; |
reconfig_video_decoder_ = false; |
+ |
+ // Prevent player restart, including job re-creation attempts. |
playing_ = false; |
- pending_event_ = NO_EVENT_PENDING; |
+ |
decoder_starvation_callback_.Cancel(); |
surface_ = gfx::ScopedJavaSurface(); |
manager()->ReleaseMediaResources(player_id()); |
+ if (process_pending_events) { |
+ DVLOG(1) << __FUNCTION__ << " : Resuming seek or config change processing"; |
+ ProcessPendingEvents(); |
+ } |
} |
void MediaSourcePlayer::SetVolume(double volume) { |
@@ -549,12 +580,16 @@ void MediaSourcePlayer::MediaDecoderCallback( |
base::IntToString(status)); |
} |
+ // Let tests hook the completion of a decode cycle. |
+ manager()->OnMediaDecoderCallbackForTesting(); |
+ |
bool is_clock_manager = is_audio || !HasAudio(); |
if (is_clock_manager) |
decoder_starvation_callback_.Cancel(); |
if (status == MEDIA_CODEC_ERROR) { |
+ DVLOG(1) << __FUNCTION__ << " : decode error"; |
Release(); |
manager()->OnError(player_id(), MEDIA_ERROR_DECODE); |
return; |
@@ -835,7 +870,17 @@ void MediaSourcePlayer::OnPrefetchDone() { |
DVLOG(1) << __FUNCTION__; |
DCHECK(!audio_decoder_job_ || !audio_decoder_job_->is_decoding()); |
DCHECK(!video_decoder_job_ || !video_decoder_job_->is_decoding()); |
- DCHECK(IsEventPending(PREFETCH_DONE_EVENT_PENDING)); |
+ |
+ // A previously posted OnPrefetchDone() could race against a Release(). If |
+ // Release() won the race, we should no longer have decoder jobs. |
+ // TODO(qinmin/wolenetz): Maintain channel state to not double-request data |
+ // or drop data received across Release()+Start(). See http://crbug.com/306314 |
+ // and http://crbug.com/304234. |
+ if (!IsEventPending(PREFETCH_DONE_EVENT_PENDING)) { |
+ DVLOG(1) << __FUNCTION__ << " : aborting"; |
+ DCHECK(!audio_decoder_job_ && !video_decoder_job_); |
+ return; |
+ } |
ClearPendingEvent(PREFETCH_DONE_EVENT_PENDING); |