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/DataSource.h>
     26 #include <media/stagefright/MediaDebug.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     LOGV("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             LOGE("findChunkRange failed");
     81             return err;
     82         }
     83     }
     84 
     85     CHECK(sampleIndex < mStopChunkSampleIndex);
     86 
     87     uint32_t chunk =
     88         (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
     89         + mFirstChunk;
     90 
     91     if (!mInitialized || chunk != mCurrentChunkIndex) {
     92         mCurrentChunkIndex = chunk;
     93 
     94         status_t err;
     95         if ((err = getChunkOffset(chunk, &mCurrentChunkOffset)) != OK) {
     96             LOGE("getChunkOffset return error");
     97             return err;
     98         }
     99 
    100         mCurrentChunkSampleSizes.clear();
    101 
    102         uint32_t firstChunkSampleIndex =
    103             mFirstChunkSampleIndex
    104                 + mSamplesPerChunk * (mCurrentChunkIndex - mFirstChunk);
    105 
    106         for (uint32_t i = 0; i < mSamplesPerChunk; ++i) {
    107             size_t sampleSize;
    108             if ((err = getSampleSizeDirect(
    109                             firstChunkSampleIndex + i, &sampleSize)) != OK) {
    110                 LOGE("getSampleSizeDirect return error");
    111                 return err;
    112             }
    113 
    114             mCurrentChunkSampleSizes.push(sampleSize);
    115         }
    116     }
    117 
    118     uint32_t chunkRelativeSampleIndex =
    119         (sampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk;
    120 
    121     mCurrentSampleOffset = mCurrentChunkOffset;
    122     for (uint32_t i = 0; i < chunkRelativeSampleIndex; ++i) {
    123         mCurrentSampleOffset += mCurrentChunkSampleSizes[i];
    124     }
    125 
    126     mCurrentSampleSize = mCurrentChunkSampleSizes[chunkRelativeSampleIndex];
    127     if (sampleIndex < mTTSSampleIndex) {
    128         mTimeToSampleIndex = 0;
    129         mTTSSampleIndex = 0;
    130         mTTSSampleTime = 0;
    131         mTTSCount = 0;
    132         mTTSDuration = 0;
    133     }
    134 
    135     status_t err;
    136     if ((err = findSampleTime(sampleIndex, &mCurrentSampleTime)) != OK) {
    137         LOGE("findSampleTime return error");
    138         return err;
    139     }
    140 
    141     mCurrentSampleIndex = sampleIndex;
    142 
    143     mInitialized = true;
    144 
    145     return OK;
    146 }
    147 
    148 status_t SampleIterator::findChunkRange(uint32_t sampleIndex) {
    149     CHECK(sampleIndex >= mFirstChunkSampleIndex);
    150 
    151     while (sampleIndex >= mStopChunkSampleIndex) {
    152         if (mSampleToChunkIndex == mTable->mNumSampleToChunkOffsets) {
    153             return ERROR_OUT_OF_RANGE;
    154         }
    155 
    156         mFirstChunkSampleIndex = mStopChunkSampleIndex;
    157 
    158         const SampleTable::SampleToChunkEntry *entry =
    159             &mTable->mSampleToChunkEntries[mSampleToChunkIndex];
    160 
    161         mFirstChunk = entry->startChunk;
    162         mSamplesPerChunk = entry->samplesPerChunk;
    163         mChunkDesc = entry->chunkDesc;
    164 
    165         if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) {
    166             mStopChunk = entry[1].startChunk;
    167 
    168             mStopChunkSampleIndex =
    169                 mFirstChunkSampleIndex
    170                     + (mStopChunk - mFirstChunk) * mSamplesPerChunk;
    171         } else {
    172             mStopChunk = 0xffffffff;
    173             mStopChunkSampleIndex = 0xffffffff;
    174         }
    175 
    176         ++mSampleToChunkIndex;
    177     }
    178 
    179     return OK;
    180 }
    181 
    182 status_t SampleIterator::getChunkOffset(uint32_t chunk, off_t *offset) {
    183     *offset = 0;
    184 
    185     if (chunk >= mTable->mNumChunkOffsets) {
    186         return ERROR_OUT_OF_RANGE;
    187     }
    188 
    189     if (mTable->mChunkOffsetType == SampleTable::kChunkOffsetType32) {
    190         uint32_t offset32;
    191 
    192         if (mTable->mDataSource->readAt(
    193                     mTable->mChunkOffsetOffset + 8 + 4 * chunk,
    194                     &offset32,
    195                     sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
    196             return ERROR_IO;
    197         }
    198 
    199         *offset = ntohl(offset32);
    200     } else {
    201         CHECK_EQ(mTable->mChunkOffsetType, SampleTable::kChunkOffsetType64);
    202 
    203         uint64_t offset64;
    204         if (mTable->mDataSource->readAt(
    205                     mTable->mChunkOffsetOffset + 8 + 8 * chunk,
    206                     &offset64,
    207                     sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
    208             return ERROR_IO;
    209         }
    210 
    211         *offset = ntoh64(offset64);
    212     }
    213 
    214     return OK;
    215 }
    216 
    217 status_t SampleIterator::getSampleSizeDirect(
    218         uint32_t sampleIndex, size_t *size) {
    219     *size = 0;
    220 
    221     if (sampleIndex >= mTable->mNumSampleSizes) {
    222         return ERROR_OUT_OF_RANGE;
    223     }
    224 
    225     if (mTable->mDefaultSampleSize > 0) {
    226         *size = mTable->mDefaultSampleSize;
    227         return OK;
    228     }
    229 
    230     switch (mTable->mSampleSizeFieldSize) {
    231         case 32:
    232         {
    233             if (mTable->mDataSource->readAt(
    234                         mTable->mSampleSizeOffset + 12 + 4 * sampleIndex,
    235                         size, sizeof(*size)) < (ssize_t)sizeof(*size)) {
    236                 return ERROR_IO;
    237             }
    238 
    239             *size = ntohl(*size);
    240             break;
    241         }
    242 
    243         case 16:
    244         {
    245             uint16_t x;
    246             if (mTable->mDataSource->readAt(
    247                         mTable->mSampleSizeOffset + 12 + 2 * sampleIndex,
    248                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
    249                 return ERROR_IO;
    250             }
    251 
    252             *size = ntohs(x);
    253             break;
    254         }
    255 
    256         case 8:
    257         {
    258             uint8_t x;
    259             if (mTable->mDataSource->readAt(
    260                         mTable->mSampleSizeOffset + 12 + sampleIndex,
    261                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
    262                 return ERROR_IO;
    263             }
    264 
    265             *size = x;
    266             break;
    267         }
    268 
    269         default:
    270         {
    271             CHECK_EQ(mTable->mSampleSizeFieldSize, 4);
    272 
    273             uint8_t x;
    274             if (mTable->mDataSource->readAt(
    275                         mTable->mSampleSizeOffset + 12 + sampleIndex / 2,
    276                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
    277                 return ERROR_IO;
    278             }
    279 
    280             *size = (sampleIndex & 1) ? x & 0x0f : x >> 4;
    281             break;
    282         }
    283     }
    284 
    285     return OK;
    286 }
    287 
    288 status_t SampleIterator::findSampleTime(
    289         uint32_t sampleIndex, uint32_t *time) {
    290     if (sampleIndex >= mTable->mNumSampleSizes) {
    291         return ERROR_OUT_OF_RANGE;
    292     }
    293 
    294     while (sampleIndex >= mTTSSampleIndex + mTTSCount) {
    295         if (mTimeToSampleIndex == mTable->mTimeToSampleCount) {
    296             return ERROR_OUT_OF_RANGE;
    297         }
    298 
    299         mTTSSampleIndex += mTTSCount;
    300         mTTSSampleTime += mTTSCount * mTTSDuration;
    301 
    302         mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex];
    303         mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1];
    304 
    305         ++mTimeToSampleIndex;
    306     }
    307 
    308     *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
    309 
    310     return OK;
    311 }
    312 
    313 }  // namespace android
    314 
    315