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