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