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