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