From eefde59bed6908a29b62330f0d3f9afcb1593f95 Mon Sep 17 00:00:00 2001 From: alwu Date: Wed, 20 Mar 2024 22:29:33 +0000 Subject: [PATCH] Bug 1885959 - part3 : postpone seek while the engine is still in initialization. r=jolin We will postpone any seek happening before the engine initialization is finished, and will resolve the seek promise based on the latest seek if there are multiple seek being requested. Differential Revision: https://phabricator.services.mozilla.com/D205017 --- dom/media/ExternalEngineStateMachine.cpp | 55 ++++++++++++++++++++++++ dom/media/ExternalEngineStateMachine.h | 8 ++++ dom/media/MediaDecoderStateMachineBase.h | 3 +- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/dom/media/ExternalEngineStateMachine.cpp b/dom/media/ExternalEngineStateMachine.cpp index 29d0dc3d42bc..1728728dc613 100644 --- a/dom/media/ExternalEngineStateMachine.cpp +++ b/dom/media/ExternalEngineStateMachine.cpp @@ -365,6 +365,58 @@ bool ExternalEngineStateMachine::IsFormatSupportedByExternalEngine( #endif } +RefPtr ExternalEngineStateMachine::InvokeSeek( + const SeekTarget& aTarget) { + return InvokeAsync( + OwnerThread(), __func__, + [self = RefPtr(this), this, + target = aTarget]() -> RefPtr { + AssertOnTaskQueue(); + if (!mEngine || !mEngine->IsInited()) { + LOG("Can't perform seek (%" PRId64 ") now, add a pending seek task", + target.GetTime().ToMicroseconds()); + // We haven't added any pending seek before + if (mPendingSeek.mPromise.IsEmpty()) { + mPendingTasks.AppendElement(NS_NewRunnableFunction( + "ExternalEngineStateMachine::InvokeSeek", + [self = RefPtr{this}, this] { + if (!mPendingSeek.Exists()) { + return; + } + Seek(*mPendingSeek.mTarget) + ->Then(OwnerThread(), __func__, + [self = RefPtr{this}, + this](const MediaDecoder::SeekPromise:: + ResolveOrRejectValue& aVal) { + mPendingSeekRequest.Complete(); + if (aVal.IsResolve()) { + mPendingSeek.Resolve(__func__); + } else { + mPendingSeek.RejectIfExists(__func__); + } + mPendingSeek = SeekJob(); + }) + ->Track(mPendingSeekRequest); + })); + } else { + // Reject previous pending promise, as we will create a new one + LOG("Replace previous pending seek with a new one"); + mPendingSeek.RejectIfExists(__func__); + mPendingSeekRequest.DisconnectIfExists(); + } + mPendingSeek.mTarget = Some(target); + return mPendingSeek.mPromise.Ensure(__func__); + } + if (mPendingSeek.Exists()) { + LOG("Discard pending seek because another new seek happens"); + mPendingSeek.RejectIfExists(__func__); + mPendingSeek = SeekJob(); + mPendingSeekRequest.DisconnectIfExists(); + } + return self->Seek(target); + }); +} + RefPtr ExternalEngineStateMachine::Seek( const SeekTarget& aTarget) { AssertOnTaskQueue(); @@ -571,6 +623,9 @@ RefPtr ExternalEngineStateMachine::Shutdown() { mSetCDMProxyPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_ABORT_ERR, __func__); mSetCDMProxyRequest.DisconnectIfExists(); + mPendingSeek.RejectIfExists(__func__); + mPendingSeekRequest.DisconnectIfExists(); + mPendingTasks.Clear(); if (mEngine) { diff --git a/dom/media/ExternalEngineStateMachine.h b/dom/media/ExternalEngineStateMachine.h index 798fff944cb2..83250b0f3c81 100644 --- a/dom/media/ExternalEngineStateMachine.h +++ b/dom/media/ExternalEngineStateMachine.h @@ -56,6 +56,9 @@ class ExternalEngineStateMachine final ExternalEngineStateMachine(MediaDecoder* aDecoder, MediaFormatReader* aReader); + RefPtr InvokeSeek( + const SeekTarget& aTarget) override; + RefPtr InvokeSetSink( const RefPtr& aSink) override; @@ -309,6 +312,11 @@ class ExternalEngineStateMachine final MozPromiseHolder mSetCDMProxyPromise; MozPromiseRequestHolder mSetCDMProxyRequest; + // If seek happens while the engine is still initializing, then we would + // postpone the seek until the engine is ready. + SeekJob mPendingSeek; + MozPromiseRequestHolder mPendingSeekRequest; + // It would be zero for audio-only playback. gfx::IntSize mVideoDisplay; diff --git a/dom/media/MediaDecoderStateMachineBase.h b/dom/media/MediaDecoderStateMachineBase.h index 58721510153f..fb172b2d2277 100644 --- a/dom/media/MediaDecoderStateMachineBase.h +++ b/dom/media/MediaDecoderStateMachineBase.h @@ -85,7 +85,8 @@ class MediaDecoderStateMachineBase { RefPtr BeginShutdown(); // Seeks to the decoder to aTarget asynchronously. - RefPtr InvokeSeek(const SeekTarget& aTarget); + virtual RefPtr InvokeSeek( + const SeekTarget& aTarget); virtual size_t SizeOfVideoQueue() const = 0; virtual size_t SizeOfAudioQueue() const = 0;