Bug 1232313: [mp4] Use cumulative decode time if tfdt box is not present. r=kentuckyfriedtakahe draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 16 Mar 2016 18:58:48 +1100
changeset 340957 c792c82b68c0bce2ce1128944f7e269c8bf4998a
parent 340857 7773387a9a2f1fd10e4424ea923c6185063f620b
child 516301 d10d2df49751882c98842d49b15e31d4daf69004
push id13101
push userbmo:jyavenard@mozilla.com
push dateWed, 16 Mar 2016 07:59:06 +0000
reviewerskentuckyfriedtakahe
bugs1232313, 14496
milestone48.0a1
Bug 1232313: [mp4] Use cumulative decode time if tfdt box is not present. r=kentuckyfriedtakahe Per ISO 14496-12, the Track fragment decode time (tfdt) is optional. MozReview-Commit-ID: LNrMPYlkDvt
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -41,17 +41,17 @@ MoofParser::RebuildFragmentedIndex(BoxCo
   bool foundValidMoof = false;
   bool foundMdat = false;
 
   for (Box box(&aContext, mOffset); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("moov") && mInitRange.IsEmpty()) {
       mInitRange = MediaByteRange(0, box.Range().mEnd);
       ParseMoov(box);
     } else if (box.IsType("moof")) {
-      Moof moof(box, mTrex, mMvhd, mMdhd, mEdts, mSinf, mIsAudio);
+      Moof moof(box, mTrex, mMvhd, mMdhd, mEdts, mSinf, &mLastDecodeTime, mIsAudio);
 
       if (!moof.IsValid() && !box.Next().IsAvailable()) {
         // Moof isn't valid abort search for now.
         break;
       }
 
       if (!mMoofs.IsEmpty()) {
         // Stitch time ranges together in the case of a (hopefully small) time
@@ -341,23 +341,23 @@ MoofParser::ParseEncrypted(Box& aBox)
 
       if (mSinf.IsValid()) {
         break;
       }
     }
   }
 }
 
-Moof::Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio)
+Moof::Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio)
   : mRange(aBox.Range())
   , mMaxRoundingError(35000)
 {
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("traf")) {
-      ParseTraf(box, aTrex, aMvhd, aMdhd, aEdts, aSinf, aIsAudio);
+      ParseTraf(box, aTrex, aMvhd, aMdhd, aEdts, aSinf, aDecodeTime, aIsAudio);
     }
   }
   if (IsValid()) {
     ProcessCenc();
   }
 }
 
 bool
@@ -420,18 +420,19 @@ Moof::ProcessCenc()
   }
   for (int i = 0; i < cencRanges.Length(); i++) {
     mIndex[i].mCencRange = cencRanges[i];
   }
   return true;
 }
 
 void
-Moof::ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio)
+Moof::ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio)
 {
+  MOZ_ASSERT(aDecodeTime);
   Tfhd tfhd(aTrex);
   Tfdt tfdt;
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("tfhd")) {
       tfhd = Tfhd(box, aTrex);
     } else if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
       if (box.IsType("tfdt")) {
         tfdt = Tfdt(box);
@@ -440,32 +441,30 @@ Moof::ParseTraf(Box& aBox, Trex& aTrex, 
       } else if (box.IsType("saio")) {
         mSaios.AppendElement(Saio(box, aSinf.mDefaultEncryptionType));
       }
     }
   }
   if (aTrex.mTrackId && tfhd.mTrackId != aTrex.mTrackId) {
     return;
   }
-  if (!tfdt.IsValid()) {
-    LOG(Moof, "Invalid tfdt dependency");
-    return;
-  }
   // Now search for TRUN boxes.
-  uint64_t decodeTime = tfdt.mBaseMediaDecodeTime;
+  uint64_t decodeTime =
+    tfdt.IsValid() ? tfdt.mBaseMediaDecodeTime : *aDecodeTime;
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("trun")) {
       if (ParseTrun(box, tfhd, aMvhd, aMdhd, aEdts, &decodeTime, aIsAudio)) {
         mValid = true;
       } else {
         mValid = false;
         break;
       }
     }
   }
+  *aDecodeTime = decodeTime;
 }
 
 void
 Moof::FixRounding(const Moof& aMoof) {
   Microseconds gap = aMoof.mTimeRange.start - mTimeRange.end;
   if (gap > 0 && gap <= mMaxRoundingError) {
     mTimeRange.end = aMoof.mTimeRange.start;
   }
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -168,46 +168,48 @@ private:
   int64_t mMoofOffset;
   Saiz& mSaiz;
   Saio& mSaio;
 };
 
 class Moof : public Atom
 {
 public:
-  Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio);
+  Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecoderTime, bool aIsAudio);
   bool GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges);
   void FixRounding(const Moof& aMoof);
 
   mozilla::MediaByteRange mRange;
   mozilla::MediaByteRange mMdatRange;
   Interval<Microseconds> mTimeRange;
   FallibleTArray<Sample> mIndex;
 
   nsTArray<Saiz> mSaizs;
   nsTArray<Saio> mSaios;
 
 private:
-  void ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio);
+    // aDecodeTime is updated to the end of the parsed TRAF on return.
+  void ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio);
   // aDecodeTime is updated to the end of the parsed TRUN on return.
   bool ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, uint64_t* aDecodeTime, bool aIsAudio);
   void ParseSaiz(Box& aBox);
   void ParseSaio(Box& aBox);
   bool ProcessCenc();
   uint64_t mMaxRoundingError;
 };
 
 class MoofParser
 {
 public:
   MoofParser(Stream* aSource, uint32_t aTrackId, bool aIsAudio)
     : mSource(aSource)
     , mOffset(0)
     , mTrex(aTrackId)
     , mIsAudio(aIsAudio)
+    , mLastDecodeTime(0)
   {
     // Setting the mTrex.mTrackId to 0 is a nasty work around for calculating
     // the composition range for MSE. We need an array of tracks.
   }
   bool RebuildFragmentedIndex(
     const mozilla::MediaByteRangeSet& aByteRanges);
   bool RebuildFragmentedIndex(BoxContext& aContext);
   Interval<Microseconds> GetCompositionRange(
@@ -242,12 +244,13 @@ public:
   Sinf mSinf;
   nsTArray<Moof>& Moofs() { return mMoofs; }
 private:
   void ScanForMetadata(mozilla::MediaByteRange& aFtyp,
                        mozilla::MediaByteRange& aMoov);
   nsTArray<Moof> mMoofs;
   nsTArray<MediaByteRange> mMediaRanges;
   bool mIsAudio;
+  uint64_t mLastDecodeTime;
 };
 }
 
 #endif