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 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 (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 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, 4); 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 302status_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 (sampleIndex >= mTTSSampleIndex + mTTSCount) { 309 if (mTimeToSampleIndex == mTable->mTimeToSampleCount) { 310 return ERROR_OUT_OF_RANGE; 311 } 312 313 mTTSSampleIndex += mTTSCount; 314 mTTSSampleTime += mTTSCount * mTTSDuration; 315 316 mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex]; 317 mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1]; 318 319 ++mTimeToSampleIndex; 320 } 321 322 *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex); 323 324 int32_t offset = mTable->getCompositionTimeOffset(sampleIndex); 325 if ((offset < 0 && *time < (offset == INT32_MIN ? 326 INT32_MAX : uint32_t(-offset))) || 327 (offset > 0 && *time > UINT32_MAX - offset)) { 328 ALOGE("%u + %d would overflow", *time, offset); 329 return ERROR_OUT_OF_RANGE; 330 } 331 if (offset > 0) { 332 *time += offset; 333 } else { 334 *time -= (offset == INT32_MIN ? INT32_MAX : (-offset)); 335 } 336 337 *duration = mTTSDuration; 338 339 return OK; 340} 341 342} // namespace android 343 344