Line data Source code
1 : /*
2 : * Copyright (C) 2009 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 "SampleTable"
19 : //#define LOG_NDEBUG 0
20 : #include <utils/Log.h>
21 :
22 : #include "include/SampleTable.h"
23 : #include "include/SampleIterator.h"
24 :
25 : #include <arpa/inet.h>
26 :
27 : #include <media/stagefright/foundation/ADebug.h>
28 : #include <media/stagefright/DataSource.h>
29 : #include <media/stagefright/Utils.h>
30 :
31 : #include "mozilla/SizePrintfMacros.h"
32 :
33 : #include <cinttypes>
34 : #include <stdint.h>
35 :
36 : namespace stagefright {
37 :
38 : // static
39 : const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
40 : // static
41 : const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
42 : // static
43 : const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
44 : // static
45 : const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
46 :
47 : const uint32_t kAuxTypeCenc = FOURCC('c', 'e', 'n', 'c');
48 :
49 : static const uint32_t kMAX_ALLOCATION =
50 : (SIZE_MAX < INT32_MAX ? SIZE_MAX : INT32_MAX) - 128;
51 :
52 : ////////////////////////////////////////////////////////////////////////////////
53 :
54 0 : struct SampleTable::CompositionDeltaLookup {
55 : CompositionDeltaLookup();
56 :
57 : void setEntries(
58 : const uint32_t *deltaEntries, size_t numDeltaEntries);
59 :
60 : uint32_t getCompositionTimeOffset(uint32_t sampleIndex);
61 :
62 : private:
63 : Mutex mLock;
64 :
65 : const uint32_t *mDeltaEntries;
66 : size_t mNumDeltaEntries;
67 :
68 : size_t mCurrentDeltaEntry;
69 : size_t mCurrentEntrySampleIndex;
70 :
71 : DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup);
72 : };
73 :
74 0 : SampleTable::CompositionDeltaLookup::CompositionDeltaLookup()
75 : : mDeltaEntries(NULL),
76 : mNumDeltaEntries(0),
77 : mCurrentDeltaEntry(0),
78 0 : mCurrentEntrySampleIndex(0) {
79 0 : }
80 :
81 0 : void SampleTable::CompositionDeltaLookup::setEntries(
82 : const uint32_t *deltaEntries, size_t numDeltaEntries) {
83 0 : Mutex::Autolock autolock(mLock);
84 :
85 0 : mDeltaEntries = deltaEntries;
86 0 : mNumDeltaEntries = numDeltaEntries;
87 0 : mCurrentDeltaEntry = 0;
88 0 : mCurrentEntrySampleIndex = 0;
89 0 : }
90 :
91 0 : uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset(
92 : uint32_t sampleIndex) {
93 0 : Mutex::Autolock autolock(mLock);
94 :
95 0 : if (mDeltaEntries == NULL) {
96 0 : return 0;
97 : }
98 :
99 0 : if (sampleIndex < mCurrentEntrySampleIndex) {
100 0 : mCurrentDeltaEntry = 0;
101 0 : mCurrentEntrySampleIndex = 0;
102 : }
103 :
104 0 : while (mCurrentDeltaEntry < mNumDeltaEntries) {
105 0 : uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry];
106 0 : if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) {
107 0 : return mDeltaEntries[2 * mCurrentDeltaEntry + 1];
108 : }
109 :
110 0 : mCurrentEntrySampleIndex += sampleCount;
111 0 : ++mCurrentDeltaEntry;
112 : }
113 :
114 0 : return 0;
115 : }
116 :
117 : ////////////////////////////////////////////////////////////////////////////////
118 :
119 0 : SampleTable::SampleTable(const sp<DataSource> &source)
120 : : mDataSource(source),
121 : mChunkOffsetOffset(-1),
122 : mChunkOffsetType(0),
123 : mNumChunkOffsets(0),
124 : mSampleToChunkOffset(-1),
125 : mNumSampleToChunkOffsets(0),
126 : mSampleSizeOffset(-1),
127 : mSampleSizeFieldSize(0),
128 : mDefaultSampleSize(0),
129 : mNumSampleSizes(0),
130 : mTimeToSampleCount(0),
131 : mTimeToSample(NULL),
132 : mSampleTimeEntries(NULL),
133 : mCompositionTimeDeltaEntries(NULL),
134 : mNumCompositionTimeDeltaEntries(0),
135 0 : mCompositionDeltaLookup(new CompositionDeltaLookup),
136 : mSyncSampleOffset(-1),
137 : mNumSyncSamples(0),
138 : mSyncSamples(NULL),
139 : mLastSyncSampleIndex(0),
140 : mSampleToChunkEntries(NULL),
141 : mCencInfo(NULL),
142 : mCencInfoCount(0),
143 0 : mCencDefaultSize(0)
144 : {
145 0 : mSampleIterator = new SampleIterator(this);
146 0 : }
147 :
148 0 : SampleTable::~SampleTable() {
149 0 : delete[] mSampleToChunkEntries;
150 0 : mSampleToChunkEntries = NULL;
151 :
152 0 : delete[] mSyncSamples;
153 0 : mSyncSamples = NULL;
154 :
155 0 : delete mCompositionDeltaLookup;
156 0 : mCompositionDeltaLookup = NULL;
157 :
158 0 : delete[] mCompositionTimeDeltaEntries;
159 0 : mCompositionTimeDeltaEntries = NULL;
160 :
161 0 : delete[] mSampleTimeEntries;
162 0 : mSampleTimeEntries = NULL;
163 :
164 0 : delete[] mTimeToSample;
165 0 : mTimeToSample = NULL;
166 :
167 0 : if (mCencInfo) {
168 0 : for (uint32_t i = 0; i < mCencInfoCount; i++) {
169 0 : if (mCencInfo[i].mSubsamples) {
170 0 : delete[] mCencInfo[i].mSubsamples;
171 : }
172 : }
173 0 : delete[] mCencInfo;
174 : }
175 :
176 0 : delete mSampleIterator;
177 0 : mSampleIterator = NULL;
178 0 : }
179 :
180 0 : bool SampleTable::isValid() const {
181 0 : return mChunkOffsetOffset >= 0
182 0 : && mSampleToChunkOffset >= 0
183 0 : && mSampleSizeOffset >= 0
184 0 : && mTimeToSample != NULL;
185 : }
186 :
187 0 : status_t SampleTable::setChunkOffsetParams(
188 : uint32_t type, off64_t data_offset, size_t data_size) {
189 0 : if (mChunkOffsetOffset >= 0) {
190 0 : return ERROR_MALFORMED;
191 : }
192 :
193 0 : CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
194 :
195 0 : mChunkOffsetOffset = data_offset;
196 0 : mChunkOffsetType = type;
197 :
198 0 : if (data_size < 8) {
199 0 : return ERROR_MALFORMED;
200 : }
201 :
202 : uint8_t header[8];
203 0 : if (mDataSource->readAt(
204 0 : data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
205 0 : return ERROR_IO;
206 : }
207 :
208 0 : if (U32_AT(header) != 0) {
209 : // Expected version = 0, flags = 0.
210 0 : return ERROR_MALFORMED;
211 : }
212 :
213 0 : mNumChunkOffsets = U32_AT(&header[4]);
214 :
215 0 : if (mChunkOffsetType == kChunkOffsetType32) {
216 0 : if (data_size < 8 + (uint64_t)mNumChunkOffsets * 4) {
217 0 : return ERROR_MALFORMED;
218 : }
219 : } else {
220 0 : if (data_size < 8 + (uint64_t)mNumChunkOffsets * 8) {
221 0 : return ERROR_MALFORMED;
222 : }
223 : }
224 :
225 0 : return OK;
226 : }
227 :
228 0 : status_t SampleTable::setSampleToChunkParams(
229 : off64_t data_offset, size_t data_size) {
230 0 : if (mSampleToChunkOffset >= 0) {
231 0 : return ERROR_MALFORMED;
232 : }
233 :
234 0 : mSampleToChunkOffset = data_offset;
235 :
236 0 : if (data_size < 8) {
237 0 : return ERROR_MALFORMED;
238 : }
239 :
240 : uint8_t header[8];
241 0 : if (mDataSource->readAt(
242 0 : data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
243 0 : return ERROR_IO;
244 : }
245 :
246 0 : if (U32_AT(header) != 0) {
247 : // Expected version = 0, flags = 0.
248 0 : return ERROR_MALFORMED;
249 : }
250 :
251 0 : mNumSampleToChunkOffsets = U32_AT(&header[4]);
252 :
253 0 : if (data_size < 8 + (uint64_t)mNumSampleToChunkOffsets * 12) {
254 0 : return ERROR_MALFORMED;
255 : }
256 :
257 0 : mSampleToChunkEntries =
258 0 : new (mozilla::fallible) SampleToChunkEntry[mNumSampleToChunkOffsets];
259 0 : if (!mSampleToChunkEntries) {
260 0 : return ERROR_BUFFER_TOO_SMALL;
261 : }
262 :
263 0 : for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
264 : uint8_t buffer[12];
265 0 : if (mDataSource->readAt(
266 0 : mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
267 : != (ssize_t)sizeof(buffer)) {
268 0 : return ERROR_IO;
269 : }
270 :
271 0 : if (!U32_AT(buffer)) {
272 0 : ALOGE("error reading sample to chunk table");
273 0 : return ERROR_MALFORMED; // chunk index is 1 based in the spec.
274 : }
275 :
276 : // We want the chunk index to be 0-based.
277 0 : mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
278 0 : mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
279 0 : mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
280 : }
281 :
282 0 : return OK;
283 : }
284 :
285 0 : status_t SampleTable::setSampleSizeParams(
286 : uint32_t type, off64_t data_offset, size_t data_size) {
287 0 : if (mSampleSizeOffset >= 0) {
288 0 : return ERROR_MALFORMED;
289 : }
290 :
291 0 : CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
292 :
293 0 : mSampleSizeOffset = data_offset;
294 :
295 0 : if (data_size < 12) {
296 0 : return ERROR_MALFORMED;
297 : }
298 :
299 : uint8_t header[12];
300 0 : if (mDataSource->readAt(
301 0 : data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
302 0 : return ERROR_IO;
303 : }
304 :
305 0 : if (U32_AT(header) != 0) {
306 : // Expected version = 0, flags = 0.
307 0 : return ERROR_MALFORMED;
308 : }
309 :
310 0 : mDefaultSampleSize = U32_AT(&header[4]);
311 0 : mNumSampleSizes = U32_AT(&header[8]);
312 :
313 0 : if (type == kSampleSizeType32) {
314 0 : mSampleSizeFieldSize = 32;
315 :
316 0 : if (mDefaultSampleSize != 0) {
317 0 : return OK;
318 : }
319 :
320 0 : if (data_size < 12 + (uint64_t)mNumSampleSizes * 4) {
321 0 : return ERROR_MALFORMED;
322 : }
323 : } else {
324 0 : if ((mDefaultSampleSize & 0xffffff00) != 0) {
325 : // The high 24 bits are reserved and must be 0.
326 0 : return ERROR_MALFORMED;
327 : }
328 :
329 0 : mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
330 0 : mDefaultSampleSize = 0;
331 :
332 0 : if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
333 0 : && mSampleSizeFieldSize != 16) {
334 0 : return ERROR_MALFORMED;
335 : }
336 :
337 0 : if (data_size < 12 + ((uint64_t)mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
338 0 : return ERROR_MALFORMED;
339 : }
340 : }
341 :
342 0 : return OK;
343 : }
344 :
345 0 : status_t SampleTable::setTimeToSampleParams(
346 : off64_t data_offset, size_t data_size) {
347 0 : if (mTimeToSample != NULL || data_size < 8) {
348 0 : return ERROR_MALFORMED;
349 : }
350 :
351 : uint8_t header[8];
352 0 : if (mDataSource->readAt(
353 0 : data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
354 0 : return ERROR_IO;
355 : }
356 :
357 0 : if (U32_AT(header) != 0) {
358 : // Expected version = 0, flags = 0.
359 0 : return ERROR_MALFORMED;
360 : }
361 :
362 0 : mTimeToSampleCount = U32_AT(&header[4]);
363 0 : if (mTimeToSampleCount > kMAX_ALLOCATION / 2 / sizeof(uint32_t)) {
364 : // Avoid later overflow.
365 0 : return ERROR_MALFORMED;
366 : }
367 :
368 0 : size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
369 :
370 0 : mTimeToSample = new (mozilla::fallible) uint32_t[mTimeToSampleCount * 2];
371 0 : if (!mTimeToSample) {
372 0 : return ERROR_BUFFER_TOO_SMALL;
373 : }
374 :
375 0 : if (mDataSource->readAt(
376 0 : data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
377 0 : return ERROR_IO;
378 : }
379 :
380 0 : for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
381 0 : mTimeToSample[i] = ntohl(mTimeToSample[i]);
382 : }
383 :
384 0 : return OK;
385 : }
386 :
387 0 : status_t SampleTable::setCompositionTimeToSampleParams(
388 : off64_t data_offset, size_t data_size) {
389 : ALOGV("There are reordered frames present.");
390 :
391 0 : if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
392 0 : return ERROR_MALFORMED;
393 : }
394 :
395 : uint8_t header[8];
396 0 : if (mDataSource->readAt(
397 0 : data_offset, header, sizeof(header))
398 : < (ssize_t)sizeof(header)) {
399 0 : return ERROR_IO;
400 : }
401 :
402 0 : uint32_t numEntries = U32_AT(&header[4]);
403 :
404 0 : if (U32_AT(header) != 0 && numEntries) {
405 : // Expected version = 0, flags = 0.
406 0 : return ERROR_MALFORMED;
407 : }
408 :
409 0 : if (data_size < ((uint64_t)numEntries + 1) * 8) {
410 0 : return ERROR_MALFORMED;
411 : }
412 :
413 0 : mNumCompositionTimeDeltaEntries = numEntries;
414 0 : mCompositionTimeDeltaEntries = new (mozilla::fallible) uint32_t[2 * numEntries];
415 0 : if (!mCompositionTimeDeltaEntries) {
416 0 : return ERROR_BUFFER_TOO_SMALL;
417 : }
418 :
419 0 : if (mDataSource->readAt(
420 0 : data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
421 0 : < (ssize_t)numEntries * 8) {
422 0 : delete[] mCompositionTimeDeltaEntries;
423 0 : mCompositionTimeDeltaEntries = NULL;
424 :
425 0 : return ERROR_IO;
426 : }
427 :
428 0 : for (size_t i = 0; i < 2 * numEntries; ++i) {
429 0 : mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
430 : }
431 :
432 0 : mCompositionDeltaLookup->setEntries(
433 0 : mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
434 :
435 0 : return OK;
436 : }
437 :
438 0 : status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
439 0 : if (mSyncSampleOffset >= 0 || data_size < 8) {
440 0 : return ERROR_MALFORMED;
441 : }
442 :
443 0 : mSyncSampleOffset = data_offset;
444 :
445 : uint8_t header[8];
446 0 : if (mDataSource->readAt(
447 0 : data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
448 0 : return ERROR_IO;
449 : }
450 :
451 0 : if (U32_AT(header) != 0) {
452 : // Expected version = 0, flags = 0.
453 0 : return ERROR_MALFORMED;
454 : }
455 :
456 0 : mNumSyncSamples = U32_AT(&header[4]);
457 0 : if (mNumSyncSamples > kMAX_ALLOCATION / sizeof(uint32_t)) {
458 : // Avoid later overflow.
459 0 : return ERROR_MALFORMED;
460 : }
461 :
462 0 : if (mNumSyncSamples < 2) {
463 : ALOGV("Table of sync samples is empty or has only a single entry!");
464 : }
465 :
466 0 : mSyncSamples = new (mozilla::fallible) uint32_t[mNumSyncSamples];
467 0 : if (!mSyncSamples) {
468 0 : return ERROR_BUFFER_TOO_SMALL;
469 : }
470 0 : size_t size = mNumSyncSamples * sizeof(uint32_t);
471 0 : if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
472 0 : != (ssize_t)size) {
473 0 : return ERROR_IO;
474 : }
475 :
476 0 : for (size_t i = 0; i < mNumSyncSamples; ++i) {
477 0 : mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
478 : }
479 :
480 0 : return OK;
481 : }
482 :
483 : static status_t
484 0 : validateCencBoxHeader(
485 : sp<DataSource>& data_source, off64_t& data_offset,
486 : uint8_t* out_version, uint32_t* out_aux_type) {
487 0 : *out_aux_type = 0;
488 :
489 0 : if (data_source->readAt(data_offset++, out_version, 1) < 1) {
490 0 : ALOGE("error reading sample aux info header");
491 0 : return ERROR_IO;
492 : }
493 :
494 : uint32_t flags;
495 0 : if (!data_source->getUInt24(data_offset, &flags)) {
496 0 : ALOGE("error reading sample aux info flags");
497 0 : return ERROR_IO;
498 : }
499 0 : data_offset += 3;
500 :
501 0 : if (flags & 1) {
502 : uint32_t aux_type;
503 : uint32_t aux_param;
504 0 : if (!data_source->getUInt32(data_offset, &aux_type) ||
505 0 : !data_source->getUInt32(data_offset + 4, &aux_param)) {
506 0 : ALOGE("error reading aux info type");
507 0 : return ERROR_IO;
508 : }
509 0 : data_offset += 8;
510 0 : *out_aux_type = aux_type;
511 : }
512 :
513 0 : return OK;
514 : }
515 :
516 : status_t
517 0 : SampleTable::setSampleAuxiliaryInformationSizeParams(
518 : off64_t data_offset, size_t data_size, uint32_t drm_scheme) {
519 0 : off64_t data_end = data_offset + data_size;
520 :
521 : uint8_t version;
522 : uint32_t aux_type;
523 0 : status_t err = validateCencBoxHeader(
524 0 : mDataSource, data_offset, &version, &aux_type);
525 0 : if (err != OK) {
526 0 : return err;
527 : }
528 :
529 0 : if (aux_type && aux_type != kAuxTypeCenc && drm_scheme != kAuxTypeCenc) {
530 : // Quietly skip aux types we don't care about.
531 0 : return OK;
532 : }
533 :
534 0 : if (!mCencSizes.IsEmpty() || mCencDefaultSize) {
535 0 : ALOGE("duplicate cenc saiz box");
536 0 : return ERROR_MALFORMED;
537 : }
538 :
539 0 : if (version) {
540 : ALOGV("unsupported cenc saiz version");
541 0 : return ERROR_UNSUPPORTED;
542 : }
543 :
544 0 : if (mDataSource->readAt(
545 0 : data_offset++, &mCencDefaultSize, sizeof(mCencDefaultSize))
546 : < sizeof(mCencDefaultSize)) {
547 0 : return ERROR_IO;
548 : }
549 :
550 0 : if (!mDataSource->getUInt32(data_offset, &mCencInfoCount)) {
551 0 : return ERROR_IO;
552 : }
553 0 : data_offset += 4;
554 :
555 0 : if (!mCencDefaultSize) {
556 0 : if (!mCencSizes.InsertElementsAt(0, mCencInfoCount, mozilla::fallible)) {
557 0 : return ERROR_IO;
558 : }
559 0 : if (mDataSource->readAt(
560 0 : data_offset, mCencSizes.Elements(), mCencInfoCount)
561 0 : < mCencInfoCount) {
562 0 : return ERROR_IO;
563 : }
564 0 : data_offset += mCencInfoCount;
565 : }
566 :
567 0 : if (data_offset != data_end) {
568 0 : ALOGW("wrong saiz data size, expected %" PRIuSIZE ", actual %" PRIu64,
569 0 : data_size, uint64_t(data_offset - (data_end - data_size)));
570 : // Continue, assume extra data is not important.
571 : // Parser will skip past the box end.
572 : }
573 :
574 0 : return parseSampleCencInfo();
575 : }
576 :
577 : status_t
578 0 : SampleTable::setSampleAuxiliaryInformationOffsetParams(
579 : off64_t data_offset, size_t data_size, uint32_t drm_scheme) {
580 0 : off64_t data_end = data_offset + data_size;
581 :
582 : uint8_t version;
583 : uint32_t aux_type;
584 0 : status_t err = validateCencBoxHeader(mDataSource, data_offset,
585 0 : &version, &aux_type);
586 0 : if (err != OK) {
587 0 : return err;
588 : }
589 :
590 0 : if (aux_type && aux_type != kAuxTypeCenc && drm_scheme != kAuxTypeCenc) {
591 : // Quietly skip aux types we don't care about.
592 0 : return OK;
593 : }
594 :
595 0 : if (!mCencOffsets.IsEmpty()) {
596 0 : ALOGE("duplicate cenc saio box");
597 0 : return ERROR_MALFORMED;
598 : }
599 :
600 : uint32_t cencOffsetCount;
601 0 : if (!mDataSource->getUInt32(data_offset, &cencOffsetCount)) {
602 0 : ALOGE("error reading cenc aux info offset count");
603 0 : return ERROR_IO;
604 : }
605 0 : data_offset += 4;
606 :
607 0 : if (cencOffsetCount >= kMAX_ALLOCATION) {
608 0 : return ERROR_MALFORMED;
609 : }
610 0 : if (!version) {
611 0 : if (!mCencOffsets.SetCapacity(cencOffsetCount, mozilla::fallible)) {
612 0 : return ERROR_MALFORMED;
613 : }
614 0 : for (uint32_t i = 0; i < cencOffsetCount; i++) {
615 : uint32_t tmp;
616 0 : if (!mDataSource->getUInt32(data_offset, &tmp)) {
617 0 : ALOGE("error reading cenc aux info offsets");
618 0 : return ERROR_IO;
619 : }
620 : // FIXME: Make this infallible after bug 968520 is done.
621 0 : MOZ_ALWAYS_TRUE(mCencOffsets.AppendElement(tmp, mozilla::fallible));
622 0 : data_offset += 4;
623 : }
624 : } else {
625 0 : if (!mCencOffsets.SetLength(cencOffsetCount, mozilla::fallible)) {
626 0 : return ERROR_MALFORMED;
627 : }
628 0 : for (uint32_t i = 0; i < cencOffsetCount; i++) {
629 0 : if (!mDataSource->getUInt64(data_offset, &mCencOffsets[i])) {
630 0 : ALOGE("error reading cenc aux info offsets");
631 0 : return ERROR_IO;
632 : }
633 0 : data_offset += 8;
634 : }
635 : }
636 :
637 0 : if (data_offset != data_end) {
638 0 : ALOGW("wrong saio data size, expected %" PRIuSIZE ", actual %" PRIu64,
639 0 : data_size, uint64_t(data_offset - (data_end - data_size)));
640 : // Continue, assume extra data is not important.
641 : // Parser will skip past the box end.
642 : }
643 :
644 0 : return parseSampleCencInfo();
645 : }
646 :
647 : status_t
648 0 : SampleTable::parseSampleCencInfo() {
649 0 : if ((!mCencDefaultSize && !mCencInfoCount) || mCencOffsets.IsEmpty()) {
650 : // We don't have all the cenc information we need yet. Quietly fail and
651 : // hope we get the data we need later in the track header.
652 : ALOGV("Got half of cenc saio/saiz pair. Deferring parse until we get the other half.");
653 0 : return OK;
654 : }
655 :
656 0 : if ((mCencOffsets.Length() > 1 && mCencOffsets.Length() < mCencInfoCount) ||
657 0 : (!mCencDefaultSize && mCencSizes.Length() < mCencInfoCount)) {
658 0 : return ERROR_MALFORMED;
659 : }
660 :
661 0 : if (mCencInfoCount > kMAX_ALLOCATION / sizeof(SampleCencInfo)) {
662 : // Avoid future OOM.
663 0 : return ERROR_MALFORMED;
664 : }
665 :
666 0 : mCencInfo = new (mozilla::fallible) SampleCencInfo[mCencInfoCount];
667 0 : if (!mCencInfo) {
668 0 : return ERROR_BUFFER_TOO_SMALL;
669 : }
670 0 : for (uint32_t i = 0; i < mCencInfoCount; i++) {
671 0 : mCencInfo[i].mSubsamples = NULL;
672 : }
673 :
674 0 : uint64_t nextOffset = mCencOffsets[0];
675 0 : for (uint32_t i = 0; i < mCencInfoCount; i++) {
676 0 : uint8_t size = mCencDefaultSize ? mCencDefaultSize : mCencSizes[i];
677 0 : uint64_t offset = mCencOffsets.Length() == 1 ? nextOffset : mCencOffsets[i];
678 0 : nextOffset = offset + size;
679 :
680 0 : auto& info = mCencInfo[i];
681 :
682 0 : if (size < IV_BYTES) {
683 0 : ALOGE("cenc aux info too small");
684 0 : return ERROR_MALFORMED;
685 : }
686 :
687 0 : if (mDataSource->readAt(offset, info.mIV, IV_BYTES) < IV_BYTES) {
688 0 : ALOGE("couldn't read init vector");
689 0 : return ERROR_IO;
690 : }
691 0 : offset += IV_BYTES;
692 :
693 0 : if (size == IV_BYTES) {
694 0 : info.mSubsampleCount = 0;
695 0 : continue;
696 : }
697 :
698 0 : if (size < IV_BYTES + sizeof(info.mSubsampleCount)) {
699 0 : ALOGE("subsample count overflows sample aux info buffer");
700 0 : return ERROR_MALFORMED;
701 : }
702 :
703 0 : if (!mDataSource->getUInt16(offset, &info.mSubsampleCount)) {
704 0 : ALOGE("error reading sample cenc info subsample count");
705 0 : return ERROR_IO;
706 : }
707 0 : offset += sizeof(info.mSubsampleCount);
708 :
709 0 : if (size < IV_BYTES + sizeof(info.mSubsampleCount) + info.mSubsampleCount * 6) {
710 0 : ALOGE("subsample descriptions overflow sample aux info buffer");
711 0 : return ERROR_MALFORMED;
712 : }
713 :
714 0 : info.mSubsamples = new (mozilla::fallible) SampleCencInfo::SubsampleSizes[info.mSubsampleCount];
715 0 : if (!info.mSubsamples) {
716 0 : return ERROR_BUFFER_TOO_SMALL;
717 : }
718 0 : for (uint16_t j = 0; j < info.mSubsampleCount; j++) {
719 0 : auto& subsample = info.mSubsamples[j];
720 0 : if (!mDataSource->getUInt16(offset, &subsample.mClearBytes) ||
721 0 : !mDataSource->getUInt32(offset + sizeof(subsample.mClearBytes),
722 : &subsample.mCipherBytes)) {
723 0 : ALOGE("error reading cenc subsample aux info");
724 0 : return ERROR_IO;
725 : }
726 0 : offset += 6;
727 : }
728 : }
729 :
730 0 : return OK;
731 : }
732 :
733 0 : uint32_t SampleTable::countChunkOffsets() const {
734 0 : return mNumChunkOffsets;
735 : }
736 :
737 0 : uint32_t SampleTable::countSamples() const {
738 0 : return mNumSampleSizes;
739 : }
740 :
741 0 : status_t SampleTable::getMaxSampleSize(size_t *max_size) {
742 0 : Mutex::Autolock autoLock(mLock);
743 :
744 0 : *max_size = 0;
745 :
746 0 : for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
747 : size_t sample_size;
748 0 : status_t err = getSampleSize_l(i, &sample_size);
749 :
750 0 : if (err != OK) {
751 0 : return err;
752 : }
753 :
754 0 : if (sample_size > *max_size) {
755 0 : *max_size = sample_size;
756 : }
757 : }
758 :
759 0 : return OK;
760 : }
761 :
762 0 : uint32_t abs_difference(uint32_t time1, uint32_t time2) {
763 0 : return time1 > time2 ? time1 - time2 : time2 - time1;
764 : }
765 :
766 : // static
767 0 : int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
768 0 : const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
769 0 : const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
770 :
771 0 : if (a->mCompositionTime < b->mCompositionTime) {
772 0 : return -1;
773 0 : } else if (a->mCompositionTime > b->mCompositionTime) {
774 0 : return 1;
775 : }
776 :
777 0 : return 0;
778 : }
779 :
780 0 : status_t SampleTable::buildSampleEntriesTable() {
781 0 : Mutex::Autolock autoLock(mLock);
782 :
783 0 : if (mSampleTimeEntries != NULL) {
784 0 : return OK;
785 : }
786 :
787 0 : mSampleTimeEntries = new (mozilla::fallible) SampleTimeEntry[mNumSampleSizes];
788 0 : if (!mSampleTimeEntries) {
789 0 : return ERROR_BUFFER_TOO_SMALL;
790 : }
791 :
792 0 : uint32_t sampleIndex = 0;
793 0 : uint32_t sampleTime = 0;
794 :
795 0 : for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
796 0 : uint32_t n = mTimeToSample[2 * i];
797 0 : uint32_t delta = mTimeToSample[2 * i + 1];
798 :
799 0 : for (uint32_t j = 0; j < n; ++j) {
800 0 : if (sampleIndex < mNumSampleSizes) {
801 : // Technically this should always be the case if the file
802 : // is well-formed, but you know... there's (gasp) malformed
803 : // content out there.
804 :
805 0 : mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
806 :
807 : uint32_t compTimeDelta =
808 0 : mCompositionDeltaLookup->getCompositionTimeOffset(
809 0 : sampleIndex);
810 :
811 0 : mSampleTimeEntries[sampleIndex].mCompositionTime =
812 0 : sampleTime + compTimeDelta;
813 : }
814 :
815 0 : ++sampleIndex;
816 0 : sampleTime += delta;
817 : }
818 : }
819 :
820 0 : qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
821 0 : CompareIncreasingTime);
822 0 : return OK;
823 : }
824 :
825 0 : status_t SampleTable::findSampleAtTime(
826 : uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
827 0 : status_t err = buildSampleEntriesTable();
828 0 : if (err != OK) {
829 0 : return err;
830 : }
831 :
832 0 : uint32_t left = 0;
833 0 : uint32_t right = mNumSampleSizes;
834 0 : while (left < right) {
835 0 : uint32_t center = (left + right) / 2;
836 0 : uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
837 :
838 0 : if (req_time < centerTime) {
839 0 : right = center;
840 0 : } else if (req_time > centerTime) {
841 0 : left = center + 1;
842 : } else {
843 0 : left = center;
844 0 : break;
845 : }
846 : }
847 :
848 0 : if (left == mNumSampleSizes) {
849 0 : if (flags == kFlagAfter) {
850 0 : return ERROR_OUT_OF_RANGE;
851 : }
852 :
853 0 : --left;
854 : }
855 :
856 0 : uint32_t closestIndex = left;
857 :
858 0 : switch (flags) {
859 : case kFlagBefore:
860 : {
861 0 : while (closestIndex > 0
862 0 : && mSampleTimeEntries[closestIndex].mCompositionTime
863 : > req_time) {
864 0 : --closestIndex;
865 : }
866 0 : break;
867 : }
868 :
869 : case kFlagAfter:
870 : {
871 0 : while (closestIndex + 1 < mNumSampleSizes
872 0 : && mSampleTimeEntries[closestIndex].mCompositionTime
873 : < req_time) {
874 0 : ++closestIndex;
875 : }
876 0 : break;
877 : }
878 :
879 : default:
880 : {
881 0 : CHECK(flags == kFlagClosest);
882 :
883 0 : if (closestIndex > 0) {
884 : // Check left neighbour and pick closest.
885 : uint32_t absdiff1 =
886 0 : abs_difference(
887 0 : mSampleTimeEntries[closestIndex].mCompositionTime,
888 0 : req_time);
889 :
890 : uint32_t absdiff2 =
891 0 : abs_difference(
892 0 : mSampleTimeEntries[closestIndex - 1].mCompositionTime,
893 0 : req_time);
894 :
895 0 : if (absdiff1 > absdiff2) {
896 0 : closestIndex = closestIndex - 1;
897 : }
898 : }
899 :
900 0 : break;
901 : }
902 : }
903 :
904 0 : *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
905 :
906 0 : return OK;
907 : }
908 :
909 0 : status_t SampleTable::findSyncSampleNear(
910 : uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
911 0 : Mutex::Autolock autoLock(mLock);
912 :
913 0 : *sample_index = 0;
914 :
915 0 : if (mSyncSampleOffset < 0) {
916 : // All samples are sync-samples.
917 0 : *sample_index = start_sample_index;
918 0 : return OK;
919 : }
920 :
921 0 : if (mNumSyncSamples == 0) {
922 0 : *sample_index = 0;
923 0 : return OK;
924 : }
925 :
926 0 : uint32_t left = 0;
927 0 : uint32_t right = mNumSyncSamples;
928 0 : while (left < right) {
929 0 : uint32_t center = left + (right - left) / 2;
930 0 : uint32_t x = mSyncSamples[center];
931 :
932 0 : if (start_sample_index < x) {
933 0 : right = center;
934 0 : } else if (start_sample_index > x) {
935 0 : left = center + 1;
936 : } else {
937 0 : left = center;
938 0 : break;
939 : }
940 : }
941 0 : if (left == mNumSyncSamples) {
942 0 : if (flags == kFlagAfter) {
943 0 : ALOGE("tried to find a sync frame after the last one: %d", left);
944 0 : return ERROR_OUT_OF_RANGE;
945 : }
946 0 : left = left - 1;
947 : }
948 :
949 : // Now ssi[left] is the sync sample index just before (or at)
950 : // start_sample_index.
951 : // Also start_sample_index < ssi[left + 1], if left + 1 < mNumSyncSamples.
952 :
953 0 : uint32_t x = mSyncSamples[left];
954 :
955 0 : if (left + 1 < mNumSyncSamples) {
956 0 : uint32_t y = mSyncSamples[left + 1];
957 :
958 : // our sample lies between sync samples x and y.
959 :
960 0 : status_t err = mSampleIterator->seekTo(start_sample_index);
961 0 : if (err != OK) {
962 0 : return err;
963 : }
964 :
965 0 : uint32_t sample_time = mSampleIterator->getSampleTime();
966 :
967 0 : err = mSampleIterator->seekTo(x);
968 0 : if (err != OK) {
969 0 : return err;
970 : }
971 0 : uint32_t x_time = mSampleIterator->getSampleTime();
972 :
973 0 : err = mSampleIterator->seekTo(y);
974 0 : if (err != OK) {
975 0 : return err;
976 : }
977 :
978 0 : uint32_t y_time = mSampleIterator->getSampleTime();
979 :
980 0 : if (abs_difference(x_time, sample_time)
981 0 : > abs_difference(y_time, sample_time)) {
982 : // Pick the sync sample closest (timewise) to the start-sample.
983 0 : x = y;
984 0 : ++left;
985 : }
986 : }
987 :
988 0 : switch (flags) {
989 : case kFlagBefore:
990 : {
991 0 : if (x > start_sample_index) {
992 0 : CHECK(left > 0);
993 :
994 0 : x = mSyncSamples[left - 1];
995 :
996 0 : if (x > start_sample_index) {
997 : // The table of sync sample indices was not sorted
998 : // properly.
999 0 : return ERROR_MALFORMED;
1000 : }
1001 : }
1002 0 : break;
1003 : }
1004 :
1005 : case kFlagAfter:
1006 : {
1007 0 : if (x < start_sample_index) {
1008 0 : if (left + 1 >= mNumSyncSamples) {
1009 0 : return ERROR_OUT_OF_RANGE;
1010 : }
1011 :
1012 0 : x = mSyncSamples[left + 1];
1013 :
1014 0 : if (x < start_sample_index) {
1015 : // The table of sync sample indices was not sorted
1016 : // properly.
1017 0 : return ERROR_MALFORMED;
1018 : }
1019 : }
1020 :
1021 0 : break;
1022 : }
1023 :
1024 : default:
1025 0 : break;
1026 : }
1027 :
1028 0 : *sample_index = x;
1029 :
1030 0 : return OK;
1031 : }
1032 :
1033 0 : status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
1034 0 : Mutex::Autolock autoLock(mLock);
1035 :
1036 0 : if (mSyncSampleOffset < 0) {
1037 : // All samples are sync-samples.
1038 0 : *sample_index = 0;
1039 0 : return OK;
1040 : }
1041 :
1042 0 : uint32_t bestSampleIndex = 0;
1043 0 : size_t maxSampleSize = 0;
1044 :
1045 : static const size_t kMaxNumSyncSamplesToScan = 20;
1046 :
1047 : // Consider the first kMaxNumSyncSamplesToScan sync samples and
1048 : // pick the one with the largest (compressed) size as the thumbnail.
1049 :
1050 0 : size_t numSamplesToScan = mNumSyncSamples;
1051 0 : if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
1052 0 : numSamplesToScan = kMaxNumSyncSamplesToScan;
1053 : }
1054 :
1055 0 : for (size_t i = 0; i < numSamplesToScan; ++i) {
1056 0 : uint32_t x = mSyncSamples[i];
1057 :
1058 : // Now x is a sample index.
1059 : size_t sampleSize;
1060 0 : status_t err = getSampleSize_l(x, &sampleSize);
1061 0 : if (err != OK) {
1062 0 : return err;
1063 : }
1064 :
1065 0 : if (i == 0 || sampleSize > maxSampleSize) {
1066 0 : bestSampleIndex = x;
1067 0 : maxSampleSize = sampleSize;
1068 : }
1069 : }
1070 :
1071 0 : *sample_index = bestSampleIndex;
1072 :
1073 0 : return OK;
1074 : }
1075 :
1076 0 : status_t SampleTable::getSampleSize_l(
1077 : uint32_t sampleIndex, size_t *sampleSize) {
1078 0 : return mSampleIterator->getSampleSizeDirect(
1079 0 : sampleIndex, sampleSize);
1080 : }
1081 :
1082 0 : status_t SampleTable::getMetaDataForSample(
1083 : uint32_t sampleIndex,
1084 : off64_t *offset,
1085 : size_t *size,
1086 : uint32_t *compositionTime,
1087 : uint32_t *duration,
1088 : bool *isSyncSample,
1089 : uint32_t *decodeTime) {
1090 0 : Mutex::Autolock autoLock(mLock);
1091 :
1092 : status_t err;
1093 0 : if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
1094 0 : return err;
1095 : }
1096 :
1097 0 : if (offset) {
1098 0 : *offset = mSampleIterator->getSampleOffset();
1099 : }
1100 :
1101 0 : if (size) {
1102 0 : *size = mSampleIterator->getSampleSize();
1103 : }
1104 :
1105 0 : if (compositionTime) {
1106 0 : *compositionTime = mSampleIterator->getSampleTime();
1107 : }
1108 :
1109 0 : if (decodeTime) {
1110 0 : *decodeTime = mSampleIterator->getSampleDecodeTime();
1111 : }
1112 :
1113 0 : if (duration) {
1114 0 : *duration = mSampleIterator->getSampleDuration();
1115 : }
1116 :
1117 0 : if (isSyncSample) {
1118 0 : *isSyncSample = false;
1119 0 : if (mSyncSampleOffset < 0) {
1120 : // Every sample is a sync sample.
1121 0 : *isSyncSample = true;
1122 : } else {
1123 0 : size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
1124 0 : && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
1125 0 : ? mLastSyncSampleIndex : 0;
1126 :
1127 0 : while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
1128 0 : ++i;
1129 : }
1130 :
1131 0 : if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
1132 0 : *isSyncSample = true;
1133 : }
1134 :
1135 0 : mLastSyncSampleIndex = i;
1136 : }
1137 : }
1138 :
1139 0 : return OK;
1140 : }
1141 :
1142 0 : uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
1143 0 : return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
1144 : }
1145 :
1146 : status_t
1147 0 : SampleTable::getSampleCencInfo(
1148 : uint32_t sample_index, nsTArray<uint16_t>& clear_sizes,
1149 : nsTArray<uint32_t>& cipher_sizes, uint8_t iv[]) {
1150 0 : CHECK(clear_sizes.IsEmpty() && cipher_sizes.IsEmpty());
1151 :
1152 0 : if (sample_index >= mCencInfoCount) {
1153 0 : ALOGE("cenc info requested for out of range sample index");
1154 0 : return ERROR_MALFORMED;
1155 : }
1156 :
1157 0 : auto& info = mCencInfo[sample_index];
1158 0 : clear_sizes.SetCapacity(info.mSubsampleCount);
1159 0 : cipher_sizes.SetCapacity(info.mSubsampleCount);
1160 :
1161 0 : for (uint32_t i = 0; i < info.mSubsampleCount; i++) {
1162 0 : clear_sizes.AppendElement(info.mSubsamples[i].mClearBytes);
1163 0 : cipher_sizes.AppendElement(info.mSubsamples[i].mCipherBytes);
1164 : }
1165 :
1166 0 : memcpy(iv, info.mIV, IV_BYTES);
1167 :
1168 0 : return OK;
1169 : }
1170 :
1171 : } // namespace stagefright
1172 :
1173 : #undef LOG_TAG
|