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