Bug 1280036: don't create video frame before seek target. r?jya draft
authorAlfredo <ayang@mozilla.com>
Thu, 16 Jun 2016 13:32:30 +0100
changeset 378400 bb32f39650c9e49aad8c5c712a64063361b2ee24
parent 377839 fbc8f897e016fe44393bb2e3c064071598b8f586
child 523528 189daad13eb423399eef6ba56788f8d00a4136c5
push id21007
push userayang@mozilla.com
push dateThu, 16 Jun 2016 12:32:55 +0000
reviewersjya
bugs1280036
milestone50.0a1
Bug 1280036: don't create video frame before seek target. r?jya MozReview-Commit-ID: 5idJj2r2d6E
dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
dom/media/platforms/wmf/WMFMediaDataDecoder.h
dom/media/platforms/wmf/WMFVideoMFTManager.cpp
dom/media/platforms/wmf/WMFVideoMFTManager.h
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
@@ -231,9 +231,24 @@ WMFMediaDataDecoder::ConfigurationChange
 void
 WMFMediaDataDecoder::ProcessConfigurationChanged(UniquePtr<TrackInfo>&& aConfig)
 {
   if (mMFTManager) {
     mMFTManager->ConfigurationChanged(*aConfig);
   }
 }
 
+void
+WMFMediaDataDecoder::SetSeekThreshold(const media::TimeUnit& aTime)
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
+
+  RefPtr<WMFMediaDataDecoder> self = this;
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewRunnableFunction([self, aTime]() {
+    media::TimeUnit threshold = aTime;
+    self->mMFTManager->SetSeekThreshold(threshold);
+  });
+  mTaskQueue->Dispatch(runnable.forget());
+}
+
 } // namespace mozilla
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.h
@@ -32,17 +32,20 @@ public:
   // or until no more is able to be produced.
   // Returns S_OK on success, or MF_E_TRANSFORM_NEED_MORE_INPUT if there's not
   // enough data to produce more output. If this returns a failure code other
   // than MF_E_TRANSFORM_NEED_MORE_INPUT, an error will be reported to the
   // MP4Reader.
   virtual HRESULT Output(int64_t aStreamOffset,
                          RefPtr<MediaData>& aOutput) = 0;
 
-  void Flush() { mDecoder->Flush(); }
+  void Flush() {
+    mDecoder->Flush();
+    mSeekTargetThreshold.reset();
+  }
 
   void Drain()
   {
     if (FAILED(mDecoder->SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0))) {
       NS_WARNING("Failed to send DRAIN command to MFT");
     }
   }
 
@@ -52,19 +55,25 @@ public:
   virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const { return false; }
 
   virtual TrackInfo::TrackType GetType() = 0;
 
   virtual void ConfigurationChanged(const TrackInfo& aConfig) {}
 
   virtual const char* GetDescriptionName() const = 0;
 
+  virtual void SetSeekThreshold(const media::TimeUnit& aTime) {
+    mSeekTargetThreshold = Some(aTime);
+  }
+
 protected:
   // IMFTransform wrapper that performs the decoding.
   RefPtr<MFTDecoder> mDecoder;
+
+  Maybe<media::TimeUnit> mSeekTargetThreshold;
 };
 
 // Decodes audio and video using Windows Media Foundation. Samples are decoded
 // using the MFTDecoder created by the MFTManager. This class implements
 // the higher-level logic that drives mapping the MFT to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
 // type are handled by MFTManager and the MFTDecoder it creates.
 class WMFMediaDataDecoder : public MediaDataDecoder {
@@ -88,16 +97,18 @@ public:
 
   nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
 
   const char* GetDescriptionName() const override
   {
     return mMFTManager ? mMFTManager->GetDescriptionName() : "";
   }
 
+  virtual void SetSeekThreshold(const media::TimeUnit& aTime) override;
+
 private:
 
   // Called on the task queue. Inserts the sample into the decoder, and
   // extracts output if available.
   void ProcessDecode(MediaRawData* aSample);
 
   // Called on the task queue. Extracts output if available, and delivers
   // it to the reader. Called after ProcessDecode() and ProcessDrain().
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -784,16 +784,30 @@ WMFVideoMFTManager::Output(int64_t aStre
         ++mNullOutputCount;
         if (mNullOutputCount > 250) {
           LOG("Excessive Video MFTDecoder returning success but no output; giving up");
           mGotExcessiveNullOutput = true;
           return E_FAIL;
         }
         continue;
       }
+      if (mSeekTargetThreshold.isSome()) {
+        media::TimeUnit pts = GetSampleTime(sample);
+        if (!pts.IsValid()) {
+          return E_FAIL;
+        }
+        if (pts < mSeekTargetThreshold.ref()) {
+          LOG("Dropping video frame which pts is smaller than seek target.");
+          // It is necessary to clear the pointer to release the previous output
+          // buffer.
+          sample = nullptr;
+          continue;
+        }
+        mSeekTargetThreshold.reset();
+      }
       break;
     }
     // Else unexpected error, assert, and bail.
     NS_WARNING("WMFVideoMFTManager::Output() unexpected error");
     return hr;
   }
 
   RefPtr<VideoData> frame;
@@ -833,9 +847,14 @@ WMFVideoMFTManager::IsHardwareAccelerate
 void
 WMFVideoMFTManager::ConfigurationChanged(const TrackInfo& aConfig)
 {
   MOZ_ASSERT(aConfig.GetAsVideoInfo());
   mVideoInfo = *aConfig.GetAsVideoInfo();
   mImageSize = mVideoInfo.mImage;
 }
 
+void
+WMFVideoMFTManager::SetSeekThreshold(const media::TimeUnit& aTime)
+{
+}
+
 } // namespace mozilla
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.h
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h
@@ -44,16 +44,18 @@ public:
 
   const char* GetDescriptionName() const override
   {
     nsCString failureReason;
     return IsHardwareAccelerated(failureReason)
       ? "wmf hardware video decoder" : "wmf software video decoder";
   }
 
+  void SetSeekThreshold(const media::TimeUnit& aTime) override;
+
 private:
 
   bool InitializeDXVA(bool aForceD3D9);
 
   bool InitInternal(bool aForceD3D9);
 
   HRESULT ConfigureVideoFrameGeometry();