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