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