blob: eae721b5fb78ac72b5b741532b46e0ce0165e92e [file] [log] [blame]
Andreas Huberc57b6792010-01-19 10:39:21 -08001/*
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
James Dongf1d5aa12012-02-06 23:46:37 -080025#include <media/stagefright/foundation/ADebug.h>
Andreas Huberc57b6792010-01-19 10:39:21 -080026#include <media/stagefright/DataSource.h>
Andreas Huberc57b6792010-01-19 10:39:21 -080027#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) {
Steve Block3856b092011-10-20 11:56:00 +010055 ALOGV("seekTo(%d)", sampleIndex);
Andreas Huberc57b6792010-01-19 10:39:21 -080056
Andreas Huber213addf2010-01-25 10:41:35 -080057 if (sampleIndex >= mTable->mNumSampleSizes) {
58 return ERROR_END_OF_STREAM;
59 }
60
Andreas Huberc57b6792010-01-19 10:39:21 -080061 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) {
Steve Block29357bc2012-01-06 19:20:56 +000080 ALOGE("findChunkRange failed");
Andreas Huberc57b6792010-01-19 10:39:21 -080081 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) {
Steve Block29357bc2012-01-06 19:20:56 +000096 ALOGE("getChunkOffset return error");
Andreas Huberc57b6792010-01-19 10:39:21 -080097 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) {
Steve Block29357bc2012-01-06 19:20:56 +0000110 ALOGE("getSampleSizeDirect return error");
Andreas Huberc57b6792010-01-19 10:39:21 -0800111 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) {
Steve Block29357bc2012-01-06 19:20:56 +0000137 ALOGE("findSampleTime return error");
Andreas Huberc57b6792010-01-19 10:39:21 -0800138 return err;
139 }
140
141 mCurrentSampleIndex = sampleIndex;
142
143 mInitialized = true;
144
145 return OK;
146}
147
148status_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
James Dongc7fc37a2010-11-16 14:04:54 -0800182status_t SampleIterator::getChunkOffset(uint32_t chunk, off64_t *offset) {
Andreas Huberc57b6792010-01-19 10:39:21 -0800183 *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
217status_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
288status_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
Andreas Huber4931bb52011-02-03 13:18:16 -0800310 *time += mTable->getCompositionTimeOffset(sampleIndex);
311
Andreas Huberc57b6792010-01-19 10:39:21 -0800312 return OK;
313}
314
315} // namespace android
316