Bug 1229987: P5. Drop frames during internal seeking early. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 18 Dec 2015 09:37:03 +1100
changeset 276882 289faf063a57
parent 276881 37e78e0926ff
child 276883 6848f6651cce
push id69314
push userjyavenard@mozilla.com
push dateFri, 18 Dec 2015 08:27:29 +0000
treeherdermozilla-inbound@289faf063a57 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1229987
milestone46.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 1229987: P5. Drop frames during internal seeking early. r=cpearce 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;