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