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 "SampleIterator.h" 22 23#include <arpa/inet.h> 24 25#include <media/DataSourceBase.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/ByteUtils.h> 28 29#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 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 155status_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 (mSamplesPerChunk == 0 || 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 196status_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 231status_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 uint32_t x; 248 if (mTable->mDataSource->readAt( 249 mTable->mSampleSizeOffset + 12 + 4 * sampleIndex, 250 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 251 return ERROR_IO; 252 } 253 254 *size = ntohl(x); 255 break; 256 } 257 258 case 16: 259 { 260 uint16_t x; 261 if (mTable->mDataSource->readAt( 262 mTable->mSampleSizeOffset + 12 + 2 * sampleIndex, 263 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 264 return ERROR_IO; 265 } 266 267 *size = ntohs(x); 268 break; 269 } 270 271 case 8: 272 { 273 uint8_t x; 274 if (mTable->mDataSource->readAt( 275 mTable->mSampleSizeOffset + 12 + sampleIndex, 276 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 277 return ERROR_IO; 278 } 279 280 *size = x; 281 break; 282 } 283 284 default: 285 { 286 CHECK_EQ(mTable->mSampleSizeFieldSize, 4u); 287 288 uint8_t x; 289 if (mTable->mDataSource->readAt( 290 mTable->mSampleSizeOffset + 12 + sampleIndex / 2, 291 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 292 return ERROR_IO; 293 } 294 295 *size = (sampleIndex & 1) ? x & 0x0f : x >> 4; 296 break; 297 } 298 } 299 300 return OK; 301} 302 303status_t SampleIterator::findSampleTimeAndDuration( 304 uint32_t sampleIndex, uint32_t *time, uint32_t *duration) { 305 if (sampleIndex >= mTable->mNumSampleSizes) { 306 return ERROR_OUT_OF_RANGE; 307 } 308 309 while (true) { 310 if (mTTSSampleIndex > UINT32_MAX - mTTSCount) { 311 return ERROR_OUT_OF_RANGE; 312 } 313 if(sampleIndex < mTTSSampleIndex + mTTSCount) { 314 break; 315 } 316 if (mTimeToSampleIndex == mTable->mTimeToSampleCount || 317 (mTTSDuration != 0 && mTTSCount > UINT32_MAX / mTTSDuration) || 318 mTTSSampleTime > UINT32_MAX - (mTTSCount * mTTSDuration)) { 319 return ERROR_OUT_OF_RANGE; 320 } 321 322 mTTSSampleIndex += mTTSCount; 323 mTTSSampleTime += mTTSCount * mTTSDuration; 324 325 mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex]; 326 mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1]; 327 328 ++mTimeToSampleIndex; 329 } 330 331 *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex); 332 333 int32_t offset = mTable->getCompositionTimeOffset(sampleIndex); 334 if ((offset < 0 && *time < (offset == INT32_MIN ? 335 INT32_MAX : uint32_t(-offset))) || 336 (offset > 0 && *time > UINT32_MAX - offset)) { 337 ALOGE("%u + %d would overflow", *time, offset); 338 return ERROR_OUT_OF_RANGE; 339 } 340 if (offset > 0) { 341 *time += offset; 342 } else { 343 *time -= (offset == INT32_MIN ? INT32_MAX : (-offset)); 344 } 345 346 *duration = mTTSDuration; 347 348 return OK; 349} 350 351} // namespace android 352 353