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