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