Bug 1325905. Part 3 - split HandleNotDecoded() into HandleAudioNotDecoded() and HandleVideoNotDecoded(). draft
authorJW Wang <jwwang@mozilla.com>
Wed, 21 Dec 2016 18:00:37 +0800
changeset 454467 25b04e270326bbf2ca10a5be6b670f0962bc57ae
parent 454466 afda477d4fb338fe005d4c39c092840fbc55825e
child 454468 3b69a728ed9c1433f398b9e5688b19ea3849eb3c
push id39938
push userjwwang@mozilla.com
push dateThu, 29 Dec 2016 11:35:09 +0000
bugs1325905
milestone53.0a1
Bug 1325905. Part 3 - split HandleNotDecoded() into HandleAudioNotDecoded() and HandleVideoNotDecoded(). MozReview-Commit-ID: 3RcG43pxGSv
dom/media/MediaDecoderStateMachine.cpp
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -189,17 +189,18 @@ public:
   virtual void Exit() {};  // Exit action.
   virtual void Step() {}   // Perform a 'cycle' of this state object.
   virtual State GetState() const = 0;
 
   // Event handlers for various events.
   virtual void HandleCDMProxyReady() {}
   virtual void HandleAudioDecoded(MediaData* aAudio) {}
   virtual void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) {}
-  virtual void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError);
+  virtual void HandleAudioNotDecoded(const MediaResult& aError);
+  virtual void HandleVideoNotDecoded(const MediaResult& aError);
   virtual void HandleAudioWaited(MediaData::Type aType);
   virtual void HandleVideoWaited(MediaData::Type aType);
   virtual void HandleNotWaited(const WaitForDataRejectValue& aRejection);
   virtual void HandleEndOfStream() {}
   virtual void HandleWaitingForData() {}
   virtual void HandleAudioCaptured() {}
 
   virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget);
@@ -795,25 +796,21 @@ public:
   virtual void Exit() override = 0;
 
   State GetState() const override
   {
     return DECODER_STATE_SEEKING;
   }
 
   void HandleAudioDecoded(MediaData* aAudio) override = 0;
-
   void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override = 0;
-
-  void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError) override = 0;
-
+  void HandleAudioNotDecoded(const MediaResult& aError) override = 0;
+  void HandleVideoNotDecoded(const MediaResult& aError) override = 0;
   void HandleAudioWaited(MediaData::Type aType) override = 0;
-
   void HandleVideoWaited(MediaData::Type aType) override = 0;
-
   void HandleNotWaited(const WaitForDataRejectValue& aRejection) override = 0;
 
   void HandleVideoSuspendTimeout() override
   {
     // Do nothing since we want a valid video frame to show when seek is done.
   }
 
   void HandleResumeVideoDecoding() override
@@ -915,61 +912,18 @@ public:
 
     if (!mDoneVideoSeeking) {
       RequestVideoData();
       return;
     }
     MaybeFinishSeek();
   }
 
-  void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError) override
-  {
-    MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking, "Seek shouldn't be finished");
-
-    // Ignore pending requests from video-only seek.
-    if (aType == MediaData::AUDIO_DATA && mSeekJob.mTarget->IsVideoOnly()) {
-      return;
-    }
-
-    // If the decoder is waiting for data, we tell it to call us back when the
-    // data arrives.
-    if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
-      mMaster->WaitForData(aType);
-      return;
-    }
-
-    if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
-      if (aType == MediaData::AUDIO_DATA) {
-        RequestAudioData();
-      } else {
-        RequestVideoData();
-      }
-      return;
-    }
-
-    if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
-      if (aType == MediaData::AUDIO_DATA) {
-        AudioQueue().Finish();
-        mDoneAudioSeeking = true;
-      } else {
-        if (mFirstVideoFrameAfterSeek) {
-          // Hit the end of stream. Move mFirstVideoFrameAfterSeek into
-          // mSeekedVideoData so we have something to display after seeking.
-          mMaster->PushVideo(mFirstVideoFrameAfterSeek);
-        }
-        VideoQueue().Finish();
-        mDoneVideoSeeking = true;
-      }
-      MaybeFinishSeek();
-      return;
-    }
-
-    // This is a decode error, delegate to the generic error path.
-    mMaster->DecodeError(aError);
-  }
+  void HandleAudioNotDecoded(const MediaResult& aError) override;
+  void HandleVideoNotDecoded(const MediaResult& aError) override;
 
   void HandleAudioWaited(MediaData::Type aType) override
   {
     MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking, "Seek shouldn't be finished");
 
     // Ignore pending requests from video-only seek.
     if (mSeekJob.mTarget->IsVideoOnly()) {
       return;
@@ -1371,58 +1325,18 @@ private:
     if (aVideo->mTime > mCurrentTime) {
       mMaster->PushVideo(aVideo);
       FinishSeek();
     } else {
       RequestVideoData();
     }
   }
 
-  void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError) override
-  {
-    MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
-    MOZ_ASSERT(NeedMoreVideo());
-
-    switch (aType) {
-    case MediaData::AUDIO_DATA:
-    {
-      // We don't care about audio decode errors in this state which will be
-      // handled by other states after seeking.
-      break;
-    }
-    case MediaData::VIDEO_DATA:
-    {
-      if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
-        VideoQueue().Finish();
-        FinishSeek();
-        break;
-      }
-
-      // Video seek not finished.
-      switch (aError.Code()) {
-        case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
-          mMaster->WaitForData(MediaData::VIDEO_DATA);
-          break;
-        case NS_ERROR_DOM_MEDIA_CANCELED:
-          RequestVideoData();
-          break;
-        case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
-          MOZ_ASSERT(false, "Shouldn't want more data for ended video.");
-          break;
-        default:
-          // Raise an error since we can't finish video seek anyway.
-          mMaster->DecodeError(aError);
-          break;
-      }
-      break;
-    }
-    default:
-      MOZ_ASSERT_UNREACHABLE("We cannot handle RAW_DATA or NULL_DATA here.");
-    }
-  }
+  void HandleAudioNotDecoded(const MediaResult& aError) override;
+  void HandleVideoNotDecoded(const MediaResult& aError) override;
 
   void HandleAudioWaited(MediaData::Type aType) override
   {
     // We don't care about audio in this state.
   }
 
   void HandleVideoWaited(MediaData::Type aType) override
   {
@@ -1703,20 +1617,18 @@ public:
     MOZ_DIAGNOSTIC_ASSERT(false, "Shouldn't escape the SHUTDOWN state.");
   }
 
   State GetState() const override
   {
     return DECODER_STATE_SHUTDOWN;
   }
 
-  void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError) override
-  {
-    return;
-  }
+  void HandleAudioNotDecoded(const MediaResult& aError) override {}
+  void HandleVideoNotDecoded(const MediaResult& aError) override {}
 
   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
   {
     MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek in shutdown state.");
     return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
   }
 
   RefPtr<ShutdownPromise> HandleShutdown() override
@@ -1733,57 +1645,16 @@ public:
   void HandleResumeVideoDecoding() override
   {
     MOZ_DIAGNOSTIC_ASSERT(false, "Already shutting down.");
   }
 };
 
 void
 MediaDecoderStateMachine::
-StateObject::HandleNotDecoded(MediaData::Type aType, const MediaResult& aError)
-{
-  bool isAudio = aType == MediaData::AUDIO_DATA;
-  MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
-
-  // If the decoder is waiting for data, we tell it to call us back when the
-  // data arrives.
-  if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
-    mMaster->WaitForData(aType);
-    HandleWaitingForData();
-    return;
-  }
-
-  if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
-    if (isAudio) {
-      mMaster->EnsureAudioDecodeTaskQueued();
-    } else {
-      mMaster->EnsureVideoDecodeTaskQueued();
-    }
-    return;
-  }
-
-  // If this is a decode error, delegate to the generic error path.
-  if (aError != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
-    mMaster->DecodeError(aError);
-    return;
-  }
-
-  // This is an EOS. Finish off the queue, and then handle things based on our
-  // state.
-  if (isAudio) {
-    AudioQueue().Finish();
-  } else {
-    VideoQueue().Finish();
-  }
-
-  HandleEndOfStream();
-}
-
-void
-MediaDecoderStateMachine::
 StateObject::HandleAudioWaited(MediaData::Type aType)
 {
   mMaster->EnsureAudioDecodeTaskQueued();
 }
 
 void
 MediaDecoderStateMachine::
 StateObject::HandleVideoWaited(MediaData::Type aType)
@@ -1793,16 +1664,58 @@ StateObject::HandleVideoWaited(MediaData
 
 void
 MediaDecoderStateMachine::
 StateObject::HandleNotWaited(const WaitForDataRejectValue& aRejection)
 {
 
 }
 
+void
+MediaDecoderStateMachine::
+StateObject::HandleAudioNotDecoded(const MediaResult& aError)
+{
+  switch (aError.Code()) {
+    case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+      mMaster->WaitForData(MediaData::AUDIO_DATA);
+      HandleWaitingForData();
+      break;
+    case NS_ERROR_DOM_MEDIA_CANCELED:
+      mMaster->EnsureAudioDecodeTaskQueued();
+      break;
+    case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+      AudioQueue().Finish();
+      HandleEndOfStream();
+      break;
+    default:
+      mMaster->DecodeError(aError);
+  }
+}
+
+void
+MediaDecoderStateMachine::
+StateObject::HandleVideoNotDecoded(const MediaResult& aError)
+{
+  switch (aError.Code()) {
+    case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+      mMaster->WaitForData(MediaData::VIDEO_DATA);
+      HandleWaitingForData();
+      break;
+    case NS_ERROR_DOM_MEDIA_CANCELED:
+      mMaster->EnsureVideoDecodeTaskQueued();
+      break;
+    case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+      VideoQueue().Finish();
+      HandleEndOfStream();
+      break;
+    default:
+      mMaster->DecodeError(aError);
+  }
+}
+
 RefPtr<MediaDecoder::SeekPromise>
 MediaDecoderStateMachine::
 StateObject::HandleSeek(SeekTarget aTarget)
 {
   SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
   SeekJob seekJob;
   seekJob.mTarget = Some(aTarget);
   return SetSeekingState(Move(seekJob), EventVisibility::Observable);
@@ -2135,16 +2048,102 @@ SeekingState::SeekCompleted()
     mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
   }
 
   SetState<DecodingState>();
 }
 
 void
 MediaDecoderStateMachine::
+AccurateSeekingState::HandleAudioNotDecoded(const MediaResult& aError)
+{
+  if (mSeekJob.mTarget->IsVideoOnly()) {
+    return;
+  }
+  MOZ_ASSERT(!mDoneAudioSeeking);
+  switch (aError.Code()) {
+    case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+      mMaster->WaitForData(MediaData::AUDIO_DATA);
+      break;
+    case NS_ERROR_DOM_MEDIA_CANCELED:
+      RequestAudioData();
+      break;
+    case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+      AudioQueue().Finish();
+      mDoneAudioSeeking = true;
+      MaybeFinishSeek();
+      break;
+    default:
+      mMaster->DecodeError(aError);
+  }
+}
+
+void
+MediaDecoderStateMachine::
+AccurateSeekingState::HandleVideoNotDecoded(const MediaResult& aError)
+{
+  MOZ_ASSERT(!mDoneVideoSeeking);
+  switch (aError.Code()) {
+    case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+      mMaster->WaitForData(MediaData::VIDEO_DATA);
+      break;
+    case NS_ERROR_DOM_MEDIA_CANCELED:
+      RequestVideoData();
+      break;
+    case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+      if (mFirstVideoFrameAfterSeek) {
+        // Hit the end of stream. Move mFirstVideoFrameAfterSeek into
+        // mSeekedVideoData so we have something to display after seeking.
+        mMaster->PushVideo(mFirstVideoFrameAfterSeek);
+      }
+      VideoQueue().Finish();
+      mDoneVideoSeeking = true;
+      MaybeFinishSeek();
+      break;
+    default:
+      mMaster->DecodeError(aError);
+  }
+}
+
+void
+MediaDecoderStateMachine::
+NextFrameSeekingState::HandleAudioNotDecoded(const MediaResult& aError)
+{
+  MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
+  MOZ_ASSERT(NeedMoreVideo());
+  // We don't care about audio decode errors in this state which will be
+  // handled by other states after seeking.
+}
+
+void
+MediaDecoderStateMachine::
+NextFrameSeekingState::HandleVideoNotDecoded(const MediaResult& aError)
+{
+  MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
+  MOZ_ASSERT(NeedMoreVideo());
+  // Video seek not finished.
+  switch (aError.Code()) {
+    case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+      mMaster->WaitForData(MediaData::VIDEO_DATA);
+      break;
+    case NS_ERROR_DOM_MEDIA_CANCELED:
+      RequestVideoData();
+      break;
+    case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+      VideoQueue().Finish();
+      FinishSeek();
+      break;
+    default:
+      // Raise an error since we can't finish video seek anyway.
+      mMaster->DecodeError(aError);
+  }
+}
+
+void
+MediaDecoderStateMachine::
 BufferingState::Step()
 {
   TimeStamp now = TimeStamp::Now();
   MOZ_ASSERT(!mBufferingStart.IsNull(), "Must know buffering start time.");
 
   // With buffering heuristics we will remain in the buffering state if
   // we've not decoded enough data to begin playback, or if we've not
   // downloaded a reasonable amount of data inside our buffering time.
@@ -3003,17 +3002,17 @@ MediaDecoderStateMachine::RequestAudioDa
         // audio->GetEndTime() is not always mono-increasing in chained ogg.
         mDecodedAudioEndTime = std::max(aAudio->GetEndTime(), mDecodedAudioEndTime);
         SAMPLE_LOG("OnAudioDecoded [%lld,%lld]", aAudio->mTime, aAudio->GetEndTime());
         mStateObj->HandleAudioDecoded(aAudio);
       },
       [this] (const MediaResult& aError) {
         SAMPLE_LOG("OnAudioNotDecoded aError=%u", aError.Code());
         mAudioDataRequest.Complete();
-        mStateObj->HandleNotDecoded(MediaData::AUDIO_DATA, aError);
+        mStateObj->HandleAudioNotDecoded(aError);
       })
   );
 }
 
 void
 MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded()
 {
   MOZ_ASSERT(OnTaskQueue());
@@ -3069,17 +3068,17 @@ MediaDecoderStateMachine::RequestVideoDa
         // Handle abnormal or negative timestamps.
         mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, aVideo->GetEndTime());
         SAMPLE_LOG("OnVideoDecoded [%lld,%lld]", aVideo->mTime, aVideo->GetEndTime());
         mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime);
       },
       [this] (const MediaResult& aError) {
         SAMPLE_LOG("OnVideoNotDecoded aError=%u", aError.Code());
         mVideoDataRequest.Complete();
-        mStateObj->HandleNotDecoded(MediaData::VIDEO_DATA, aError);
+        mStateObj->HandleVideoNotDecoded(aError);
       })
   );
 }
 
 void
 MediaDecoderStateMachine::WaitForData(MediaData::Type aType)
 {
   MOZ_ASSERT(OnTaskQueue());