Home | History | Annotate | Download | only in libstagefright
      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 namespace android {
     31 
     32 // static
     33 const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
     34 // static
     35 const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
     36 // static
     37 const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
     38 // static
     39 const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
     40 
     41 ////////////////////////////////////////////////////////////////////////////////
     42 
     43 struct SampleTable::CompositionDeltaLookup {
     44     CompositionDeltaLookup();
     45 
     46     void setEntries(
     47             const uint32_t *deltaEntries, size_t numDeltaEntries);
     48 
     49     uint32_t getCompositionTimeOffset(uint32_t sampleIndex);
     50 
     51 private:
     52     Mutex mLock;
     53 
     54     const uint32_t *mDeltaEntries;
     55     size_t mNumDeltaEntries;
     56 
     57     size_t mCurrentDeltaEntry;
     58     size_t mCurrentEntrySampleIndex;
     59 
     60     DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup);
     61 };
     62 
     63 SampleTable::CompositionDeltaLookup::CompositionDeltaLookup()
     64     : mDeltaEntries(NULL),
     65       mNumDeltaEntries(0),
     66       mCurrentDeltaEntry(0),
     67       mCurrentEntrySampleIndex(0) {
     68 }
     69 
     70 void SampleTable::CompositionDeltaLookup::setEntries(
     71         const uint32_t *deltaEntries, size_t numDeltaEntries) {
     72     Mutex::Autolock autolock(mLock);
     73 
     74     mDeltaEntries = deltaEntries;
     75     mNumDeltaEntries = numDeltaEntries;
     76     mCurrentDeltaEntry = 0;
     77     mCurrentEntrySampleIndex = 0;
     78 }
     79 
     80 uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset(
     81         uint32_t sampleIndex) {
     82     Mutex::Autolock autolock(mLock);
     83 
     84     if (mDeltaEntries == NULL) {
     85         return 0;
     86     }
     87 
     88     if (sampleIndex < mCurrentEntrySampleIndex) {
     89         mCurrentDeltaEntry = 0;
     90         mCurrentEntrySampleIndex = 0;
     91     }
     92 
     93     while (mCurrentDeltaEntry < mNumDeltaEntries) {
     94         uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry];
     95         if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) {
     96             return mDeltaEntries[2 * mCurrentDeltaEntry + 1];
     97         }
     98 
     99         mCurrentEntrySampleIndex += sampleCount;
    100         ++mCurrentDeltaEntry;
    101     }
    102 
    103     return 0;
    104 }
    105 
    106 ////////////////////////////////////////////////////////////////////////////////
    107 
    108 SampleTable::SampleTable(const sp<DataSource> &source)
    109     : mDataSource(source),
    110       mChunkOffsetOffset(-1),
    111       mChunkOffsetType(0),
    112       mNumChunkOffsets(0),
    113       mSampleToChunkOffset(-1),
    114       mNumSampleToChunkOffsets(0),
    115       mSampleSizeOffset(-1),
    116       mSampleSizeFieldSize(0),
    117       mDefaultSampleSize(0),
    118       mNumSampleSizes(0),
    119       mTimeToSampleCount(0),
    120       mTimeToSample(NULL),
    121       mSampleTimeEntries(NULL),
    122       mCompositionTimeDeltaEntries(NULL),
    123       mNumCompositionTimeDeltaEntries(0),
    124       mCompositionDeltaLookup(new CompositionDeltaLookup),
    125       mSyncSampleOffset(-1),
    126       mNumSyncSamples(0),
    127       mSyncSamples(NULL),
    128       mLastSyncSampleIndex(0),
    129       mSampleToChunkEntries(NULL) {
    130     mSampleIterator = new SampleIterator(this);
    131 }
    132 
    133 SampleTable::~SampleTable() {
    134     delete[] mSampleToChunkEntries;
    135     mSampleToChunkEntries = NULL;
    136 
    137     delete[] mSyncSamples;
    138     mSyncSamples = NULL;
    139 
    140     delete mCompositionDeltaLookup;
    141     mCompositionDeltaLookup = NULL;
    142 
    143     delete[] mCompositionTimeDeltaEntries;
    144     mCompositionTimeDeltaEntries = NULL;
    145 
    146     delete[] mSampleTimeEntries;
    147     mSampleTimeEntries = NULL;
    148 
    149     delete[] mTimeToSample;
    150     mTimeToSample = NULL;
    151 
    152     delete mSampleIterator;
    153     mSampleIterator = NULL;
    154 }
    155 
    156 bool SampleTable::isValid() const {
    157     return mChunkOffsetOffset >= 0
    158         && mSampleToChunkOffset >= 0
    159         && mSampleSizeOffset >= 0
    160         && mTimeToSample != NULL;
    161 }
    162 
    163 status_t SampleTable::setChunkOffsetParams(
    164         uint32_t type, off64_t data_offset, size_t data_size) {
    165     if (mChunkOffsetOffset >= 0) {
    166         return ERROR_MALFORMED;
    167     }
    168 
    169     CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
    170 
    171     mChunkOffsetOffset = data_offset;
    172     mChunkOffsetType = type;
    173 
    174     if (data_size < 8) {
    175         return ERROR_MALFORMED;
    176     }
    177 
    178     uint8_t header[8];
    179     if (mDataSource->readAt(
    180                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
    181         return ERROR_IO;
    182     }
    183 
    184     if (U32_AT(header) != 0) {
    185         // Expected version = 0, flags = 0.
    186         return ERROR_MALFORMED;
    187     }
    188 
    189     mNumChunkOffsets = U32_AT(&header[4]);
    190 
    191     if (mChunkOffsetType == kChunkOffsetType32) {
    192         if (data_size < 8 + mNumChunkOffsets * 4) {
    193             return ERROR_MALFORMED;
    194         }
    195     } else {
    196         if (data_size < 8 + mNumChunkOffsets * 8) {
    197             return ERROR_MALFORMED;
    198         }
    199     }
    200 
    201     return OK;
    202 }
    203 
    204 status_t SampleTable::setSampleToChunkParams(
    205         off64_t data_offset, size_t data_size) {
    206     if (mSampleToChunkOffset >= 0) {
    207         return ERROR_MALFORMED;
    208     }
    209 
    210     mSampleToChunkOffset = data_offset;
    211 
    212     if (data_size < 8) {
    213         return ERROR_MALFORMED;
    214     }
    215 
    216     uint8_t header[8];
    217     if (mDataSource->readAt(
    218                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
    219         return ERROR_IO;
    220     }
    221 
    222     if (U32_AT(header) != 0) {
    223         // Expected version = 0, flags = 0.
    224         return ERROR_MALFORMED;
    225     }
    226 
    227     mNumSampleToChunkOffsets = U32_AT(&header[4]);
    228 
    229     if (data_size < 8 + mNumSampleToChunkOffsets * 12) {
    230         return ERROR_MALFORMED;
    231     }
    232 
    233     mSampleToChunkEntries =
    234         new SampleToChunkEntry[mNumSampleToChunkOffsets];
    235 
    236     for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
    237         uint8_t buffer[12];
    238         if (mDataSource->readAt(
    239                     mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
    240                 != (ssize_t)sizeof(buffer)) {
    241             return ERROR_IO;
    242         }
    243 
    244         CHECK(U32_AT(buffer) >= 1);  // chunk index is 1 based in the spec.
    245 
    246         // We want the chunk index to be 0-based.
    247         mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
    248         mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
    249         mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
    250     }
    251 
    252     return OK;
    253 }
    254 
    255 status_t SampleTable::setSampleSizeParams(
    256         uint32_t type, off64_t data_offset, size_t data_size) {
    257     if (mSampleSizeOffset >= 0) {
    258         return ERROR_MALFORMED;
    259     }
    260 
    261     CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
    262 
    263     mSampleSizeOffset = data_offset;
    264 
    265     if (data_size < 12) {
    266         return ERROR_MALFORMED;
    267     }
    268 
    269     uint8_t header[12];
    270     if (mDataSource->readAt(
    271                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
    272         return ERROR_IO;
    273     }
    274 
    275     if (U32_AT(header) != 0) {
    276         // Expected version = 0, flags = 0.
    277         return ERROR_MALFORMED;
    278     }
    279 
    280     mDefaultSampleSize = U32_AT(&header[4]);
    281     mNumSampleSizes = U32_AT(&header[8]);
    282 
    283     if (type == kSampleSizeType32) {
    284         mSampleSizeFieldSize = 32;
    285 
    286         if (mDefaultSampleSize != 0) {
    287             return OK;
    288         }
    289 
    290         if (data_size < 12 + mNumSampleSizes * 4) {
    291             return ERROR_MALFORMED;
    292         }
    293     } else {
    294         if ((mDefaultSampleSize & 0xffffff00) != 0) {
    295             // The high 24 bits are reserved and must be 0.
    296             return ERROR_MALFORMED;
    297         }
    298 
    299         mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
    300         mDefaultSampleSize = 0;
    301 
    302         if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
    303             && mSampleSizeFieldSize != 16) {
    304             return ERROR_MALFORMED;
    305         }
    306 
    307         if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
    308             return ERROR_MALFORMED;
    309         }
    310     }
    311 
    312     return OK;
    313 }
    314 
    315 status_t SampleTable::setTimeToSampleParams(
    316         off64_t data_offset, size_t data_size) {
    317     if (mTimeToSample != NULL || data_size < 8) {
    318         return ERROR_MALFORMED;
    319     }
    320 
    321     uint8_t header[8];
    322     if (mDataSource->readAt(
    323                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
    324         return ERROR_IO;
    325     }
    326 
    327     if (U32_AT(header) != 0) {
    328         // Expected version = 0, flags = 0.
    329         return ERROR_MALFORMED;
    330     }
    331 
    332     mTimeToSampleCount = U32_AT(&header[4]);
    333     mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
    334 
    335     size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
    336     if (mDataSource->readAt(
    337                 data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
    338         return ERROR_IO;
    339     }
    340 
    341     for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
    342         mTimeToSample[i] = ntohl(mTimeToSample[i]);
    343     }
    344 
    345     return OK;
    346 }
    347 
    348 status_t SampleTable::setCompositionTimeToSampleParams(
    349         off64_t data_offset, size_t data_size) {
    350     ALOGI("There are reordered frames present.");
    351 
    352     if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
    353         return ERROR_MALFORMED;
    354     }
    355 
    356     uint8_t header[8];
    357     if (mDataSource->readAt(
    358                 data_offset, header, sizeof(header))
    359             < (ssize_t)sizeof(header)) {
    360         return ERROR_IO;
    361     }
    362 
    363     if (U32_AT(header) != 0) {
    364         // Expected version = 0, flags = 0.
    365         return ERROR_MALFORMED;
    366     }
    367 
    368     size_t numEntries = U32_AT(&header[4]);
    369 
    370     if (data_size != (numEntries + 1) * 8) {
    371         return ERROR_MALFORMED;
    372     }
    373 
    374     mNumCompositionTimeDeltaEntries = numEntries;
    375     mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries];
    376 
    377     if (mDataSource->readAt(
    378                 data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
    379             < (ssize_t)numEntries * 8) {
    380         delete[] mCompositionTimeDeltaEntries;
    381         mCompositionTimeDeltaEntries = NULL;
    382 
    383         return ERROR_IO;
    384     }
    385 
    386     for (size_t i = 0; i < 2 * numEntries; ++i) {
    387         mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
    388     }
    389 
    390     mCompositionDeltaLookup->setEntries(
    391             mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
    392 
    393     return OK;
    394 }
    395 
    396 status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
    397     if (mSyncSampleOffset >= 0 || data_size < 8) {
    398         return ERROR_MALFORMED;
    399     }
    400 
    401     mSyncSampleOffset = data_offset;
    402 
    403     uint8_t header[8];
    404     if (mDataSource->readAt(
    405                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
    406         return ERROR_IO;
    407     }
    408 
    409     if (U32_AT(header) != 0) {
    410         // Expected version = 0, flags = 0.
    411         return ERROR_MALFORMED;
    412     }
    413 
    414     mNumSyncSamples = U32_AT(&header[4]);
    415 
    416     if (mNumSyncSamples < 2) {
    417         ALOGV("Table of sync samples is empty or has only a single entry!");
    418     }
    419 
    420     mSyncSamples = new uint32_t[mNumSyncSamples];
    421     size_t size = mNumSyncSamples * sizeof(uint32_t);
    422     if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
    423             != (ssize_t)size) {
    424         return ERROR_IO;
    425     }
    426 
    427     for (size_t i = 0; i < mNumSyncSamples; ++i) {
    428         mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
    429     }
    430 
    431     return OK;
    432 }
    433 
    434 uint32_t SampleTable::countChunkOffsets() const {
    435     return mNumChunkOffsets;
    436 }
    437 
    438 uint32_t SampleTable::countSamples() const {
    439     return mNumSampleSizes;
    440 }
    441 
    442 status_t SampleTable::getMaxSampleSize(size_t *max_size) {
    443     Mutex::Autolock autoLock(mLock);
    444 
    445     *max_size = 0;
    446 
    447     for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
    448         size_t sample_size;
    449         status_t err = getSampleSize_l(i, &sample_size);
    450 
    451         if (err != OK) {
    452             return err;
    453         }
    454 
    455         if (sample_size > *max_size) {
    456             *max_size = sample_size;
    457         }
    458     }
    459 
    460     return OK;
    461 }
    462 
    463 uint32_t abs_difference(uint32_t time1, uint32_t time2) {
    464     return time1 > time2 ? time1 - time2 : time2 - time1;
    465 }
    466 
    467 // static
    468 int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
    469     const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
    470     const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
    471 
    472     if (a->mCompositionTime < b->mCompositionTime) {
    473         return -1;
    474     } else if (a->mCompositionTime > b->mCompositionTime) {
    475         return 1;
    476     }
    477 
    478     return 0;
    479 }
    480 
    481 void SampleTable::buildSampleEntriesTable() {
    482     Mutex::Autolock autoLock(mLock);
    483 
    484     if (mSampleTimeEntries != NULL) {
    485         return;
    486     }
    487 
    488     mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
    489 
    490     uint32_t sampleIndex = 0;
    491     uint32_t sampleTime = 0;
    492 
    493     for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
    494         uint32_t n = mTimeToSample[2 * i];
    495         uint32_t delta = mTimeToSample[2 * i + 1];
    496 
    497         for (uint32_t j = 0; j < n; ++j) {
    498             if (sampleIndex < mNumSampleSizes) {
    499                 // Technically this should always be the case if the file
    500                 // is well-formed, but you know... there's (gasp) malformed
    501                 // content out there.
    502 
    503                 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
    504 
    505                 uint32_t compTimeDelta =
    506                     mCompositionDeltaLookup->getCompositionTimeOffset(
    507                             sampleIndex);
    508 
    509                 mSampleTimeEntries[sampleIndex].mCompositionTime =
    510                     sampleTime + compTimeDelta;
    511             }
    512 
    513             ++sampleIndex;
    514             sampleTime += delta;
    515         }
    516     }
    517 
    518     qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
    519           CompareIncreasingTime);
    520 }
    521 
    522 status_t SampleTable::findSampleAtTime(
    523         uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
    524     buildSampleEntriesTable();
    525 
    526     uint32_t left = 0;
    527     uint32_t right = mNumSampleSizes;
    528     while (left < right) {
    529         uint32_t center = (left + right) / 2;
    530         uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
    531 
    532         if (req_time < centerTime) {
    533             right = center;
    534         } else if (req_time > centerTime) {
    535             left = center + 1;
    536         } else {
    537             left = center;
    538             break;
    539         }
    540     }
    541 
    542     if (left == mNumSampleSizes) {
    543         if (flags == kFlagAfter) {
    544             return ERROR_OUT_OF_RANGE;
    545         }
    546 
    547         --left;
    548     }
    549 
    550     uint32_t closestIndex = left;
    551 
    552     switch (flags) {
    553         case kFlagBefore:
    554         {
    555             while (closestIndex > 0
    556                     && mSampleTimeEntries[closestIndex].mCompositionTime
    557                             > req_time) {
    558                 --closestIndex;
    559             }
    560             break;
    561         }
    562 
    563         case kFlagAfter:
    564         {
    565             while (closestIndex + 1 < mNumSampleSizes
    566                     && mSampleTimeEntries[closestIndex].mCompositionTime
    567                             < req_time) {
    568                 ++closestIndex;
    569             }
    570             break;
    571         }
    572 
    573         default:
    574         {
    575             CHECK(flags == kFlagClosest);
    576 
    577             if (closestIndex > 0) {
    578                 // Check left neighbour and pick closest.
    579                 uint32_t absdiff1 =
    580                     abs_difference(
    581                             mSampleTimeEntries[closestIndex].mCompositionTime,
    582                             req_time);
    583 
    584                 uint32_t absdiff2 =
    585                     abs_difference(
    586                             mSampleTimeEntries[closestIndex - 1].mCompositionTime,
    587                             req_time);
    588 
    589                 if (absdiff1 > absdiff2) {
    590                     closestIndex = closestIndex - 1;
    591                 }
    592             }
    593 
    594             break;
    595         }
    596     }
    597 
    598     *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
    599 
    600     return OK;
    601 }
    602 
    603 status_t SampleTable::findSyncSampleNear(
    604         uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
    605     Mutex::Autolock autoLock(mLock);
    606 
    607     *sample_index = 0;
    608 
    609     if (mSyncSampleOffset < 0) {
    610         // All samples are sync-samples.
    611         *sample_index = start_sample_index;
    612         return OK;
    613     }
    614 
    615     if (mNumSyncSamples == 0) {
    616         *sample_index = 0;
    617         return OK;
    618     }
    619 
    620     uint32_t left = 0;
    621     uint32_t right = mNumSyncSamples;
    622     while (left < right) {
    623         uint32_t center = left + (right - left) / 2;
    624         uint32_t x = mSyncSamples[center];
    625 
    626         if (start_sample_index < x) {
    627             right = center;
    628         } else if (start_sample_index > x) {
    629             left = center + 1;
    630         } else {
    631             left = center;
    632             break;
    633         }
    634     }
    635     if (left == mNumSyncSamples) {
    636         if (flags == kFlagAfter) {
    637             ALOGE("tried to find a sync frame after the last one: %d", left);
    638             return ERROR_OUT_OF_RANGE;
    639         }
    640         left = left - 1;
    641     }
    642 
    643     // Now ssi[left] is the sync sample index just before (or at)
    644     // start_sample_index.
    645     // Also start_sample_index < ssi[left + 1], if left + 1 < mNumSyncSamples.
    646 
    647     uint32_t x = mSyncSamples[left];
    648 
    649     if (left + 1 < mNumSyncSamples) {
    650         uint32_t y = mSyncSamples[left + 1];
    651 
    652         // our sample lies between sync samples x and y.
    653 
    654         status_t err = mSampleIterator->seekTo(start_sample_index);
    655         if (err != OK) {
    656             return err;
    657         }
    658 
    659         uint32_t sample_time = mSampleIterator->getSampleTime();
    660 
    661         err = mSampleIterator->seekTo(x);
    662         if (err != OK) {
    663             return err;
    664         }
    665         uint32_t x_time = mSampleIterator->getSampleTime();
    666 
    667         err = mSampleIterator->seekTo(y);
    668         if (err != OK) {
    669             return err;
    670         }
    671 
    672         uint32_t y_time = mSampleIterator->getSampleTime();
    673 
    674         if (abs_difference(x_time, sample_time)
    675                 > abs_difference(y_time, sample_time)) {
    676             // Pick the sync sample closest (timewise) to the start-sample.
    677             x = y;
    678             ++left;
    679         }
    680     }
    681 
    682     switch (flags) {
    683         case kFlagBefore:
    684         {
    685             if (x > start_sample_index) {
    686                 CHECK(left > 0);
    687 
    688                 x = mSyncSamples[left - 1];
    689 
    690                 if (x > start_sample_index) {
    691                     // The table of sync sample indices was not sorted
    692                     // properly.
    693                     return ERROR_MALFORMED;
    694                 }
    695             }
    696             break;
    697         }
    698 
    699         case kFlagAfter:
    700         {
    701             if (x < start_sample_index) {
    702                 if (left + 1 >= mNumSyncSamples) {
    703                     return ERROR_OUT_OF_RANGE;
    704                 }
    705 
    706                 x = mSyncSamples[left + 1];
    707 
    708                 if (x < start_sample_index) {
    709                     // The table of sync sample indices was not sorted
    710                     // properly.
    711                     return ERROR_MALFORMED;
    712                 }
    713             }
    714 
    715             break;
    716         }
    717 
    718         default:
    719             break;
    720     }
    721 
    722     *sample_index = x;
    723 
    724     return OK;
    725 }
    726 
    727 status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
    728     Mutex::Autolock autoLock(mLock);
    729 
    730     if (mSyncSampleOffset < 0) {
    731         // All samples are sync-samples.
    732         *sample_index = 0;
    733         return OK;
    734     }
    735 
    736     uint32_t bestSampleIndex = 0;
    737     size_t maxSampleSize = 0;
    738 
    739     static const size_t kMaxNumSyncSamplesToScan = 20;
    740 
    741     // Consider the first kMaxNumSyncSamplesToScan sync samples and
    742     // pick the one with the largest (compressed) size as the thumbnail.
    743 
    744     size_t numSamplesToScan = mNumSyncSamples;
    745     if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
    746         numSamplesToScan = kMaxNumSyncSamplesToScan;
    747     }
    748 
    749     for (size_t i = 0; i < numSamplesToScan; ++i) {
    750         uint32_t x = mSyncSamples[i];
    751 
    752         // Now x is a sample index.
    753         size_t sampleSize;
    754         status_t err = getSampleSize_l(x, &sampleSize);
    755         if (err != OK) {
    756             return err;
    757         }
    758 
    759         if (i == 0 || sampleSize > maxSampleSize) {
    760             bestSampleIndex = x;
    761             maxSampleSize = sampleSize;
    762         }
    763     }
    764 
    765     *sample_index = bestSampleIndex;
    766 
    767     return OK;
    768 }
    769 
    770 status_t SampleTable::getSampleSize_l(
    771         uint32_t sampleIndex, size_t *sampleSize) {
    772     return mSampleIterator->getSampleSizeDirect(
    773             sampleIndex, sampleSize);
    774 }
    775 
    776 status_t SampleTable::getMetaDataForSample(
    777         uint32_t sampleIndex,
    778         off64_t *offset,
    779         size_t *size,
    780         uint32_t *compositionTime,
    781         bool *isSyncSample) {
    782     Mutex::Autolock autoLock(mLock);
    783 
    784     status_t err;
    785     if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
    786         return err;
    787     }
    788 
    789     if (offset) {
    790         *offset = mSampleIterator->getSampleOffset();
    791     }
    792 
    793     if (size) {
    794         *size = mSampleIterator->getSampleSize();
    795     }
    796 
    797     if (compositionTime) {
    798         *compositionTime = mSampleIterator->getSampleTime();
    799     }
    800 
    801     if (isSyncSample) {
    802         *isSyncSample = false;
    803         if (mSyncSampleOffset < 0) {
    804             // Every sample is a sync sample.
    805             *isSyncSample = true;
    806         } else {
    807             size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
    808                     && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
    809                 ? mLastSyncSampleIndex : 0;
    810 
    811             while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
    812                 ++i;
    813             }
    814 
    815             if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
    816                 *isSyncSample = true;
    817             }
    818 
    819             mLastSyncSampleIndex = i;
    820         }
    821     }
    822 
    823     return OK;
    824 }
    825 
    826 uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
    827     return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
    828 }
    829 
    830 }  // namespace android
    831 
    832