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, off64_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 *time += mTable->getCompositionTimeOffset(sampleIndex); 311 312 return OK; 313 } 314 315 } // namespace android 316 317