SampleTable.cpp revision 7a33c062046a6b38cbe12c2f9928a0f1f0e82ebc
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 uint32_t *deltaEntries, size_t numDeltaEntries);
53
54    uint32_t getCompositionTimeOffset(uint32_t sampleIndex);
55
56private:
57    Mutex mLock;
58
59    const uint32_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 uint32_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
85uint32_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      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
139SampleTable::~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
159bool SampleTable::isValid() const {
160    return mChunkOffsetOffset >= 0
161        && mSampleToChunkOffset >= 0
162        && mSampleSizeOffset >= 0
163        && mHasTimeToSample;
164}
165
166status_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 + mNumChunkOffsets * 4) {
196            return ERROR_MALFORMED;
197        }
198    } else {
199        if (data_size < 8 + mNumChunkOffsets * 8) {
200            return ERROR_MALFORMED;
201        }
202    }
203
204    return OK;
205}
206
207status_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 + mNumSampleToChunkOffsets * 12) {
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        if (mDataSource->readAt(
247                    mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
248                != (ssize_t)sizeof(buffer)) {
249            return ERROR_IO;
250        }
251
252        CHECK(U32_AT(buffer) >= 1);  // chunk index is 1 based in the spec.
253
254        // We want the chunk index to be 0-based.
255        mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
256        mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
257        mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
258    }
259
260    return OK;
261}
262
263status_t SampleTable::setSampleSizeParams(
264        uint32_t type, off64_t data_offset, size_t data_size) {
265    if (mSampleSizeOffset >= 0) {
266        return ERROR_MALFORMED;
267    }
268
269    CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
270
271    mSampleSizeOffset = data_offset;
272
273    if (data_size < 12) {
274        return ERROR_MALFORMED;
275    }
276
277    uint8_t header[12];
278    if (mDataSource->readAt(
279                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
280        return ERROR_IO;
281    }
282
283    if (U32_AT(header) != 0) {
284        // Expected version = 0, flags = 0.
285        return ERROR_MALFORMED;
286    }
287
288    mDefaultSampleSize = U32_AT(&header[4]);
289    mNumSampleSizes = U32_AT(&header[8]);
290    if (mNumSampleSizes > (UINT32_MAX - 12) / 16) {
291        ALOGE("b/23247055, mNumSampleSizes(%u)", mNumSampleSizes);
292        return ERROR_MALFORMED;
293    }
294
295    if (type == kSampleSizeType32) {
296        mSampleSizeFieldSize = 32;
297
298        if (mDefaultSampleSize != 0) {
299            return OK;
300        }
301
302        if (data_size < 12 + mNumSampleSizes * 4) {
303            return ERROR_MALFORMED;
304        }
305    } else {
306        if ((mDefaultSampleSize & 0xffffff00) != 0) {
307            // The high 24 bits are reserved and must be 0.
308            return ERROR_MALFORMED;
309        }
310
311        mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
312        mDefaultSampleSize = 0;
313
314        if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
315            && mSampleSizeFieldSize != 16) {
316            return ERROR_MALFORMED;
317        }
318
319        if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
320            return ERROR_MALFORMED;
321        }
322    }
323
324    return OK;
325}
326
327status_t SampleTable::setTimeToSampleParams(
328        off64_t data_offset, size_t data_size) {
329    if (mHasTimeToSample || data_size < 8) {
330        return ERROR_MALFORMED;
331    }
332
333    uint8_t header[8];
334    if (mDataSource->readAt(
335                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
336        return ERROR_IO;
337    }
338
339    if (U32_AT(header) != 0) {
340        // Expected version = 0, flags = 0.
341        return ERROR_MALFORMED;
342    }
343
344    mTimeToSampleCount = U32_AT(&header[4]);
345    if ((uint64_t)mTimeToSampleCount >
346        (uint64_t)UINT32_MAX / (2 * sizeof(uint32_t))) {
347        // Choose this bound because
348        // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
349        //    time-to-sample entry in the time-to-sample table.
350        // 2) mTimeToSampleCount is the number of entries of the time-to-sample
351        //    table.
352        // 3) We hope that the table size does not exceed UINT32_MAX.
353        ALOGE("  Error: Time-to-sample table size too large.");
354        return ERROR_OUT_OF_RANGE;
355    }
356
357    // Note: At this point, we know that mTimeToSampleCount * 2 will not
358    // overflow because of the above condition.
359    if (!mDataSource->getVector(data_offset + 8, &mTimeToSample,
360                                mTimeToSampleCount * 2)) {
361        ALOGE("  Error: Incomplete data read for time-to-sample table.");
362        return ERROR_IO;
363    }
364
365    for (size_t i = 0; i < mTimeToSample.size(); ++i) {
366        mTimeToSample.editItemAt(i) = ntohl(mTimeToSample[i]);
367    }
368
369    mHasTimeToSample = true;
370    return OK;
371}
372
373status_t SampleTable::setCompositionTimeToSampleParams(
374        off64_t data_offset, size_t data_size) {
375    ALOGI("There are reordered frames present.");
376
377    if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
378        return ERROR_MALFORMED;
379    }
380
381    uint8_t header[8];
382    if (mDataSource->readAt(
383                data_offset, header, sizeof(header))
384            < (ssize_t)sizeof(header)) {
385        return ERROR_IO;
386    }
387
388    if (U32_AT(header) != 0) {
389        // Expected version = 0, flags = 0.
390        return ERROR_MALFORMED;
391    }
392
393    size_t numEntries = U32_AT(&header[4]);
394
395    if (data_size != (numEntries + 1) * 8) {
396        return ERROR_MALFORMED;
397    }
398
399    mNumCompositionTimeDeltaEntries = numEntries;
400    uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t);
401    if (allocSize > UINT32_MAX) {
402        return ERROR_OUT_OF_RANGE;
403    }
404
405    mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries];
406    if (!mCompositionTimeDeltaEntries)
407        return ERROR_OUT_OF_RANGE;
408
409    if (mDataSource->readAt(
410                data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
411            < (ssize_t)numEntries * 8) {
412        delete[] mCompositionTimeDeltaEntries;
413        mCompositionTimeDeltaEntries = NULL;
414
415        return ERROR_IO;
416    }
417
418    for (size_t i = 0; i < 2 * numEntries; ++i) {
419        mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
420    }
421
422    mCompositionDeltaLookup->setEntries(
423            mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
424
425    return OK;
426}
427
428status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
429    if (mSyncSampleOffset >= 0 || data_size < 8) {
430        return ERROR_MALFORMED;
431    }
432
433    mSyncSampleOffset = data_offset;
434
435    uint8_t header[8];
436    if (mDataSource->readAt(
437                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
438        return ERROR_IO;
439    }
440
441    if (U32_AT(header) != 0) {
442        // Expected version = 0, flags = 0.
443        return ERROR_MALFORMED;
444    }
445
446    mNumSyncSamples = U32_AT(&header[4]);
447
448    if (mNumSyncSamples < 2) {
449        ALOGV("Table of sync samples is empty or has only a single entry!");
450    }
451
452    uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t);
453    if (allocSize > SIZE_MAX) {
454        return ERROR_OUT_OF_RANGE;
455    }
456
457    mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples];
458    if (!mSyncSamples)
459        return ERROR_OUT_OF_RANGE;
460
461    size_t size = mNumSyncSamples * sizeof(uint32_t);
462    if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
463            != (ssize_t)size) {
464        return ERROR_IO;
465    }
466
467    for (size_t i = 0; i < mNumSyncSamples; ++i) {
468        mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
469    }
470
471    return OK;
472}
473
474uint32_t SampleTable::countChunkOffsets() const {
475    return mNumChunkOffsets;
476}
477
478uint32_t SampleTable::countSamples() const {
479    return mNumSampleSizes;
480}
481
482status_t SampleTable::getMaxSampleSize(size_t *max_size) {
483    Mutex::Autolock autoLock(mLock);
484
485    *max_size = 0;
486
487    for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
488        size_t sample_size;
489        status_t err = getSampleSize_l(i, &sample_size);
490
491        if (err != OK) {
492            return err;
493        }
494
495        if (sample_size > *max_size) {
496            *max_size = sample_size;
497        }
498    }
499
500    return OK;
501}
502
503uint32_t abs_difference(uint32_t time1, uint32_t time2) {
504    return time1 > time2 ? time1 - time2 : time2 - time1;
505}
506
507// static
508int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
509    const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
510    const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
511
512    if (a->mCompositionTime < b->mCompositionTime) {
513        return -1;
514    } else if (a->mCompositionTime > b->mCompositionTime) {
515        return 1;
516    }
517
518    return 0;
519}
520
521void SampleTable::buildSampleEntriesTable() {
522    Mutex::Autolock autoLock(mLock);
523
524    if (mSampleTimeEntries != NULL || mNumSampleSizes == 0) {
525        if (mNumSampleSizes == 0) {
526            ALOGE("b/23247055, mNumSampleSizes(%u)", mNumSampleSizes);
527        }
528        return;
529    }
530
531    mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
532    if (!mSampleTimeEntries)
533        return;
534
535    uint32_t sampleIndex = 0;
536    uint32_t sampleTime = 0;
537
538    for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
539        uint32_t n = mTimeToSample[2 * i];
540        uint32_t delta = mTimeToSample[2 * i + 1];
541
542        for (uint32_t j = 0; j < n; ++j) {
543            if (sampleIndex < mNumSampleSizes) {
544                // Technically this should always be the case if the file
545                // is well-formed, but you know... there's (gasp) malformed
546                // content out there.
547
548                mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
549
550                uint32_t compTimeDelta =
551                    mCompositionDeltaLookup->getCompositionTimeOffset(
552                            sampleIndex);
553
554                mSampleTimeEntries[sampleIndex].mCompositionTime =
555                    sampleTime + compTimeDelta;
556            }
557
558            ++sampleIndex;
559            sampleTime += delta;
560        }
561    }
562
563    qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
564          CompareIncreasingTime);
565}
566
567status_t SampleTable::findSampleAtTime(
568        uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
569        uint32_t *sample_index, uint32_t flags) {
570    buildSampleEntriesTable();
571
572    if (mSampleTimeEntries == NULL) {
573        return ERROR_OUT_OF_RANGE;
574    }
575
576    uint32_t left = 0;
577    uint32_t right_plus_one = mNumSampleSizes;
578    while (left < right_plus_one) {
579        uint32_t center = left + (right_plus_one - left) / 2;
580        uint64_t centerTime =
581            getSampleTime(center, scale_num, scale_den);
582
583        if (req_time < centerTime) {
584            right_plus_one = center;
585        } else if (req_time > centerTime) {
586            left = center + 1;
587        } else {
588            *sample_index = mSampleTimeEntries[center].mSampleIndex;
589            return OK;
590        }
591    }
592
593    uint32_t closestIndex = left;
594
595    if (closestIndex == mNumSampleSizes) {
596        if (flags == kFlagAfter) {
597            return ERROR_OUT_OF_RANGE;
598        }
599        flags = kFlagBefore;
600    } else if (closestIndex == 0) {
601        if (flags == kFlagBefore) {
602            // normally we should return out of range, but that is
603            // treated as end-of-stream.  instead return first sample
604            //
605            // return ERROR_OUT_OF_RANGE;
606        }
607        flags = kFlagAfter;
608    }
609
610    switch (flags) {
611        case kFlagBefore:
612        {
613            --closestIndex;
614            break;
615        }
616
617        case kFlagAfter:
618        {
619            // nothing to do
620            break;
621        }
622
623        default:
624        {
625            CHECK(flags == kFlagClosest);
626            // pick closest based on timestamp. use abs_difference for safety
627            if (abs_difference(
628                    getSampleTime(closestIndex, scale_num, scale_den), req_time) >
629                abs_difference(
630                    req_time, getSampleTime(closestIndex - 1, scale_num, scale_den))) {
631                --closestIndex;
632            }
633            break;
634        }
635    }
636
637    *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
638    return OK;
639}
640
641status_t SampleTable::findSyncSampleNear(
642        uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
643    Mutex::Autolock autoLock(mLock);
644
645    *sample_index = 0;
646
647    if (mSyncSampleOffset < 0) {
648        // All samples are sync-samples.
649        *sample_index = start_sample_index;
650        return OK;
651    }
652
653    if (mNumSyncSamples == 0) {
654        *sample_index = 0;
655        return OK;
656    }
657
658    uint32_t left = 0;
659    uint32_t right_plus_one = mNumSyncSamples;
660    while (left < right_plus_one) {
661        uint32_t center = left + (right_plus_one - left) / 2;
662        uint32_t x = mSyncSamples[center];
663
664        if (start_sample_index < x) {
665            right_plus_one = center;
666        } else if (start_sample_index > x) {
667            left = center + 1;
668        } else {
669            *sample_index = x;
670            return OK;
671        }
672    }
673
674    if (left == mNumSyncSamples) {
675        if (flags == kFlagAfter) {
676            ALOGE("tried to find a sync frame after the last one: %d", left);
677            return ERROR_OUT_OF_RANGE;
678        }
679        flags = kFlagBefore;
680    }
681    else if (left == 0) {
682        if (flags == kFlagBefore) {
683            ALOGE("tried to find a sync frame before the first one: %d", left);
684
685            // normally we should return out of range, but that is
686            // treated as end-of-stream.  instead seek to first sync
687            //
688            // return ERROR_OUT_OF_RANGE;
689        }
690        flags = kFlagAfter;
691    }
692
693    // Now ssi[left - 1] <(=) start_sample_index <= ssi[left]
694    switch (flags) {
695        case kFlagBefore:
696        {
697            --left;
698            break;
699        }
700        case kFlagAfter:
701        {
702            // nothing to do
703            break;
704        }
705        default:
706        {
707            // this route is not used, but implement it nonetheless
708            CHECK(flags == kFlagClosest);
709
710            status_t err = mSampleIterator->seekTo(start_sample_index);
711            if (err != OK) {
712                return err;
713            }
714            uint32_t sample_time = mSampleIterator->getSampleTime();
715
716            err = mSampleIterator->seekTo(mSyncSamples[left]);
717            if (err != OK) {
718                return err;
719            }
720            uint32_t upper_time = mSampleIterator->getSampleTime();
721
722            err = mSampleIterator->seekTo(mSyncSamples[left - 1]);
723            if (err != OK) {
724                return err;
725            }
726            uint32_t lower_time = mSampleIterator->getSampleTime();
727
728            // use abs_difference for safety
729            if (abs_difference(upper_time, sample_time) >
730                abs_difference(sample_time, lower_time)) {
731                --left;
732            }
733            break;
734        }
735    }
736
737    *sample_index = mSyncSamples[left];
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        uint32_t *sampleDuration) {
797    Mutex::Autolock autoLock(mLock);
798
799    status_t err;
800    if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
801        return err;
802    }
803
804    if (offset) {
805        *offset = mSampleIterator->getSampleOffset();
806    }
807
808    if (size) {
809        *size = mSampleIterator->getSampleSize();
810    }
811
812    if (compositionTime) {
813        *compositionTime = mSampleIterator->getSampleTime();
814    }
815
816    if (isSyncSample) {
817        *isSyncSample = false;
818        if (mSyncSampleOffset < 0) {
819            // Every sample is a sync sample.
820            *isSyncSample = true;
821        } else {
822            size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
823                    && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
824                ? mLastSyncSampleIndex : 0;
825
826            while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
827                ++i;
828            }
829
830            if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
831                *isSyncSample = true;
832            }
833
834            mLastSyncSampleIndex = i;
835        }
836    }
837
838    if (sampleDuration) {
839        *sampleDuration = mSampleIterator->getSampleDuration();
840    }
841
842    return OK;
843}
844
845uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
846    return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
847}
848
849}  // namespace android
850
851