Bug 1393087 - P3: Retry backward to find keyframe. r?kinetik draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 25 Sep 2017 16:47:08 +0200
changeset 670079 a61e52a975bcf505a6bc2c2affc12f63559471f3
parent 670078 faa3f5e0de33ad320742dc16c1f04baff7661234
child 670080 2d9f007918fd0d75872541f0d71420396bd45989
push id81501
push userbmo:jyavenard@mozilla.com
push dateMon, 25 Sep 2017 19:17:09 +0000
reviewerskinetik
bugs1393087
milestone58.0a1
Bug 1393087 - P3: Retry backward to find keyframe. r?kinetik When we seek in a webm containing an alpha channel, the first frame of a cluster may not be a keyframe for both channels. So seek backward until we find one. MozReview-Commit-ID: 14ETazkQ0AG
dom/media/webm/WebMDemuxer.cpp
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -1092,33 +1092,52 @@ WebMTrackDemuxer::GetInfo() const
 
 RefPtr<WebMTrackDemuxer::SeekPromise>
 WebMTrackDemuxer::Seek(const TimeUnit& aTime)
 {
   // Seeks to aTime. Upon success, SeekPromise will be resolved with the
   // actual time seeked to. Typically the random access point time
 
   auto seekTime = aTime;
-  mSamples.Reset();
-  mParent->SeekInternal(mType, aTime);
-  nsresult rv = mParent->GetNextPacket(mType, &mSamples);
-  if (NS_FAILED(rv)) {
-    if (rv == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
-      // Ignore the error for now, the next GetSample will be rejected with EOS.
-      return SeekPromise::CreateAndResolve(TimeUnit::Zero(), __func__);
-    }
-    return SeekPromise::CreateAndReject(rv, __func__);
-  }
+  bool keyframe = false;
+
   mNeedKeyframe = true;
 
-  // Check what time we actually seeked to.
-  if (mSamples.GetSize() > 0) {
-    const RefPtr<MediaRawData>& sample = mSamples.First();
-    seekTime = sample->mTime;
-  }
+  do {
+    mSamples.Reset();
+    mParent->SeekInternal(mType, seekTime);
+    nsresult rv = mParent->GetNextPacket(mType, &mSamples);
+    if (NS_FAILED(rv)) {
+      if (rv == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+        // Ignore the error for now, the next GetSample will be rejected with EOS.
+        return SeekPromise::CreateAndResolve(TimeUnit::Zero(), __func__);
+      }
+      return SeekPromise::CreateAndReject(rv, __func__);
+    }
+
+    // Check what time we actually seeked to.
+    if (mSamples.GetSize() == 0) {
+      // We can't determine if the seek succeeded at this stage, so break the
+      // loop.
+      break;
+    }
+
+    for (const auto& sample : mSamples) {
+      seekTime = sample->mTime;
+      keyframe = sample->mKeyframe;
+      if (keyframe) {
+        break;
+      }
+    }
+    if (!keyframe) {
+      // We didn't find any keyframe, attempt to seek to the previous cluster.
+      seekTime = mSamples.First()->mTime - TimeUnit::FromMicroseconds(1);
+    }
+  } while (!keyframe && seekTime >= TimeUnit::Zero());
+
   SetNextKeyFrameTime();
 
   return SeekPromise::CreateAndResolve(seekTime, __func__);
 }
 
 nsresult
 WebMTrackDemuxer::NextSample(RefPtr<MediaRawData>& aData)
 {