Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright (C) 2010 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 "SampleIterator"
     18 //#define LOG_NDEBUG 0
     19 #include <utils/Log.h>
     20 
     21 #include "include/SampleIterator.h"
     22 
     23 #include <arpa/inet.h>
     24 
     25 #include <media/stagefright/foundation/ADebug.h>
     26 #include <media/stagefright/DataSource.h>
     27 #include <media/stagefright/Utils.h>
     28 
     29 #include "include/SampleTable.h"
     30 
     31 namespace android {
     32 
     33 SampleIterator::SampleIterator(SampleTable *table)
     34     : mTable(table),
     35       mInitialized(false),
     36       mTimeToSampleIndex(0),
     37       mTTSSampleIndex(0),
     38       mTTSSampleTime(0),
     39       mTTSCount(0),
     40       mTTSDuration(0) {
     41     reset();
     42 }
     43 
     44 void SampleIterator::reset() {
     45     mSampleToChunkIndex = 0;
     46     mFirstChunk = 0;
     47     mFirstChunkSampleIndex = 0;
     48     mStopChunk = 0;
     49     mStopChunkSampleIndex = 0;
     50     mSamplesPerChunk = 0;
     51     mChunkDesc = 0;
     52 }
     53 
     54 status_t SampleIterator::seekTo(uint32_t sampleIndex) {
     55     ALOGV("seekTo(%d)", sampleIndex);
     56 
     57     if (sampleIndex >= mTable->mNumSampleSizes) {
     58         return ERROR_END_OF_STREAM;
     59     }
     60 
     61     if (mTable->mSampleToChunkOffset < 0
     62             || mTable->mChunkOffsetOffset < 0
     63             || mTable->mSampleSizeOffset < 0
     64             || mTable->mTimeToSampleCount == 0) {
     65 
     66         return ERROR_MALFORMED;
     67     }
     68 
     69     if (mInitialized && mCurrentSampleIndex == sampleIndex) {
     70         return OK;
     71     }
     72 
     73     if (!mInitialized || sampleIndex < mFirstChunkSampleIndex) {
     74         reset();
     75     }
     76 
     77     if (sampleIndex >= mStopChunkSampleIndex) {
     78         status_t err;
     79         if ((err = findChunkRange(sampleIndex)) != OK) {
     80             ALOGE("findChunkRange failed");
     81             return err;
     82         }
     83     }
     84 
     85     CHECK(sampleIndex < mStopChunkSampleIndex);
     86 
     87     if (mSamplesPerChunk == 0) {
     88         ALOGE("b/22802344");
     89         return ERROR_MALFORMED;
     90     }
     91 
     92     uint32_t chunk =
     93         (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
     94         + mFirstChunk;
     95 
     96     if (!mInitialized || chunk != mCurrentChunkIndex) {
     97         status_t err;
     98         if ((err = getChunkOffset(chunk, &mCurrentChunkOffset)) != OK) {
     99             ALOGE("getChunkOffset return error");
    100             return err;
    101         }
    102 
    103         mCurrentChunkSampleSizes.clear();
    104 
    105         uint32_t firstChunkSampleIndex =
    106             mFirstChunkSampleIndex
    107                 + mSamplesPerChunk * (chunk - mFirstChunk);
    108 
    109         for (uint32_t i = 0; i < mSamplesPerChunk; ++i) {
    110             size_t sampleSize;
    111             if ((err = getSampleSizeDirect(
    112                             firstChunkSampleIndex + i, &sampleSize)) != OK) {
    113                 ALOGE("getSampleSizeDirect return error");
    114                 mCurrentChunkSampleSizes.clear();
    115                 return err;
    116             }
    117 
    118             mCurrentChunkSampleSizes.push(sampleSize);
    119         }
    120 
    121         mCurrentChunkIndex = chunk;
    122     }
    123 
    124     uint32_t chunkRelativeSampleIndex =
    125         (sampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk;
    126 
    127     mCurrentSampleOffset = mCurrentChunkOffset;
    128     for (uint32_t i = 0; i < chunkRelativeSampleIndex; ++i) {
    129         mCurrentSampleOffset += mCurrentChunkSampleSizes[i];
    130     }
    131 
    132     mCurrentSampleSize = mCurrentChunkSampleSizes[chunkRelativeSampleIndex];
    133     if (sampleIndex < mTTSSampleIndex) {
    134         mTimeToSampleIndex = 0;
    135         mTTSSampleIndex = 0;
    136         mTTSSampleTime = 0;
    137         mTTSCount = 0;
    138         mTTSDuration = 0;
    139     }
    140 
    141     status_t err;
    142     if ((err = findSampleTimeAndDuration(
    143             sampleIndex, &mCurrentSampleTime, &mCurrentSampleDuration)) != OK) {
    144         ALOGE("findSampleTime return error");
    145         return err;
    146     }
    147 
    148     mCurrentSampleIndex = sampleIndex;
    149 
    150     mInitialized = true;
    151 
    152     return OK;
    153 }
    154 
    155 status_t SampleIterator::findChunkRange(uint32_t sampleIndex) {
    156     CHECK(sampleIndex >= mFirstChunkSampleIndex);
    157 
    158     while (sampleIndex >= mStopChunkSampleIndex) {
    159         if (mSampleToChunkIndex == mTable->mNumSampleToChunkOffsets) {
    160             return ERROR_OUT_OF_RANGE;
    161         }
    162 
    163         mFirstChunkSampleIndex = mStopChunkSampleIndex;
    164 
    165         const SampleTable::SampleToChunkEntry *entry =
    166             &mTable->mSampleToChunkEntries[mSampleToChunkIndex];
    167 
    168         mFirstChunk = entry->startChunk;
    169         mSamplesPerChunk = entry->samplesPerChunk;
    170         mChunkDesc = entry->chunkDesc;
    171 
    172         if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) {
    173             mStopChunk = entry[1].startChunk;
    174 
    175             if (mStopChunk < mFirstChunk ||
    176                 (mStopChunk - mFirstChunk) > UINT32_MAX / mSamplesPerChunk ||
    177                 ((mStopChunk - mFirstChunk) * mSamplesPerChunk >
    178                  UINT32_MAX - mFirstChunkSampleIndex)) {
    179 
    180                 return ERROR_OUT_OF_RANGE;
    181             }
    182             mStopChunkSampleIndex =
    183                 mFirstChunkSampleIndex
    184                     + (mStopChunk - mFirstChunk) * mSamplesPerChunk;
    185         } else {
    186             mStopChunk = 0xffffffff;
    187             mStopChunkSampleIndex = 0xffffffff;
    188         }
    189 
    190         ++mSampleToChunkIndex;
    191     }
    192 
    193     return OK;
    194 }
    195 
    196 status_t SampleIterator::getChunkOffset(uint32_t chunk, off64_t *offset) {
    197     *offset = 0;
    198 
    199     if (chunk >= mTable->mNumChunkOffsets) {
    200         return ERROR_OUT_OF_RANGE;
    201     }
    202 
    203     if (mTable->mChunkOffsetType == SampleTable::kChunkOffsetType32) {
    204         uint32_t offset32;
    205 
    206         if (mTable->mDataSource->readAt(
    207                     mTable->mChunkOffsetOffset + 8 + 4 * chunk,
    208                     &offset32,
    209                     sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
    210             return ERROR_IO;
    211         }
    212 
    213         *offset = ntohl(offset32);
    214     } else {
    215         CHECK_EQ(mTable->mChunkOffsetType, SampleTable::kChunkOffsetType64);
    216 
    217         uint64_t offset64;
    218         if (mTable->mDataSource->readAt(
    219                     mTable->mChunkOffsetOffset + 8 + 8 * chunk,
    220                     &offset64,
    221                     sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
    222             return ERROR_IO;
    223         }
    224 
    225         *offset = ntoh64(offset64);
    226     }
    227 
    228     return OK;
    229 }
    230 
    231 status_t SampleIterator::getSampleSizeDirect(
    232         uint32_t sampleIndex, size_t *size) {
    233     *size = 0;
    234 
    235     if (sampleIndex >= mTable->mNumSampleSizes) {
    236         return ERROR_OUT_OF_RANGE;
    237     }
    238 
    239     if (mTable->mDefaultSampleSize > 0) {
    240         *size = mTable->mDefaultSampleSize;
    241         return OK;
    242     }
    243 
    244     switch (mTable->mSampleSizeFieldSize) {
    245         case 32:
    246         {
    247             if (mTable->mDataSource->readAt(
    248                         mTable->mSampleSizeOffset + 12 + 4 * sampleIndex,
    249                         size, sizeof(*size)) < (ssize_t)sizeof(*size)) {
    250                 return ERROR_IO;
    251             }
    252 
    253             *size = ntohl(*size);
    254             break;
    255         }
    256 
    257         case 16:
    258         {
    259             uint16_t x;
    260             if (mTable->mDataSource->readAt(
    261                         mTable->mSampleSizeOffset + 12 + 2 * sampleIndex,
    262                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
    263                 return ERROR_IO;
    264             }
    265 
    266             *size = ntohs(x);
    267             break;
    268         }
    269 
    270         case 8:
    271         {
    272             uint8_t x;
    273             if (mTable->mDataSource->readAt(
    274                         mTable->mSampleSizeOffset + 12 + sampleIndex,
    275                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
    276                 return ERROR_IO;
    277             }
    278 
    279             *size = x;
    280             break;
    281         }
    282 
    283         default:
    284         {
    285             CHECK_EQ(mTable->mSampleSizeFieldSize, 4u);
    286 
    287             uint8_t x;
    288             if (mTable->mDataSource->readAt(
    289                         mTable->mSampleSizeOffset + 12 + sampleIndex / 2,
    290                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
    291                 return ERROR_IO;
    292             }
    293 
    294             *size = (sampleIndex & 1) ? x & 0x0f : x >> 4;
    295             break;
    296         }
    297     }
    298 
    299     return OK;
    300 }
    301 
    302 status_t SampleIterator::findSampleTimeAndDuration(
    303         uint32_t sampleIndex, uint32_t *time, uint32_t *duration) {
    304     if (sampleIndex >= mTable->mNumSampleSizes) {
    305         return ERROR_OUT_OF_RANGE;
    306     }
    307 
    308     while (true) {
    309         if (mTTSSampleIndex > UINT32_MAX - mTTSCount) {
    310             return ERROR_OUT_OF_RANGE;
    311         }
    312         if(sampleIndex < mTTSSampleIndex + mTTSCount) {
    313             break;
    314         }
    315         if (mTimeToSampleIndex == mTable->mTimeToSampleCount ||
    316             (mTTSDuration != 0 && mTTSCount > UINT32_MAX / mTTSDuration) ||
    317             mTTSSampleTime > UINT32_MAX - (mTTSCount * mTTSDuration)) {
    318             return ERROR_OUT_OF_RANGE;
    319         }
    320 
    321         mTTSSampleIndex += mTTSCount;
    322         mTTSSampleTime += mTTSCount * mTTSDuration;
    323 
    324         mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex];
    325         mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1];
    326 
    327         ++mTimeToSampleIndex;
    328     }
    329 
    330     *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
    331 
    332     int32_t offset = mTable->getCompositionTimeOffset(sampleIndex);
    333     if ((offset < 0 && *time < (offset == INT32_MIN ?
    334             INT32_MAX : uint32_t(-offset))) ||
    335             (offset > 0 && *time > UINT32_MAX - offset)) {
    336         ALOGE("%u + %d would overflow", *time, offset);
    337         return ERROR_OUT_OF_RANGE;
    338     }
    339     if (offset > 0) {
    340         *time += offset;
    341     } else {
    342         *time -= (offset == INT32_MIN ? INT32_MAX : (-offset));
    343     }
    344 
    345     *duration = mTTSDuration;
    346 
    347     return OK;
    348 }
    349 
    350 }  // namespace android
    351 
    352