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