SampleTable.cpp revision 3cc11bfc00cbb3ed87a4464777a75606b4973b51
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    mSampleToChunkEntries =
234        new SampleToChunkEntry[mNumSampleToChunkOffsets];
235
236    for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
237        uint8_t buffer[12];
238        if (mDataSource->readAt(
239                    mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
240                != (ssize_t)sizeof(buffer)) {
241            return ERROR_IO;
242        }
243
244        CHECK(U32_AT(buffer) >= 1);  // chunk index is 1 based in the spec.
245
246        // We want the chunk index to be 0-based.
247        mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
248        mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
249        mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
250    }
251
252    return OK;
253}
254
255status_t SampleTable::setSampleSizeParams(
256        uint32_t type, off64_t data_offset, size_t data_size) {
257    if (mSampleSizeOffset >= 0) {
258        return ERROR_MALFORMED;
259    }
260
261    CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
262
263    mSampleSizeOffset = data_offset;
264
265    if (data_size < 12) {
266        return ERROR_MALFORMED;
267    }
268
269    uint8_t header[12];
270    if (mDataSource->readAt(
271                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
272        return ERROR_IO;
273    }
274
275    if (U32_AT(header) != 0) {
276        // Expected version = 0, flags = 0.
277        return ERROR_MALFORMED;
278    }
279
280    mDefaultSampleSize = U32_AT(&header[4]);
281    mNumSampleSizes = U32_AT(&header[8]);
282
283    if (type == kSampleSizeType32) {
284        mSampleSizeFieldSize = 32;
285
286        if (mDefaultSampleSize != 0) {
287            return OK;
288        }
289
290        if (data_size < 12 + mNumSampleSizes * 4) {
291            return ERROR_MALFORMED;
292        }
293    } else {
294        if ((mDefaultSampleSize & 0xffffff00) != 0) {
295            // The high 24 bits are reserved and must be 0.
296            return ERROR_MALFORMED;
297        }
298
299        mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
300        mDefaultSampleSize = 0;
301
302        if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
303            && mSampleSizeFieldSize != 16) {
304            return ERROR_MALFORMED;
305        }
306
307        if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
308            return ERROR_MALFORMED;
309        }
310    }
311
312    return OK;
313}
314
315status_t SampleTable::setTimeToSampleParams(
316        off64_t data_offset, size_t data_size) {
317    if (mTimeToSample != NULL || data_size < 8) {
318        return ERROR_MALFORMED;
319    }
320
321    uint8_t header[8];
322    if (mDataSource->readAt(
323                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
324        return ERROR_IO;
325    }
326
327    if (U32_AT(header) != 0) {
328        // Expected version = 0, flags = 0.
329        return ERROR_MALFORMED;
330    }
331
332    mTimeToSampleCount = U32_AT(&header[4]);
333    uint64_t allocSize = mTimeToSampleCount * 2 * (uint64_t)sizeof(uint32_t);
334    if (allocSize > SIZE_MAX) {
335        return ERROR_OUT_OF_RANGE;
336    }
337    mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
338
339    size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
340    if (mDataSource->readAt(
341                data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
342        return ERROR_IO;
343    }
344
345    for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
346        mTimeToSample[i] = ntohl(mTimeToSample[i]);
347    }
348
349    return OK;
350}
351
352status_t SampleTable::setCompositionTimeToSampleParams(
353        off64_t data_offset, size_t data_size) {
354    ALOGI("There are reordered frames present.");
355
356    if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
357        return ERROR_MALFORMED;
358    }
359
360    uint8_t header[8];
361    if (mDataSource->readAt(
362                data_offset, header, sizeof(header))
363            < (ssize_t)sizeof(header)) {
364        return ERROR_IO;
365    }
366
367    if (U32_AT(header) != 0) {
368        // Expected version = 0, flags = 0.
369        return ERROR_MALFORMED;
370    }
371
372    size_t numEntries = U32_AT(&header[4]);
373
374    if (data_size != (numEntries + 1) * 8) {
375        return ERROR_MALFORMED;
376    }
377
378    mNumCompositionTimeDeltaEntries = numEntries;
379    uint64_t allocSize = numEntries * 2 * (uint64_t)sizeof(uint32_t);
380    if (allocSize > SIZE_MAX) {
381        return ERROR_OUT_OF_RANGE;
382    }
383
384    mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries];
385
386    if (mDataSource->readAt(
387                data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
388            < (ssize_t)numEntries * 8) {
389        delete[] mCompositionTimeDeltaEntries;
390        mCompositionTimeDeltaEntries = NULL;
391
392        return ERROR_IO;
393    }
394
395    for (size_t i = 0; i < 2 * numEntries; ++i) {
396        mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
397    }
398
399    mCompositionDeltaLookup->setEntries(
400            mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
401
402    return OK;
403}
404
405status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
406    if (mSyncSampleOffset >= 0 || data_size < 8) {
407        return ERROR_MALFORMED;
408    }
409
410    mSyncSampleOffset = data_offset;
411
412    uint8_t header[8];
413    if (mDataSource->readAt(
414                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
415        return ERROR_IO;
416    }
417
418    if (U32_AT(header) != 0) {
419        // Expected version = 0, flags = 0.
420        return ERROR_MALFORMED;
421    }
422
423    mNumSyncSamples = U32_AT(&header[4]);
424
425    if (mNumSyncSamples < 2) {
426        ALOGV("Table of sync samples is empty or has only a single entry!");
427    }
428
429    uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t);
430    if (allocSize > SIZE_MAX) {
431        return ERROR_OUT_OF_RANGE;
432    }
433
434    mSyncSamples = new uint32_t[mNumSyncSamples];
435    size_t size = mNumSyncSamples * sizeof(uint32_t);
436    if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
437            != (ssize_t)size) {
438        return ERROR_IO;
439    }
440
441    for (size_t i = 0; i < mNumSyncSamples; ++i) {
442        mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
443    }
444
445    return OK;
446}
447
448uint32_t SampleTable::countChunkOffsets() const {
449    return mNumChunkOffsets;
450}
451
452uint32_t SampleTable::countSamples() const {
453    return mNumSampleSizes;
454}
455
456status_t SampleTable::getMaxSampleSize(size_t *max_size) {
457    Mutex::Autolock autoLock(mLock);
458
459    *max_size = 0;
460
461    for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
462        size_t sample_size;
463        status_t err = getSampleSize_l(i, &sample_size);
464
465        if (err != OK) {
466            return err;
467        }
468
469        if (sample_size > *max_size) {
470            *max_size = sample_size;
471        }
472    }
473
474    return OK;
475}
476
477uint32_t abs_difference(uint32_t time1, uint32_t time2) {
478    return time1 > time2 ? time1 - time2 : time2 - time1;
479}
480
481// static
482int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
483    const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
484    const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
485
486    if (a->mCompositionTime < b->mCompositionTime) {
487        return -1;
488    } else if (a->mCompositionTime > b->mCompositionTime) {
489        return 1;
490    }
491
492    return 0;
493}
494
495void SampleTable::buildSampleEntriesTable() {
496    Mutex::Autolock autoLock(mLock);
497
498    if (mSampleTimeEntries != NULL) {
499        return;
500    }
501
502    mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
503
504    uint32_t sampleIndex = 0;
505    uint32_t sampleTime = 0;
506
507    for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
508        uint32_t n = mTimeToSample[2 * i];
509        uint32_t delta = mTimeToSample[2 * i + 1];
510
511        for (uint32_t j = 0; j < n; ++j) {
512            if (sampleIndex < mNumSampleSizes) {
513                // Technically this should always be the case if the file
514                // is well-formed, but you know... there's (gasp) malformed
515                // content out there.
516
517                mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
518
519                uint32_t compTimeDelta =
520                    mCompositionDeltaLookup->getCompositionTimeOffset(
521                            sampleIndex);
522
523                mSampleTimeEntries[sampleIndex].mCompositionTime =
524                    sampleTime + compTimeDelta;
525            }
526
527            ++sampleIndex;
528            sampleTime += delta;
529        }
530    }
531
532    qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
533          CompareIncreasingTime);
534}
535
536status_t SampleTable::findSampleAtTime(
537        uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
538    buildSampleEntriesTable();
539
540    uint32_t left = 0;
541    uint32_t right = mNumSampleSizes;
542    while (left < right) {
543        uint32_t center = (left + right) / 2;
544        uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
545
546        if (req_time < centerTime) {
547            right = center;
548        } else if (req_time > centerTime) {
549            left = center + 1;
550        } else {
551            left = center;
552            break;
553        }
554    }
555
556    if (left == mNumSampleSizes) {
557        if (flags == kFlagAfter) {
558            return ERROR_OUT_OF_RANGE;
559        }
560
561        --left;
562    }
563
564    uint32_t closestIndex = left;
565
566    switch (flags) {
567        case kFlagBefore:
568        {
569            while (closestIndex > 0
570                    && mSampleTimeEntries[closestIndex].mCompositionTime
571                            > req_time) {
572                --closestIndex;
573            }
574            break;
575        }
576
577        case kFlagAfter:
578        {
579            while (closestIndex + 1 < mNumSampleSizes
580                    && mSampleTimeEntries[closestIndex].mCompositionTime
581                            < req_time) {
582                ++closestIndex;
583            }
584            break;
585        }
586
587        default:
588        {
589            CHECK(flags == kFlagClosest);
590
591            if (closestIndex > 0) {
592                // Check left neighbour and pick closest.
593                uint32_t absdiff1 =
594                    abs_difference(
595                            mSampleTimeEntries[closestIndex].mCompositionTime,
596                            req_time);
597
598                uint32_t absdiff2 =
599                    abs_difference(
600                            mSampleTimeEntries[closestIndex - 1].mCompositionTime,
601                            req_time);
602
603                if (absdiff1 > absdiff2) {
604                    closestIndex = closestIndex - 1;
605                }
606            }
607
608            break;
609        }
610    }
611
612    *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
613
614    return OK;
615}
616
617status_t SampleTable::findSyncSampleNear(
618        uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
619    Mutex::Autolock autoLock(mLock);
620
621    *sample_index = 0;
622
623    if (mSyncSampleOffset < 0) {
624        // All samples are sync-samples.
625        *sample_index = start_sample_index;
626        return OK;
627    }
628
629    if (mNumSyncSamples == 0) {
630        *sample_index = 0;
631        return OK;
632    }
633
634    uint32_t left = 0;
635    uint32_t right = mNumSyncSamples;
636    while (left < right) {
637        uint32_t center = left + (right - left) / 2;
638        uint32_t x = mSyncSamples[center];
639
640        if (start_sample_index < x) {
641            right = center;
642        } else if (start_sample_index > x) {
643            left = center + 1;
644        } else {
645            left = center;
646            break;
647        }
648    }
649    if (left == mNumSyncSamples) {
650        if (flags == kFlagAfter) {
651            ALOGE("tried to find a sync frame after the last one: %d", left);
652            return ERROR_OUT_OF_RANGE;
653        }
654        left = left - 1;
655    }
656
657    // Now ssi[left] is the sync sample index just before (or at)
658    // start_sample_index.
659    // Also start_sample_index < ssi[left + 1], if left + 1 < mNumSyncSamples.
660
661    uint32_t x = mSyncSamples[left];
662
663    if (left + 1 < mNumSyncSamples) {
664        uint32_t y = mSyncSamples[left + 1];
665
666        // our sample lies between sync samples x and y.
667
668        status_t err = mSampleIterator->seekTo(start_sample_index);
669        if (err != OK) {
670            return err;
671        }
672
673        uint32_t sample_time = mSampleIterator->getSampleTime();
674
675        err = mSampleIterator->seekTo(x);
676        if (err != OK) {
677            return err;
678        }
679        uint32_t x_time = mSampleIterator->getSampleTime();
680
681        err = mSampleIterator->seekTo(y);
682        if (err != OK) {
683            return err;
684        }
685
686        uint32_t y_time = mSampleIterator->getSampleTime();
687
688        if (abs_difference(x_time, sample_time)
689                > abs_difference(y_time, sample_time)) {
690            // Pick the sync sample closest (timewise) to the start-sample.
691            x = y;
692            ++left;
693        }
694    }
695
696    switch (flags) {
697        case kFlagBefore:
698        {
699            if (x > start_sample_index) {
700                CHECK(left > 0);
701
702                x = mSyncSamples[left - 1];
703
704                if (x > start_sample_index) {
705                    // The table of sync sample indices was not sorted
706                    // properly.
707                    return ERROR_MALFORMED;
708                }
709            }
710            break;
711        }
712
713        case kFlagAfter:
714        {
715            if (x < start_sample_index) {
716                if (left + 1 >= mNumSyncSamples) {
717                    return ERROR_OUT_OF_RANGE;
718                }
719
720                x = mSyncSamples[left + 1];
721
722                if (x < start_sample_index) {
723                    // The table of sync sample indices was not sorted
724                    // properly.
725                    return ERROR_MALFORMED;
726                }
727            }
728
729            break;
730        }
731
732        default:
733            break;
734    }
735
736    *sample_index = x;
737
738    return OK;
739}
740
741status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
742    Mutex::Autolock autoLock(mLock);
743
744    if (mSyncSampleOffset < 0) {
745        // All samples are sync-samples.
746        *sample_index = 0;
747        return OK;
748    }
749
750    uint32_t bestSampleIndex = 0;
751    size_t maxSampleSize = 0;
752
753    static const size_t kMaxNumSyncSamplesToScan = 20;
754
755    // Consider the first kMaxNumSyncSamplesToScan sync samples and
756    // pick the one with the largest (compressed) size as the thumbnail.
757
758    size_t numSamplesToScan = mNumSyncSamples;
759    if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
760        numSamplesToScan = kMaxNumSyncSamplesToScan;
761    }
762
763    for (size_t i = 0; i < numSamplesToScan; ++i) {
764        uint32_t x = mSyncSamples[i];
765
766        // Now x is a sample index.
767        size_t sampleSize;
768        status_t err = getSampleSize_l(x, &sampleSize);
769        if (err != OK) {
770            return err;
771        }
772
773        if (i == 0 || sampleSize > maxSampleSize) {
774            bestSampleIndex = x;
775            maxSampleSize = sampleSize;
776        }
777    }
778
779    *sample_index = bestSampleIndex;
780
781    return OK;
782}
783
784status_t SampleTable::getSampleSize_l(
785        uint32_t sampleIndex, size_t *sampleSize) {
786    return mSampleIterator->getSampleSizeDirect(
787            sampleIndex, sampleSize);
788}
789
790status_t SampleTable::getMetaDataForSample(
791        uint32_t sampleIndex,
792        off64_t *offset,
793        size_t *size,
794        uint32_t *compositionTime,
795        bool *isSyncSample) {
796    Mutex::Autolock autoLock(mLock);
797
798    status_t err;
799    if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
800        return err;
801    }
802
803    if (offset) {
804        *offset = mSampleIterator->getSampleOffset();
805    }
806
807    if (size) {
808        *size = mSampleIterator->getSampleSize();
809    }
810
811    if (compositionTime) {
812        *compositionTime = mSampleIterator->getSampleTime();
813    }
814
815    if (isSyncSample) {
816        *isSyncSample = false;
817        if (mSyncSampleOffset < 0) {
818            // Every sample is a sync sample.
819            *isSyncSample = true;
820        } else {
821            size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
822                    && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
823                ? mLastSyncSampleIndex : 0;
824
825            while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
826                ++i;
827            }
828
829            if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
830                *isSyncSample = true;
831            }
832
833            mLastSyncSampleIndex = i;
834        }
835    }
836
837    return OK;
838}
839
840uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
841    return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
842}
843
844}  // namespace android
845
846