Bug 1342913: P2. Terminate draining operations when possible. r=gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 07 Mar 2017 20:13:39 +1100
changeset 498743 22cae85837a1216b6a6248910e17a96796ede773
parent 498742 2b7cc2b452988668b40056b81ce33f39ed9afb66
child 549237 af6530e06098e5f68953518109d5d5ae5f0dd167
push id49292
push userbmo:jyavenard@mozilla.com
push dateWed, 15 Mar 2017 07:43:11 +0000
reviewersgerald
bugs1342913
milestone55.0a1
Bug 1342913: P2. Terminate draining operations when possible. r=gerald An interesting intermittent condition not previously handled. We were incorrectly assuming that we always had a decode promise pending when a drain was requested. If a change of content occurred when resuming from a waiting for data condition: we would have stalled forever as the waiting promise would never have been resolved even after new data was appended. MozReview-Commit-ID: BQSRSHYqTSe
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -2139,16 +2139,26 @@ MediaFormatReader::Update(TrackType aTra
     return;
   }
 
   if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
     LOGV("Skipping in progress, nothing more to do");
     return;
   }
 
+  if (decoder.HasWaitingPromise() && decoder.HasCompletedDrain()) {
+    // This situation will occur when a change of stream ID occurred during
+    // internal seeking following a gap encountered in the data, a drain was
+    // requested and has now completed. We need to complete the draining process
+    // so that the new data can be processed.
+    // We can complete the draining operation now as we have no pending
+    // operation when a waiting promise is pending.
+    decoder.mDrainState = DrainState::None;
+  }
+
   if (UpdateReceivedNewData(aTrack)) {
     LOGV("Nothing more to do");
     return;
   }
 
   if (decoder.mSeekRequest.Exists()) {
     LOGV("Seeking hasn't completed, nothing more to do");
     return;
@@ -2225,18 +2235,17 @@ MediaFormatReader::Update(TrackType aTra
         nsCString error;
         mVideo.mIsHardwareAccelerated =
           mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
       }
     } else if (decoder.HasFatalError()) {
       LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
       decoder.RejectPromise(decoder.mError.ref(), __func__);
       return;
-    } else if (decoder.mDrainState == DrainState::DrainCompleted
-               || decoder.mDrainState == DrainState::DrainAborted) {
+    } else if (decoder.HasCompletedDrain()) {
       if (decoder.mDemuxEOS) {
         LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
         decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
       } else if (decoder.mWaitingForData) {
         if (decoder.mDrainState == DrainState::DrainCompleted
             && decoder.mLastSampleTime
             && !decoder.mNextStreamSourceID) {
           // We have completed draining the decoder following WaitingForData.
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -258,16 +258,21 @@ private:
     RefPtr<SharedShutdownPromiseHolder> mShutdownPromise;
 
     MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDrainRequest;
     DrainState mDrainState;
     bool HasPendingDrain() const
     {
       return mDrainState != DrainState::None;
     }
+    bool HasCompletedDrain() const
+    {
+      return mDrainState == DrainState::DrainCompleted ||
+             mDrainState == DrainState::DrainAborted;
+    }
     void RequestDrain()
     {
         MOZ_RELEASE_ASSERT(mDrainState == DrainState::None);
         mDrainState = DrainState::DrainRequested;
     }
 
     uint32_t mNumOfConsecutiveError;
     uint32_t mMaxConsecutiveError;