Bug 1229987: P5. Drop frames during internal seeking early. r=cpearce a=sylvestre
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 18 Dec 2015 09:37:03 +1100
changeset 298058 aa47aa5c7a22
parent 298057 50de8c9efef8
child 298059 081b14fd8bf9
push id8857
push userkwierso@gmail.com
push dateMon, 28 Dec 2015 16:46:13 +0000
treeherdermozilla-aurora@5628bb302871 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, sylvestre
bugs1229987
milestone45.0a2
Bug 1229987: P5. Drop frames during internal seeking early. r=cpearce a=sylvestre We would only start to drop frames once we had a request for data. On platforms such as windows WMF, following a drain we would typically hold over 33 decoded frames which would have been held resulting in unnecessarily high memory usage. This also results in a simplified logic for the following steps.
dom/media/MediaFormatReader.cpp
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1036,78 +1036,76 @@ MediaFormatReader::Update(TrackType aTra
     LOGV("Nothing more to do");
     return;
   }
 
   // Record number of frames decoded and parsed. Automatically update the
   // stats counters using the AutoNotifyDecoded stack-based class.
   AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
 
-  if (aTrack == TrackInfo::kVideoTrack) {
-    uint64_t delta =
-      decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames;
-    a.mDecoded = static_cast<uint32_t>(delta);
-    mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal;
+  // Drop any frames found prior our internal seek target.
+  while (decoder.mTimeThreshold && decoder.mOutput.Length()) {
+    RefPtr<MediaData>& output = decoder.mOutput[0];
+    SeekTarget target = decoder.mTimeThreshold.ref();
+    media::TimeUnit time = media::TimeUnit::FromMicroseconds(output->mTime);
+    if (time >= target.mTime) {
+      // We have reached our internal seek target.
+      decoder.mTimeThreshold.reset();
+    }
+    if (time < target.mTime || target.mDropTarget) {
+      LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)",
+           TrackTypeToStr(aTrack),
+           media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(),
+           target.mTime.ToSeconds(),
+           output->mKeyframe);
+      decoder.mOutput.RemoveElementAt(0);
+    }
   }
 
   if (decoder.HasPromise()) {
     needOutput = true;
-    if (!decoder.mOutput.IsEmpty()) {
+    if (decoder.mOutput.Length()) {
       // We have a decoded sample ready to be returned.
       if (aTrack == TrackType::kVideoTrack) {
+        uint64_t delta =
+          decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames;
+        a.mDecoded = static_cast<uint32_t>(delta);
+        mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal;
         nsCString error;
         mVideo.mIsHardwareAccelerated =
           mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
       }
-      while (decoder.mOutput.Length()) {
-        RefPtr<MediaData> output = decoder.mOutput[0];
-        decoder.mOutput.RemoveElementAt(0);
-        decoder.mSizeOfQueue -= 1;
-        decoder.mLastSampleTime =
-          Some(media::TimeUnit::FromMicroseconds(output->mTime));
-        auto target = decoder.mTimeThreshold;
-        auto time = media::TimeUnit::FromMicroseconds(output->mTime);
-        if (target && time >= target.ref().mTime) {
-          // We have reached our internal seek target.
-          decoder.mTimeThreshold.reset();
-        }
-        if (target && (time < target.ref().mTime || target.ref().mDropTarget)) {
-          LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)",
-               TrackTypeToStr(aTrack),
-               media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(),
-               target.ref().mTime.ToSeconds(),
-               output->mKeyframe);
-        } else {
-           ReturnOutput(output, aTrack);
-           break;
-        }
-      }
-    }
-  }
-  if (decoder.HasPromise() && decoder.mOutput.IsEmpty()) {
-    if (decoder.mError) {
+      RefPtr<MediaData> output = decoder.mOutput[0];
+      decoder.mOutput.RemoveElementAt(0);
+      decoder.mSizeOfQueue -= 1;
+      decoder.mLastSampleTime =
+        Some(media::TimeUnit::FromMicroseconds(output->mTime));
+      ReturnOutput(output, aTrack);
+    } else if (decoder.mError) {
+      LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
       decoder.RejectPromise(DECODE_ERROR, __func__);
       return;
-    }
-    if (decoder.mDrainComplete) {
+    } else if (decoder.mDrainComplete) {
       bool wasDraining = decoder.mDraining;
       decoder.mDrainComplete = false;
       decoder.mDraining = false;
       if (decoder.mDemuxEOS) {
+        LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
         decoder.RejectPromise(END_OF_STREAM, __func__);
       } else if (decoder.mWaitingForData) {
         if (wasDraining && decoder.mLastSampleTime &&
             !decoder.mNextStreamSourceID) {
           // We have completed draining the decoder following WaitingForData.
           // Set up the internal seek machinery to be able to resume from the
           // last sample decoded.
           LOG("Seeking to last sample time: %lld",
               decoder.mLastSampleTime.ref().ToMicroseconds());
           InternalSeek(aTrack, SeekTarget(decoder.mLastSampleTime.ref(), true));
         }
+        LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack));
         decoder.RejectPromise(WAITING_FOR_DATA, __func__);
       }
       // Now that draining has completed, we check if we have received
       // new data again as the result may now be different from the earlier
       // run.
       if (UpdateReceivedNewData(aTrack)) {
         LOGV("Nothing more to do");
         return;