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/foundation/ADebug.h>
26 #include <media/stagefright/DataSource.h>
27 #include <media/stagefright/Utils.h>
28
29 #include "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 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 ALOGE("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 ALOGE("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 ALOGE("findSampleTime return error");
138 return err;
139 }
140
141 mCurrentSampleIndex = sampleIndex;
142
143 mInitialized = true;
144
145 return OK;
146 }
147
findChunkRange(uint32_t sampleIndex)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
getChunkOffset(uint32_t chunk,off64_t * offset)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
getSampleSizeDirect(uint32_t sampleIndex,size_t * size)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
findSampleTime(uint32_t sampleIndex,uint32_t * time)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