Bug 1331070 - Delay seek request until decoding first frames for non-MSE media. r=kaku, a=lizzard
authorJW Wang <jwwang@mozilla.com>
Fri, 10 Feb 2017 10:22:36 +0800
changeset 376098 a6042b35e7ce777ce5bd70189daae2024ef4e23d
parent 376097 81a4f7ad167146c67d00a4deedb20e40fc37b490
child 376099 5c0b8a190eb779b48be00454f00310aac1fe4875
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskaku, lizzard
bugs1331070, 1321198
milestone53.0a2
Bug 1331070 - Delay seek request until decoding first frames for non-MSE media. r=kaku, a=lizzard See see bug 1321198 comment 17. This is a workaround to alleviate the issue which seems to happen on win8 x64 opt only.
dom/media/MediaDecoder.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/mediasource/MediaSourceDecoder.h
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -227,16 +227,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);
@@ -586,20 +593,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.
@@ -2067,17 +2088,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);
 
@@ -2502,16 +2527,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
@@ -679,16 +679,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;