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 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
findChunkRange(uint32_t sampleIndex)155 status_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 (mSamplesPerChunk == 0 || 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
getChunkOffset(uint32_t chunk,off64_t * offset)196 status_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
getSampleSizeDirect(uint32_t sampleIndex,size_t * size)231 status_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 uint32_t x;
248 if (mTable->mDataSource->readAt(
249 mTable->mSampleSizeOffset + 12 + 4 * sampleIndex,
250 &x, sizeof(x)) < (ssize_t)sizeof(x)) {
251 return ERROR_IO;
252 }
253
254 *size = ntohl(x);
255 break;
256 }
257
258 case 16:
259 {
260 uint16_t x;
261 if (mTable->mDataSource->readAt(
262 mTable->mSampleSizeOffset + 12 + 2 * sampleIndex,
263 &x, sizeof(x)) < (ssize_t)sizeof(x)) {
264 return ERROR_IO;
265 }
266
267 *size = ntohs(x);
268 break;
269 }
270
271 case 8:
272 {
273 uint8_t x;
274 if (mTable->mDataSource->readAt(
275 mTable->mSampleSizeOffset + 12 + sampleIndex,
276 &x, sizeof(x)) < (ssize_t)sizeof(x)) {
277 return ERROR_IO;
278 }
279
280 *size = x;
281 break;
282 }
283
284 default:
285 {
286 CHECK_EQ(mTable->mSampleSizeFieldSize, 4u);
287
288 uint8_t x;
289 if (mTable->mDataSource->readAt(
290 mTable->mSampleSizeOffset + 12 + sampleIndex / 2,
291 &x, sizeof(x)) < (ssize_t)sizeof(x)) {
292 return ERROR_IO;
293 }
294
295 *size = (sampleIndex & 1) ? x & 0x0f : x >> 4;
296 break;
297 }
298 }
299
300 return OK;
301 }
302
findSampleTimeAndDuration(uint32_t sampleIndex,uint32_t * time,uint32_t * duration)303 status_t SampleIterator::findSampleTimeAndDuration(
304 uint32_t sampleIndex, uint32_t *time, uint32_t *duration) {
305 if (sampleIndex >= mTable->mNumSampleSizes) {
306 return ERROR_OUT_OF_RANGE;
307 }
308
309 while (true) {
310 if (mTTSSampleIndex > UINT32_MAX - mTTSCount) {
311 return ERROR_OUT_OF_RANGE;
312 }
313 if(sampleIndex < mTTSSampleIndex + mTTSCount) {
314 break;
315 }
316 if (mTimeToSampleIndex == mTable->mTimeToSampleCount ||
317 (mTTSDuration != 0 && mTTSCount > UINT32_MAX / mTTSDuration) ||
318 mTTSSampleTime > UINT32_MAX - (mTTSCount * mTTSDuration)) {
319 return ERROR_OUT_OF_RANGE;
320 }
321
322 mTTSSampleIndex += mTTSCount;
323 mTTSSampleTime += mTTSCount * mTTSDuration;
324
325 mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex];
326 mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1];
327
328 ++mTimeToSampleIndex;
329 }
330
331 *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
332
333 int32_t offset = mTable->getCompositionTimeOffset(sampleIndex);
334 if ((offset < 0 && *time < (offset == INT32_MIN ?
335 INT32_MAX : uint32_t(-offset))) ||
336 (offset > 0 && *time > UINT32_MAX - offset)) {
337 ALOGE("%u + %d would overflow", *time, offset);
338 return ERROR_OUT_OF_RANGE;
339 }
340 if (offset > 0) {
341 *time += offset;
342 } else {
343 *time -= (offset == INT32_MIN ? INT32_MAX : (-offset));
344 }
345
346 *duration = mTTSDuration;
347
348 return OK;
349 }
350
351 } // namespace android
352
353