Bug 1366362: P3. Have seekToNextFrame properly handle dormant mode. r?jwwang draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 24 May 2017 09:11:10 +0200
changeset 583606 b4b2d369ac66be409651ebd17d963198a9de595b
parent 583605 817fde2d43ac1faf48659a4e4de63fb34de70749
child 630123 db1b3d196c713441a24aed922c6399f60eab31dd
push id60463
push userbmo:jyavenard@mozilla.com
push dateWed, 24 May 2017 09:09:09 +0000
reviewersjwwang
bugs1366362
milestone55.0a1
Bug 1366362: P3. Have seekToNextFrame properly handle dormant mode. r?jwwang When coming out of dormant mode, we first perform an accurate seek, that will ensure the MediaDecoderReader has been reinitialised correctly. MozReview-Commit-ID: 2rWgu9AGAcY
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/SeekJob.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -474,16 +474,18 @@ public:
     }
 
     // Calculate the position to seek to when exiting dormant.
     auto t = mMaster->mMediaSink->IsStarted()
       ? mMaster->GetClock() : mMaster->GetMediaTime();
     mPendingSeek.mTarget.emplace(t, SeekTarget::Accurate);
     // SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
     // need to create the promise even it is not used at all.
+    // The promise may be used when coming out of DormantState into
+    // SeekingState.
     RefPtr<MediaDecoder::SeekPromise> x =
       mPendingSeek.mPromise.Ensure(__func__);
 
     // No need to call ResetDecode() and StopMediaSink() here.
     // We will do them during seeking when exiting dormant.
 
     // Ignore WAIT_FOR_DATA since we won't decode in dormant.
     mMaster->mAudioWaitRequest.DisconnectIfExists();
@@ -496,16 +498,18 @@ public:
   {
     // mPendingSeek is either moved when exiting dormant or
     // should be rejected here before transition to SHUTDOWN.
     mPendingSeek.RejectIfExists(__func__);
   }
 
   State GetState() const override { return DECODER_STATE_DORMANT; }
 
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
+
   void HandleVideoSuspendTimeout() override
   {
     // Do nothing since we've released decoders in Enter().
   }
 
   void HandleResumeVideoDecoding(const TimeUnit&) override
   {
     // Do nothing since we won't resume decoding until exiting dormant.
@@ -1698,16 +1702,78 @@ private:
   /*
    * Internal state.
    */
   TimeUnit mCurrentTime;
   TimeUnit mDuration;
   RefPtr<AysncNextFrameSeekTask> mAsyncSeekTask;
 };
 
+class MediaDecoderStateMachine::NextFrameSeekingFromDormantState
+  : public MediaDecoderStateMachine::AccurateSeekingState
+{
+public:
+  explicit NextFrameSeekingFromDormantState(Master* aPtr)
+    : AccurateSeekingState(aPtr)
+  {
+  }
+
+  RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aCurrentSeekJob,
+                                          SeekJob&& aFutureSeekJob)
+  {
+    mFutureSeekJob = Move(aFutureSeekJob);
+
+    SeekJob seekJob(Move(aCurrentSeekJob));
+    // Ensure that we don't transition to DecodingState once this seek
+    // completes.
+    seekJob.mTransition = false;
+
+    AccurateSeekingState::Enter(Move(seekJob), EventVisibility::Suppressed)
+      ->Then(OwnerThread(),
+             __func__,
+             [this]() {
+               mAccurateSeekRequest.Complete();
+               SetState<NextFrameSeekingState>(Move(mFutureSeekJob),
+                                               EventVisibility::Observable);
+             },
+             [this]() { mAccurateSeekRequest.Complete(); })
+      ->Track(mAccurateSeekRequest);
+    return mFutureSeekJob.mPromise.Ensure(__func__);
+  }
+
+  void Exit() override
+  {
+    mAccurateSeekRequest.DisconnectIfExists();
+    mFutureSeekJob.RejectIfExists(__func__);
+    AccurateSeekingState::Exit();
+  }
+
+private:
+  MozPromiseRequestHolder<MediaDecoder::SeekPromise> mAccurateSeekRequest;
+  SeekJob mFutureSeekJob;
+};
+
+RefPtr<MediaDecoder::SeekPromise>
+MediaDecoderStateMachine::DormantState::HandleSeek(SeekTarget aTarget)
+{
+  if (aTarget.IsNextFrame()) {
+    // NextFrameSeekingState doesn't reset the decoder unlike
+    // AccurateSeekingState. So we first must come out of dormant by seeking to
+    // mPendingSeek and continue later with the NextFrameSeek
+    SLOG("Changed state to SEEKING (to %" PRId64 ")",
+        aTarget.GetTime().ToMicroseconds());
+    SeekJob seekJob;
+    seekJob.mTarget = Some(aTarget);
+    return StateObject::SetState<NextFrameSeekingFromDormantState>(
+      Move(mPendingSeek), Move(seekJob));
+  }
+
+  return StateObject::HandleSeek(aTarget);
+}
+
 /**
  * Purpose: stop playback until enough data is decoded to continue playback.
  *
  * Transition to:
  *   SEEKING if any seek request.
  *   SHUTDOWN if any decode error.
  *   COMPLETED when having decoded all audio/video data.
  *   DECODING when having decoded enough data to continue playback.
@@ -2452,17 +2518,19 @@ SeekingState::SeekCompleted()
   SLOG("Seek completed, mCurrentPosition=%" PRId64,
        mMaster->mCurrentPosition.Ref().ToMicroseconds());
 
   if (mMaster->VideoQueue().PeekFront()) {
     mMaster->mMediaSink->Redraw(Info().mVideo);
     mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
   }
 
-  SetState<DecodingState>();
+  if (mSeekJob.mTransition) {
+    SetState<DecodingState>();
+  }
 }
 
 void
 MediaDecoderStateMachine::
 BufferingState::DispatchDecodeTasksIfNeeded()
 {
   if (mMaster->IsAudioDecoding()
       && !mMaster->HaveEnoughDecodedAudio()
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -243,16 +243,17 @@ private:
   class DecodeMetadataState;
   class WaitForCDMState;
   class DormantState;
   class DecodingFirstFrameState;
   class DecodingState;
   class SeekingState;
   class AccurateSeekingState;
   class NextFrameSeekingState;
+  class NextFrameSeekingFromDormantState;
   class BufferingState;
   class CompletedState;
   class ShutdownState;
 
   static const char* ToStateStr(State aState);
   static const char* ToStr(NextFrameStatus aStatus);
   const char* ToStateStr();
 
--- a/dom/media/SeekJob.h
+++ b/dom/media/SeekJob.h
@@ -22,13 +22,14 @@ struct SeekJob
   ~SeekJob();
 
   bool Exists() const;
   void Resolve(const char* aCallSite);
   void RejectIfExists(const char* aCallSite);
 
   Maybe<SeekTarget> mTarget;
   MozPromiseHolder<MediaDecoder::SeekPromise> mPromise;
+  bool mTransition = true;
 };
 
 } // namespace mozilla
 
 #endif /* SEEK_JOB_H */