From 174d5b15dc123a2a330b6eafe35f64dfe49b4198 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Thu, 10 Jul 2014 03:22:00 +0200 Subject: [PATCH] Bug 996465 - add ability to delay running state machine cycles for synchronization between decoding/main and state machine threads. r=cpearce. --- content/media/MediaDecoderStateMachine.cpp | 4 ++ .../MediaDecoderStateMachineScheduler.cpp | 41 ++++++++++++++++++- .../media/MediaDecoderStateMachineScheduler.h | 9 ++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/content/media/MediaDecoderStateMachine.cpp b/content/media/MediaDecoderStateMachine.cpp index c5bcd7a9fb2..37214602693 100644 --- a/content/media/MediaDecoderStateMachine.cpp +++ b/content/media/MediaDecoderStateMachine.cpp @@ -2162,6 +2162,9 @@ MediaDecoderStateMachine::SeekCompleted() // Try to decode another frame to detect if we're at the end... DECODER_LOG(PR_LOG_DEBUG, "Seek completed, mCurrentFrameTime=%lld", mCurrentFrameTime); + // Prevent changes in playback position before 'seeked' is fired for we + // expect currentTime equals seek target in 'seeked' callback. + mScheduler->FreezeScheduling(); { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC); @@ -2173,6 +2176,7 @@ MediaDecoderStateMachine::SeekCompleted() mQuickBuffering = false; ScheduleStateMachine(); + mScheduler->ThawScheduling(); } // Runnable to dispose of the decoder and state machine on the main thread. diff --git a/content/media/MediaDecoderStateMachineScheduler.cpp b/content/media/MediaDecoderStateMachineScheduler.cpp index 421c89db2c2..ff21bf56695 100644 --- a/content/media/MediaDecoderStateMachineScheduler.cpp +++ b/content/media/MediaDecoderStateMachineScheduler.cpp @@ -94,8 +94,15 @@ MediaDecoderStateMachineScheduler::Schedule(int64_t aUsecs) { mMonitor.AssertCurrentThreadIn(); - if (mState == SCHEDULER_STATE_SHUTDOWN) { + switch(mState) { + case SCHEDULER_STATE_SHUTDOWN: return NS_ERROR_FAILURE; + case SCHEDULER_STATE_FROZEN: + mState = SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK; + case SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK: + return NS_OK; + case SCHEDULER_STATE_NONE: + break; } aUsecs = std::max(aUsecs, 0); @@ -164,6 +171,9 @@ void MediaDecoderStateMachineScheduler::ScheduleAndShutdown() { mMonitor.AssertCurrentThreadIn(); + if (IsFrozen()) { + ThawScheduling(); + } // Schedule next cycle to handle SHUTDOWN in state machine thread. Schedule(); // This must be set after calling Schedule() @@ -194,4 +204,33 @@ MediaDecoderStateMachineScheduler::ResetTimer() mTimeout = TimeStamp(); } +void MediaDecoderStateMachineScheduler::FreezeScheduling() +{ + mMonitor.AssertCurrentThreadIn(); + if (mState == SCHEDULER_STATE_SHUTDOWN) { + return; + } + MOZ_ASSERT(mState == SCHEDULER_STATE_NONE); + mState = !IsScheduled() ? SCHEDULER_STATE_FROZEN : + SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK; + // Nullify pending timer task if any. + ++mTimerId; + mTimeout = TimeStamp(); +} + +void MediaDecoderStateMachineScheduler::ThawScheduling() +{ + mMonitor.AssertCurrentThreadIn(); + if (mState == SCHEDULER_STATE_SHUTDOWN) { + return; + } + // We should be in frozen state and no pending timer task. + MOZ_ASSERT(IsFrozen() && !IsScheduled()); + bool pendingTask = mState == SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK; + mState = SCHEDULER_STATE_NONE; + if (pendingTask) { + Schedule(); + } +} + } // namespace mozilla diff --git a/content/media/MediaDecoderStateMachineScheduler.h b/content/media/MediaDecoderStateMachineScheduler.h index f79cd15066e..6c3bc98f7f5 100644 --- a/content/media/MediaDecoderStateMachineScheduler.h +++ b/content/media/MediaDecoderStateMachineScheduler.h @@ -21,6 +21,8 @@ class ReentrantMonitor; class MediaDecoderStateMachineScheduler { enum State { SCHEDULER_STATE_NONE, + SCHEDULER_STATE_FROZEN, + SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK, SCHEDULER_STATE_SHUTDOWN }; public: @@ -32,6 +34,8 @@ public: nsresult Schedule(int64_t aUsecs = 0); void ScheduleAndShutdown(); nsresult TimeoutExpired(int aTimerId); + void FreezeScheduling(); + void ThawScheduling(); bool OnStateMachineThread() const; bool IsScheduled() const; @@ -44,6 +48,11 @@ public: return mEventTarget; } + bool IsFrozen() const { + return mState == SCHEDULER_STATE_FROZEN || + mState == SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK; + } + private: void ResetTimer();