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