Bug 1378691 P3 - [WIP] keep decoding audio; draft
authorKaku Kuo <kaku@mozilla.com>
Fri, 07 Jul 2017 18:42:30 +0800
changeset 605303 54ebbf12828a536943d8007bc35f8c4026fe7c21
parent 605302 3c9b0f09445db224399e98f359c5ead466f89886
child 605304 e916e1898359208100a969c0bd9567764607249a
push id67360
push userbmo:kaku@mozilla.com
push dateFri, 07 Jul 2017 11:06:26 +0000
bugs1378691
milestone56.0a1
Bug 1378691 P3 - [WIP] keep decoding audio; MozReview-Commit-ID: 2NiKCnMVYcH
dom/media/MediaDecoderStateMachine.cpp
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1431,17 +1431,17 @@ protected:
     return NS_OK;
   }
 
   virtual media::TimeUnit GetSeekTarget() const
   {
     return mSeekJob.mTarget->GetTime();
   }
 
-  void MaybeFinishSeek()
+  virtual void MaybeFinishSeek()
   {
     if (mDoneAudioSeeking && mDoneVideoSeeking) {
       SeekCompleted();
     }
   }
 
   /*
    * Track the current seek promise made by the reader.
@@ -1768,68 +1768,89 @@ public:
     // of video-only seek.
     mMaster->mOnPlaybackEvent.Notify(MediaEventType::VideoOnlySeekCompleted);
 
     AccurateSeekingState::Exit();
   }
 
   void HandleAudioDecoded(AudioData* aAudio) override
   {
-    MOZ_ASSERT(mDoneAudioSeeking && !mDoneVideoSeeking,
-               "Seek shouldn't be finished");
+    MOZ_ASSERT(mDoneVideoSeeking, "Should have done video seeking.");
+    MOZ_ASSERT(!mDoneAudioSeeking, "Seek shouldn't be finished.");
     MOZ_ASSERT(aAudio);
 
-    // Video-only seek doesn't reset audio decoder. There might be pending audio
-    // requests when AccurateSeekTask::Seek() begins. We will just store the
-    // data without checking |mDiscontinuity| or calling
-    // DropAudioUpToSeekTarget().
+    // Video-only seek doesn't reset audio decoder and might decode audio if
+    // needed. Just store the data without calling DropAudioUpToSeekTarget().
     mMaster->PushAudio(aAudio);
-  }
-
-  void HandleWaitingForAudio() override { }
-
-  void HandleAudioCanceled() override { }
-
-  void HandleEndOfAudio() override { }
-
-  void HandleAudioWaited(MediaData::Type aType) override
-  {
-    MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking,
-               "Seek shouldn't be finished");
-
-    // Ignore pending requests from video-only seek.
+
+    // Stop decoding audio if the queued audio samples' end time is larger than
+    // the sought video data's end time.
+    // Note that the case of "audio is shorter than the video seek target" is
+    // handled by AccurateSeekingState::HandleEndOfAudio().
+    if (mMaster->mDecodedAudioEndTime >= mMaster->mDecodedVideoEndTime) {
+      mDoneAudioSeeking = true;
+    }
+
+    if (!mDoneAudioSeeking) {
+      RequestAudioData();
+      return;
+    }
+
+    MaybeFinishSeek();
   }
 
   void DoSeek() override
   {
     // TODO: keep decoding audio.
     mDoneAudioSeeking = true;
     mDoneVideoSeeking = !Info().HasVideo();
 
     mMaster->ResetDecode(TrackInfo::kVideoTrack);
 
     DemuxerSeek();
   }
 
+  void Step() override
+  {
+    // Keep update the current time in JS, so that JS players, such as YouTube,
+    // are able to keep buffering.
+    mMaster->UpdatePlaybackPositionPeriodically();
+  }
+
 private:
   // Trigger skip-to-next-key-frame if the video decoding is too slow to catch
   // up playback position.
   void RequestVideoData() override
   {
     MOZ_ASSERT(!mDoneVideoSeeking);
     mMaster->RequestVideoData(GetSeekTarget());
   }
 
   // Drop video until catch up playback position.
   media::TimeUnit GetSeekTarget() const override
   {
     return mMaster->mMediaSink->IsStarted()
            ? mMaster->GetClock()
            : mSeekJob.mTarget->GetTime();
   }
+
+  void MaybeFinishSeek() override
+  {
+    if (mDoneAudioSeeking && mDoneVideoSeeking) {
+
+      // Decode audio data if we don't have enough samples.
+      if (mMaster->mDecodedAudioEndTime < mMaster->mDecodedVideoEndTime) {
+        mDoneAudioSeeking = false;
+        RequestAudioData();
+        return;
+      }
+
+      SeekCompleted();
+    }
+  }
 };
 
 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