Bug 1331070 - delay seek request until decoding first frames for non-MSE media.
See see
bug 1321198 comment 17. This is a workaround to alleviate the issue
which seems to happen on win8 x64 opt only.
MozReview-Commit-ID: Lr4viEjuFkC
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -237,16 +237,19 @@ public:
// Return true if we are currently seeking in the media resource.
// Call on the main thread only.
bool IsSeeking() const;
// Return true if the decoder has reached the end of playback.
bool IsEnded() const;
+ // True if we are playing a MediaSource object.
+ virtual bool IsMSE() const { return false; }
+
// Return true if the MediaDecoderOwner's error attribute is not null.
// Must be called before Shutdown().
bool OwnerHasError() const;
already_AddRefed<GMPCrashHelper> GetCrashHelper() override;
protected:
// Updates the media duration. This is called while the media is being
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -516,16 +516,23 @@ private:
class MediaDecoderStateMachine::DecodingFirstFrameState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit DecodingFirstFrameState(Master* aPtr) : StateObject(aPtr) { }
void Enter();
+ void Exit() override
+ {
+ // mPendingSeek is either moved in MaybeFinishDecodeFirstFrame()
+ // or should be rejected here before transition to SHUTDOWN.
+ mPendingSeek.RejectIfExists(__func__);
+ }
+
State GetState() const override
{
return DECODER_STATE_DECODING_FIRSTFRAME;
}
void HandleAudioDecoded(MediaData* aAudio) override
{
mMaster->PushAudio(aAudio);
@@ -587,20 +594,34 @@ public:
}
void HandleResumeVideoDecoding() override
{
// We never suspend video decoding in this state.
MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
}
+ RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+ {
+ if (mMaster->mIsMSE) {
+ return StateObject::HandleSeek(aTarget);
+ }
+ // Delay seek request until decoding first frames for non-MSE media.
+ SLOG("Not Enough Data to seek at this stage, queuing seek");
+ mPendingSeek.RejectIfExists(__func__);
+ mPendingSeek.mTarget.emplace(aTarget);
+ return mPendingSeek.mPromise.Ensure(__func__);
+ }
+
private:
// Notify FirstFrameLoaded if having decoded first frames and
// transition to SEEKING if there is any pending seek, or DECODING otherwise.
void MaybeFinishDecodeFirstFrame();
+
+ SeekJob mPendingSeek;
};
/**
* Purpose: decode audio/video data for playback.
*
* Transition to:
* DORMANT if playback is paused for a while.
* SEEKING if any seek request.
@@ -2094,17 +2115,21 @@ DecodingFirstFrameState::MaybeFinishDeco
MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
if ((mMaster->IsAudioDecoding() && AudioQueue().GetSize() == 0)
|| (mMaster->IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
return;
}
mMaster->FinishDecodeFirstFrame();
- SetState<DecodingState>();
+ if (mPendingSeek.Exists()) {
+ SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
+ } else {
+ SetState<DecodingState>();
+ }
}
void
MediaDecoderStateMachine::
DecodingState::Enter()
{
MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
@@ -2542,16 +2567,17 @@ MediaDecoderStateMachine::MediaDecoderSt
mAudioCaptured(false),
mMinimizePreroll(aDecoder->GetMinimizePreroll()),
mSentLoadedMetadataEvent(false),
mSentFirstFrameLoadedEvent(false),
mVideoDecodeSuspended(false),
mVideoDecodeSuspendTimer(mTaskQueue),
mOutputStreamManager(new OutputStreamManager()),
mResource(aDecoder->GetResource()),
+ mIsMSE(aDecoder->IsMSE()),
INIT_MIRROR(mBuffered, TimeIntervals()),
INIT_MIRROR(mEstimatedDuration, NullableTimeUnit()),
INIT_MIRROR(mExplicitDuration, Maybe<double>()),
INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
INIT_MIRROR(mNextPlayState, MediaDecoder::PLAY_STATE_PAUSED),
INIT_MIRROR(mVolume, 1.0),
INIT_MIRROR(mPreservesPitch, true),
INIT_MIRROR(mSameOriginMedia, false),
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -688,16 +688,18 @@ private:
MediaEventProducer<DecoderDoctorEvent> mOnDecoderDoctorEvent;
void OnCDMProxyReady(RefPtr<CDMProxy> aProxy);
void OnCDMProxyNotReady();
RefPtr<CDMProxy> mCDMProxy;
MozPromiseRequestHolder<MediaDecoder::CDMProxyPromise> mCDMProxyPromise;
+ const bool mIsMSE;
+
private:
// The buffered range. Mirrored from the decoder thread.
Mirror<media::TimeIntervals> mBuffered;
// The duration according to the demuxer's current estimate, mirrored from the main thread.
Mirror<media::NullableTimeUnit> mEstimatedDuration;
// The duration explicitly set by JS, mirrored from the main thread.
--- a/dom/media/mediasource/MediaSourceDecoder.h
+++ b/dom/media/mediasource/MediaSourceDecoder.h
@@ -71,16 +71,18 @@ public:
MediaDecoderOwner::NextFrameStatus NextFrameBufferedStatus() override;
bool CanPlayThrough() override;
void NotifyWaitingForKey() override;
MediaEventSource<void>* WaitingForKeyEvent() override;
+ bool IsMSE() const override { return true; }
+
private:
void DoSetMediaSourceDuration(double aDuration);
media::TimeInterval ClampIntervalToEnd(const media::TimeInterval& aInterval);
// The owning MediaSource holds a strong reference to this decoder, and
// calls Attach/DetachMediaSource on this decoder to set and clear
// mMediaSource.
dom::MediaSource* mMediaSource;