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