Bug 1252767 - Remove MediaDecoderStateMachine::mPendingSeek. r=cpearce.
MozReview-Commit-ID: G0ey8NkHICg
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -857,19 +857,18 @@ MediaDecoderStateMachine::MaybeFinishDec
return false;
}
FinishDecodeFirstFrame();
if (!mQueuedSeek.Exists()) {
return false;
}
// We can now complete the pending seek.
- mPendingSeek.Steal(mQueuedSeek);
SetState(DECODER_STATE_SEEKING);
- ScheduleStateMachine();
+ InitiateSeek(mQueuedSeek);
return true;
}
void
MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample,
TimeStamp aDecodeStartTime)
{
MOZ_ASSERT(OnTaskQueue());
@@ -949,18 +948,17 @@ MediaDecoderStateMachine::OnVideoDecoded
// We are doing a fastSeek, but we ended up *before* the previous
// playback position. This is surprising UX, so switch to an accurate
// seek and decode to the seek target. This is not conformant to the
// spec, fastSeek should always be fast, but until we get the time to
// change all Readers to seek to the keyframe after the currentTime
// in this case, we'll just decode forward. Bug 1026330.
mCurrentSeek.mTarget.SetType(SeekTarget::Accurate);
}
- if (mCurrentSeek.mTarget.IsFast() ||
- mPendingSeek.Exists()) {
+ if (mCurrentSeek.mTarget.IsFast()) {
// Non-precise seek; or a pending seek exists ; we can stop the seek
// at the first sample.
Push(video, MediaData::VIDEO_DATA);
} else {
// We're doing an accurate seek. We still need to discard
// MediaData up to the one containing exact seek target.
if (NS_FAILED(DropVideoUpToSeekTarget(video))) {
DecodeError();
@@ -1265,18 +1263,16 @@ MediaDecoderStateMachine::SetDormant(boo
mPendingDormant.reset();
DECODER_LOG("SetDormant=%d", aDormant);
if (aDormant) {
if (mState == DECODER_STATE_SEEKING) {
if (mQueuedSeek.Exists()) {
// Keep latest seek target
- } else if (mPendingSeek.Exists()) {
- mQueuedSeek.Steal(mPendingSeek);
} else if (mCurrentSeek.Exists()) {
mQueuedSeek.Steal(mCurrentSeek);
} else {
mQueuedSeek.mTarget = SeekTarget(mCurrentPosition,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// XXXbholley - Nobody is listening to this promise. Do we need to pass it
// back to MediaDecoder when we come out of dormant?
@@ -1285,17 +1281,16 @@ MediaDecoderStateMachine::SetDormant(boo
} else {
mQueuedSeek.mTarget = SeekTarget(mCurrentPosition,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// XXXbholley - Nobody is listening to this promise. Do we need to pass it
// back to MediaDecoder when we come out of dormant?
RefPtr<MediaDecoder::SeekPromise> unused = mQueuedSeek.mPromise.Ensure(__func__);
}
- mPendingSeek.RejectIfExists(__func__);
mCurrentSeek.RejectIfExists(__func__);
SetState(DECODER_STATE_DORMANT);
if (IsPlaying()) {
StopPlayback();
}
Reset();
@@ -1321,17 +1316,16 @@ MediaDecoderStateMachine::Shutdown()
// Once we've entered the shutdown state here there's no going back.
// Change state before issuing shutdown request to threads so those
// threads can start exiting cleanly during the Shutdown call.
ScheduleStateMachine();
SetState(DECODER_STATE_SHUTDOWN);
mQueuedSeek.RejectIfExists(__func__);
- mPendingSeek.RejectIfExists(__func__);
mCurrentSeek.RejectIfExists(__func__);
#ifdef MOZ_EME
mCDMProxyPromise.DisconnectIfExists();
#endif
if (IsPlaying()) {
StopPlayback();
@@ -1375,19 +1369,18 @@ void MediaDecoderStateMachine::StartDeco
// the first samples in order to determine the media start time,
// we have the start time from last time we loaded.
// FinishDecodeFirstFrame will be launched upon completion of the seek when
// we have data ready to play.
MOZ_ASSERT(mQueuedSeek.Exists() && mSentFirstFrameLoadedEvent,
"Return from dormant must have queued seek");
}
if (mQueuedSeek.Exists()) {
- mPendingSeek.Steal(mQueuedSeek);
SetState(DECODER_STATE_SEEKING);
- ScheduleStateMachine();
+ InitiateSeek(mQueuedSeek);
return;
}
}
mDecodeStartTime = TimeStamp::Now();
CheckIfDecodeComplete();
if (mState == DECODER_STATE_COMPLETED) {
@@ -1493,24 +1486,24 @@ MediaDecoderStateMachine::Seek(SeekTarge
if (mState < DECODER_STATE_DECODING ||
(IsDecodingFirstFrame() && !mReader->ForceZeroStartTime())) {
DECODER_LOG("Seek() Not Enough Data to continue at this stage, queuing seek");
mQueuedSeek.RejectIfExists(__func__);
mQueuedSeek.mTarget = aTarget;
return mQueuedSeek.mPromise.Ensure(__func__);
}
mQueuedSeek.RejectIfExists(__func__);
- mPendingSeek.RejectIfExists(__func__);
- mPendingSeek.mTarget = aTarget;
-
- DECODER_LOG("Changed state to SEEKING (to %lld)", mPendingSeek.mTarget.GetTime().ToMicroseconds());
+
+ DECODER_LOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
SetState(DECODER_STATE_SEEKING);
- ScheduleStateMachine();
-
- return mPendingSeek.mPromise.Ensure(__func__);
+
+ SeekJob seekJob;
+ seekJob.mTarget = aTarget;
+ InitiateSeek(seekJob);
+ return mCurrentSeek.mPromise.Ensure(__func__);
}
RefPtr<MediaDecoder::SeekPromise>
MediaDecoderStateMachine::InvokeSeek(SeekTarget aTarget)
{
return InvokeAsync(OwnerThread(), this, __func__,
&MediaDecoderStateMachine::Seek, aTarget);
}
@@ -1580,22 +1573,22 @@ MediaDecoderStateMachine::DispatchDecode
GetDecodedAudioDuration(),
VideoQueue().Duration());
nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::SetIdle);
DecodeTaskQueue()->Dispatch(task.forget());
}
}
void
-MediaDecoderStateMachine::InitiateSeek()
+MediaDecoderStateMachine::InitiateSeek(SeekJob& aSeekJob)
{
MOZ_ASSERT(OnTaskQueue());
mCurrentSeek.RejectIfExists(__func__);
- mCurrentSeek.Steal(mPendingSeek);
+ mCurrentSeek.Steal(aSeekJob);
// Bound the seek time to be inside the media range.
int64_t end = Duration().ToMicroseconds();
NS_ASSERTION(end != -1, "Should know end time by now");
int64_t seekTime = mCurrentSeek.mTarget.GetTime().ToMicroseconds();
seekTime = std::min(seekTime, end);
seekTime = std::max(int64_t(0), seekTime);
NS_ASSERTION(seekTime >= 0 && seekTime <= end,
@@ -2099,22 +2092,17 @@ MediaDecoderStateMachine::SeekCompleted(
}
// Change state to DECODING or COMPLETED now. SeekingStopped will
// call MediaDecoderStateMachine::Seek to reset our state to SEEKING
// if we need to seek again.
bool isLiveStream = mResource->IsLiveStream();
State nextState;
- if (mPendingSeek.Exists()) {
- // A new seek target came in while we were processing the old one. No rest
- // for the seeking.
- DECODER_LOG("A new seek came along while we were finishing the old one - staying in SEEKING");
- nextState = DECODER_STATE_SEEKING;
- } else if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) {
+ if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) {
// Seeked to end of media, move to COMPLETED state. Note we don't do
// this when playing a live stream, since the end of media will advance
// once we download more data!
DECODER_LOG("Changed state from SEEKING (to %lld) to COMPLETED", seekTime);
// Explicitly set our state so we don't decode further, and so
// we report playback ended to the media element.
nextState = DECODER_STATE_COMPLETED;
} else {
@@ -2311,19 +2299,16 @@ nsresult MediaDecoderStateMachine::RunSt
DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
StartDecoding();
NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled");
return NS_OK;
}
case DECODER_STATE_SEEKING: {
- if (mPendingSeek.Exists()) {
- InitiateSeek();
- }
return NS_OK;
}
case DECODER_STATE_COMPLETED: {
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
StopPlayback();
}
// Play the remaining media. We want to run AdvanceFrame() at least
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -522,19 +522,57 @@ protected:
// Dispatches a LoadedMetadataEvent.
// This is threadsafe and can be called on any thread.
// The decoder monitor must be held.
void EnqueueLoadedMetadataEvent();
void EnqueueFirstFrameLoadedEvent();
+ struct SeekJob {
+ void Steal(SeekJob& aOther)
+ {
+ MOZ_DIAGNOSTIC_ASSERT(!Exists());
+ mTarget = aOther.mTarget;
+ aOther.mTarget.Reset();
+ mPromise = Move(aOther.mPromise);
+ }
+
+ bool Exists()
+ {
+ MOZ_ASSERT(mTarget.IsValid() == !mPromise.IsEmpty());
+ return mTarget.IsValid();
+ }
+
+ void Resolve(bool aAtEnd, const char* aCallSite)
+ {
+ mTarget.Reset();
+ MediaDecoder::SeekResolveValue val(aAtEnd, mTarget.mEventVisibility);
+ mPromise.Resolve(val, aCallSite);
+ }
+
+ void RejectIfExists(const char* aCallSite)
+ {
+ mTarget.Reset();
+ mPromise.RejectIfExists(true, aCallSite);
+ }
+
+ ~SeekJob()
+ {
+ MOZ_DIAGNOSTIC_ASSERT(!mTarget.IsValid());
+ MOZ_DIAGNOSTIC_ASSERT(mPromise.IsEmpty());
+ }
+
+ SeekTarget mTarget;
+ MozPromiseHolder<MediaDecoder::SeekPromise> mPromise;
+ };
+
// Clears any previous seeking state and initiates a new see on the decoder.
// The decoder monitor must be held.
- void InitiateSeek();
+ void InitiateSeek(SeekJob& aSeekJob);
nsresult DispatchAudioDecodeTaskIfNeeded();
// Ensures a task to decode audio has been dispatched to the decode task queue.
// If a task to decode has already been dispatched, this does nothing,
// otherwise this dispatches a task to do the decode.
// This is called on the state machine or decode threads.
// The decoder monitor must be held.
@@ -829,60 +867,19 @@ private:
// The decoder monitor must be held.
bool IsLogicallyPlaying()
{
MOZ_ASSERT(OnTaskQueue());
return mPlayState == MediaDecoder::PLAY_STATE_PLAYING ||
mNextPlayState == MediaDecoder::PLAY_STATE_PLAYING;
}
- struct SeekJob {
- void Steal(SeekJob& aOther)
- {
- MOZ_DIAGNOSTIC_ASSERT(!Exists());
- mTarget = aOther.mTarget;
- aOther.mTarget.Reset();
- mPromise = Move(aOther.mPromise);
- }
-
- bool Exists()
- {
- MOZ_ASSERT(mTarget.IsValid() == !mPromise.IsEmpty());
- return mTarget.IsValid();
- }
-
- void Resolve(bool aAtEnd, const char* aCallSite)
- {
- mTarget.Reset();
- MediaDecoder::SeekResolveValue val(aAtEnd, mTarget.mEventVisibility);
- mPromise.Resolve(val, aCallSite);
- }
-
- void RejectIfExists(const char* aCallSite)
- {
- mTarget.Reset();
- mPromise.RejectIfExists(true, aCallSite);
- }
-
- ~SeekJob()
- {
- MOZ_DIAGNOSTIC_ASSERT(!mTarget.IsValid());
- MOZ_DIAGNOSTIC_ASSERT(mPromise.IsEmpty());
- }
-
- SeekTarget mTarget;
- MozPromiseHolder<MediaDecoder::SeekPromise> mPromise;
- };
-
- // Queued seek - moves to mPendingSeek when DecodeFirstFrame completes.
+ // Queued seek - moves to mCurrentSeek when DecodeFirstFrame completes.
SeekJob mQueuedSeek;
- // Position to seek to in microseconds when the seek state transition occurs.
- SeekJob mPendingSeek;
-
// The position that we're currently seeking to.
SeekJob mCurrentSeek;
// Media Fragment end time in microseconds. Access controlled by decoder monitor.
int64_t mFragmentEndTime;
// The media sink resource. Used on the state machine thread.
RefPtr<media::MediaSink> mMediaSink;