Bug 1508434 - p1: Support explicitly resetting seek threshold. r=jya
authorJohn Lin <jolin@mozilla.com>
Fri, 11 Jan 2019 17:07:49 +0000
changeset 513489 6e9fd9ef59df4ed2cd1a622a12f4a17aa74d4c81
parent 513488 189dd5e62ffb0f67cbca7e709672da6218d922b4
child 513490 dcfc482c09693d7289fa275c850ccb4105caa95a
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1508434
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1508434 - p1: Support explicitly resetting seek threshold. r=jya Usually the threshold is reset internally in MediaDataDecoder subclasses that support the hint in their Flush() implementations so the value will start fresh after seeking completed. But sometimes when there are consecutive seek requests, MediaFormatReader::DecoderData::Flush() could return early because DecoderData::mFlushed stays true when there is no sample demuxed yet, and the threshold will not be cleared. Also, in MediaFormatReader::SetVideoDecodeThreshold() we decide not to set the hint when the seek target is close to EOS by checking the existence of the next keyframe, and that could fail when there are gaps between MSE buffered ranges. To make sure the hint is never out of date, we should clear it rather than leaving it untouched. Differential Revision: https://phabricator.services.mozilla.com/D15227
dom/media/MediaFormatReader.cpp
dom/media/ipc/PRemoteVideoDecoder.ipdl
dom/media/ipc/PVideoDecoder.ipdl
dom/media/ipc/RemoteVideoDecoderChild.cpp
dom/media/ipc/RemoteVideoDecoderParent.cpp
dom/media/ipc/VideoDecoderChild.cpp
dom/media/ipc/VideoDecoderParent.cpp
dom/media/platforms/PlatformDecoderModule.h
dom/media/platforms/android/RemoteDataDecoder.cpp
dom/media/platforms/apple/AppleVTDecoder.cpp
dom/media/platforms/wmf/WMFMediaDataDecoder.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -2885,20 +2885,19 @@ void MediaFormatReader::SetVideoDecodeTh
     // If IsSeeking() is true, then video seek must have completed already.
     TimeUnit keyframe;
     if (NS_FAILED(mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&keyframe))) {
       return;
     }
 
     // If the key frame is invalid/infinite, it means the target position is
     // closing to end of stream. We don't want to skip any frame at this point.
-    if (!keyframe.IsValid() || keyframe.IsInfinite()) {
-      return;
-    }
-    threshold = mOriginalSeekTarget.GetTime();
+    threshold = keyframe.IsValid() && !keyframe.IsInfinite()
+                    ? mOriginalSeekTarget.GetTime()
+                    : TimeUnit::Invalid();
   } else {
     return;
   }
 
   LOG("Set seek threshold to %" PRId64, threshold.ToMicroseconds());
   mVideo.mDecoder->SetSeekThreshold(threshold);
 }
 
--- a/dom/media/ipc/PRemoteVideoDecoder.ipdl
+++ b/dom/media/ipc/PRemoteVideoDecoder.ipdl
@@ -32,17 +32,17 @@ async protocol PRemoteVideoDecoder
 parent:
   async Init();
 
   async Input(MediaRawDataIPDL data);
 
   async Flush();
   async Drain();
   async Shutdown();
-
+  // To clear the threshold, call with INT64_MIN.
   async SetSeekThreshold(int64_t time);
 
   async __delete__();
 
 child:
   async InitComplete(nsCString decoderDescription,
                      ConversionRequired conversion);
   async InitFailed(nsresult reason);
--- a/dom/media/ipc/PVideoDecoder.ipdl
+++ b/dom/media/ipc/PVideoDecoder.ipdl
@@ -32,17 +32,17 @@ async protocol PVideoDecoder
 parent:
   async Init();
 
   async Input(MediaRawDataIPDL data);
 
   async Flush();
   async Drain();
   async Shutdown();
-
+  // To clear the threshold, call with INT64_MIN.
   async SetSeekThreshold(int64_t time);
 
   async __delete__();
 
 child:
   async InitComplete(nsCString decoderDescription, bool hardware, nsCString hardwareReason, uint32_t conversion);
   async InitFailed(nsresult reason);
 
--- a/dom/media/ipc/RemoteVideoDecoderChild.cpp
+++ b/dom/media/ipc/RemoteVideoDecoderChild.cpp
@@ -284,17 +284,17 @@ bool RemoteVideoDecoderChild::IsHardware
 nsCString RemoteVideoDecoderChild::GetDescriptionName() const {
   AssertOnManagerThread();
   return mDescription;
 }
 
 void RemoteVideoDecoderChild::SetSeekThreshold(const media::TimeUnit& aTime) {
   AssertOnManagerThread();
   if (mCanSend) {
-    SendSetSeekThreshold(aTime.ToMicroseconds());
+    SendSetSeekThreshold(aTime.IsValid() ? aTime.ToMicroseconds() : INT64_MIN);
   }
 }
 
 MediaDataDecoder::ConversionRequired RemoteVideoDecoderChild::NeedsConversion()
     const {
   AssertOnManagerThread();
   return mConversion;
 }
--- a/dom/media/ipc/RemoteVideoDecoderParent.cpp
+++ b/dom/media/ipc/RemoteVideoDecoderParent.cpp
@@ -199,17 +199,19 @@ mozilla::ipc::IPCResult RemoteVideoDecod
   mDecoder = nullptr;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult RemoteVideoDecoderParent::RecvSetSeekThreshold(
     const int64_t& aTime) {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(OnManagerThread());
-  mDecoder->SetSeekThreshold(TimeUnit::FromMicroseconds(aTime));
+  mDecoder->SetSeekThreshold(aTime == INT64_MIN
+                                 ? TimeUnit::Invalid()
+                                 : TimeUnit::FromMicroseconds(aTime));
   return IPC_OK();
 }
 
 void RemoteVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy) {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
     mDecoder->Shutdown();
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -299,17 +299,17 @@ bool VideoDecoderChild::IsHardwareAccele
 nsCString VideoDecoderChild::GetDescriptionName() const {
   AssertOnManagerThread();
   return mDescription;
 }
 
 void VideoDecoderChild::SetSeekThreshold(const media::TimeUnit& aTime) {
   AssertOnManagerThread();
   if (mCanSend) {
-    SendSetSeekThreshold(aTime.ToMicroseconds());
+    SendSetSeekThreshold(aTime.IsValid() ? aTime.ToMicroseconds() : INT64_MIN);
   }
 }
 
 MediaDataDecoder::ConversionRequired VideoDecoderChild::NeedsConversion()
     const {
   AssertOnManagerThread();
   return mConversion;
 }
--- a/dom/media/ipc/VideoDecoderParent.cpp
+++ b/dom/media/ipc/VideoDecoderParent.cpp
@@ -247,17 +247,19 @@ mozilla::ipc::IPCResult VideoDecoderPare
   mDecoder = nullptr;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult VideoDecoderParent::RecvSetSeekThreshold(
     const int64_t& aTime) {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(OnManagerThread());
-  mDecoder->SetSeekThreshold(TimeUnit::FromMicroseconds(aTime));
+  mDecoder->SetSeekThreshold(aTime == INT64_MIN
+                                 ? TimeUnit::Invalid()
+                                 : TimeUnit::FromMicroseconds(aTime));
   return IPC_OK();
 }
 
 void VideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy) {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
     mDecoder->Shutdown();
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -314,17 +314,18 @@ class MediaDataDecoder : public DecoderD
   }
 
   // Return the name of the MediaDataDecoder, only used for decoding.
   // May be accessed in a non thread-safe fashion.
   virtual nsCString GetDescriptionName() const = 0;
 
   // Set a hint of seek target time to decoder. Decoder will drop any decoded
   // data which pts is smaller than this value. This threshold needs to be clear
-  // after reset decoder.
+  // after reset decoder. To clear it explicitly, call this method with
+  // TimeUnit::Invalid().
   // Decoder may not honor this value. However, it'd be better that
   // video decoder implements this API to improve seek performance.
   // Note: it should be called before Input() or after Flush().
   virtual void SetSeekThreshold(const media::TimeUnit& aTime) {}
 
   // When playing adaptive playback, recreating an Android video decoder will
   // cause the transition not smooth during resolution change.
   // Reuse the decoder if the decoder support recycling.
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -216,18 +216,23 @@ class RemoteVideoDecoder : public Remote
 
   bool SupportDecoderRecycling() const override {
     return mIsCodecSupportAdaptivePlayback;
   }
 
   void SetSeekThreshold(const TimeUnit& aTime) override {
     RefPtr<RemoteVideoDecoder> self = this;
     nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
-        "RemoteVideoDecoder::SetSeekThreshold",
-        [self, aTime]() { self->mSeekTarget = Some(aTime); });
+        "RemoteVideoDecoder::SetSeekThreshold", [self, aTime]() {
+          if (aTime.IsValid()) {
+            self->mSeekTarget = Some(aTime);
+          } else {
+            self->mSeekTarget.reset();
+          }
+        });
     nsresult rv = mTaskQueue->Dispatch(runnable.forget());
     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
     Unused << rv;
   }
 
   bool IsUsefulData(const RefPtr<MediaData>& aSample) override {
     AssertOnTaskQueue();
 
--- a/dom/media/platforms/apple/AppleVTDecoder.cpp
+++ b/dom/media/platforms/apple/AppleVTDecoder.cpp
@@ -241,17 +241,21 @@ RefPtr<MediaDataDecoder::DecodePromise> 
 AppleVTDecoder::AppleFrameRef* AppleVTDecoder::CreateAppleFrameRef(
     const MediaRawData* aSample) {
   MOZ_ASSERT(aSample);
   return new AppleFrameRef(*aSample);
 }
 
 void AppleVTDecoder::SetSeekThreshold(const media::TimeUnit& aTime) {
   LOG("SetSeekThreshold %lld", aTime.ToMicroseconds());
-  mSeekTargetThreshold = Some(aTime);
+  if (aTime.IsValid()) {
+    mSeekTargetThreshold = Some(aTime);
+  } else {
+    mSeekTargetThreshold.reset();
+  }
 }
 
 //
 // Implementation details.
 //
 
 // Callback passed to the VideoToolbox decoder for returning data.
 // This needs to be static because the API takes a C-style pair of
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.h
@@ -53,17 +53,21 @@ class MFTManager {
     return false;
   }
 
   virtual TrackInfo::TrackType GetType() = 0;
 
   virtual nsCString GetDescriptionName() const = 0;
 
   virtual void SetSeekThreshold(const media::TimeUnit& aTime) {
-    mSeekTargetThreshold = Some(aTime);
+    if (aTime.IsValid()) {
+      mSeekTargetThreshold = Some(aTime);
+    } else {
+      mSeekTargetThreshold.reset();
+    }
   }
 
   virtual MediaDataDecoder::ConversionRequired NeedsConversion() const {
     return MediaDataDecoder::ConversionRequired::kNeedNone;
   }
 
  protected:
   // IMFTransform wrapper that performs the decoding.