Bug 1269325: [mp4] Recalculate dts after adjusting cts. r=kentuckyfriedtakahe,r=gerald a=ritu
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 03 May 2016 16:02:10 +1000
changeset 326296 23ea2f0b3f66cf8b6aeb15346b5018bf3c0aade8
parent 326295 4f2def663d8476fcd19da7fae3575371003afe11
child 326297 5b21738fb29eea1d8374922dbe5d48b6465c48a1
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskentuckyfriedtakahe, gerald, ritu
bugs1269325
milestone47.0
Bug 1269325: [mp4] Recalculate dts after adjusting cts. r=kentuckyfriedtakahe,r=gerald a=ritu CTS are adjusted so that all frames within a moof are contiguous and gapless. This means that the duration of each sample are updated accordingly. In MP4, the definition of a sample's duration is the delta between two decoding timestamp. As such, when changing the duration, the decode timestamp should be updated accordingly. MozReview-Commit-ID: 8D8DeNeyzy
media/libstagefright/binding/MoofParser.cpp
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -549,18 +549,16 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
     if (flags & 0x800) {
       ctsOffset = reader->Read32();
     }
 
     Sample sample;
     sample.mByteRange = MediaByteRange(offset, offset + sampleSize);
     offset += sampleSize;
 
-    sample.mDecodeTime =
-      aMdhd.ToMicroseconds((int64_t)decodeTime - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset);
     sample.mCompositionRange = Interval<Microseconds>(
       aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset),
       aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset + sampleDuration - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset));
     decodeTime += sampleDuration;
 
     // Sometimes audio streams don't properly mark their samples as keyframes,
     // because every audio sample is a keyframe.
     sample.mSync = !(sampleFlags & 0x1010000) || aIsAudio;
@@ -578,19 +576,42 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
   }
   ctsOrder.Sort(CtsComparator());
 
   for (size_t i = 0; i < ctsOrder.Length(); i++) {
     if (i + 1 < ctsOrder.Length()) {
       ctsOrder[i]->mCompositionRange.end = ctsOrder[i + 1]->mCompositionRange.start;
     }
   }
+  // In MP4, the duration of a sample is defined as the delta between two decode
+  // timestamps. The operation above has updated the duration of each sample
+  // as a Sample's duration is mCompositionRange.end - mCompositionRange.start
+  // MSE's TrackBuffersManager expects dts that increased by the sample's
+  // duration, so we rewrite the dts accordingly.
+  int64_t presentationDuration = ctsOrder.LastElement()->mCompositionRange.end
+                                 - ctsOrder[0]->mCompositionRange.start;
+  int64_t decodeDuration = aMdhd.ToMicroseconds(decodeTime - *aDecodeTime);
+  float adjust = (float)decodeDuration / presentationDuration;
+  int64_t dtsOffset =
+    aMdhd.ToMicroseconds((int64_t)*aDecodeTime - aEdts.mMediaStart)
+    + aMvhd.ToMicroseconds(aEdts.mEmptyOffset);
+  int64_t compositionDuration = 0;
+  // Adjust the dts, ensuring that the new adjusted dts will never be greater
+  // than decodeTime (the next moof's decode start time).
+  for (auto& sample : mIndex) {
+    sample.mDecodeTime = dtsOffset + compositionDuration * adjust;
+    compositionDuration += sample.mCompositionRange.Length();
+  }
   mTimeRange = Interval<Microseconds>(ctsOrder[0]->mCompositionRange.start,
       ctsOrder.LastElement()->mCompositionRange.end);
   *aDecodeTime = decodeTime;
+  MOZ_ASSERT(aMdhd.ToMicroseconds((int64_t)decodeTime - aEdts.mMediaStart)
+             + aMvhd.ToMicroseconds(aEdts.mEmptyOffset)
+             >= mIndex[mIndex.Length() -1].mDecodeTime,
+             "Adjusted dts is too high");
   return true;
 }
 
 Tkhd::Tkhd(Box& aBox)
 {
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Tkhd, "Incomplete Box (missing flags)");