Bug 1271847: Only adjust the samples once we have a complete moof. r?kentuckyfriedtakahe draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 11 May 2016 15:59:33 +1000
changeset 365639 780a0b4ba905401d6870fe2328abd96b035ab9fc
parent 365638 25eb7d4919953d28059045b0aa96c038891075ac
child 520611 11835f16f5621397bf7ee362bd6181e7e2367da2
push id17802
push userbmo:jyavenard@mozilla.com
push dateWed, 11 May 2016 06:07:08 +0000
reviewerskentuckyfriedtakahe
bugs1271847
milestone49.0a1
Bug 1271847: Only adjust the samples once we have a complete moof. r?kentuckyfriedtakahe MozReview-Commit-ID: 5TO0d20uUhZ
media/libstagefright/binding/MoofParser.cpp
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -341,26 +341,75 @@ MoofParser::ParseEncrypted(Box& aBox)
 
       if (mSinf.IsValid()) {
         break;
       }
     }
   }
 }
 
+class CtsComparator
+{
+public:
+  bool Equals(Sample* const aA, Sample* const aB) const
+  {
+    return aA->mCompositionRange.start == aB->mCompositionRange.start;
+  }
+  bool
+  LessThan(Sample* const aA, Sample* const aB) const
+  {
+    return aA->mCompositionRange.start < aB->mCompositionRange.start;
+  }
+};
+
 Moof::Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio)
   : mRange(aBox.Range())
   , mMaxRoundingError(35000)
 {
+  uint64_t startDecodeTime = *aDecodeTime;
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("traf")) {
       ParseTraf(box, aTrex, aMvhd, aMdhd, aEdts, aSinf, aDecodeTime, aIsAudio);
     }
   }
   if (IsValid()) {
+    // Ensure the samples are contiguous with no gaps.
+    nsTArray<Sample*> ctsOrder;
+    for (auto& sample : mIndex) {
+      ctsOrder.AppendElement(&sample);
+    }
+    ctsOrder.Sort(CtsComparator());
+
+    for (size_t i = 1; i < ctsOrder.Length(); i++) {
+      ctsOrder[i-1]->mCompositionRange.end = ctsOrder[i]->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(*aDecodeTime - startDecodeTime);
+    float adjust = (float)decodeDuration / presentationDuration;
+    int64_t dtsOffset =
+      aMdhd.ToMicroseconds((int64_t)startDecodeTime - 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);
+
     ProcessCenc();
   }
 }
 
 bool
 Moof::GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges)
 {
   aByteRanges->Clear();
@@ -465,30 +514,16 @@ Moof::ParseTraf(Box& aBox, Trex& aTrex, 
 void
 Moof::FixRounding(const Moof& aMoof) {
   Microseconds gap = aMoof.mTimeRange.start - mTimeRange.end;
   if (gap > 0 && gap <= mMaxRoundingError) {
     mTimeRange.end = aMoof.mTimeRange.start;
   }
 }
 
-class CtsComparator
-{
-public:
-  bool Equals(Sample* const aA, Sample* const aB) const
-  {
-    return aA->mCompositionRange.start == aB->mCompositionRange.start;
-  }
-  bool
-  LessThan(Sample* const aA, Sample* const aB) const
-  {
-    return aA->mCompositionRange.start < aB->mCompositionRange.start;
-  }
-};
-
 bool
 Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, uint64_t* aDecodeTime, bool aIsAudio)
 {
   if (!aTfhd.IsValid() || !aMvhd.IsValid() || !aMdhd.IsValid() ||
       !aEdts.IsValid()) {
     LOG(Moof, "Invalid dependencies: aTfhd(%d) aMvhd(%d) aMdhd(%d) aEdts(%d)",
         aTfhd.IsValid(), aMvhd.IsValid(), aMdhd.IsValid(), !aEdts.IsValid());
     return false;
@@ -565,53 +600,18 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
 
     // FIXME: Make this infallible after bug 968520 is done.
     MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample, fallible));
 
     mMdatRange = mMdatRange.Span(sample.mByteRange);
   }
   mMaxRoundingError += aMdhd.ToMicroseconds(sampleCount);
 
-  nsTArray<Sample*> ctsOrder;
-  for (int i = 0; i < mIndex.Length(); i++) {
-    ctsOrder.AppendElement(&mIndex[i]);
-  }
-  ctsOrder.Sort(CtsComparator());
+  *aDecodeTime = decodeTime;
 
-  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)");