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