blob: a4c31eae22d13d6fd0b97f12be6bc375c4f2764b [file] [log] [blame]
Andreas Huber84066782011-08-16 09:34:26 -07001/*
2 * Copyright (C) 2012 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_NDEBUG 0
18#define LOG_TAG "TrackFragment"
19#include <utils/Log.h>
20
21#include "TrackFragment.h"
22
23#include <media/stagefright/MediaErrors.h>
24#include <media/stagefright/Utils.h>
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
Andreas Huberb9787142012-08-09 09:15:48 -070027#include <media/stagefright/foundation/hexdump.h>
Andreas Huber84066782011-08-16 09:34:26 -070028
29namespace android {
30
31Parser::DynamicTrackFragment::DynamicTrackFragment()
32 : mComplete(false),
33 mSampleIndex(0) {
34}
35
36Parser::DynamicTrackFragment::~DynamicTrackFragment() {
37}
38
39status_t Parser::DynamicTrackFragment::getSample(SampleInfo *info) {
40 if (mSampleIndex >= mSamples.size()) {
41 return mComplete ? ERROR_END_OF_STREAM : -EWOULDBLOCK;
42 }
43
44 *info = mSamples.itemAt(mSampleIndex);
45
46 return OK;
47}
48
49void Parser::DynamicTrackFragment::advance() {
50 ++mSampleIndex;
51}
52
53void Parser::DynamicTrackFragment::addSample(
54 off64_t dataOffset, size_t sampleSize,
55 uint32_t presentationTime,
56 size_t sampleDescIndex,
57 uint32_t flags) {
58 mSamples.push();
59 SampleInfo *sampleInfo = &mSamples.editItemAt(mSamples.size() - 1);
60
61 sampleInfo->mOffset = dataOffset;
62 sampleInfo->mSize = sampleSize;
63 sampleInfo->mPresentationTime = presentationTime;
64 sampleInfo->mSampleDescIndex = sampleDescIndex;
65 sampleInfo->mFlags = flags;
66}
67
68status_t Parser::DynamicTrackFragment::signalCompletion() {
69 mComplete = true;
70
71 return OK;
72}
73
74bool Parser::DynamicTrackFragment::complete() const {
75 return mComplete;
76}
77
78////////////////////////////////////////////////////////////////////////////////
79
80Parser::StaticTrackFragment::StaticTrackFragment()
81 : mSampleIndex(0),
82 mSampleCount(0),
Andreas Huberb9787142012-08-09 09:15:48 -070083 mChunkIndex(0),
Andreas Huber84066782011-08-16 09:34:26 -070084 mSampleToChunkIndex(-1),
85 mSampleToChunkRemaining(0),
86 mPrevChunkIndex(0xffffffff),
87 mNextSampleOffset(0) {
88}
89
90Parser::StaticTrackFragment::~StaticTrackFragment() {
91}
92
93status_t Parser::StaticTrackFragment::getSample(SampleInfo *info) {
94 if (mSampleIndex >= mSampleCount) {
95 return ERROR_END_OF_STREAM;
96 }
97
98 *info = mSampleInfo;
99
100 ALOGV("returning sample %d at [0x%08llx, 0x%08llx)",
101 mSampleIndex,
102 info->mOffset, info->mOffset + info->mSize);
103
104 return OK;
105}
106
107void Parser::StaticTrackFragment::updateSampleInfo() {
108 if (mSampleIndex >= mSampleCount) {
109 return;
110 }
111
112 if (mSampleSizes != NULL) {
113 uint32_t defaultSampleSize = U32_AT(mSampleSizes->data() + 4);
114 if (defaultSampleSize > 0) {
115 mSampleInfo.mSize = defaultSampleSize;
116 } else {
117 mSampleInfo.mSize= U32_AT(mSampleSizes->data() + 12 + 4 * mSampleIndex);
118 }
119 } else {
120 CHECK(mCompactSampleSizes != NULL);
121
122 uint32_t fieldSize = U32_AT(mCompactSampleSizes->data() + 4);
123
124 switch (fieldSize) {
125 case 4:
126 {
127 unsigned byte = mCompactSampleSizes->data()[12 + mSampleIndex / 2];
128 mSampleInfo.mSize = (mSampleIndex & 1) ? byte & 0x0f : byte >> 4;
129 break;
130 }
131
132 case 8:
133 {
134 mSampleInfo.mSize = mCompactSampleSizes->data()[12 + mSampleIndex];
135 break;
136 }
137
138 default:
139 {
140 CHECK_EQ(fieldSize, 16);
141 mSampleInfo.mSize =
142 U16_AT(mCompactSampleSizes->data() + 12 + mSampleIndex * 2);
143 break;
144 }
145 }
146 }
147
148 CHECK_GT(mSampleToChunkRemaining, 0);
149
150 // The sample desc index is 1-based... XXX
151 mSampleInfo.mSampleDescIndex =
152 U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 8);
153
Andreas Huberb9787142012-08-09 09:15:48 -0700154 if (mChunkIndex != mPrevChunkIndex) {
155 mPrevChunkIndex = mChunkIndex;
Andreas Huber84066782011-08-16 09:34:26 -0700156
157 if (mChunkOffsets != NULL) {
158 uint32_t entryCount = U32_AT(mChunkOffsets->data() + 4);
159
Andreas Huberb9787142012-08-09 09:15:48 -0700160 if (mChunkIndex >= entryCount) {
Andreas Huber84066782011-08-16 09:34:26 -0700161 mSampleIndex = mSampleCount;
162 return;
163 }
164
165 mNextSampleOffset =
Andreas Huberb9787142012-08-09 09:15:48 -0700166 U32_AT(mChunkOffsets->data() + 8 + 4 * mChunkIndex);
Andreas Huber84066782011-08-16 09:34:26 -0700167 } else {
168 CHECK(mChunkOffsets64 != NULL);
169
170 uint32_t entryCount = U32_AT(mChunkOffsets64->data() + 4);
171
Andreas Huberb9787142012-08-09 09:15:48 -0700172 if (mChunkIndex >= entryCount) {
Andreas Huber84066782011-08-16 09:34:26 -0700173 mSampleIndex = mSampleCount;
174 return;
175 }
176
177 mNextSampleOffset =
Andreas Huberb9787142012-08-09 09:15:48 -0700178 U64_AT(mChunkOffsets64->data() + 8 + 8 * mChunkIndex);
Andreas Huber84066782011-08-16 09:34:26 -0700179 }
180 }
181
182 mSampleInfo.mOffset = mNextSampleOffset;
183
184 mSampleInfo.mPresentationTime = 0;
185 mSampleInfo.mFlags = 0;
186}
187
188void Parser::StaticTrackFragment::advance() {
189 mNextSampleOffset += mSampleInfo.mSize;
190
191 ++mSampleIndex;
192 if (--mSampleToChunkRemaining == 0) {
Andreas Huberb9787142012-08-09 09:15:48 -0700193 ++mChunkIndex;
194
Andreas Huber84066782011-08-16 09:34:26 -0700195 uint32_t entryCount = U32_AT(mSampleToChunk->data() + 4);
196
Andreas Huberb9787142012-08-09 09:15:48 -0700197 // If this is the last entry in the sample to chunk table, we will
198 // stay on this entry.
199 if ((uint32_t)(mSampleToChunkIndex + 1) < entryCount) {
200 uint32_t nextChunkIndex =
201 U32_AT(mSampleToChunk->data() + 8 + 12 * (mSampleToChunkIndex + 1));
202
203 CHECK_GE(nextChunkIndex, 1u);
204 --nextChunkIndex;
205
206 if (mChunkIndex >= nextChunkIndex) {
207 CHECK_EQ(mChunkIndex, nextChunkIndex);
208 ++mSampleToChunkIndex;
209 }
Andreas Huber84066782011-08-16 09:34:26 -0700210 }
211
Andreas Huber84066782011-08-16 09:34:26 -0700212 mSampleToChunkRemaining =
213 U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4);
214 }
215
216 updateSampleInfo();
217}
218
219static void setU32At(uint8_t *ptr, uint32_t x) {
220 ptr[0] = x >> 24;
221 ptr[1] = (x >> 16) & 0xff;
222 ptr[2] = (x >> 8) & 0xff;
223 ptr[3] = x & 0xff;
224}
225
Andreas Huber84066782011-08-16 09:34:26 -0700226status_t Parser::StaticTrackFragment::signalCompletion() {
Andreas Huber84066782011-08-16 09:34:26 -0700227 mSampleToChunkIndex = 0;
228
Andreas Huberb9787142012-08-09 09:15:48 -0700229 mSampleToChunkRemaining =
230 (mSampleToChunk == NULL)
231 ? 0
232 : U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4);
Andreas Huber84066782011-08-16 09:34:26 -0700233
234 updateSampleInfo();
235
236 return OK;
237}
238
239bool Parser::StaticTrackFragment::complete() const {
240 return true;
241}
242
243status_t Parser::StaticTrackFragment::parseSampleSizes(
244 Parser *parser, uint32_t type, size_t offset, uint64_t size) {
245 if (offset + 12 > size) {
246 return ERROR_MALFORMED;
247 }
248
249 if (parser->readU32(offset) != 0) {
250 return ERROR_MALFORMED;
251 }
252
253 uint32_t sampleSize = parser->readU32(offset + 4);
254 uint32_t sampleCount = parser->readU32(offset + 8);
255
256 if (sampleSize == 0 && offset + 12 + sampleCount * 4 != size) {
257 return ERROR_MALFORMED;
258 }
259
260 parser->copyBuffer(&mSampleSizes, offset, size);
261
262 mSampleCount = sampleCount;
263
264 return OK;
265}
266
267status_t Parser::StaticTrackFragment::parseCompactSampleSizes(
268 Parser *parser, uint32_t type, size_t offset, uint64_t size) {
269 if (offset + 12 > size) {
270 return ERROR_MALFORMED;
271 }
272
273 if (parser->readU32(offset) != 0) {
274 return ERROR_MALFORMED;
275 }
276
277 uint32_t fieldSize = parser->readU32(offset + 4);
278
279 if (fieldSize != 4 && fieldSize != 8 && fieldSize != 16) {
280 return ERROR_MALFORMED;
281 }
282
283 uint32_t sampleCount = parser->readU32(offset + 8);
284
285 if (offset + 12 + (sampleCount * fieldSize + 4) / 8 != size) {
286 return ERROR_MALFORMED;
287 }
288
289 parser->copyBuffer(&mCompactSampleSizes, offset, size);
290
291 mSampleCount = sampleCount;
292
293 return OK;
294}
295
296status_t Parser::StaticTrackFragment::parseSampleToChunk(
297 Parser *parser, uint32_t type, size_t offset, uint64_t size) {
298 if (offset + 8 > size) {
299 return ERROR_MALFORMED;
300 }
301
302 if (parser->readU32(offset) != 0) {
303 return ERROR_MALFORMED;
304 }
305
306 uint32_t entryCount = parser->readU32(offset + 4);
307
Marco Nelissenb7e75cf2012-08-08 09:19:05 -0700308 if (entryCount == 0) {
309 return OK;
310 }
311
312 if (offset + 8 + entryCount * 12 != size) {
Andreas Huber84066782011-08-16 09:34:26 -0700313 return ERROR_MALFORMED;
314 }
315
Andreas Huberb9787142012-08-09 09:15:48 -0700316 parser->copyBuffer(&mSampleToChunk, offset, size);
Andreas Huber84066782011-08-16 09:34:26 -0700317
318 return OK;
319}
320
321status_t Parser::StaticTrackFragment::parseChunkOffsets(
322 Parser *parser, uint32_t type, size_t offset, uint64_t size) {
323 if (offset + 8 > size) {
324 return ERROR_MALFORMED;
325 }
326
327 if (parser->readU32(offset) != 0) {
328 return ERROR_MALFORMED;
329 }
330
331 uint32_t entryCount = parser->readU32(offset + 4);
332
333 if (offset + 8 + entryCount * 4 != size) {
334 return ERROR_MALFORMED;
335 }
336
337 parser->copyBuffer(&mChunkOffsets, offset, size);
338
339 return OK;
340}
341
342status_t Parser::StaticTrackFragment::parseChunkOffsets64(
343 Parser *parser, uint32_t type, size_t offset, uint64_t size) {
344 if (offset + 8 > size) {
345 return ERROR_MALFORMED;
346 }
347
348 if (parser->readU32(offset) != 0) {
349 return ERROR_MALFORMED;
350 }
351
352 uint32_t entryCount = parser->readU32(offset + 4);
353
354 if (offset + 8 + entryCount * 8 != size) {
355 return ERROR_MALFORMED;
356 }
357
358 parser->copyBuffer(&mChunkOffsets64, offset, size);
359
360 return OK;
361}
362
363} // namespace android
364