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/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/foundation/ByteUtils.h>
27
28 #include "SampleTable.h"
29
30 namespace android {
31
SampleIterator(SampleTable * table)32 SampleIterator::SampleIterator(SampleTable *table)
33 : mTable(table),
34 mInitialized(false),
35 mTimeToSampleIndex(0),
36 mTTSSampleIndex(0),
37 mTTSSampleTime(0),
38 mTTSCount(0),
39 mTTSDuration(0) {
40 reset();
41 }
42
reset()43 void SampleIterator::reset() {
44 mSampleToChunkIndex = 0;
45 mFirstChunk = 0;
46 mFirstChunkSampleIndex = 0;
47 mStopChunk = 0;
48 mStopChunkSampleIndex = 0;
49 mSamplesPerChunk = 0;
50 mChunkDesc = 0;
51 }
52
seekTo(uint32_t sampleIndex)53 status_t SampleIterator::seekTo(uint32_t sampleIndex) {
54 ALOGV("seekTo(%d)", sampleIndex);
55
56 if (sampleIndex >= mTable->mNumSampleSizes) {
57 return ERROR_END_OF_STREAM;
58 }
59
60 if (mTable->mSampleToChunkOffset < 0
61 || mTable->mChunkOffsetOffset < 0
62 || mTable->mSampleSizeOffset < 0
63 || mTable->mTimeToSampleCount == 0) {
64
65 return ERROR_MALFORMED;
66 }
67
68 if (mInitialized && mCurrentSampleIndex == sampleIndex) {
69 return OK;
70 }
71
72 if (!mInitialized || sampleIndex < mFirstChunkSampleIndex) {
73 reset();
74 }
75
76 if (sampleIndex >= mStopChunkSampleIndex) {
77 status_t err;
78 if ((err = findChunkRange(sampleIndex)) != OK) {
79 ALOGE("findChunkRange failed");
80 return err;
81 }
82 }
83
84 CHECK(sampleIndex < mStopChunkSampleIndex);
85
86 if (mSamplesPerChunk == 0) {
87 ALOGE("b/22802344");
88 return ERROR_MALFORMED;
89 }
90
91 uint32_t chunk =
92 (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
93 + mFirstChunk;
94
95 if (!mInitialized || chunk != mCurrentChunkIndex) {
96 status_t err;
97 if ((err = getChunkOffset(chunk, &mCurrentChunkOffset)) != OK) {
98 ALOGE("getChunkOffset return error");
99 return err;
100 }
101
102 mCurrentChunkSampleSizes.clear();
103
104 uint32_t firstChunkSampleIndex =
105 mFirstChunkSampleIndex
106 + mSamplesPerChunk * (chunk - mFirstChunk);
107
108 for (uint32_t i = 0; i < mSamplesPerChunk; ++i) {
109 size_t sampleSize;
110 if ((err = getSampleSizeDirect(
111 firstChunkSampleIndex + i, &sampleSize)) != OK) {
112 ALOGE("getSampleSizeDirect return error");
113 // stsc sample count is not sync with stsz sample count
114 if (err == ERROR_OUT_OF_RANGE) {
115 ALOGW("stsc samples(%d) not sync with stsz samples(%d)", mSamplesPerChunk, i);
116 mSamplesPerChunk = i;
117 break;
118 } else{
119 mCurrentChunkSampleSizes.clear();
120 return err;
121 }
122 }
123
124 mCurrentChunkSampleSizes.push(sampleSize);
125 }
126
127 mCurrentChunkIndex = chunk;
128 }
129
130 uint32_t chunkRelativeSampleIndex =
131 (sampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk;
132
133 mCurrentSampleOffset = mCurrentChunkOffset;
134 for (uint32_t i = 0; i < chunkRelativeSampleIndex; ++i) {
135 mCurrentSampleOffset += mCurrentChunkSampleSizes[i];
136 }
137
138 mCurrentSampleSize = mCurrentChunkSampleSizes[chunkRelativeSampleIndex];
139 if (sampleIndex < mTTSSampleIndex) {
140 mTimeToSampleIndex = 0;
141 mTTSSampleIndex = 0;
142 mTTSSampleTime = 0;
143 mTTSCount = 0;
144 mTTSDuration = 0;
145 }
146
147 status_t err;
148 if ((err = findSampleTimeAndDuration(
149 sampleIndex, &mCurrentSampleTime, &mCurrentSampleDuration)) != OK) {
150 ALOGE("findSampleTime return error");
151 return err;
152 }
153
154 mCurrentSampleIndex = sampleIndex;
155
156 mInitialized = true;
157
158 return OK;
159 }
160
findChunkRange(uint32_t sampleIndex)161 status_t SampleIterator::findChunkRange(uint32_t sampleIndex) {
162 CHECK(sampleIndex >= mFirstChunkSampleIndex);
163
164 while (sampleIndex >= mStopChunkSampleIndex) {
165 if (mSampleToChunkIndex == mTable->mNumSampleToChunkOffsets) {
166 return ERROR_OUT_OF_RANGE;
167 }
168
169 mFirstChunkSampleIndex = mStopChunkSampleIndex;
170
171 const SampleTable::SampleToChunkEntry *entry =
172 &mTable->mSampleToChunkEntries[mSampleToChunkIndex];
173
174 mFirstChunk = entry->startChunk;
175 mSamplesPerChunk = entry->samplesPerChunk;
176 mChunkDesc = entry->chunkDesc;
177
178 if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) {
179 mStopChunk = entry[1].startChunk;
180
181 if (mSamplesPerChunk == 0 || mStopChunk < mFirstChunk ||
182 (mStopChunk - mFirstChunk) > UINT32_MAX / mSamplesPerChunk ||
183 ((mStopChunk - mFirstChunk) * mSamplesPerChunk >
184 UINT32_MAX - mFirstChunkSampleIndex)) {
185
186 return ERROR_OUT_OF_RANGE;
187 }
188 mStopChunkSampleIndex =
189 mFirstChunkSampleIndex
190 + (mStopChunk - mFirstChunk) * mSamplesPerChunk;
191 } else {
192 mStopChunk = 0xffffffff;
193 mStopChunkSampleIndex = 0xffffffff;
194 }
195
196 ++mSampleToChunkIndex;
197 }
198
199 return OK;
200 }
201
getChunkOffset(uint32_t chunk,off64_t * offset)202 status_t SampleIterator::getChunkOffset(uint32_t chunk, off64_t *offset) {
203 *offset = 0;
204
205 if (chunk >= mTable->mNumChunkOffsets) {
206 return ERROR_OUT_OF_RANGE;
207 }
208
209 if (mTable->mChunkOffsetType == SampleTable::kChunkOffsetType32) {
210 uint32_t offset32;
211
212 if (mTable->mDataSource->readAt(
213 mTable->mChunkOffsetOffset + 8 + 4 * chunk,
214 &offset32,
215 sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
216 return ERROR_IO;
217 }
218
219 *offset = ntohl(offset32);
220 } else {
221 CHECK_EQ(mTable->mChunkOffsetType, SampleTable::kChunkOffsetType64);
222
223 uint64_t offset64;
224 if (mTable->mDataSource->readAt(
225 mTable->mChunkOffsetOffset + 8 + 8 * chunk,
226 &offset64,
227 sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
228 return ERROR_IO;
229 }
230
231 *offset = ntoh64(offset64);
232 }
233
234 return OK;
235 }
236
getSampleSizeDirect(uint32_t sampleIndex,size_t * size)237 status_t SampleIterator::getSampleSizeDirect(
238 uint32_t sampleIndex, size_t *size) {
239 *size = 0;
240
241 if (sampleIndex >= mTable->mNumSampleSizes) {
242 return ERROR_OUT_OF_RANGE;
243 }
244
245 if (mTable->mDefaultSampleSize > 0) {
246 *size = mTable->mDefaultSampleSize;
247 return OK;
248 }
249
250 switch (mTable->mSampleSizeFieldSize) {
251 case 32:
252 {
253 uint32_t x;
254 if (mTable->mDataSource->readAt(
255 mTable->mSampleSizeOffset + 12 + 4 * sampleIndex,
256 &x, sizeof(x)) < (ssize_t)sizeof(x)) {
257 return ERROR_IO;
258 }
259
260 *size = ntohl(x);
261 break;
262 }
263
264 case 16:
265 {
266 uint16_t x;
267 if (mTable->mDataSource->readAt(
268 mTable->mSampleSizeOffset + 12 + 2 * sampleIndex,
269 &x, sizeof(x)) < (ssize_t)sizeof(x)) {
270 return ERROR_IO;
271 }
272
273 *size = ntohs(x);
274 break;
275 }
276
277 case 8:
278 {
279 uint8_t x;
280 if (mTable->mDataSource->readAt(
281 mTable->mSampleSizeOffset + 12 + sampleIndex,
282 &x, sizeof(x)) < (ssize_t)sizeof(x)) {
283 return ERROR_IO;
284 }
285
286 *size = x;
287 break;
288 }
289
290 default:
291 {
292 CHECK_EQ(mTable->mSampleSizeFieldSize, 4u);
293
294 uint8_t x;
295 if (mTable->mDataSource->readAt(
296 mTable->mSampleSizeOffset + 12 + sampleIndex / 2,
297 &x, sizeof(x)) < (ssize_t)sizeof(x)) {
298 return ERROR_IO;
299 }
300
301 *size = (sampleIndex & 1) ? x & 0x0f : x >> 4;
302 break;
303 }
304 }
305
306 return OK;
307 }
308
findSampleTimeAndDuration(uint32_t sampleIndex,uint64_t * time,uint64_t * duration)309 status_t SampleIterator::findSampleTimeAndDuration(
310 uint32_t sampleIndex, uint64_t *time, uint64_t *duration) {
311 if (sampleIndex >= mTable->mNumSampleSizes) {
312 return ERROR_OUT_OF_RANGE;
313 }
314
315 while (true) {
316 if (mTTSSampleIndex > UINT32_MAX - mTTSCount) {
317 return ERROR_OUT_OF_RANGE;
318 }
319 if(sampleIndex < mTTSSampleIndex + mTTSCount) {
320 break;
321 }
322 if (mTimeToSampleIndex == mTable->mTimeToSampleCount ||
323 (mTTSDuration != 0 && mTTSCount > UINT64_MAX / mTTSDuration) ||
324 mTTSSampleTime > UINT64_MAX - (mTTSCount * mTTSDuration)) {
325 return ERROR_OUT_OF_RANGE;
326 }
327
328 mTTSSampleIndex += mTTSCount;
329 mTTSSampleTime += mTTSCount * mTTSDuration;
330
331 mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex];
332 mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1];
333
334 ++mTimeToSampleIndex;
335 }
336
337 // below is equivalent to:
338 // *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
339 uint64_t tmp;
340 if (__builtin_sub_overflow(sampleIndex, mTTSSampleIndex, &tmp) ||
341 __builtin_mul_overflow(mTTSDuration, tmp, &tmp) ||
342 __builtin_add_overflow(mTTSSampleTime, tmp, &tmp)) {
343 return ERROR_OUT_OF_RANGE;
344 }
345 *time = tmp;
346
347 int32_t offset = mTable->getCompositionTimeOffset(sampleIndex);
348 if ((offset < 0 && *time < (offset == INT32_MIN ?
349 INT64_MAX : uint64_t(-offset))) ||
350 (offset > 0 && *time > UINT64_MAX - offset)) {
351 ALOGE("%llu + %d would overflow", (unsigned long long) *time, offset);
352 return ERROR_OUT_OF_RANGE;
353 }
354 if (offset > 0) {
355 *time += offset;
356 } else {
357 *time -= (offset == INT32_MIN ? INT64_MAX : (-offset));
358 }
359
360 *duration = mTTSDuration;
361
362 return OK;
363 }
364
365 } // namespace android
366
367