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