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 31namespace android { 32 33SampleIterator::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 44void 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 54status_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 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 ALOGE("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 ALOGE("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 = findSampleTimeAndDuration( 137 sampleIndex, &mCurrentSampleTime, &mCurrentSampleDuration)) != OK) { 138 ALOGE("findSampleTime return error"); 139 return err; 140 } 141 142 mCurrentSampleIndex = sampleIndex; 143 144 mInitialized = true; 145 146 return OK; 147} 148 149status_t SampleIterator::findChunkRange(uint32_t sampleIndex) { 150 CHECK(sampleIndex >= mFirstChunkSampleIndex); 151 152 while (sampleIndex >= mStopChunkSampleIndex) { 153 if (mSampleToChunkIndex == mTable->mNumSampleToChunkOffsets) { 154 return ERROR_OUT_OF_RANGE; 155 } 156 157 mFirstChunkSampleIndex = mStopChunkSampleIndex; 158 159 const SampleTable::SampleToChunkEntry *entry = 160 &mTable->mSampleToChunkEntries[mSampleToChunkIndex]; 161 162 mFirstChunk = entry->startChunk; 163 mSamplesPerChunk = entry->samplesPerChunk; 164 mChunkDesc = entry->chunkDesc; 165 166 if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) { 167 mStopChunk = entry[1].startChunk; 168 169 mStopChunkSampleIndex = 170 mFirstChunkSampleIndex 171 + (mStopChunk - mFirstChunk) * mSamplesPerChunk; 172 } else { 173 mStopChunk = 0xffffffff; 174 mStopChunkSampleIndex = 0xffffffff; 175 } 176 177 ++mSampleToChunkIndex; 178 } 179 180 return OK; 181} 182 183status_t SampleIterator::getChunkOffset(uint32_t chunk, off64_t *offset) { 184 *offset = 0; 185 186 if (chunk >= mTable->mNumChunkOffsets) { 187 return ERROR_OUT_OF_RANGE; 188 } 189 190 if (mTable->mChunkOffsetType == SampleTable::kChunkOffsetType32) { 191 uint32_t offset32; 192 193 if (mTable->mDataSource->readAt( 194 mTable->mChunkOffsetOffset + 8 + 4 * chunk, 195 &offset32, 196 sizeof(offset32)) < (ssize_t)sizeof(offset32)) { 197 return ERROR_IO; 198 } 199 200 *offset = ntohl(offset32); 201 } else { 202 CHECK_EQ(mTable->mChunkOffsetType, SampleTable::kChunkOffsetType64); 203 204 uint64_t offset64; 205 if (mTable->mDataSource->readAt( 206 mTable->mChunkOffsetOffset + 8 + 8 * chunk, 207 &offset64, 208 sizeof(offset64)) < (ssize_t)sizeof(offset64)) { 209 return ERROR_IO; 210 } 211 212 *offset = ntoh64(offset64); 213 } 214 215 return OK; 216} 217 218status_t SampleIterator::getSampleSizeDirect( 219 uint32_t sampleIndex, size_t *size) { 220 *size = 0; 221 222 if (sampleIndex >= mTable->mNumSampleSizes) { 223 return ERROR_OUT_OF_RANGE; 224 } 225 226 if (mTable->mDefaultSampleSize > 0) { 227 *size = mTable->mDefaultSampleSize; 228 return OK; 229 } 230 231 switch (mTable->mSampleSizeFieldSize) { 232 case 32: 233 { 234 if (mTable->mDataSource->readAt( 235 mTable->mSampleSizeOffset + 12 + 4 * sampleIndex, 236 size, sizeof(*size)) < (ssize_t)sizeof(*size)) { 237 return ERROR_IO; 238 } 239 240 *size = ntohl(*size); 241 break; 242 } 243 244 case 16: 245 { 246 uint16_t x; 247 if (mTable->mDataSource->readAt( 248 mTable->mSampleSizeOffset + 12 + 2 * sampleIndex, 249 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 250 return ERROR_IO; 251 } 252 253 *size = ntohs(x); 254 break; 255 } 256 257 case 8: 258 { 259 uint8_t x; 260 if (mTable->mDataSource->readAt( 261 mTable->mSampleSizeOffset + 12 + sampleIndex, 262 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 263 return ERROR_IO; 264 } 265 266 *size = x; 267 break; 268 } 269 270 default: 271 { 272 CHECK_EQ(mTable->mSampleSizeFieldSize, 4); 273 274 uint8_t x; 275 if (mTable->mDataSource->readAt( 276 mTable->mSampleSizeOffset + 12 + sampleIndex / 2, 277 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 278 return ERROR_IO; 279 } 280 281 *size = (sampleIndex & 1) ? x & 0x0f : x >> 4; 282 break; 283 } 284 } 285 286 return OK; 287} 288 289status_t SampleIterator::findSampleTimeAndDuration( 290 uint32_t sampleIndex, uint32_t *time, uint32_t *duration) { 291 if (sampleIndex >= mTable->mNumSampleSizes) { 292 return ERROR_OUT_OF_RANGE; 293 } 294 295 while (sampleIndex >= mTTSSampleIndex + mTTSCount) { 296 if (mTimeToSampleIndex == mTable->mTimeToSampleCount) { 297 return ERROR_OUT_OF_RANGE; 298 } 299 300 mTTSSampleIndex += mTTSCount; 301 mTTSSampleTime += mTTSCount * mTTSDuration; 302 303 mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex]; 304 mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1]; 305 306 ++mTimeToSampleIndex; 307 } 308 309 *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex); 310 311 *time += mTable->getCompositionTimeOffset(sampleIndex); 312 313 *duration = mTTSDuration; 314 315 return OK; 316} 317 318} // namespace android 319 320