Bug 996465 - add ability to delay running state machine cycles for synchronization between decoding/main and state machine threads. r=cpearce.

This commit is contained in:
JW Wang 2014-07-10 03:22:00 +02:00
parent 77fd946c1c
commit 174d5b15dc
3 changed files with 53 additions and 1 deletions

View File

@ -2162,6 +2162,9 @@ MediaDecoderStateMachine::SeekCompleted()
// Try to decode another frame to detect if we're at the end... // Try to decode another frame to detect if we're at the end...
DECODER_LOG(PR_LOG_DEBUG, "Seek completed, mCurrentFrameTime=%lld", mCurrentFrameTime); 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()); ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC); NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC);
@ -2173,6 +2176,7 @@ MediaDecoderStateMachine::SeekCompleted()
mQuickBuffering = false; mQuickBuffering = false;
ScheduleStateMachine(); ScheduleStateMachine();
mScheduler->ThawScheduling();
} }
// Runnable to dispose of the decoder and state machine on the main thread. // Runnable to dispose of the decoder and state machine on the main thread.

View File

@ -94,8 +94,15 @@ MediaDecoderStateMachineScheduler::Schedule(int64_t aUsecs)
{ {
mMonitor.AssertCurrentThreadIn(); mMonitor.AssertCurrentThreadIn();
if (mState == SCHEDULER_STATE_SHUTDOWN) { switch(mState) {
case SCHEDULER_STATE_SHUTDOWN:
return NS_ERROR_FAILURE; 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<int64_t>(aUsecs, 0); aUsecs = std::max<int64_t>(aUsecs, 0);
@ -164,6 +171,9 @@ void
MediaDecoderStateMachineScheduler::ScheduleAndShutdown() MediaDecoderStateMachineScheduler::ScheduleAndShutdown()
{ {
mMonitor.AssertCurrentThreadIn(); mMonitor.AssertCurrentThreadIn();
if (IsFrozen()) {
ThawScheduling();
}
// Schedule next cycle to handle SHUTDOWN in state machine thread. // Schedule next cycle to handle SHUTDOWN in state machine thread.
Schedule(); Schedule();
// This must be set after calling Schedule() // This must be set after calling Schedule()
@ -194,4 +204,33 @@ MediaDecoderStateMachineScheduler::ResetTimer()
mTimeout = TimeStamp(); 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 } // namespace mozilla

View File

@ -21,6 +21,8 @@ class ReentrantMonitor;
class MediaDecoderStateMachineScheduler { class MediaDecoderStateMachineScheduler {
enum State { enum State {
SCHEDULER_STATE_NONE, SCHEDULER_STATE_NONE,
SCHEDULER_STATE_FROZEN,
SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK,
SCHEDULER_STATE_SHUTDOWN SCHEDULER_STATE_SHUTDOWN
}; };
public: public:
@ -32,6 +34,8 @@ public:
nsresult Schedule(int64_t aUsecs = 0); nsresult Schedule(int64_t aUsecs = 0);
void ScheduleAndShutdown(); void ScheduleAndShutdown();
nsresult TimeoutExpired(int aTimerId); nsresult TimeoutExpired(int aTimerId);
void FreezeScheduling();
void ThawScheduling();
bool OnStateMachineThread() const; bool OnStateMachineThread() const;
bool IsScheduled() const; bool IsScheduled() const;
@ -44,6 +48,11 @@ public:
return mEventTarget; return mEventTarget;
} }
bool IsFrozen() const {
return mState == SCHEDULER_STATE_FROZEN ||
mState == SCHEDULER_STATE_FROZEN_WITH_PENDING_TASK;
}
private: private:
void ResetTimer(); void ResetTimer();