Bug 1595603 - part2 : delay seeking task when media is inactive r=bryce a=RyanVM
authoralwu <alwu@mozilla.com>
Thu, 09 Jan 2020 17:10:08 +0000
changeset 571171 ab154f7d32b08b46178c536f56efbf85b5b4e27e
parent 571170 84c1d1cd152f774673504c04577e0aa667d4b224
child 571172 b267babdbb3a81b815de9a4b56242d68d0e5f014
push id12553
push usercbrindusan@mozilla.com
push dateTue, 14 Jan 2020 20:45:36 +0000
treeherdermozilla-beta@b267babdbb3a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbryce, RyanVM
bugs1595603
milestone73.0
Bug 1595603 - part2 : delay seeking task when media is inactive r=bryce a=RyanVM When media element is inactive, asking MDSM to seek is actually useless, because all the data we decode won't be showed to user. In addition, we have to store extra pending events for `seeking` and `seeked`, which might result in memory overflow if the inactive page is calling `seek()` all the time. Therfore, we should delay all seeking tasks while media is inactive, and perform the latest seeking task when media becomes active. Differential Revision: https://phabricator.services.mozilla.com/D58918
dom/html/HTMLMediaElement.cpp
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/SeekTarget.h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -6521,30 +6521,32 @@ void HTMLMediaElement::SuspendOrResumeEl
     // to do on shutdown.
     if (mMediaKeys) {
       nsAutoString keySystem;
       mMediaKeys->GetKeySystem(keySystem);
     }
     if (mDecoder) {
       mDecoder->Pause();
       mDecoder->Suspend();
+      mDecoder->SetDelaySeekMode(true);
     }
     mEventDeliveryPaused = true;
     // We won't want to resume media element from the bfcache.
     ClearResumeDelayedMediaPlaybackAgentIfNeeded();
     StopListeningMediaControlEventIfNeeded();
   } else {
     if (!mPaused) {
       mCurrentLoadPlayTime.Start();
     }
     if (mDecoder) {
       mDecoder->Resume();
       if (!mPaused && !mDecoder->IsEnded()) {
         mDecoder->Play();
       }
+      mDecoder->SetDelaySeekMode(false);
     }
     if (mEventDeliveryPaused) {
       mEventDeliveryPaused = false;
       DispatchPendingMediaEvents();
     }
     // If the media element has been blocked and isn't still allowed to play
     // when it comes back from the bfcache, we would notify front end to show
     // the blocking icon in order to inform user that the site is still being
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -625,38 +625,56 @@ void MediaDecoder::Seek(double aTime, Se
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   AbstractThread::AutoEnter context(AbstractMainThread());
   MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value.");
 
   auto time = TimeUnit::FromSeconds(aTime);
 
   mLogicalPosition = aTime;
-
   mLogicallySeeking = true;
   SeekTarget target = SeekTarget(time, aSeekType);
   CallSeek(target);
 
   if (mPlayState == PLAY_STATE_ENDED) {
     ChangeState(GetOwner()->GetPaused() ? PLAY_STATE_PAUSED
                                         : PLAY_STATE_PLAYING);
   }
 }
 
+void MediaDecoder::SetDelaySeekMode(bool aShouldDelaySeek) {
+  MOZ_ASSERT(NS_IsMainThread());
+  LOG("SetDelaySeekMode, shouldDelaySeek=%d", aShouldDelaySeek);
+  if (mShouldDelaySeek == aShouldDelaySeek) {
+    return;
+  }
+  mShouldDelaySeek = aShouldDelaySeek;
+  if (!mShouldDelaySeek && mDelayedSeekTarget) {
+    Seek(mDelayedSeekTarget->GetTime().ToSeconds(),
+         mDelayedSeekTarget->GetType());
+    mDelayedSeekTarget.reset();
+  }
+}
+
 void MediaDecoder::DiscardOngoingSeekIfExists() {
   MOZ_ASSERT(NS_IsMainThread());
   AbstractThread::AutoEnter context(AbstractMainThread());
   mSeekRequest.DisconnectIfExists();
 }
 
 void MediaDecoder::CallSeek(const SeekTarget& aTarget) {
   MOZ_ASSERT(NS_IsMainThread());
   AbstractThread::AutoEnter context(AbstractMainThread());
+  if (mShouldDelaySeek) {
+    LOG("Delay seek to %f and store it to delayed seek target",
+        mDelayedSeekTarget->GetTime().ToSeconds());
+    mDelayedSeekTarget = Some(aTarget);
+    return;
+  }
   DiscardOngoingSeekIfExists();
-
   mDecoderStateMachine->InvokeSeek(aTarget)
       ->Then(mAbstractMainThread, __func__, this, &MediaDecoder::OnSeekResolved,
              &MediaDecoder::OnSeekRejected)
       ->Track(mSeekRequest);
 }
 
 double MediaDecoder::GetCurrentTime() {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -154,16 +154,24 @@ class MediaDecoder : public DecoderDocto
   void SetPreservesPitch(bool aPreservesPitch);
   void SetLooping(bool aLooping);
 
   // Set the given device as the output device.
   RefPtr<GenericPromise> SetSink(AudioDeviceInfo* aSinkDevice);
 
   bool GetMinimizePreroll() const { return mMinimizePreroll; }
 
+  // When we enable delay seek mode, media decoder won't actually ask MDSM to do
+  // seeking. During this period, we would store the latest seeking target and
+  // perform the seek to that target when we leave the mode. If we have any
+  // delayed seeks stored `IsSeeking()` will return true. E.g. During delay
+  // seeking mode, if we get seek target to 5s, 10s, 7s. When we stop delaying
+  // seeking, we would only seek to 7s.
+  void SetDelaySeekMode(bool aShouldDelaySeek);
+
   // All MediaStream-related data is protected by mReentrantMonitor.
   // We have at most one DecodedStreamData per MediaDecoder. Its stream
   // is used as the input for each ProcessedMediaTrack created by calls to
   // captureStream(UntilEnded). Seeking creates a new source stream, as does
   // replaying after the input as ended. In the latter case, the new source is
   // not connected to streams created by captureStreamUntilEnded.
 
   // Turn output capturing of this decoder on or off. If it is on, the
@@ -659,16 +667,21 @@ class MediaDecoder : public DecoderDocto
   // conditions, eg. when the cursor is hovering over the tab. This observer is
   // used to listen the related events.
   RefPtr<BackgroundVideoDecodingPermissionObserver> mVideoDecodingOberver;
 
   // True if we want to resume video decoding even the media element is in the
   // background.
   bool mIsBackgroundVideoDecodingAllowed;
 
+  // True if we want to delay seeking, and and save the latest seeking target to
+  // resume to when we stop delaying seeking.
+  bool mShouldDelaySeek = false;
+  Maybe<SeekTarget> mDelayedSeekTarget;
+
  public:
   AbstractCanonical<double>* CanonicalVolume() { return &mVolume; }
   AbstractCanonical<bool>* CanonicalPreservesPitch() {
     return &mPreservesPitch;
   }
   AbstractCanonical<bool>* CanonicalLooping() { return &mLooping; }
   AbstractCanonical<RefPtr<AudioDeviceInfo>>* CanonicalSinkDevice() {
     return &mSinkDevice;
--- a/dom/media/SeekTarget.h
+++ b/dom/media/SeekTarget.h
@@ -52,16 +52,17 @@ struct SeekTarget {
     mTime = aTime;
   }
   void SetType(Type aType) { mType = aType; }
   void SetVideoOnly(bool aVideoOnly) { mVideoOnly = aVideoOnly; }
   bool IsFast() const { return mType == SeekTarget::Type::PrevSyncPoint; }
   bool IsAccurate() const { return mType == SeekTarget::Type::Accurate; }
   bool IsNextFrame() const { return mType == SeekTarget::Type::NextFrame; }
   bool IsVideoOnly() const { return mVideoOnly; }
+  Type GetType() const { return mType; }
 
  private:
   // Seek target time.
   media::TimeUnit mTime;
   // Whether we should seek "Fast", or "Accurate".
   // "Fast" seeks to the seek point preceding mTime, whereas
   // "Accurate" seeks as close as possible to mTime.
   Type mType;