LCOV - code coverage report
Current view: top level - media/libstagefright/binding - MoofParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 637 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 45 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "mp4_demuxer/MoofParser.h"
       6             : #include "mp4_demuxer/Box.h"
       7             : #include "mp4_demuxer/SinfParser.h"
       8             : #include <limits>
       9             : #include "Intervals.h"
      10             : 
      11             : #include "mozilla/CheckedInt.h"
      12             : #include "mozilla/Logging.h"
      13             : #include "mozilla/SizePrintfMacros.h"
      14             : 
      15             : #if defined(MOZ_FMP4)
      16             : extern mozilla::LogModule* GetDemuxerLog();
      17             : 
      18             : #define STRINGIFY(x) #x
      19             : #define TOSTRING(x) STRINGIFY(x)
      20             : #define LOG(name, arg, ...) MOZ_LOG(GetDemuxerLog(), mozilla::LogLevel::Debug, (TOSTRING(name) "(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      21             : #else
      22             : #define LOG(...)
      23             : #endif
      24             : 
      25             : namespace mp4_demuxer
      26             : {
      27             : 
      28             : using namespace stagefright;
      29             : using namespace mozilla;
      30             : 
      31             : const uint32_t kKeyIdSize = 16;
      32             : 
      33             : bool
      34           0 : MoofParser::RebuildFragmentedIndex(const MediaByteRangeSet& aByteRanges)
      35             : {
      36           0 :   BoxContext context(mSource, aByteRanges);
      37           0 :   return RebuildFragmentedIndex(context);
      38             : }
      39             : 
      40             : bool
      41           0 : MoofParser::RebuildFragmentedIndex(
      42             :   const MediaByteRangeSet& aByteRanges, bool* aCanEvict)
      43             : {
      44           0 :   MOZ_ASSERT(aCanEvict);
      45           0 :   if (*aCanEvict && mMoofs.Length() > 1) {
      46           0 :     MOZ_ASSERT(mMoofs.Length() == mMediaRanges.Length());
      47           0 :     mMoofs.RemoveElementsAt(0, mMoofs.Length() - 1);
      48           0 :     mMediaRanges.RemoveElementsAt(0, mMediaRanges.Length() - 1);
      49           0 :     *aCanEvict = true;
      50             :   } else {
      51           0 :     *aCanEvict = false;
      52             :   }
      53           0 :   return RebuildFragmentedIndex(aByteRanges);
      54             : }
      55             : 
      56             : bool
      57           0 : MoofParser::RebuildFragmentedIndex(BoxContext& aContext)
      58             : {
      59           0 :   bool foundValidMoof = false;
      60           0 :   bool foundMdat = false;
      61             : 
      62           0 :   for (Box box(&aContext, mOffset); box.IsAvailable(); box = box.Next()) {
      63           0 :     if (box.IsType("moov") && mInitRange.IsEmpty()) {
      64           0 :       mInitRange = MediaByteRange(0, box.Range().mEnd);
      65           0 :       ParseMoov(box);
      66           0 :     } else if (box.IsType("moof")) {
      67           0 :       Moof moof(box, mTrex, mMvhd, mMdhd, mEdts, mSinf, &mLastDecodeTime, mIsAudio);
      68             : 
      69           0 :       if (!moof.IsValid() && !box.Next().IsAvailable()) {
      70             :         // Moof isn't valid abort search for now.
      71           0 :         break;
      72             :       }
      73             : 
      74           0 :       if (!mMoofs.IsEmpty()) {
      75             :         // Stitch time ranges together in the case of a (hopefully small) time
      76             :         // range gap between moofs.
      77           0 :         mMoofs.LastElement().FixRounding(moof);
      78             :       }
      79             : 
      80           0 :       mMoofs.AppendElement(moof);
      81           0 :       mMediaRanges.AppendElement(moof.mRange);
      82           0 :       foundValidMoof = true;
      83           0 :     } else if (box.IsType("mdat") && !Moofs().IsEmpty()) {
      84             :       // Check if we have all our data from last moof.
      85           0 :       Moof& moof = Moofs().LastElement();
      86           0 :       media::Interval<int64_t> datarange(moof.mMdatRange.mStart, moof.mMdatRange.mEnd, 0);
      87           0 :       media::Interval<int64_t> mdat(box.Range().mStart, box.Range().mEnd, 0);
      88           0 :       if (datarange.Intersects(mdat)) {
      89           0 :         mMediaRanges.LastElement() =
      90           0 :           mMediaRanges.LastElement().Span(box.Range());
      91             :       }
      92             :     }
      93           0 :     mOffset = box.NextOffset();
      94             :   }
      95           0 :   return foundValidMoof;
      96             : }
      97             : 
      98             : MediaByteRange
      99           0 : MoofParser::FirstCompleteMediaHeader()
     100             : {
     101           0 :   if (Moofs().IsEmpty()) {
     102           0 :     return MediaByteRange();
     103             :   }
     104           0 :   return Moofs()[0].mRange;
     105             : }
     106             : 
     107             : MediaByteRange
     108           0 : MoofParser::FirstCompleteMediaSegment()
     109             : {
     110           0 :   for (uint32_t i = 0 ; i < mMediaRanges.Length(); i++) {
     111           0 :     if (mMediaRanges[i].Contains(Moofs()[i].mMdatRange)) {
     112           0 :       return mMediaRanges[i];
     113             :     }
     114             :   }
     115           0 :   return MediaByteRange();
     116             : }
     117             : 
     118           0 : class BlockingStream : public Stream {
     119             : public:
     120           0 :   explicit BlockingStream(Stream* aStream) : mStream(aStream)
     121             :   {
     122           0 :   }
     123             : 
     124           0 :   bool ReadAt(int64_t offset, void* data, size_t size, size_t* bytes_read)
     125             :     override
     126             :   {
     127           0 :     return mStream->ReadAt(offset, data, size, bytes_read);
     128             :   }
     129             : 
     130           0 :   bool CachedReadAt(int64_t offset, void* data, size_t size, size_t* bytes_read)
     131             :     override
     132             :   {
     133           0 :     return mStream->ReadAt(offset, data, size, bytes_read);
     134             :   }
     135             : 
     136           0 :   virtual bool Length(int64_t* size) override
     137             :   {
     138           0 :     return mStream->Length(size);
     139             :   }
     140             : 
     141             : private:
     142             :   RefPtr<Stream> mStream;
     143             : };
     144             : 
     145             : bool
     146           0 : MoofParser::BlockingReadNextMoof()
     147             : {
     148           0 :   int64_t length = std::numeric_limits<int64_t>::max();
     149           0 :   mSource->Length(&length);
     150           0 :   MediaByteRangeSet byteRanges;
     151           0 :   byteRanges += MediaByteRange(0, length);
     152           0 :   RefPtr<mp4_demuxer::BlockingStream> stream = new BlockingStream(mSource);
     153             : 
     154           0 :   BoxContext context(stream, byteRanges);
     155           0 :   for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) {
     156           0 :     if (box.IsType("moof")) {
     157           0 :       byteRanges.Clear();
     158           0 :       byteRanges += MediaByteRange(mOffset, box.Range().mEnd);
     159           0 :       return RebuildFragmentedIndex(context);
     160             :     }
     161             :   }
     162           0 :   return false;
     163             : }
     164             : 
     165             : void
     166           0 : MoofParser::ScanForMetadata(mozilla::MediaByteRange& aFtyp,
     167             :                             mozilla::MediaByteRange& aMoov)
     168             : {
     169           0 :   int64_t length = std::numeric_limits<int64_t>::max();
     170           0 :   mSource->Length(&length);
     171           0 :   MediaByteRangeSet byteRanges;
     172           0 :   byteRanges += MediaByteRange(0, length);
     173           0 :   RefPtr<mp4_demuxer::BlockingStream> stream = new BlockingStream(mSource);
     174             : 
     175           0 :   BoxContext context(stream, byteRanges);
     176           0 :   for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) {
     177           0 :     if (box.IsType("ftyp")) {
     178           0 :       aFtyp = box.Range();
     179           0 :       continue;
     180             :     }
     181           0 :     if (box.IsType("moov")) {
     182           0 :       aMoov = box.Range();
     183           0 :       break;
     184             :     }
     185             :   }
     186           0 :   mInitRange = aFtyp.Span(aMoov);
     187           0 : }
     188             : 
     189             : bool
     190           0 : MoofParser::HasMetadata()
     191             : {
     192           0 :   MediaByteRange ftyp;
     193           0 :   MediaByteRange moov;
     194           0 :   ScanForMetadata(ftyp, moov);
     195           0 :   return !!ftyp.Length() && !!moov.Length();
     196             : }
     197             : 
     198             : already_AddRefed<mozilla::MediaByteBuffer>
     199           0 : MoofParser::Metadata()
     200             : {
     201           0 :   MediaByteRange ftyp;
     202           0 :   MediaByteRange moov;
     203           0 :   ScanForMetadata(ftyp, moov);
     204           0 :   CheckedInt<MediaByteBuffer::size_type> ftypLength = ftyp.Length();
     205           0 :   CheckedInt<MediaByteBuffer::size_type> moovLength = moov.Length();
     206           0 :   if (!ftypLength.isValid() || !moovLength.isValid()
     207           0 :       || !ftypLength.value() || !moovLength.value()) {
     208             :     // No ftyp or moov, or they cannot be used as array size.
     209           0 :     return nullptr;
     210             :   }
     211           0 :   CheckedInt<MediaByteBuffer::size_type> totalLength = ftypLength + moovLength;
     212           0 :   if (!totalLength.isValid()) {
     213             :     // Addition overflow, or sum cannot be used as array size.
     214           0 :     return nullptr;
     215             :   }
     216           0 :   RefPtr<MediaByteBuffer> metadata = new MediaByteBuffer();
     217           0 :   if (!metadata->SetLength(totalLength.value(), fallible)) {
     218             :     // OOM
     219           0 :     return nullptr;
     220             :   }
     221             : 
     222           0 :   RefPtr<mp4_demuxer::BlockingStream> stream = new BlockingStream(mSource);
     223             :   size_t read;
     224             :   bool rv =
     225           0 :     stream->ReadAt(ftyp.mStart, metadata->Elements(), ftypLength.value(), &read);
     226           0 :   if (!rv || read != ftypLength.value()) {
     227           0 :     return nullptr;
     228             :   }
     229             :   rv =
     230           0 :     stream->ReadAt(moov.mStart, metadata->Elements() + ftypLength.value(), moovLength.value(), &read);
     231           0 :   if (!rv || read != moovLength.value()) {
     232           0 :     return nullptr;
     233             :   }
     234           0 :   return metadata.forget();
     235             : }
     236             : 
     237             : Interval<Microseconds>
     238           0 : MoofParser::GetCompositionRange(const MediaByteRangeSet& aByteRanges)
     239             : {
     240           0 :   Interval<Microseconds> compositionRange;
     241           0 :   BoxContext context(mSource, aByteRanges);
     242           0 :   for (size_t i = 0; i < mMoofs.Length(); i++) {
     243           0 :     Moof& moof = mMoofs[i];
     244           0 :     Box box(&context, moof.mRange.mStart);
     245           0 :     if (box.IsAvailable()) {
     246           0 :       compositionRange = compositionRange.Extents(moof.mTimeRange);
     247             :     }
     248             :   }
     249           0 :   return compositionRange;
     250             : }
     251             : 
     252             : bool
     253           0 : MoofParser::ReachedEnd()
     254             : {
     255             :   int64_t length;
     256           0 :   return mSource->Length(&length) && mOffset == length;
     257             : }
     258             : 
     259             : void
     260           0 : MoofParser::ParseMoov(Box& aBox)
     261             : {
     262           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     263           0 :     if (box.IsType("mvhd")) {
     264           0 :       mMvhd = Mvhd(box);
     265           0 :     } else if (box.IsType("trak")) {
     266           0 :       ParseTrak(box);
     267           0 :     } else if (box.IsType("mvex")) {
     268           0 :       ParseMvex(box);
     269             :     }
     270             :   }
     271           0 : }
     272             : 
     273             : void
     274           0 : MoofParser::ParseTrak(Box& aBox)
     275             : {
     276           0 :   Tkhd tkhd;
     277           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     278           0 :     if (box.IsType("tkhd")) {
     279           0 :       tkhd = Tkhd(box);
     280           0 :     } else if (box.IsType("mdia")) {
     281           0 :       if (!mTrex.mTrackId || tkhd.mTrackId == mTrex.mTrackId) {
     282           0 :         ParseMdia(box, tkhd);
     283             :       }
     284           0 :     } else if (box.IsType("edts") &&
     285           0 :                (!mTrex.mTrackId || tkhd.mTrackId == mTrex.mTrackId)) {
     286           0 :       mEdts = Edts(box);
     287             :     }
     288             :   }
     289           0 : }
     290             : 
     291             : void
     292           0 : MoofParser::ParseMdia(Box& aBox, Tkhd& aTkhd)
     293             : {
     294           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     295           0 :     if (box.IsType("mdhd")) {
     296           0 :       mMdhd = Mdhd(box);
     297           0 :     } else if (box.IsType("minf")) {
     298           0 :       ParseMinf(box);
     299             :     }
     300             :   }
     301           0 : }
     302             : 
     303             : void
     304           0 : MoofParser::ParseMvex(Box& aBox)
     305             : {
     306           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     307           0 :     if (box.IsType("trex")) {
     308           0 :       Trex trex = Trex(box);
     309           0 :       if (!mTrex.mTrackId || trex.mTrackId == mTrex.mTrackId) {
     310           0 :         auto trackId = mTrex.mTrackId;
     311           0 :         mTrex = trex;
     312             :         // Keep the original trackId, as should it be 0 we want to continue
     313             :         // parsing all tracks.
     314           0 :         mTrex.mTrackId = trackId;
     315             :       }
     316             :     }
     317             :   }
     318           0 : }
     319             : 
     320             : void
     321           0 : MoofParser::ParseMinf(Box& aBox)
     322             : {
     323           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     324           0 :     if (box.IsType("stbl")) {
     325           0 :       ParseStbl(box);
     326             :     }
     327             :   }
     328           0 : }
     329             : 
     330             : void
     331           0 : MoofParser::ParseStbl(Box& aBox)
     332             : {
     333           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     334           0 :     if (box.IsType("stsd")) {
     335           0 :       ParseStsd(box);
     336           0 :     } else if (box.IsType("sgpd")) {
     337           0 :       Sgpd sgpd(box);
     338           0 :       if (sgpd.IsValid() && sgpd.mGroupingType == "seig") {
     339           0 :         mTrackSampleEncryptionInfoEntries.Clear();
     340           0 :         mTrackSampleEncryptionInfoEntries.AppendElements(sgpd.mEntries);
     341             :       }
     342           0 :     } else if (box.IsType("sbgp")) {
     343           0 :       Sbgp sbgp(box);
     344           0 :       if (sbgp.IsValid() && sbgp.mGroupingType == "seig") {
     345           0 :         mTrackSampleToGroupEntries.Clear();
     346           0 :         mTrackSampleToGroupEntries.AppendElements(sbgp.mEntries);
     347             :       }
     348             :     }
     349             :   }
     350           0 : }
     351             : 
     352             : void
     353           0 : MoofParser::ParseStsd(Box& aBox)
     354             : {
     355           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     356           0 :     if (box.IsType("encv") || box.IsType("enca")) {
     357           0 :       ParseEncrypted(box);
     358             :     }
     359             :   }
     360           0 : }
     361             : 
     362             : void
     363           0 : MoofParser::ParseEncrypted(Box& aBox)
     364             : {
     365           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     366             :     // Some MP4 files have been found to have multiple sinf boxes in the same
     367             :     // enc* box. This does not match spec anyway, so just choose the first
     368             :     // one that parses properly.
     369           0 :     if (box.IsType("sinf")) {
     370           0 :       mSinf = Sinf(box);
     371             : 
     372           0 :       if (mSinf.IsValid()) {
     373           0 :         break;
     374             :       }
     375             :     }
     376             :   }
     377           0 : }
     378             : 
     379             : class CtsComparator
     380             : {
     381             : public:
     382           0 :   bool Equals(Sample* const aA, Sample* const aB) const
     383             :   {
     384           0 :     return aA->mCompositionRange.start == aB->mCompositionRange.start;
     385             :   }
     386             :   bool
     387           0 :   LessThan(Sample* const aA, Sample* const aB) const
     388             :   {
     389           0 :     return aA->mCompositionRange.start < aB->mCompositionRange.start;
     390             :   }
     391             : };
     392             : 
     393           0 : Moof::Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio)
     394           0 :   : mRange(aBox.Range())
     395           0 :   , mMaxRoundingError(35000)
     396             : {
     397           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     398           0 :     if (box.IsType("traf")) {
     399           0 :       ParseTraf(box, aTrex, aMvhd, aMdhd, aEdts, aSinf, aDecodeTime, aIsAudio);
     400             :     }
     401             :   }
     402           0 :   if (IsValid()) {
     403           0 :     if (mIndex.Length()) {
     404             :       // Ensure the samples are contiguous with no gaps.
     405           0 :       nsTArray<Sample*> ctsOrder;
     406           0 :       for (auto& sample : mIndex) {
     407           0 :         ctsOrder.AppendElement(&sample);
     408             :       }
     409           0 :       ctsOrder.Sort(CtsComparator());
     410             : 
     411           0 :       for (size_t i = 1; i < ctsOrder.Length(); i++) {
     412           0 :         ctsOrder[i-1]->mCompositionRange.end = ctsOrder[i]->mCompositionRange.start;
     413             :       }
     414             : 
     415             :       // In MP4, the duration of a sample is defined as the delta between two decode
     416             :       // timestamps. The operation above has updated the duration of each sample
     417             :       // as a Sample's duration is mCompositionRange.end - mCompositionRange.start
     418             :       // MSE's TrackBuffersManager expects dts that increased by the sample's
     419             :       // duration, so we rewrite the dts accordingly.
     420             :       int64_t presentationDuration =
     421           0 :         ctsOrder.LastElement()->mCompositionRange.end
     422           0 :         - ctsOrder[0]->mCompositionRange.start;
     423             :       int64_t endDecodeTime =
     424           0 :         aMdhd.ToMicroseconds((int64_t)*aDecodeTime - aEdts.mMediaStart)
     425           0 :         + aMvhd.ToMicroseconds(aEdts.mEmptyOffset);
     426           0 :       int64_t decodeDuration = endDecodeTime - mIndex[0].mDecodeTime;
     427           0 :       double adjust = (double)decodeDuration / presentationDuration;
     428           0 :       int64_t dtsOffset = mIndex[0].mDecodeTime;
     429           0 :       int64_t compositionDuration = 0;
     430             :       // Adjust the dts, ensuring that the new adjusted dts will never be greater
     431             :       // than decodeTime (the next moof's decode start time).
     432           0 :       for (auto& sample : mIndex) {
     433           0 :         sample.mDecodeTime = dtsOffset + int64_t(compositionDuration * adjust);
     434           0 :         compositionDuration += sample.mCompositionRange.Length();
     435             :       }
     436           0 :       mTimeRange = Interval<Microseconds>(ctsOrder[0]->mCompositionRange.start,
     437           0 :           ctsOrder.LastElement()->mCompositionRange.end);
     438             :     }
     439           0 :     ProcessCenc();
     440             :   }
     441           0 : }
     442             : 
     443             : bool
     444           0 : Moof::GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges)
     445             : {
     446           0 :   aByteRanges->Clear();
     447             : 
     448           0 :   Saiz* saiz = nullptr;
     449           0 :   for (int i = 0; ; i++) {
     450           0 :     if (i == mSaizs.Length()) {
     451           0 :       return false;
     452             :     }
     453           0 :     if (mSaizs[i].mAuxInfoType == aType) {
     454           0 :       saiz = &mSaizs[i];
     455           0 :       break;
     456             :     }
     457             :   }
     458           0 :   Saio* saio = nullptr;
     459           0 :   for (int i = 0; ; i++) {
     460           0 :     if (i == mSaios.Length()) {
     461           0 :       return false;
     462             :     }
     463           0 :     if (mSaios[i].mAuxInfoType == aType) {
     464           0 :       saio = &mSaios[i];
     465           0 :       break;
     466             :     }
     467             :   }
     468             : 
     469           0 :   if (saio->mOffsets.Length() == 1) {
     470           0 :     aByteRanges->SetCapacity(saiz->mSampleInfoSize.Length());
     471           0 :     uint64_t offset = mRange.mStart + saio->mOffsets[0];
     472           0 :     for (size_t i = 0; i < saiz->mSampleInfoSize.Length(); i++) {
     473           0 :       aByteRanges->AppendElement(
     474           0 :         MediaByteRange(offset, offset + saiz->mSampleInfoSize[i]));
     475           0 :       offset += saiz->mSampleInfoSize[i];
     476             :     }
     477           0 :     return true;
     478             :   }
     479             : 
     480           0 :   if (saio->mOffsets.Length() == saiz->mSampleInfoSize.Length()) {
     481           0 :     aByteRanges->SetCapacity(saiz->mSampleInfoSize.Length());
     482           0 :     for (size_t i = 0; i < saio->mOffsets.Length(); i++) {
     483           0 :       uint64_t offset = mRange.mStart + saio->mOffsets[i];
     484           0 :       aByteRanges->AppendElement(
     485           0 :         MediaByteRange(offset, offset + saiz->mSampleInfoSize[i]));
     486             :     }
     487           0 :     return true;
     488             :   }
     489             : 
     490           0 :   return false;
     491             : }
     492             : 
     493             : bool
     494           0 : Moof::ProcessCenc()
     495             : {
     496           0 :   nsTArray<MediaByteRange> cencRanges;
     497           0 :   if (!GetAuxInfo(AtomType("cenc"), &cencRanges) ||
     498           0 :       cencRanges.Length() != mIndex.Length()) {
     499           0 :     return false;
     500             :   }
     501           0 :   for (int i = 0; i < cencRanges.Length(); i++) {
     502           0 :     mIndex[i].mCencRange = cencRanges[i];
     503             :   }
     504           0 :   return true;
     505             : }
     506             : 
     507             : void
     508           0 : Moof::ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio)
     509             : {
     510           0 :   MOZ_ASSERT(aDecodeTime);
     511           0 :   Tfhd tfhd(aTrex);
     512           0 :   Tfdt tfdt;
     513             : 
     514           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     515           0 :     if (box.IsType("tfhd")) {
     516           0 :       tfhd = Tfhd(box, aTrex);
     517           0 :     } else if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
     518           0 :       if (box.IsType("tfdt")) {
     519           0 :         tfdt = Tfdt(box);
     520           0 :       } else if (box.IsType("sgpd")) {
     521           0 :         Sgpd sgpd(box);
     522           0 :         if (sgpd.IsValid() && sgpd.mGroupingType == "seig") {
     523           0 :           mFragmentSampleEncryptionInfoEntries.Clear();
     524           0 :           mFragmentSampleEncryptionInfoEntries.AppendElements(sgpd.mEntries);
     525             :         }
     526           0 :       } else if (box.IsType("sbgp")) {
     527           0 :         Sbgp sbgp(box);
     528           0 :         if (sbgp.IsValid() && sbgp.mGroupingType == "seig") {
     529           0 :           mFragmentSampleToGroupEntries.Clear();
     530           0 :           mFragmentSampleToGroupEntries.AppendElements(sbgp.mEntries);
     531             :         }
     532           0 :       } else if (box.IsType("saiz")) {
     533           0 :         mSaizs.AppendElement(Saiz(box, aSinf.mDefaultEncryptionType));
     534           0 :       } else if (box.IsType("saio")) {
     535           0 :         mSaios.AppendElement(Saio(box, aSinf.mDefaultEncryptionType));
     536             :       }
     537             :     }
     538             :   }
     539           0 :   if (aTrex.mTrackId && tfhd.mTrackId != aTrex.mTrackId) {
     540           0 :     return;
     541             :   }
     542             :   // Now search for TRUN boxes.
     543             :   uint64_t decodeTime =
     544           0 :     tfdt.IsValid() ? tfdt.mBaseMediaDecodeTime : *aDecodeTime;
     545           0 :   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     546           0 :     if (box.IsType("trun")) {
     547           0 :       if (ParseTrun(box, tfhd, aMvhd, aMdhd, aEdts, &decodeTime, aIsAudio)) {
     548           0 :         mValid = true;
     549             :       } else {
     550           0 :         mValid = false;
     551           0 :         break;
     552             :       }
     553             :     }
     554             :   }
     555           0 :   *aDecodeTime = decodeTime;
     556             : }
     557             : 
     558             : void
     559           0 : Moof::FixRounding(const Moof& aMoof) {
     560           0 :   Microseconds gap = aMoof.mTimeRange.start - mTimeRange.end;
     561           0 :   if (gap > 0 && gap <= mMaxRoundingError) {
     562           0 :     mTimeRange.end = aMoof.mTimeRange.start;
     563             :   }
     564           0 : }
     565             : 
     566             : bool
     567           0 : Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, uint64_t* aDecodeTime, bool aIsAudio)
     568             : {
     569           0 :   if (!aTfhd.IsValid() || !aMvhd.IsValid() || !aMdhd.IsValid() ||
     570           0 :       !aEdts.IsValid()) {
     571           0 :     LOG(Moof, "Invalid dependencies: aTfhd(%d) aMvhd(%d) aMdhd(%d) aEdts(%d)",
     572             :         aTfhd.IsValid(), aMvhd.IsValid(), aMdhd.IsValid(), !aEdts.IsValid());
     573           0 :     return false;
     574             :   }
     575             : 
     576           0 :   BoxReader reader(aBox);
     577           0 :   if (!reader->CanReadType<uint32_t>()) {
     578           0 :     LOG(Moof, "Incomplete Box (missing flags)");
     579           0 :     return false;
     580             :   }
     581           0 :   uint32_t flags = reader->ReadU32();
     582           0 :   uint8_t version = flags >> 24;
     583             : 
     584           0 :   if (!reader->CanReadType<uint32_t>()) {
     585           0 :     LOG(Moof, "Incomplete Box (missing sampleCount)");
     586           0 :     return false;
     587             :   }
     588           0 :   uint32_t sampleCount = reader->ReadU32();
     589           0 :   if (sampleCount == 0) {
     590           0 :     return true;
     591             :   }
     592             : 
     593             :   size_t need =
     594           0 :     ((flags & 1) ? sizeof(uint32_t) : 0) +
     595           0 :     ((flags & 4) ? sizeof(uint32_t) : 0);
     596           0 :   uint16_t flag[] = { 0x100, 0x200, 0x400, 0x800, 0 };
     597           0 :   for (size_t i = 0; flag[i]; i++) {
     598           0 :     if (flags & flag[i]) {
     599           0 :       need += sizeof(uint32_t) * sampleCount;
     600             :     }
     601             :   }
     602           0 :   if (reader->Remaining() < need) {
     603           0 :     LOG(Moof, "Incomplete Box (have:%" PRIuSIZE " need:%" PRIuSIZE ")",
     604             :         reader->Remaining(), need);
     605           0 :     return false;
     606             :   }
     607             : 
     608           0 :   uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0);
     609             :   uint32_t firstSampleFlags =
     610           0 :     flags & 4 ? reader->ReadU32() : aTfhd.mDefaultSampleFlags;
     611           0 :   uint64_t decodeTime = *aDecodeTime;
     612           0 :   nsTArray<Interval<Microseconds>> timeRanges;
     613             : 
     614           0 :   if (!mIndex.SetCapacity(sampleCount, fallible)) {
     615           0 :     LOG(Moof, "Out of Memory");
     616           0 :     return false;
     617             :   }
     618             : 
     619           0 :   for (size_t i = 0; i < sampleCount; i++) {
     620             :     uint32_t sampleDuration =
     621           0 :       flags & 0x100 ? reader->ReadU32() : aTfhd.mDefaultSampleDuration;
     622             :     uint32_t sampleSize =
     623           0 :       flags & 0x200 ? reader->ReadU32() : aTfhd.mDefaultSampleSize;
     624             :     uint32_t sampleFlags =
     625           0 :       flags & 0x400 ? reader->ReadU32()
     626           0 :                     : i ? aTfhd.mDefaultSampleFlags : firstSampleFlags;
     627           0 :     int32_t ctsOffset = 0;
     628           0 :     if (flags & 0x800) {
     629           0 :       ctsOffset = reader->Read32();
     630             :     }
     631             : 
     632           0 :     Sample sample;
     633           0 :     sample.mByteRange = MediaByteRange(offset, offset + sampleSize);
     634           0 :     offset += sampleSize;
     635             : 
     636           0 :     sample.mDecodeTime =
     637           0 :       aMdhd.ToMicroseconds((int64_t)decodeTime - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset);
     638           0 :     sample.mCompositionRange = Interval<Microseconds>(
     639           0 :       aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset),
     640           0 :       aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset + sampleDuration - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset));
     641           0 :     decodeTime += sampleDuration;
     642             : 
     643             :     // Sometimes audio streams don't properly mark their samples as keyframes,
     644             :     // because every audio sample is a keyframe.
     645           0 :     sample.mSync = !(sampleFlags & 0x1010000) || aIsAudio;
     646             : 
     647             :     // FIXME: Make this infallible after bug 968520 is done.
     648           0 :     MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample, fallible));
     649             : 
     650           0 :     mMdatRange = mMdatRange.Span(sample.mByteRange);
     651             :   }
     652           0 :   mMaxRoundingError += aMdhd.ToMicroseconds(sampleCount);
     653             : 
     654           0 :   *aDecodeTime = decodeTime;
     655             : 
     656           0 :   return true;
     657             : }
     658             : 
     659           0 : Tkhd::Tkhd(Box& aBox)
     660             : {
     661           0 :   BoxReader reader(aBox);
     662           0 :   if (!reader->CanReadType<uint32_t>()) {
     663           0 :     LOG(Tkhd, "Incomplete Box (missing flags)");
     664           0 :     return;
     665             :   }
     666           0 :   uint32_t flags = reader->ReadU32();
     667           0 :   uint8_t version = flags >> 24;
     668             :   size_t need =
     669           0 :     3*(version ? sizeof(int64_t) : sizeof(int32_t)) + 2*sizeof(int32_t);
     670           0 :   if (reader->Remaining() < need) {
     671           0 :     LOG(Tkhd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     672             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     673           0 :     return;
     674             :   }
     675           0 :   if (version == 0) {
     676           0 :     mCreationTime = reader->ReadU32();
     677           0 :     mModificationTime = reader->ReadU32();
     678           0 :     mTrackId = reader->ReadU32();
     679           0 :     uint32_t reserved = reader->ReadU32();
     680           0 :     NS_ASSERTION(!reserved, "reserved should be 0");
     681           0 :     mDuration = reader->ReadU32();
     682           0 :   } else if (version == 1) {
     683           0 :     mCreationTime = reader->ReadU64();
     684           0 :     mModificationTime = reader->ReadU64();
     685           0 :     mTrackId = reader->ReadU32();
     686           0 :     uint32_t reserved = reader->ReadU32();
     687           0 :     NS_ASSERTION(!reserved, "reserved should be 0");
     688           0 :     mDuration = reader->ReadU64();
     689             :   }
     690             :   // We don't care about whatever else may be in the box.
     691           0 :   mValid = true;
     692             : }
     693             : 
     694           0 : Mvhd::Mvhd(Box& aBox)
     695             : {
     696           0 :   BoxReader reader(aBox);
     697           0 :   if (!reader->CanReadType<uint32_t>()) {
     698           0 :     LOG(Mdhd, "Incomplete Box (missing flags)");
     699           0 :     return;
     700             :   }
     701           0 :   uint32_t flags = reader->ReadU32();
     702           0 :   uint8_t version = flags >> 24;
     703             :   size_t need =
     704           0 :     3*(version ? sizeof(int64_t) : sizeof(int32_t)) + sizeof(uint32_t);
     705           0 :   if (reader->Remaining() < need) {
     706           0 :     LOG(Mvhd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     707             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     708           0 :     return;
     709             :   }
     710             : 
     711           0 :   if (version == 0) {
     712           0 :     mCreationTime = reader->ReadU32();
     713           0 :     mModificationTime = reader->ReadU32();
     714           0 :     mTimescale = reader->ReadU32();
     715           0 :     mDuration = reader->ReadU32();
     716           0 :   } else if (version == 1) {
     717           0 :     mCreationTime = reader->ReadU64();
     718           0 :     mModificationTime = reader->ReadU64();
     719           0 :     mTimescale = reader->ReadU32();
     720           0 :     mDuration = reader->ReadU64();
     721             :   } else {
     722           0 :     return;
     723             :   }
     724             :   // We don't care about whatever else may be in the box.
     725           0 :   if (mTimescale) {
     726           0 :     mValid = true;
     727             :   }
     728             : }
     729             : 
     730           0 : Mdhd::Mdhd(Box& aBox)
     731           0 :   : Mvhd(aBox)
     732             : {
     733           0 : }
     734             : 
     735           0 : Trex::Trex(Box& aBox)
     736             : {
     737           0 :   BoxReader reader(aBox);
     738           0 :   if (reader->Remaining() < 6*sizeof(uint32_t)) {
     739           0 :     LOG(Trex, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     740             :         (uint64_t)reader->Remaining(), (uint64_t)6*sizeof(uint32_t));
     741           0 :     return;
     742             :   }
     743           0 :   mFlags = reader->ReadU32();
     744           0 :   mTrackId = reader->ReadU32();
     745           0 :   mDefaultSampleDescriptionIndex = reader->ReadU32();
     746           0 :   mDefaultSampleDuration = reader->ReadU32();
     747           0 :   mDefaultSampleSize = reader->ReadU32();
     748           0 :   mDefaultSampleFlags = reader->ReadU32();
     749           0 :   mValid = true;
     750             : }
     751             : 
     752           0 : Tfhd::Tfhd(Box& aBox, Trex& aTrex)
     753           0 :   : Trex(aTrex)
     754             : {
     755           0 :   MOZ_ASSERT(aBox.IsType("tfhd"));
     756           0 :   MOZ_ASSERT(aBox.Parent()->IsType("traf"));
     757           0 :   MOZ_ASSERT(aBox.Parent()->Parent()->IsType("moof"));
     758             : 
     759           0 :   BoxReader reader(aBox);
     760           0 :   if (!reader->CanReadType<uint32_t>()) {
     761           0 :     LOG(Tfhd, "Incomplete Box (missing flags)");
     762           0 :     return;
     763             :   }
     764           0 :   mFlags = reader->ReadU32();
     765           0 :   size_t need = sizeof(uint32_t) /* trackid */;
     766           0 :   uint8_t flag[] = { 1, 2, 8, 0x10, 0x20, 0 };
     767           0 :   uint8_t flagSize[] = { sizeof(uint64_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t) };
     768           0 :   for (size_t i = 0; flag[i]; i++) {
     769           0 :     if (mFlags & flag[i]) {
     770           0 :       need += flagSize[i];
     771             :     }
     772             :   }
     773           0 :   if (reader->Remaining() < need) {
     774           0 :     LOG(Tfhd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     775             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     776           0 :     return;
     777             :   }
     778           0 :   mTrackId = reader->ReadU32();
     779           0 :   mBaseDataOffset =
     780           0 :     mFlags & 1 ? reader->ReadU64() : aBox.Parent()->Parent()->Offset();
     781           0 :   if (mFlags & 2) {
     782           0 :     mDefaultSampleDescriptionIndex = reader->ReadU32();
     783             :   }
     784           0 :   if (mFlags & 8) {
     785           0 :     mDefaultSampleDuration = reader->ReadU32();
     786             :   }
     787           0 :   if (mFlags & 0x10) {
     788           0 :     mDefaultSampleSize = reader->ReadU32();
     789             :   }
     790           0 :   if (mFlags & 0x20) {
     791           0 :     mDefaultSampleFlags = reader->ReadU32();
     792             :   }
     793           0 :   mValid = true;
     794             : }
     795             : 
     796           0 : Tfdt::Tfdt(Box& aBox)
     797             : {
     798           0 :   BoxReader reader(aBox);
     799           0 :   if (!reader->CanReadType<uint32_t>()) {
     800           0 :     LOG(Tfdt, "Incomplete Box (missing flags)");
     801           0 :     return;
     802             :   }
     803           0 :   uint32_t flags = reader->ReadU32();
     804           0 :   uint8_t version = flags >> 24;
     805           0 :   size_t need = version ? sizeof(uint64_t) : sizeof(uint32_t) ;
     806           0 :   if (reader->Remaining() < need) {
     807           0 :     LOG(Tfdt, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     808             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     809           0 :     return;
     810             :   }
     811           0 :   if (version == 0) {
     812           0 :     mBaseMediaDecodeTime = reader->ReadU32();
     813           0 :   } else if (version == 1) {
     814           0 :     mBaseMediaDecodeTime = reader->ReadU64();
     815             :   }
     816           0 :   mValid = true;
     817             : }
     818             : 
     819           0 : Edts::Edts(Box& aBox)
     820             :   : mMediaStart(0)
     821           0 :   , mEmptyOffset(0)
     822             : {
     823           0 :   Box child = aBox.FirstChild();
     824           0 :   if (!child.IsType("elst")) {
     825           0 :     return;
     826             :   }
     827             : 
     828           0 :   BoxReader reader(child);
     829           0 :   if (!reader->CanReadType<uint32_t>()) {
     830           0 :     LOG(Edts, "Incomplete Box (missing flags)");
     831           0 :     return;
     832             :   }
     833           0 :   uint32_t flags = reader->ReadU32();
     834           0 :   uint8_t version = flags >> 24;
     835             :   size_t need =
     836           0 :     sizeof(uint32_t) + 2*(version ? sizeof(int64_t) : sizeof(uint32_t));
     837           0 :   if (reader->Remaining() < need) {
     838           0 :     LOG(Edts, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     839             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     840           0 :     return;
     841             :   }
     842           0 :   bool emptyEntry = false;
     843           0 :   uint32_t entryCount = reader->ReadU32();
     844           0 :   for (uint32_t i = 0; i < entryCount; i++) {
     845             :     uint64_t segment_duration;
     846             :     int64_t media_time;
     847           0 :     if (version == 1) {
     848           0 :       segment_duration = reader->ReadU64();
     849           0 :       media_time = reader->Read64();
     850             :     } else {
     851           0 :       segment_duration = reader->ReadU32();
     852           0 :       media_time = reader->Read32();
     853             :     }
     854           0 :     if (media_time == -1 && i) {
     855           0 :       LOG(Edts, "Multiple empty edit, not handled");
     856           0 :     } else if (media_time == -1) {
     857           0 :       mEmptyOffset = segment_duration;
     858           0 :       emptyEntry = true;
     859           0 :     } else if (i > 1 || (i > 0 && !emptyEntry)) {
     860           0 :       LOG(Edts, "More than one edit entry, not handled. A/V sync will be wrong");
     861           0 :       break;
     862             :     } else {
     863           0 :       mMediaStart = media_time;
     864             :     }
     865           0 :     reader->ReadU32(); // media_rate_integer and media_rate_fraction
     866             :   }
     867             : }
     868             : 
     869           0 : Saiz::Saiz(Box& aBox, AtomType aDefaultType)
     870             :   : mAuxInfoType(aDefaultType)
     871           0 :   , mAuxInfoTypeParameter(0)
     872             : {
     873           0 :   BoxReader reader(aBox);
     874           0 :   if (!reader->CanReadType<uint32_t>()) {
     875           0 :     LOG(Saiz, "Incomplete Box (missing flags)");
     876           0 :     return;
     877             :   }
     878           0 :   uint32_t flags = reader->ReadU32();
     879           0 :   uint8_t version = flags >> 24;
     880             :   size_t need =
     881           0 :     ((flags & 1) ? 2*sizeof(uint32_t) : 0) + sizeof(uint8_t) + sizeof(uint32_t);
     882           0 :   if (reader->Remaining() < need) {
     883           0 :     LOG(Saiz, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     884             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     885           0 :     return;
     886             :   }
     887           0 :   if (flags & 1) {
     888           0 :     mAuxInfoType = reader->ReadU32();
     889           0 :     mAuxInfoTypeParameter = reader->ReadU32();
     890             :   }
     891           0 :   uint8_t defaultSampleInfoSize = reader->ReadU8();
     892           0 :   uint32_t count = reader->ReadU32();
     893           0 :   if (defaultSampleInfoSize) {
     894           0 :     if (!mSampleInfoSize.SetLength(count, fallible)) {
     895           0 :       LOG(Saiz, "OOM");
     896           0 :       return;
     897             :     }
     898           0 :     memset(mSampleInfoSize.Elements(), defaultSampleInfoSize, mSampleInfoSize.Length());
     899             :   } else {
     900           0 :     if (!reader->ReadArray(mSampleInfoSize, count)) {
     901           0 :       LOG(Saiz, "Incomplete Box (OOM or missing count:%u)", count);
     902           0 :       return;
     903             :     }
     904             :   }
     905           0 :   mValid = true;
     906             : }
     907             : 
     908           0 : Saio::Saio(Box& aBox, AtomType aDefaultType)
     909             :   : mAuxInfoType(aDefaultType)
     910           0 :   , mAuxInfoTypeParameter(0)
     911             : {
     912           0 :   BoxReader reader(aBox);
     913           0 :   if (!reader->CanReadType<uint32_t>()) {
     914           0 :     LOG(Saio, "Incomplete Box (missing flags)");
     915           0 :     return;
     916             :   }
     917           0 :   uint32_t flags = reader->ReadU32();
     918           0 :   uint8_t version = flags >> 24;
     919           0 :   size_t need = ((flags & 1) ? (2*sizeof(uint32_t)) : 0) + sizeof(uint32_t);
     920           0 :   if (reader->Remaining() < need) {
     921           0 :     LOG(Saio, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     922             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     923           0 :     return;
     924             :   }
     925           0 :   if (flags & 1) {
     926           0 :     mAuxInfoType = reader->ReadU32();
     927           0 :     mAuxInfoTypeParameter = reader->ReadU32();
     928             :   }
     929           0 :   size_t count = reader->ReadU32();
     930           0 :   need = (version ? sizeof(uint64_t) : sizeof(uint32_t)) * count;
     931           0 :   if (reader->Remaining() < need) {
     932           0 :     LOG(Saio, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
     933             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     934           0 :     return;
     935             :   }
     936           0 :   if (!mOffsets.SetCapacity(count, fallible)) {
     937           0 :     LOG(Saiz, "OOM");
     938           0 :     return;
     939             :   }
     940           0 :   if (version == 0) {
     941           0 :     for (size_t i = 0; i < count; i++) {
     942           0 :       MOZ_ALWAYS_TRUE(mOffsets.AppendElement(reader->ReadU32(), fallible));
     943             :     }
     944             :   } else {
     945           0 :     for (size_t i = 0; i < count; i++) {
     946           0 :       MOZ_ALWAYS_TRUE(mOffsets.AppendElement(reader->ReadU64(), fallible));
     947             :     }
     948             :   }
     949           0 :   mValid = true;
     950             : }
     951             : 
     952           0 : Sbgp::Sbgp(Box& aBox)
     953             : {
     954           0 :   BoxReader reader(aBox);
     955             : 
     956           0 :   if (!reader->CanReadType<uint32_t>()) {
     957           0 :     LOG(Sbgp, "Incomplete Box (missing flags)");
     958           0 :     return;
     959             :   }
     960             : 
     961           0 :   uint32_t flags = reader->ReadU32();
     962           0 :   const uint8_t version = flags >> 24;
     963           0 :   flags = flags & 0xffffff;
     964             : 
     965             :   // Make sure we have enough bytes to read as far as the count.
     966           0 :   uint32_t need = (version == 1 ? sizeof(uint32_t) : 0) + sizeof(uint32_t) * 2;
     967           0 :   if (reader->Remaining() < need) {
     968           0 :     LOG(Sbgp, "Incomplete Box (have:%" PRIu64 ", need:%" PRIu64 ")",
     969             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     970           0 :     return;
     971             :   }
     972             : 
     973           0 :   mGroupingType = reader->ReadU32();
     974             : 
     975           0 :   if (version == 1) {
     976           0 :     mGroupingTypeParam = reader->Read32();
     977             :   }
     978             : 
     979           0 :   uint32_t count = reader->ReadU32();
     980             : 
     981             :   // Make sure we can read all the entries.
     982           0 :   need = sizeof(uint32_t) * 2 * count;
     983           0 :   if (reader->Remaining() < need) {
     984           0 :     LOG(Sbgp, "Incomplete Box (have:%" PRIu64 ", need:%" PRIu64 "). Failed to read entries",
     985             :         (uint64_t)reader->Remaining(), (uint64_t)need);
     986           0 :     return;
     987             :   }
     988             : 
     989           0 :   for (uint32_t i = 0; i < count; i++) {
     990           0 :     uint32_t sampleCount = reader->ReadU32();
     991           0 :     uint32_t groupDescriptionIndex = reader->ReadU32();
     992             : 
     993           0 :     SampleToGroupEntry entry(sampleCount, groupDescriptionIndex);
     994           0 :     mEntries.AppendElement(entry);
     995             :   }
     996             : 
     997           0 :   mValid = true;
     998             : }
     999             : 
    1000           0 : Sgpd::Sgpd(Box& aBox)
    1001             : {
    1002           0 :   BoxReader reader(aBox);
    1003             : 
    1004           0 :   if (!reader->CanReadType<uint32_t>()) {
    1005           0 :     LOG(Sgpd, "Incomplete Box (missing flags)");
    1006           0 :     return;
    1007             :   }
    1008             : 
    1009           0 :   uint32_t flags = reader->ReadU32();
    1010           0 :   const uint8_t version = flags >> 24;
    1011           0 :   flags = flags & 0xffffff;
    1012             : 
    1013           0 :   uint32_t need = ((flags & 1) ? sizeof(uint32_t) : 0) + sizeof(uint32_t) * 2;
    1014           0 :   if (reader->Remaining() < need) {
    1015           0 :     LOG(Sgpd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
    1016             :         (uint64_t)reader->Remaining(), (uint64_t)need);
    1017           0 :     return;
    1018             :   }
    1019             : 
    1020           0 :   mGroupingType = reader->ReadU32();
    1021             : 
    1022           0 :   const uint32_t entrySize = sizeof(uint32_t) + kKeyIdSize;
    1023           0 :   uint32_t defaultLength = 0;
    1024             : 
    1025           0 :   if (version == 1) {
    1026           0 :     defaultLength = reader->ReadU32();
    1027           0 :     if (defaultLength < entrySize && defaultLength != 0) {
    1028           0 :       return;
    1029             :     }
    1030             :   }
    1031             : 
    1032           0 :   uint32_t count = reader->ReadU32();
    1033             : 
    1034             :   // Make sure we have sufficient remaining bytes to read the entries.
    1035           0 :   need =
    1036           0 :     count * (sizeof(uint32_t) * (version == 1 && defaultLength == 0 ? 2 : 1) +
    1037           0 :              kKeyIdSize * sizeof(uint8_t));
    1038           0 :   if (reader->Remaining() < need) {
    1039           0 :     LOG(Sgpd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 "). Failed to read entries",
    1040             :         (uint64_t)reader->Remaining(), (uint64_t)need);
    1041           0 :     return;
    1042             :   }
    1043           0 :   for (uint32_t i = 0; i < count; ++i) {
    1044           0 :     if (version == 1 && defaultLength == 0) {
    1045           0 :       uint32_t descriptionLength = reader->ReadU32();
    1046           0 :       if (descriptionLength < entrySize) {
    1047           0 :         return;
    1048             :       }
    1049             :     }
    1050             : 
    1051           0 :     CencSampleEncryptionInfoEntry entry;
    1052           0 :     bool valid = entry.Init(reader);
    1053           0 :     if (!valid) {
    1054           0 :       return;
    1055             :     }
    1056           0 :     mEntries.AppendElement(entry);
    1057             :   }
    1058             : 
    1059           0 :   mValid = true;
    1060             : }
    1061             : 
    1062           0 : bool CencSampleEncryptionInfoEntry::Init(BoxReader& aReader)
    1063             : {
    1064             :   // Skip a reserved byte.
    1065           0 :   aReader->ReadU8();
    1066             : 
    1067           0 :   uint8_t possiblePatternInfo = aReader->ReadU8();
    1068           0 :   uint8_t flag = aReader->ReadU8();
    1069             : 
    1070           0 :   mIVSize = aReader->ReadU8();
    1071             : 
    1072             :   // Read the key id.
    1073           0 :   for (uint32_t i = 0; i < kKeyIdSize; ++i) {
    1074           0 :     mKeyId.AppendElement(aReader->ReadU8());
    1075             :   }
    1076             : 
    1077           0 :   mIsEncrypted = flag != 0;
    1078             : 
    1079           0 :   if (mIsEncrypted) {
    1080           0 :     if (mIVSize != 8 && mIVSize != 16) {
    1081           0 :       return false;
    1082             :     }
    1083           0 :   } else if (mIVSize != 0) {
    1084           0 :     return false;
    1085             :   }
    1086             : 
    1087           0 :   return true;
    1088             : }
    1089             : 
    1090             : #undef LOG
    1091             : }

Generated by: LCOV version 1.13