LCOV - code coverage report
Current view: top level - media/libstagefright/binding - Index.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 315 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 19 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/ByteReader.h"
       6             : #include "mp4_demuxer/Index.h"
       7             : #include "mp4_demuxer/Interval.h"
       8             : #include "mp4_demuxer/MP4Metadata.h"
       9             : #include "mp4_demuxer/SinfParser.h"
      10             : #include "nsAutoPtr.h"
      11             : #include "mozilla/RefPtr.h"
      12             : 
      13             : #include <algorithm>
      14             : #include <limits>
      15             : 
      16             : using namespace stagefright;
      17             : using namespace mozilla;
      18             : using namespace mozilla::media;
      19             : 
      20             : namespace mp4_demuxer
      21             : {
      22             : 
      23             : class MOZ_STACK_CLASS RangeFinder
      24             : {
      25             : public:
      26             :   // Given that we're processing this in order we don't use a binary search
      27             :   // to find the apropriate time range. Instead we search linearly from the
      28             :   // last used point.
      29           0 :   explicit RangeFinder(const MediaByteRangeSet& ranges)
      30           0 :     : mRanges(ranges), mIndex(0)
      31             :   {
      32             :     // Ranges must be normalised for this to work
      33           0 :   }
      34             : 
      35             :   bool Contains(MediaByteRange aByteRange);
      36             : 
      37             : private:
      38             :   const MediaByteRangeSet& mRanges;
      39             :   size_t mIndex;
      40             : };
      41             : 
      42             : bool
      43           0 : RangeFinder::Contains(MediaByteRange aByteRange)
      44             : {
      45           0 :   if (!mRanges.Length()) {
      46           0 :     return false;
      47             :   }
      48             : 
      49           0 :   if (mRanges[mIndex].ContainsStrict(aByteRange)) {
      50           0 :     return true;
      51             :   }
      52             : 
      53           0 :   if (aByteRange.mStart < mRanges[mIndex].mStart) {
      54             :     // Search backwards
      55           0 :     do {
      56           0 :       if (!mIndex) {
      57           0 :         return false;
      58             :       }
      59           0 :       --mIndex;
      60           0 :       if (mRanges[mIndex].ContainsStrict(aByteRange)) {
      61           0 :         return true;
      62             :       }
      63           0 :     } while (aByteRange.mStart < mRanges[mIndex].mStart);
      64             : 
      65           0 :     return false;
      66             :   }
      67             : 
      68           0 :   while (aByteRange.mEnd > mRanges[mIndex].mEnd) {
      69           0 :     if (mIndex == mRanges.Length() - 1) {
      70           0 :       return false;
      71             :     }
      72           0 :     ++mIndex;
      73           0 :     if (mRanges[mIndex].ContainsStrict(aByteRange)) {
      74           0 :       return true;
      75             :     }
      76             :   }
      77             : 
      78           0 :   return false;
      79             : }
      80             : 
      81           0 : SampleIterator::SampleIterator(Index* aIndex)
      82             :   : mIndex(aIndex)
      83             :   , mCurrentMoof(0)
      84           0 :   , mCurrentSample(0)
      85             : {
      86           0 :   mIndex->RegisterIterator(this);
      87           0 : }
      88             : 
      89           0 : SampleIterator::~SampleIterator()
      90             : {
      91           0 :   mIndex->UnregisterIterator(this);
      92           0 : }
      93             : 
      94           0 : already_AddRefed<MediaRawData> SampleIterator::GetNext()
      95             : {
      96           0 :   Sample* s(Get());
      97           0 :   if (!s) {
      98           0 :     return nullptr;
      99             :   }
     100             : 
     101           0 :   int64_t length = std::numeric_limits<int64_t>::max();
     102           0 :   mIndex->mSource->Length(&length);
     103           0 :   if (s->mByteRange.mEnd > length) {
     104             :     // We don't have this complete sample.
     105           0 :     return nullptr;
     106             :   }
     107             : 
     108           0 :   RefPtr<MediaRawData> sample = new MediaRawData();
     109           0 :   sample->mTimecode= TimeUnit::FromMicroseconds(s->mDecodeTime);
     110           0 :   sample->mTime = TimeUnit::FromMicroseconds(s->mCompositionRange.start);
     111           0 :   sample->mDuration = TimeUnit::FromMicroseconds(s->mCompositionRange.Length());
     112           0 :   sample->mOffset = s->mByteRange.mStart;
     113           0 :   sample->mKeyframe = s->mSync;
     114             : 
     115           0 :   nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
     116             :   // Do the blocking read
     117           0 :   if (!writer->SetSize(s->mByteRange.Length())) {
     118           0 :     return nullptr;
     119             :   }
     120             : 
     121             :   size_t bytesRead;
     122           0 :   if (!mIndex->mSource->ReadAt(sample->mOffset, writer->Data(), sample->Size(),
     123           0 :                                &bytesRead) || bytesRead != sample->Size()) {
     124           0 :     return nullptr;
     125             :   }
     126             : 
     127           0 :   if (!s->mCencRange.IsEmpty()) {
     128           0 :     MoofParser* parser = mIndex->mMoofParser.get();
     129             : 
     130           0 :     if (!parser || !parser->mSinf.IsValid()) {
     131           0 :       return nullptr;
     132             :     }
     133             : 
     134           0 :     uint8_t ivSize = parser->mSinf.mDefaultIVSize;
     135             : 
     136             :     // The size comes from an 8 bit field
     137           0 :     AutoTArray<uint8_t, 256> cenc;
     138           0 :     cenc.SetLength(s->mCencRange.Length());
     139           0 :     if (!mIndex->mSource->ReadAt(s->mCencRange.mStart, cenc.Elements(), cenc.Length(),
     140           0 :                                  &bytesRead) || bytesRead != cenc.Length()) {
     141           0 :       return nullptr;
     142             :     }
     143           0 :     ByteReader reader(cenc);
     144           0 :     writer->mCrypto.mValid = true;
     145           0 :     writer->mCrypto.mIVSize = ivSize;
     146             : 
     147           0 :     CencSampleEncryptionInfoEntry* sampleInfo = GetSampleEncryptionEntry();
     148           0 :     if (sampleInfo) {
     149           0 :       writer->mCrypto.mKeyId.AppendElements(sampleInfo->mKeyId);
     150             :     }
     151             : 
     152           0 :     if (!reader.ReadArray(writer->mCrypto.mIV, ivSize)) {
     153           0 :       return nullptr;
     154             :     }
     155             : 
     156           0 :     if (reader.CanRead16()) {
     157           0 :       uint16_t count = reader.ReadU16();
     158             : 
     159           0 :       if (reader.Remaining() < count * 6) {
     160           0 :         return nullptr;
     161             :       }
     162             : 
     163           0 :       for (size_t i = 0; i < count; i++) {
     164           0 :         writer->mCrypto.mPlainSizes.AppendElement(reader.ReadU16());
     165           0 :         writer->mCrypto.mEncryptedSizes.AppendElement(reader.ReadU32());
     166             :       }
     167             :     } else {
     168             :       // No subsample information means the entire sample is encrypted.
     169           0 :       writer->mCrypto.mPlainSizes.AppendElement(0);
     170           0 :       writer->mCrypto.mEncryptedSizes.AppendElement(sample->Size());
     171             :     }
     172             :   }
     173             : 
     174           0 :   Next();
     175             : 
     176           0 :   return sample.forget();
     177             : }
     178             : 
     179           0 : CencSampleEncryptionInfoEntry* SampleIterator::GetSampleEncryptionEntry()
     180             : {
     181           0 :   nsTArray<Moof>& moofs = mIndex->mMoofParser->Moofs();
     182           0 :   Moof* currentMoof = &moofs[mCurrentMoof];
     183           0 :   SampleToGroupEntry* sampleToGroupEntry = nullptr;
     184             : 
     185             :   // Default to using the sample to group entries for the fragment, otherwise
     186             :   // fall back to the sample to group entries for the track.
     187             :   nsTArray<SampleToGroupEntry>* sampleToGroupEntries =
     188           0 :     currentMoof->mFragmentSampleToGroupEntries.Length() != 0
     189           0 :     ? &currentMoof->mFragmentSampleToGroupEntries
     190           0 :     : &mIndex->mMoofParser->mTrackSampleToGroupEntries;
     191             : 
     192           0 :   uint32_t seen = 0;
     193             : 
     194           0 :   for (SampleToGroupEntry& entry : *sampleToGroupEntries) {
     195           0 :     if (seen + entry.mSampleCount > mCurrentSample) {
     196           0 :       sampleToGroupEntry = &entry;
     197           0 :       break;
     198             :     }
     199           0 :     seen += entry.mSampleCount;
     200             :   }
     201             : 
     202             :   // ISO-14496-12 Section 8.9.2.3 and 8.9.4 : group description index
     203             :   // (1) ranges from 1 to the number of sample group entries in the track
     204             :   // level SampleGroupDescription Box, or (2) takes the value 0 to
     205             :   // indicate that this sample is a member of no group, in this case, the
     206             :   // sample is associated with the default values specified in
     207             :   // TrackEncryption Box, or (3) starts at 0x10001, i.e. the index value
     208             :   // 1, with the value 1 in the top 16 bits, to reference fragment-local
     209             :   // SampleGroupDescription Box.
     210             : 
     211             :   // According to the spec, ISO-14496-12, the sum of the sample counts in this
     212             :   // box should be equal to the total number of samples, and, if less, the
     213             :   // reader should behave as if an extra SampleToGroupEntry existed, with
     214             :   // groupDescriptionIndex 0.
     215             : 
     216           0 :   if (!sampleToGroupEntry || sampleToGroupEntry->mGroupDescriptionIndex == 0) {
     217           0 :     return nullptr;
     218             :   }
     219             : 
     220             :   nsTArray<CencSampleEncryptionInfoEntry>* entries =
     221           0 :                       &mIndex->mMoofParser->mTrackSampleEncryptionInfoEntries;
     222             : 
     223           0 :   uint32_t groupIndex = sampleToGroupEntry->mGroupDescriptionIndex;
     224             : 
     225             :   // If the first bit is set to a one, then we should use the sample group
     226             :   // descriptions from the fragment.
     227           0 :   if (groupIndex > SampleToGroupEntry::kFragmentGroupDescriptionIndexBase) {
     228           0 :     groupIndex -= SampleToGroupEntry::kFragmentGroupDescriptionIndexBase;
     229           0 :     entries = &currentMoof->mFragmentSampleEncryptionInfoEntries;
     230             :   }
     231             : 
     232             :   // The group_index is one based.
     233           0 :   return groupIndex > entries->Length()
     234           0 :          ? nullptr
     235           0 :          : &entries->ElementAt(groupIndex - 1);
     236             : }
     237             : 
     238           0 : Sample* SampleIterator::Get()
     239             : {
     240           0 :   if (!mIndex->mMoofParser) {
     241           0 :     MOZ_ASSERT(!mCurrentMoof);
     242           0 :     return mCurrentSample < mIndex->mIndex.Length()
     243           0 :       ? &mIndex->mIndex[mCurrentSample]
     244           0 :       : nullptr;
     245             :   }
     246             : 
     247           0 :   nsTArray<Moof>& moofs = mIndex->mMoofParser->Moofs();
     248             :   while (true) {
     249           0 :     if (mCurrentMoof == moofs.Length()) {
     250           0 :       if (!mIndex->mMoofParser->BlockingReadNextMoof()) {
     251           0 :         return nullptr;
     252             :       }
     253           0 :       MOZ_ASSERT(mCurrentMoof < moofs.Length());
     254             :     }
     255           0 :     if (mCurrentSample < moofs[mCurrentMoof].mIndex.Length()) {
     256           0 :       break;
     257             :     }
     258           0 :     mCurrentSample = 0;
     259           0 :     ++mCurrentMoof;
     260             :   }
     261           0 :   return &moofs[mCurrentMoof].mIndex[mCurrentSample];
     262             : }
     263             : 
     264           0 : void SampleIterator::Next()
     265             : {
     266           0 :   ++mCurrentSample;
     267           0 : }
     268             : 
     269           0 : void SampleIterator::Seek(Microseconds aTime)
     270             : {
     271           0 :   size_t syncMoof = 0;
     272           0 :   size_t syncSample = 0;
     273           0 :   mCurrentMoof = 0;
     274           0 :   mCurrentSample = 0;
     275             :   Sample* sample;
     276           0 :   while (!!(sample = Get())) {
     277           0 :     if (sample->mCompositionRange.start > aTime) {
     278           0 :       break;
     279             :     }
     280           0 :     if (sample->mSync) {
     281           0 :       syncMoof = mCurrentMoof;
     282           0 :       syncSample = mCurrentSample;
     283             :     }
     284           0 :     if (sample->mCompositionRange.start == aTime) {
     285           0 :       break;
     286             :     }
     287           0 :     Next();
     288             :   }
     289           0 :   mCurrentMoof = syncMoof;
     290           0 :   mCurrentSample = syncSample;
     291           0 : }
     292             : 
     293             : Microseconds
     294           0 : SampleIterator::GetNextKeyframeTime()
     295             : {
     296           0 :   SampleIterator itr(*this);
     297             :   Sample* sample;
     298           0 :   while (!!(sample = itr.Get())) {
     299           0 :     if (sample->mSync) {
     300           0 :       return sample->mCompositionRange.start;
     301             :     }
     302           0 :     itr.Next();
     303             :   }
     304           0 :   return -1;
     305             : }
     306             : 
     307           0 : Index::Index(const IndiceWrapper& aIndices,
     308             :              Stream* aSource,
     309             :              uint32_t aTrackId,
     310           0 :              bool aIsAudio)
     311             :   : mSource(aSource)
     312           0 :   , mIsAudio(aIsAudio)
     313             : {
     314           0 :   if (!aIndices.Length()) {
     315           0 :     mMoofParser = new MoofParser(aSource, aTrackId, aIsAudio);
     316             :   } else {
     317           0 :     if (!mIndex.SetCapacity(aIndices.Length(), fallible)) {
     318             :       // OOM.
     319           0 :       return;
     320             :     }
     321           0 :     media::IntervalSet<int64_t> intervalTime;
     322           0 :     MediaByteRange intervalRange;
     323           0 :     bool haveSync = false;
     324           0 :     bool progressive = true;
     325           0 :     int64_t lastOffset = 0;
     326           0 :     for (size_t i = 0; i < aIndices.Length(); i++) {
     327             :       Indice indice;
     328           0 :       if (!aIndices.GetIndice(i, indice)) {
     329             :         // Out of index?
     330           0 :         return;
     331             :       }
     332           0 :       if (indice.sync || mIsAudio) {
     333           0 :         haveSync = true;
     334             :       }
     335           0 :       if (!haveSync) {
     336           0 :         continue;
     337             :       }
     338             : 
     339           0 :       Sample sample;
     340           0 :       sample.mByteRange = MediaByteRange(indice.start_offset,
     341           0 :                                          indice.end_offset);
     342           0 :       sample.mCompositionRange = Interval<Microseconds>(indice.start_composition,
     343           0 :                                                         indice.end_composition);
     344           0 :       sample.mDecodeTime = indice.start_decode;
     345           0 :       sample.mSync = indice.sync || mIsAudio;
     346             :       // FIXME: Make this infallible after bug 968520 is done.
     347           0 :       MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample, fallible));
     348           0 :       if (indice.start_offset < lastOffset) {
     349           0 :         NS_WARNING("Chunks in MP4 out of order, expect slow down");
     350           0 :         progressive = false;
     351             :       }
     352           0 :       lastOffset = indice.end_offset;
     353             : 
     354             :       // Pack audio samples in group of 128.
     355           0 :       if (sample.mSync && progressive && (!mIsAudio || !(i % 128))) {
     356           0 :         if (mDataOffset.Length()) {
     357           0 :           auto& last = mDataOffset.LastElement();
     358           0 :           last.mEndOffset = intervalRange.mEnd;
     359           0 :           NS_ASSERTION(intervalTime.Length() == 1, "Discontinuous samples between keyframes");
     360           0 :           last.mTime.start = intervalTime.GetStart();
     361           0 :           last.mTime.end = intervalTime.GetEnd();
     362             :         }
     363           0 :         if (!mDataOffset.AppendElement(MP4DataOffset(mIndex.Length() - 1,
     364           0 :                                                      indice.start_offset),
     365             :                                        fallible)) {
     366             :           // OOM.
     367           0 :           return;
     368             :         }
     369           0 :         intervalTime = media::IntervalSet<int64_t>();
     370           0 :         intervalRange = MediaByteRange();
     371             :       }
     372           0 :       intervalTime += media::Interval<int64_t>(sample.mCompositionRange.start,
     373           0 :                                                sample.mCompositionRange.end);
     374           0 :       intervalRange = intervalRange.Span(sample.mByteRange);
     375             :     }
     376             : 
     377           0 :     if (mDataOffset.Length() && progressive) {
     378             :       Indice indice;
     379           0 :       if (!aIndices.GetIndice(aIndices.Length() - 1, indice)) {
     380           0 :         return;
     381             :       }
     382           0 :       auto& last = mDataOffset.LastElement();
     383           0 :       last.mEndOffset = indice.end_offset;
     384           0 :       last.mTime = Interval<int64_t>(intervalTime.GetStart(), intervalTime.GetEnd());
     385             :     } else {
     386           0 :       mDataOffset.Clear();
     387             :     }
     388             :   }
     389             : }
     390             : 
     391           0 : Index::~Index() {}
     392             : 
     393             : void
     394           0 : Index::UpdateMoofIndex(const MediaByteRangeSet& aByteRanges)
     395             : {
     396           0 :   UpdateMoofIndex(aByteRanges, false);
     397           0 : }
     398             : 
     399             : void
     400           0 : Index::UpdateMoofIndex(const MediaByteRangeSet& aByteRanges, bool aCanEvict)
     401             : {
     402           0 :   if (!mMoofParser) {
     403           0 :     return;
     404             :   }
     405           0 :   size_t moofs = mMoofParser->Moofs().Length();
     406           0 :   bool canEvict = aCanEvict && moofs > 1;
     407           0 :   if (canEvict) {
     408             :     // Check that we can trim the mMoofParser. We can only do so if all
     409             :     // iterators have demuxed all possible samples.
     410           0 :     for (const SampleIterator* iterator : mIterators) {
     411           0 :       if ((iterator->mCurrentSample == 0 && iterator->mCurrentMoof == moofs) ||
     412           0 :           iterator->mCurrentMoof == moofs - 1) {
     413           0 :         continue;
     414             :       }
     415           0 :       canEvict = false;
     416           0 :       break;
     417             :     }
     418             :   }
     419           0 :   mMoofParser->RebuildFragmentedIndex(aByteRanges, &canEvict);
     420           0 :   if (canEvict) {
     421             :     // The moofparser got trimmed. Adjust all registered iterators.
     422           0 :     for (SampleIterator* iterator : mIterators) {
     423           0 :       iterator->mCurrentMoof -= moofs - 1;
     424             :     }
     425             :   }
     426             : }
     427             : 
     428             : Microseconds
     429           0 : Index::GetEndCompositionIfBuffered(const MediaByteRangeSet& aByteRanges)
     430             : {
     431             :   FallibleTArray<Sample>* index;
     432           0 :   if (mMoofParser) {
     433           0 :     if (!mMoofParser->ReachedEnd() || mMoofParser->Moofs().IsEmpty()) {
     434           0 :       return 0;
     435             :     }
     436           0 :     index = &mMoofParser->Moofs().LastElement().mIndex;
     437             :   } else {
     438           0 :     index = &mIndex;
     439             :   }
     440             : 
     441           0 :   Microseconds lastComposition = 0;
     442           0 :   RangeFinder rangeFinder(aByteRanges);
     443           0 :   for (size_t i = index->Length(); i--;) {
     444           0 :     const Sample& sample = (*index)[i];
     445           0 :     if (!rangeFinder.Contains(sample.mByteRange)) {
     446           0 :       return 0;
     447             :     }
     448           0 :     lastComposition = std::max(lastComposition, sample.mCompositionRange.end);
     449           0 :     if (sample.mSync) {
     450           0 :       return lastComposition;
     451             :     }
     452             :   }
     453           0 :   return 0;
     454             : }
     455             : 
     456             : TimeIntervals
     457           0 : Index::ConvertByteRangesToTimeRanges(const MediaByteRangeSet& aByteRanges)
     458             : {
     459           0 :   if (aByteRanges == mLastCachedRanges) {
     460           0 :     return mLastBufferedRanges;
     461             :   }
     462           0 :   mLastCachedRanges = aByteRanges;
     463             : 
     464           0 :   if (mDataOffset.Length()) {
     465           0 :     TimeIntervals timeRanges;
     466           0 :     for (const auto& range : aByteRanges) {
     467           0 :       uint32_t start = mDataOffset.IndexOfFirstElementGt(range.mStart - 1);
     468           0 :       if (!mIsAudio && start == mDataOffset.Length()) {
     469           0 :         continue;
     470             :       }
     471           0 :       uint32_t end = mDataOffset.IndexOfFirstElementGt(range.mEnd, MP4DataOffset::EndOffsetComparator());
     472           0 :       if (!mIsAudio && end < start) {
     473           0 :         continue;
     474             :       }
     475           0 :       if (mIsAudio && start &&
     476           0 :           range.Intersects(MediaByteRange(mDataOffset[start-1].mStartOffset,
     477           0 :                                           mDataOffset[start-1].mEndOffset))) {
     478             :         // Check if previous audio data block contains some available samples.
     479           0 :         for (size_t i = mDataOffset[start-1].mIndex; i < mIndex.Length(); i++) {
     480           0 :           if (range.ContainsStrict(mIndex[i].mByteRange)) {
     481             :             timeRanges +=
     482           0 :               TimeInterval(TimeUnit::FromMicroseconds(mIndex[i].mCompositionRange.start),
     483           0 :                            TimeUnit::FromMicroseconds(mIndex[i].mCompositionRange.end));
     484             :           }
     485             :         }
     486             :       }
     487           0 :       if (end > start) {
     488             :         timeRanges +=
     489           0 :           TimeInterval(TimeUnit::FromMicroseconds(mDataOffset[start].mTime.start),
     490           0 :                        TimeUnit::FromMicroseconds(mDataOffset[end-1].mTime.end));
     491             :       }
     492           0 :       if (end < mDataOffset.Length()) {
     493             :         // Find samples in partial block contained in the byte range.
     494           0 :         for (size_t i = mDataOffset[end].mIndex;
     495           0 :              i < mIndex.Length() && range.ContainsStrict(mIndex[i].mByteRange);
     496             :              i++) {
     497             :           timeRanges +=
     498           0 :             TimeInterval(TimeUnit::FromMicroseconds(mIndex[i].mCompositionRange.start),
     499           0 :                          TimeUnit::FromMicroseconds(mIndex[i].mCompositionRange.end));
     500             :         }
     501             :       }
     502             :     }
     503           0 :     mLastBufferedRanges = timeRanges;
     504           0 :     return timeRanges;
     505             :   }
     506             : 
     507           0 :   RangeFinder rangeFinder(aByteRanges);
     508           0 :   nsTArray<Interval<Microseconds>> timeRanges;
     509           0 :   nsTArray<FallibleTArray<Sample>*> indexes;
     510           0 :   if (mMoofParser) {
     511             :     // We take the index out of the moof parser and move it into a local
     512             :     // variable so we don't get concurrency issues. It gets freed when we
     513             :     // exit this function.
     514           0 :     for (int i = 0; i < mMoofParser->Moofs().Length(); i++) {
     515           0 :       Moof& moof = mMoofParser->Moofs()[i];
     516             : 
     517             :       // We need the entire moof in order to play anything
     518           0 :       if (rangeFinder.Contains(moof.mRange)) {
     519           0 :         if (rangeFinder.Contains(moof.mMdatRange)) {
     520           0 :           Interval<Microseconds>::SemiNormalAppend(timeRanges, moof.mTimeRange);
     521             :         } else {
     522           0 :           indexes.AppendElement(&moof.mIndex);
     523             :         }
     524             :       }
     525             :     }
     526             :   } else {
     527           0 :     indexes.AppendElement(&mIndex);
     528             :   }
     529             : 
     530           0 :   bool hasSync = false;
     531           0 :   for (size_t i = 0; i < indexes.Length(); i++) {
     532           0 :     FallibleTArray<Sample>* index = indexes[i];
     533           0 :     for (size_t j = 0; j < index->Length(); j++) {
     534           0 :       const Sample& sample = (*index)[j];
     535           0 :       if (!rangeFinder.Contains(sample.mByteRange)) {
     536             :         // We process the index in decode order so we clear hasSync when we hit
     537             :         // a range that isn't buffered.
     538           0 :         hasSync = false;
     539           0 :         continue;
     540             :       }
     541             : 
     542           0 :       hasSync |= sample.mSync;
     543           0 :       if (!hasSync) {
     544           0 :         continue;
     545             :       }
     546             : 
     547             :       Interval<Microseconds>::SemiNormalAppend(timeRanges,
     548           0 :                                                sample.mCompositionRange);
     549             :     }
     550             :   }
     551             : 
     552             :   // This fixes up when the compositon order differs from the byte range order
     553           0 :   nsTArray<Interval<Microseconds>> timeRangesNormalized;
     554           0 :   Interval<Microseconds>::Normalize(timeRanges, &timeRangesNormalized);
     555             :   // convert timeRanges.
     556           0 :   media::TimeIntervals ranges;
     557           0 :   for (size_t i = 0; i < timeRangesNormalized.Length(); i++) {
     558             :     ranges +=
     559           0 :       media::TimeInterval(media::TimeUnit::FromMicroseconds(timeRangesNormalized[i].start),
     560           0 :                           media::TimeUnit::FromMicroseconds(timeRangesNormalized[i].end));
     561             :   }
     562           0 :   mLastBufferedRanges = ranges;
     563           0 :   return ranges;
     564             : }
     565             : 
     566             : uint64_t
     567           0 : Index::GetEvictionOffset(Microseconds aTime)
     568             : {
     569           0 :   uint64_t offset = std::numeric_limits<uint64_t>::max();
     570           0 :   if (mMoofParser) {
     571             :     // We need to keep the whole moof if we're keeping any of it because the
     572             :     // parser doesn't keep parsed moofs.
     573           0 :     for (int i = 0; i < mMoofParser->Moofs().Length(); i++) {
     574           0 :       Moof& moof = mMoofParser->Moofs()[i];
     575             : 
     576           0 :       if (moof.mTimeRange.Length() && moof.mTimeRange.end > aTime) {
     577           0 :         offset = std::min(offset, uint64_t(std::min(moof.mRange.mStart,
     578           0 :                                                     moof.mMdatRange.mStart)));
     579             :       }
     580             :     }
     581             :   } else {
     582             :     // We've already parsed and stored the moov so we don't need to keep it.
     583             :     // All we need to keep is the sample data itself.
     584           0 :     for (size_t i = 0; i < mIndex.Length(); i++) {
     585           0 :       const Sample& sample = mIndex[i];
     586           0 :       if (aTime >= sample.mCompositionRange.end) {
     587           0 :         offset = std::min(offset, uint64_t(sample.mByteRange.mEnd));
     588             :       }
     589             :     }
     590             :   }
     591           0 :   return offset;
     592             : }
     593             : 
     594             : void
     595           0 : Index::RegisterIterator(SampleIterator* aIterator)
     596             : {
     597           0 :   mIterators.AppendElement(aIterator);
     598           0 : }
     599             : 
     600             : void
     601           0 : Index::UnregisterIterator(SampleIterator* aIterator)
     602             : {
     603           0 :   mIterators.RemoveElement(aIterator);
     604           0 : }
     605             : 
     606             : }

Generated by: LCOV version 1.13