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