• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "SampleTable"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include <limits>
22 
23 #include "include/SampleTable.h"
24 #include "include/SampleIterator.h"
25 
26 #include <arpa/inet.h>
27 
28 #include <media/stagefright/foundation/ADebug.h>
29 #include <media/stagefright/DataSource.h>
30 #include <media/stagefright/Utils.h>
31 
32 namespace android {
33 
34 // static
35 const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
36 // static
37 const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
38 // static
39 const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
40 // static
41 const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 
45 const off64_t kMaxOffset = std::numeric_limits<off64_t>::max();
46 
47 struct SampleTable::CompositionDeltaLookup {
48     CompositionDeltaLookup();
49 
50     void setEntries(
51             const uint32_t *deltaEntries, size_t numDeltaEntries);
52 
53     uint32_t getCompositionTimeOffset(uint32_t sampleIndex);
54 
55 private:
56     Mutex mLock;
57 
58     const uint32_t *mDeltaEntries;
59     size_t mNumDeltaEntries;
60 
61     size_t mCurrentDeltaEntry;
62     size_t mCurrentEntrySampleIndex;
63 
64     DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup);
65 };
66 
CompositionDeltaLookup()67 SampleTable::CompositionDeltaLookup::CompositionDeltaLookup()
68     : mDeltaEntries(NULL),
69       mNumDeltaEntries(0),
70       mCurrentDeltaEntry(0),
71       mCurrentEntrySampleIndex(0) {
72 }
73 
setEntries(const uint32_t * deltaEntries,size_t numDeltaEntries)74 void SampleTable::CompositionDeltaLookup::setEntries(
75         const uint32_t *deltaEntries, size_t numDeltaEntries) {
76     Mutex::Autolock autolock(mLock);
77 
78     mDeltaEntries = deltaEntries;
79     mNumDeltaEntries = numDeltaEntries;
80     mCurrentDeltaEntry = 0;
81     mCurrentEntrySampleIndex = 0;
82 }
83 
getCompositionTimeOffset(uint32_t sampleIndex)84 uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset(
85         uint32_t sampleIndex) {
86     Mutex::Autolock autolock(mLock);
87 
88     if (mDeltaEntries == NULL) {
89         return 0;
90     }
91 
92     if (sampleIndex < mCurrentEntrySampleIndex) {
93         mCurrentDeltaEntry = 0;
94         mCurrentEntrySampleIndex = 0;
95     }
96 
97     while (mCurrentDeltaEntry < mNumDeltaEntries) {
98         uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry];
99         if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) {
100             return mDeltaEntries[2 * mCurrentDeltaEntry + 1];
101         }
102 
103         mCurrentEntrySampleIndex += sampleCount;
104         ++mCurrentDeltaEntry;
105     }
106 
107     return 0;
108 }
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 
SampleTable(const sp<DataSource> & source)112 SampleTable::SampleTable(const sp<DataSource> &source)
113     : mDataSource(source),
114       mChunkOffsetOffset(-1),
115       mChunkOffsetType(0),
116       mNumChunkOffsets(0),
117       mSampleToChunkOffset(-1),
118       mNumSampleToChunkOffsets(0),
119       mSampleSizeOffset(-1),
120       mSampleSizeFieldSize(0),
121       mDefaultSampleSize(0),
122       mNumSampleSizes(0),
123       mHasTimeToSample(false),
124       mTimeToSampleCount(0),
125       mTimeToSample(NULL),
126       mSampleTimeEntries(NULL),
127       mCompositionTimeDeltaEntries(NULL),
128       mNumCompositionTimeDeltaEntries(0),
129       mCompositionDeltaLookup(new CompositionDeltaLookup),
130       mSyncSampleOffset(-1),
131       mNumSyncSamples(0),
132       mSyncSamples(NULL),
133       mLastSyncSampleIndex(0),
134       mSampleToChunkEntries(NULL),
135       mTotalSize(0) {
136     mSampleIterator = new SampleIterator(this);
137 }
138 
~SampleTable()139 SampleTable::~SampleTable() {
140     delete[] mSampleToChunkEntries;
141     mSampleToChunkEntries = NULL;
142 
143     delete[] mSyncSamples;
144     mSyncSamples = NULL;
145 
146     delete[] mTimeToSample;
147     mTimeToSample = NULL;
148 
149     delete mCompositionDeltaLookup;
150     mCompositionDeltaLookup = NULL;
151 
152     delete[] mCompositionTimeDeltaEntries;
153     mCompositionTimeDeltaEntries = NULL;
154 
155     delete[] mSampleTimeEntries;
156     mSampleTimeEntries = NULL;
157 
158     delete mSampleIterator;
159     mSampleIterator = NULL;
160 }
161 
isValid() const162 bool SampleTable::isValid() const {
163     return mChunkOffsetOffset >= 0
164         && mSampleToChunkOffset >= 0
165         && mSampleSizeOffset >= 0
166         && mHasTimeToSample;
167 }
168 
setChunkOffsetParams(uint32_t type,off64_t data_offset,size_t data_size)169 status_t SampleTable::setChunkOffsetParams(
170         uint32_t type, off64_t data_offset, size_t data_size) {
171     if (mChunkOffsetOffset >= 0) {
172         return ERROR_MALFORMED;
173     }
174 
175     CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
176 
177     mChunkOffsetOffset = data_offset;
178     mChunkOffsetType = type;
179 
180     if (data_size < 8) {
181         return ERROR_MALFORMED;
182     }
183 
184     uint8_t header[8];
185     if (mDataSource->readAt(
186                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
187         return ERROR_IO;
188     }
189 
190     if (U32_AT(header) != 0) {
191         // Expected version = 0, flags = 0.
192         return ERROR_MALFORMED;
193     }
194 
195     mNumChunkOffsets = U32_AT(&header[4]);
196 
197     if (mChunkOffsetType == kChunkOffsetType32) {
198         if (data_size < 8 + mNumChunkOffsets * 4) {
199             return ERROR_MALFORMED;
200         }
201     } else {
202         if (data_size < 8 + mNumChunkOffsets * 8) {
203             return ERROR_MALFORMED;
204         }
205     }
206 
207     return OK;
208 }
209 
setSampleToChunkParams(off64_t data_offset,size_t data_size)210 status_t SampleTable::setSampleToChunkParams(
211         off64_t data_offset, size_t data_size) {
212     if (mSampleToChunkOffset >= 0) {
213         return ERROR_MALFORMED;
214     }
215 
216     mSampleToChunkOffset = data_offset;
217 
218     if (data_size < 8) {
219         return ERROR_MALFORMED;
220     }
221 
222     uint8_t header[8];
223     if (mDataSource->readAt(
224                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
225         return ERROR_IO;
226     }
227 
228     if (U32_AT(header) != 0) {
229         // Expected version = 0, flags = 0.
230         return ERROR_MALFORMED;
231     }
232 
233     mNumSampleToChunkOffsets = U32_AT(&header[4]);
234 
235     if ((data_size - 8) / sizeof(SampleToChunkEntry) < mNumSampleToChunkOffsets) {
236         return ERROR_MALFORMED;
237     }
238 
239     if ((uint64_t)kMaxTotalSize / sizeof(SampleToChunkEntry) <=
240             (uint64_t)mNumSampleToChunkOffsets) {
241         ALOGE("Sample-to-chunk table size too large.");
242         return ERROR_OUT_OF_RANGE;
243     }
244 
245     mTotalSize += (uint64_t)mNumSampleToChunkOffsets *
246             sizeof(SampleToChunkEntry);
247     if (mTotalSize > kMaxTotalSize) {
248         ALOGE("Sample-to-chunk table size would make sample table too large.\n"
249               "    Requested sample-to-chunk table size = %llu\n"
250               "    Eventual sample table size >= %llu\n"
251               "    Allowed sample table size = %llu\n",
252               (unsigned long long)mNumSampleToChunkOffsets *
253                       sizeof(SampleToChunkEntry),
254               (unsigned long long)mTotalSize,
255               (unsigned long long)kMaxTotalSize);
256         return ERROR_OUT_OF_RANGE;
257     }
258 
259     mSampleToChunkEntries =
260         new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets];
261     if (!mSampleToChunkEntries) {
262         ALOGE("Cannot allocate sample-to-chunk table with %llu entries.",
263                 (unsigned long long)mNumSampleToChunkOffsets);
264         return ERROR_OUT_OF_RANGE;
265     }
266 
267     if (mNumSampleToChunkOffsets == 0) {
268         return OK;
269     }
270 
271     if ((off64_t)(kMaxOffset - 8 -
272             ((mNumSampleToChunkOffsets - 1) * sizeof(SampleToChunkEntry)))
273             < mSampleToChunkOffset) {
274         return ERROR_MALFORMED;
275     }
276 
277     for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
278         uint8_t buffer[sizeof(SampleToChunkEntry)];
279 
280         if (mDataSource->readAt(
281                     mSampleToChunkOffset + 8 + i * sizeof(SampleToChunkEntry),
282                     buffer,
283                     sizeof(buffer))
284                 != (ssize_t)sizeof(buffer)) {
285             return ERROR_IO;
286         }
287         // chunk index is 1 based in the spec.
288         if (U32_AT(buffer) < 1) {
289             ALOGE("b/23534160");
290             return ERROR_OUT_OF_RANGE;
291         }
292 
293         // We want the chunk index to be 0-based.
294         mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
295         mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
296         mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
297     }
298 
299     return OK;
300 }
301 
setSampleSizeParams(uint32_t type,off64_t data_offset,size_t data_size)302 status_t SampleTable::setSampleSizeParams(
303         uint32_t type, off64_t data_offset, size_t data_size) {
304     if (mSampleSizeOffset >= 0) {
305         return ERROR_MALFORMED;
306     }
307 
308     CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
309 
310     mSampleSizeOffset = data_offset;
311 
312     if (data_size < 12) {
313         return ERROR_MALFORMED;
314     }
315 
316     uint8_t header[12];
317     if (mDataSource->readAt(
318                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
319         return ERROR_IO;
320     }
321 
322     if (U32_AT(header) != 0) {
323         // Expected version = 0, flags = 0.
324         return ERROR_MALFORMED;
325     }
326 
327     mDefaultSampleSize = U32_AT(&header[4]);
328     mNumSampleSizes = U32_AT(&header[8]);
329     if (mNumSampleSizes > (UINT32_MAX - 12) / 16) {
330         return ERROR_MALFORMED;
331     }
332 
333     if (type == kSampleSizeType32) {
334         mSampleSizeFieldSize = 32;
335 
336         if (mDefaultSampleSize != 0) {
337             return OK;
338         }
339 
340         if (data_size < 12 + mNumSampleSizes * 4) {
341             return ERROR_MALFORMED;
342         }
343     } else {
344         if ((mDefaultSampleSize & 0xffffff00) != 0) {
345             // The high 24 bits are reserved and must be 0.
346             return ERROR_MALFORMED;
347         }
348 
349         mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
350         mDefaultSampleSize = 0;
351 
352         if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
353             && mSampleSizeFieldSize != 16) {
354             return ERROR_MALFORMED;
355         }
356 
357         if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
358             return ERROR_MALFORMED;
359         }
360     }
361 
362     return OK;
363 }
364 
setTimeToSampleParams(off64_t data_offset,size_t data_size)365 status_t SampleTable::setTimeToSampleParams(
366         off64_t data_offset, size_t data_size) {
367     if (mHasTimeToSample || data_size < 8) {
368         return ERROR_MALFORMED;
369     }
370 
371     uint8_t header[8];
372     if (mDataSource->readAt(
373                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
374         return ERROR_IO;
375     }
376 
377     if (U32_AT(header) != 0) {
378         // Expected version = 0, flags = 0.
379         return ERROR_MALFORMED;
380     }
381 
382     mTimeToSampleCount = U32_AT(&header[4]);
383     if (mTimeToSampleCount > UINT32_MAX / (2 * sizeof(uint32_t))) {
384         // Choose this bound because
385         // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
386         //    time-to-sample entry in the time-to-sample table.
387         // 2) mTimeToSampleCount is the number of entries of the time-to-sample
388         //    table.
389         // 3) We hope that the table size does not exceed UINT32_MAX.
390         ALOGE("Time-to-sample table size too large.");
391         return ERROR_OUT_OF_RANGE;
392     }
393 
394     // Note: At this point, we know that mTimeToSampleCount * 2 will not
395     // overflow because of the above condition.
396 
397     uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t);
398     mTotalSize += allocSize;
399     if (mTotalSize > kMaxTotalSize) {
400         ALOGE("Time-to-sample table size would make sample table too large.\n"
401               "    Requested time-to-sample table size = %llu\n"
402               "    Eventual sample table size >= %llu\n"
403               "    Allowed sample table size = %llu\n",
404               (unsigned long long)allocSize,
405               (unsigned long long)mTotalSize,
406               (unsigned long long)kMaxTotalSize);
407         return ERROR_OUT_OF_RANGE;
408     }
409 
410     mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2];
411     if (!mTimeToSample) {
412         ALOGE("Cannot allocate time-to-sample table with %llu entries.",
413                 (unsigned long long)mTimeToSampleCount);
414         return ERROR_OUT_OF_RANGE;
415     }
416 
417     if (mDataSource->readAt(data_offset + 8, mTimeToSample,
418             (size_t)allocSize) < (ssize_t)allocSize) {
419         ALOGE("Incomplete data read for time-to-sample table.");
420         return ERROR_IO;
421     }
422 
423     for (size_t i = 0; i < mTimeToSampleCount * 2; ++i) {
424         mTimeToSample[i] = ntohl(mTimeToSample[i]);
425     }
426 
427     mHasTimeToSample = true;
428     return OK;
429 }
430 
setCompositionTimeToSampleParams(off64_t data_offset,size_t data_size)431 status_t SampleTable::setCompositionTimeToSampleParams(
432         off64_t data_offset, size_t data_size) {
433     ALOGI("There are reordered frames present.");
434 
435     if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
436         return ERROR_MALFORMED;
437     }
438 
439     uint8_t header[8];
440     if (mDataSource->readAt(
441                 data_offset, header, sizeof(header))
442             < (ssize_t)sizeof(header)) {
443         return ERROR_IO;
444     }
445 
446     if (U32_AT(header) != 0) {
447         // Expected version = 0, flags = 0.
448         return ERROR_MALFORMED;
449     }
450 
451     size_t numEntries = U32_AT(&header[4]);
452 
453     if (data_size != (numEntries + 1) * 8) {
454         return ERROR_MALFORMED;
455     }
456 
457     mNumCompositionTimeDeltaEntries = numEntries;
458     uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t);
459     if (allocSize > kMaxTotalSize) {
460         ALOGE("Composition-time-to-sample table size too large.");
461         return ERROR_OUT_OF_RANGE;
462     }
463 
464     mTotalSize += allocSize;
465     if (mTotalSize > kMaxTotalSize) {
466         ALOGE("Composition-time-to-sample table would make sample table too large.\n"
467               "    Requested composition-time-to-sample table size = %llu\n"
468               "    Eventual sample table size >= %llu\n"
469               "    Allowed sample table size = %llu\n",
470               (unsigned long long)allocSize,
471               (unsigned long long)mTotalSize,
472               (unsigned long long)kMaxTotalSize);
473         return ERROR_OUT_OF_RANGE;
474     }
475 
476     mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries];
477     if (!mCompositionTimeDeltaEntries) {
478         ALOGE("Cannot allocate composition-time-to-sample table with %llu "
479                 "entries.", (unsigned long long)numEntries);
480         return ERROR_OUT_OF_RANGE;
481     }
482 
483     if (mDataSource->readAt(data_offset + 8, mCompositionTimeDeltaEntries,
484             (size_t)allocSize) < (ssize_t)allocSize) {
485         delete[] mCompositionTimeDeltaEntries;
486         mCompositionTimeDeltaEntries = NULL;
487 
488         return ERROR_IO;
489     }
490 
491     for (size_t i = 0; i < 2 * numEntries; ++i) {
492         mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
493     }
494 
495     mCompositionDeltaLookup->setEntries(
496             mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
497 
498     return OK;
499 }
500 
setSyncSampleParams(off64_t data_offset,size_t data_size)501 status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
502     if (mSyncSampleOffset >= 0 || data_size < 8) {
503         return ERROR_MALFORMED;
504     }
505 
506     mSyncSampleOffset = data_offset;
507 
508     uint8_t header[8];
509     if (mDataSource->readAt(
510                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
511         return ERROR_IO;
512     }
513 
514     if (U32_AT(header) != 0) {
515         // Expected version = 0, flags = 0.
516         return ERROR_MALFORMED;
517     }
518 
519     mNumSyncSamples = U32_AT(&header[4]);
520 
521     if (mNumSyncSamples < 2) {
522         ALOGV("Table of sync samples is empty or has only a single entry!");
523     }
524 
525     uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t);
526     if (allocSize > kMaxTotalSize) {
527         ALOGE("Sync sample table size too large.");
528         return ERROR_OUT_OF_RANGE;
529     }
530 
531     mTotalSize += allocSize;
532     if (mTotalSize > kMaxTotalSize) {
533         ALOGE("Sync sample table size would make sample table too large.\n"
534               "    Requested sync sample table size = %llu\n"
535               "    Eventual sample table size >= %llu\n"
536               "    Allowed sample table size = %llu\n",
537               (unsigned long long)allocSize,
538               (unsigned long long)mTotalSize,
539               (unsigned long long)kMaxTotalSize);
540         return ERROR_OUT_OF_RANGE;
541     }
542 
543     mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples];
544     if (!mSyncSamples) {
545         ALOGE("Cannot allocate sync sample table with %llu entries.",
546                 (unsigned long long)mNumSyncSamples);
547         return ERROR_OUT_OF_RANGE;
548     }
549 
550     if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples,
551             (size_t)allocSize) != (ssize_t)allocSize) {
552         return ERROR_IO;
553     }
554 
555     for (size_t i = 0; i < mNumSyncSamples; ++i) {
556         mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
557     }
558 
559     return OK;
560 }
561 
countChunkOffsets() const562 uint32_t SampleTable::countChunkOffsets() const {
563     return mNumChunkOffsets;
564 }
565 
countSamples() const566 uint32_t SampleTable::countSamples() const {
567     return mNumSampleSizes;
568 }
569 
getMaxSampleSize(size_t * max_size)570 status_t SampleTable::getMaxSampleSize(size_t *max_size) {
571     Mutex::Autolock autoLock(mLock);
572 
573     *max_size = 0;
574 
575     for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
576         size_t sample_size;
577         status_t err = getSampleSize_l(i, &sample_size);
578 
579         if (err != OK) {
580             return err;
581         }
582 
583         if (sample_size > *max_size) {
584             *max_size = sample_size;
585         }
586     }
587 
588     return OK;
589 }
590 
abs_difference(uint32_t time1,uint32_t time2)591 uint32_t abs_difference(uint32_t time1, uint32_t time2) {
592     return time1 > time2 ? time1 - time2 : time2 - time1;
593 }
594 
595 // static
CompareIncreasingTime(const void * _a,const void * _b)596 int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
597     const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
598     const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
599 
600     if (a->mCompositionTime < b->mCompositionTime) {
601         return -1;
602     } else if (a->mCompositionTime > b->mCompositionTime) {
603         return 1;
604     }
605 
606     return 0;
607 }
608 
buildSampleEntriesTable()609 void SampleTable::buildSampleEntriesTable() {
610     Mutex::Autolock autoLock(mLock);
611 
612     if (mSampleTimeEntries != NULL || mNumSampleSizes == 0) {
613         return;
614     }
615 
616     mTotalSize += (uint64_t)mNumSampleSizes * sizeof(SampleTimeEntry);
617     if (mTotalSize > kMaxTotalSize) {
618         ALOGE("Sample entry table size would make sample table too large.\n"
619               "    Requested sample entry table size = %llu\n"
620               "    Eventual sample table size >= %llu\n"
621               "    Allowed sample table size = %llu\n",
622               (unsigned long long)mNumSampleSizes * sizeof(SampleTimeEntry),
623               (unsigned long long)mTotalSize,
624               (unsigned long long)kMaxTotalSize);
625         return;
626     }
627 
628     mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
629     if (!mSampleTimeEntries) {
630         ALOGE("Cannot allocate sample entry table with %llu entries.",
631                 (unsigned long long)mNumSampleSizes);
632         return;
633     }
634 
635     uint32_t sampleIndex = 0;
636     uint32_t sampleTime = 0;
637 
638     for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
639         uint32_t n = mTimeToSample[2 * i];
640         uint32_t delta = mTimeToSample[2 * i + 1];
641 
642         for (uint32_t j = 0; j < n; ++j) {
643             if (sampleIndex < mNumSampleSizes) {
644                 // Technically this should always be the case if the file
645                 // is well-formed, but you know... there's (gasp) malformed
646                 // content out there.
647 
648                 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
649 
650                 uint32_t compTimeDelta =
651                     mCompositionDeltaLookup->getCompositionTimeOffset(
652                             sampleIndex);
653 
654                 mSampleTimeEntries[sampleIndex].mCompositionTime =
655                     sampleTime + compTimeDelta;
656             }
657 
658             ++sampleIndex;
659             sampleTime += delta;
660         }
661     }
662 
663     qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
664           CompareIncreasingTime);
665 }
666 
findSampleAtTime(uint64_t req_time,uint64_t scale_num,uint64_t scale_den,uint32_t * sample_index,uint32_t flags)667 status_t SampleTable::findSampleAtTime(
668         uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
669         uint32_t *sample_index, uint32_t flags) {
670     buildSampleEntriesTable();
671 
672     if (mSampleTimeEntries == NULL) {
673         return ERROR_OUT_OF_RANGE;
674     }
675 
676     uint32_t left = 0;
677     uint32_t right_plus_one = mNumSampleSizes;
678     while (left < right_plus_one) {
679         uint32_t center = left + (right_plus_one - left) / 2;
680         uint64_t centerTime =
681             getSampleTime(center, scale_num, scale_den);
682 
683         if (req_time < centerTime) {
684             right_plus_one = center;
685         } else if (req_time > centerTime) {
686             left = center + 1;
687         } else {
688             *sample_index = mSampleTimeEntries[center].mSampleIndex;
689             return OK;
690         }
691     }
692 
693     uint32_t closestIndex = left;
694 
695     if (closestIndex == mNumSampleSizes) {
696         if (flags == kFlagAfter) {
697             return ERROR_OUT_OF_RANGE;
698         }
699         flags = kFlagBefore;
700     } else if (closestIndex == 0) {
701         if (flags == kFlagBefore) {
702             // normally we should return out of range, but that is
703             // treated as end-of-stream.  instead return first sample
704             //
705             // return ERROR_OUT_OF_RANGE;
706         }
707         flags = kFlagAfter;
708     }
709 
710     switch (flags) {
711         case kFlagBefore:
712         {
713             --closestIndex;
714             break;
715         }
716 
717         case kFlagAfter:
718         {
719             // nothing to do
720             break;
721         }
722 
723         default:
724         {
725             CHECK(flags == kFlagClosest);
726             // pick closest based on timestamp. use abs_difference for safety
727             if (abs_difference(
728                     getSampleTime(closestIndex, scale_num, scale_den), req_time) >
729                 abs_difference(
730                     req_time, getSampleTime(closestIndex - 1, scale_num, scale_den))) {
731                 --closestIndex;
732             }
733             break;
734         }
735     }
736 
737     *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
738     return OK;
739 }
740 
findSyncSampleNear(uint32_t start_sample_index,uint32_t * sample_index,uint32_t flags)741 status_t SampleTable::findSyncSampleNear(
742         uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
743     Mutex::Autolock autoLock(mLock);
744 
745     *sample_index = 0;
746 
747     if (mSyncSampleOffset < 0) {
748         // All samples are sync-samples.
749         *sample_index = start_sample_index;
750         return OK;
751     }
752 
753     if (mNumSyncSamples == 0) {
754         *sample_index = 0;
755         return OK;
756     }
757 
758     uint32_t left = 0;
759     uint32_t right_plus_one = mNumSyncSamples;
760     while (left < right_plus_one) {
761         uint32_t center = left + (right_plus_one - left) / 2;
762         uint32_t x = mSyncSamples[center];
763 
764         if (start_sample_index < x) {
765             right_plus_one = center;
766         } else if (start_sample_index > x) {
767             left = center + 1;
768         } else {
769             *sample_index = x;
770             return OK;
771         }
772     }
773 
774     if (left == mNumSyncSamples) {
775         if (flags == kFlagAfter) {
776             ALOGE("tried to find a sync frame after the last one: %d", left);
777             return ERROR_OUT_OF_RANGE;
778         }
779         flags = kFlagBefore;
780     }
781     else if (left == 0) {
782         if (flags == kFlagBefore) {
783             ALOGE("tried to find a sync frame before the first one: %d", left);
784 
785             // normally we should return out of range, but that is
786             // treated as end-of-stream.  instead seek to first sync
787             //
788             // return ERROR_OUT_OF_RANGE;
789         }
790         flags = kFlagAfter;
791     }
792 
793     // Now ssi[left - 1] <(=) start_sample_index <= ssi[left]
794     switch (flags) {
795         case kFlagBefore:
796         {
797             --left;
798             break;
799         }
800         case kFlagAfter:
801         {
802             // nothing to do
803             break;
804         }
805         default:
806         {
807             // this route is not used, but implement it nonetheless
808             CHECK(flags == kFlagClosest);
809 
810             status_t err = mSampleIterator->seekTo(start_sample_index);
811             if (err != OK) {
812                 return err;
813             }
814             uint32_t sample_time = mSampleIterator->getSampleTime();
815 
816             err = mSampleIterator->seekTo(mSyncSamples[left]);
817             if (err != OK) {
818                 return err;
819             }
820             uint32_t upper_time = mSampleIterator->getSampleTime();
821 
822             err = mSampleIterator->seekTo(mSyncSamples[left - 1]);
823             if (err != OK) {
824                 return err;
825             }
826             uint32_t lower_time = mSampleIterator->getSampleTime();
827 
828             // use abs_difference for safety
829             if (abs_difference(upper_time, sample_time) >
830                 abs_difference(sample_time, lower_time)) {
831                 --left;
832             }
833             break;
834         }
835     }
836 
837     *sample_index = mSyncSamples[left];
838     return OK;
839 }
840 
findThumbnailSample(uint32_t * sample_index)841 status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
842     Mutex::Autolock autoLock(mLock);
843 
844     if (mSyncSampleOffset < 0) {
845         // All samples are sync-samples.
846         *sample_index = 0;
847         return OK;
848     }
849 
850     uint32_t bestSampleIndex = 0;
851     size_t maxSampleSize = 0;
852 
853     static const size_t kMaxNumSyncSamplesToScan = 20;
854 
855     // Consider the first kMaxNumSyncSamplesToScan sync samples and
856     // pick the one with the largest (compressed) size as the thumbnail.
857 
858     size_t numSamplesToScan = mNumSyncSamples;
859     if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
860         numSamplesToScan = kMaxNumSyncSamplesToScan;
861     }
862 
863     for (size_t i = 0; i < numSamplesToScan; ++i) {
864         uint32_t x = mSyncSamples[i];
865 
866         // Now x is a sample index.
867         size_t sampleSize;
868         status_t err = getSampleSize_l(x, &sampleSize);
869         if (err != OK) {
870             return err;
871         }
872 
873         if (i == 0 || sampleSize > maxSampleSize) {
874             bestSampleIndex = x;
875             maxSampleSize = sampleSize;
876         }
877     }
878 
879     *sample_index = bestSampleIndex;
880 
881     return OK;
882 }
883 
getSampleSize_l(uint32_t sampleIndex,size_t * sampleSize)884 status_t SampleTable::getSampleSize_l(
885         uint32_t sampleIndex, size_t *sampleSize) {
886     return mSampleIterator->getSampleSizeDirect(
887             sampleIndex, sampleSize);
888 }
889 
getMetaDataForSample(uint32_t sampleIndex,off64_t * offset,size_t * size,uint32_t * compositionTime,bool * isSyncSample,uint32_t * sampleDuration)890 status_t SampleTable::getMetaDataForSample(
891         uint32_t sampleIndex,
892         off64_t *offset,
893         size_t *size,
894         uint32_t *compositionTime,
895         bool *isSyncSample,
896         uint32_t *sampleDuration) {
897     Mutex::Autolock autoLock(mLock);
898 
899     status_t err;
900     if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
901         return err;
902     }
903 
904     if (offset) {
905         *offset = mSampleIterator->getSampleOffset();
906     }
907 
908     if (size) {
909         *size = mSampleIterator->getSampleSize();
910     }
911 
912     if (compositionTime) {
913         *compositionTime = mSampleIterator->getSampleTime();
914     }
915 
916     if (isSyncSample) {
917         *isSyncSample = false;
918         if (mSyncSampleOffset < 0) {
919             // Every sample is a sync sample.
920             *isSyncSample = true;
921         } else {
922             size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
923                     && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
924                 ? mLastSyncSampleIndex : 0;
925 
926             while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
927                 ++i;
928             }
929 
930             if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
931                 *isSyncSample = true;
932             }
933 
934             mLastSyncSampleIndex = i;
935         }
936     }
937 
938     if (sampleDuration) {
939         *sampleDuration = mSampleIterator->getSampleDuration();
940     }
941 
942     return OK;
943 }
944 
getCompositionTimeOffset(uint32_t sampleIndex)945 uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
946     return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
947 }
948 
949 }  // namespace android
950 
951