Bug 1365190 P1 - NextFrameSeekingState should be aware of the existing video data request; r?jwwang
MozReview-Commit-ID: 3deIwYbQ3BM
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -985,19 +985,21 @@ public:
if (aVisibility == EventVisibility::Observable) {
mMaster->mOnPlaybackEvent.Notify(MediaEventType::SeekStarted);
// We want dormant actions to be transparent to the user.
// So we only notify the change when the seek request is from the user.
mMaster->UpdateNextFrameStatus(
MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING);
}
+ RefPtr<MediaDecoder::SeekPromise> p = mSeekJob.mPromise.Ensure(__func__);
+
DoSeek();
- return mSeekJob.mPromise.Ensure(__func__);
+ return p;
}
virtual void Exit() override = 0;
State GetState() const override
{
return DECODER_STATE_SEEKING;
}
@@ -1512,17 +1514,17 @@ public:
mCurrentTime = mMaster->GetMediaTime();
mDuration = mMaster->Duration();
return SeekingState::Enter(Move(aSeekJob), aVisibility);
}
void Exit() override
{
// Disconnect my async seek operation.
- mAsyncSeekTask->Cancel();
+ if (mAsyncSeekTask) { mAsyncSeekTask->Cancel(); }
// Disconnect MediaDecoder.
mSeekJob.RejectIfExists(__func__);
}
void HandleAudioDecoded(AudioData* aAudio) override
{
mMaster->PushAudio(aAudio);
@@ -1604,17 +1606,31 @@ public:
{
// The HTMLMediaElement.currentTime should be updated to the seek target
// which has been updated to the next frame's time.
return mSeekJob.mTarget->GetTime();
}
void DoSeek() override
{
- // We need to do the seek operation asynchronously. Because for a special
+ auto currentTime = mCurrentTime;
+ DiscardFrames(VideoQueue(), [currentTime] (int64_t aSampleTime) {
+ return aSampleTime <= currentTime.ToMicroseconds();
+ });
+
+ // If there is a pending video request, finish the seeking if we don't need
+ // more data, or wait for HandleVideoDecoded() to finish seeking.
+ if (mMaster->IsRequestingVideoData()) {
+ if (!NeedMoreVideo()) {
+ FinishSeek();
+ }
+ return;
+ }
+
+ // Otherwise, we need to do the seek operation asynchronously for a special
// case (bug504613.ogv) which has no data at all, the 1st seekToNextFrame()
// operation reaches the end of the media. If we did the seek operation
// synchronously, we immediately resolve the SeekPromise in mSeekJob and
// then switch to the CompletedState which dispatches an "ended" event.
// However, the ThenValue of the SeekPromise has not yet been set, so the
// promise resolving is postponed and then the JS developer receives the
// "ended" event before the seek promise is resolved.
// An asynchronous seek operation helps to solve this issue since while the
@@ -1622,20 +1638,19 @@ public:
// been set so that it won't be postponed.
RefPtr<Runnable> r = mAsyncSeekTask = new AysncNextFrameSeekTask(this);
OwnerThread()->Dispatch(r.forget());
}
private:
void DoSeekInternal()
{
- auto currentTime = mCurrentTime;
- DiscardFrames(VideoQueue(), [currentTime] (int64_t aSampleTime) {
- return aSampleTime <= currentTime.ToMicroseconds();
- });
+ // We don't need to discard frames to the mCurrentTime here because we have
+ // done it at DoSeek() and any video data received in between either
+ // finishes the seek operation or be discarded, see HandleVideoDecoded().
if (!NeedMoreVideo()) {
FinishSeek();
} else if (!mMaster->IsRequestingVideoData()
&& !mMaster->IsWaitingVideoData()) {
RequestVideoData();
}
}