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 #define LOG_TAG "SampleTable"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <limits>
22
23 #include "SampleTable.h"
24 #include "SampleIterator.h"
25
26 #include <arpa/inet.h>
27
28 #include <media/DataSourceBase.h>
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <media/stagefright/foundation/ByteUtils.h>
31
32 /* TODO: remove after being merged into other branches */
33 #ifndef UINT32_MAX
34 #define UINT32_MAX (4294967295U)
35 #endif
36
37 namespace android {
38
39 // static
40 const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
41 // static
42 const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
43 // static
44 const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
45 // static
46 const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
47
48 ////////////////////////////////////////////////////////////////////////////////
49
50 const off64_t kMaxOffset = std::numeric_limits<off64_t>::max();
51
52 struct SampleTable::CompositionDeltaLookup {
53 CompositionDeltaLookup();
54
55 void setEntries(
56 const int32_t *deltaEntries, size_t numDeltaEntries);
57
58 int32_t getCompositionTimeOffset(uint32_t sampleIndex);
59
60 private:
61 Mutex mLock;
62
63 const int32_t *mDeltaEntries;
64 size_t mNumDeltaEntries;
65
66 size_t mCurrentDeltaEntry;
67 size_t mCurrentEntrySampleIndex;
68
69 DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup);
70 };
71
CompositionDeltaLookup()72 SampleTable::CompositionDeltaLookup::CompositionDeltaLookup()
73 : mDeltaEntries(NULL),
74 mNumDeltaEntries(0),
75 mCurrentDeltaEntry(0),
76 mCurrentEntrySampleIndex(0) {
77 }
78
setEntries(const int32_t * deltaEntries,size_t numDeltaEntries)79 void SampleTable::CompositionDeltaLookup::setEntries(
80 const int32_t *deltaEntries, size_t numDeltaEntries) {
81 Mutex::Autolock autolock(mLock);
82
83 mDeltaEntries = deltaEntries;
84 mNumDeltaEntries = numDeltaEntries;
85 mCurrentDeltaEntry = 0;
86 mCurrentEntrySampleIndex = 0;
87 }
88
getCompositionTimeOffset(uint32_t sampleIndex)89 int32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset(
90 uint32_t sampleIndex) {
91 Mutex::Autolock autolock(mLock);
92
93 if (mDeltaEntries == NULL) {
94 return 0;
95 }
96
97 if (sampleIndex < mCurrentEntrySampleIndex) {
98 mCurrentDeltaEntry = 0;
99 mCurrentEntrySampleIndex = 0;
100 }
101
102 while (mCurrentDeltaEntry < mNumDeltaEntries) {
103 uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry];
104 if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) {
105 return mDeltaEntries[2 * mCurrentDeltaEntry + 1];
106 }
107
108 mCurrentEntrySampleIndex += sampleCount;
109 ++mCurrentDeltaEntry;
110 }
111
112 return 0;
113 }
114
115 ////////////////////////////////////////////////////////////////////////////////
116
SampleTable(DataSourceBase * source)117 SampleTable::SampleTable(DataSourceBase *source)
118 : mDataSource(source),
119 mChunkOffsetOffset(-1),
120 mChunkOffsetType(0),
121 mNumChunkOffsets(0),
122 mSampleToChunkOffset(-1),
123 mNumSampleToChunkOffsets(0),
124 mSampleSizeOffset(-1),
125 mSampleSizeFieldSize(0),
126 mDefaultSampleSize(0),
127 mNumSampleSizes(0),
128 mHasTimeToSample(false),
129 mTimeToSampleCount(0),
130 mTimeToSample(NULL),
131 mSampleTimeEntries(NULL),
132 mCompositionTimeDeltaEntries(NULL),
133 mNumCompositionTimeDeltaEntries(0),
134 mCompositionDeltaLookup(new CompositionDeltaLookup),
135 mSyncSampleOffset(-1),
136 mNumSyncSamples(0),
137 mSyncSamples(NULL),
138 mLastSyncSampleIndex(0),
139 mSampleToChunkEntries(NULL),
140 mTotalSize(0) {
141 mSampleIterator = new SampleIterator(this);
142 }
143
~SampleTable()144 SampleTable::~SampleTable() {
145 delete[] mSampleToChunkEntries;
146 mSampleToChunkEntries = NULL;
147
148 delete[] mSyncSamples;
149 mSyncSamples = NULL;
150
151 delete[] mTimeToSample;
152 mTimeToSample = NULL;
153
154 delete mCompositionDeltaLookup;
155 mCompositionDeltaLookup = NULL;
156
157 delete[] mCompositionTimeDeltaEntries;
158 mCompositionTimeDeltaEntries = NULL;
159
160 delete[] mSampleTimeEntries;
161 mSampleTimeEntries = NULL;
162
163 delete mSampleIterator;
164 mSampleIterator = NULL;
165 }
166
isValid() const167 bool SampleTable::isValid() const {
168 return mChunkOffsetOffset >= 0
169 && mSampleToChunkOffset >= 0
170 && mSampleSizeOffset >= 0
171 && mHasTimeToSample;
172 }
173
setChunkOffsetParams(uint32_t type,off64_t data_offset,size_t data_size)174 status_t SampleTable::setChunkOffsetParams(
175 uint32_t type, off64_t data_offset, size_t data_size) {
176 if (mChunkOffsetOffset >= 0) {
177 return ERROR_MALFORMED;
178 }
179
180 CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
181
182 mChunkOffsetOffset = data_offset;
183 mChunkOffsetType = type;
184
185 if (data_size < 8) {
186 return ERROR_MALFORMED;
187 }
188
189 uint8_t header[8];
190 if (mDataSource->readAt(
191 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
192 return ERROR_IO;
193 }
194
195 if (U32_AT(header) != 0) {
196 // Expected version = 0, flags = 0.
197 return ERROR_MALFORMED;
198 }
199
200 mNumChunkOffsets = U32_AT(&header[4]);
201
202 if (mChunkOffsetType == kChunkOffsetType32) {
203 if ((data_size - 8) / 4 < mNumChunkOffsets) {
204 return ERROR_MALFORMED;
205 }
206 } else {
207 if ((data_size - 8) / 8 < mNumChunkOffsets) {
208 return ERROR_MALFORMED;
209 }
210 }
211
212 return OK;
213 }
214
setSampleToChunkParams(off64_t data_offset,size_t data_size)215 status_t SampleTable::setSampleToChunkParams(
216 off64_t data_offset, size_t data_size) {
217 if (mSampleToChunkOffset >= 0) {
218 // already set
219 return ERROR_MALFORMED;
220 }
221
222 if (data_offset < 0) {
223 return ERROR_MALFORMED;
224 }
225
226 mSampleToChunkOffset = data_offset;
227
228 if (data_size < 8) {
229 return ERROR_MALFORMED;
230 }
231
232 uint8_t header[8];
233 if (mDataSource->readAt(
234 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
235 return ERROR_IO;
236 }
237
238 if (U32_AT(header) != 0) {
239 // Expected version = 0, flags = 0.
240 return ERROR_MALFORMED;
241 }
242
243 mNumSampleToChunkOffsets = U32_AT(&header[4]);
244
245 if ((data_size - 8) / sizeof(SampleToChunkEntry) < mNumSampleToChunkOffsets) {
246 return ERROR_MALFORMED;
247 }
248
249 if ((uint64_t)kMaxTotalSize / sizeof(SampleToChunkEntry) <=
250 (uint64_t)mNumSampleToChunkOffsets) {
251 ALOGE("Sample-to-chunk table size too large.");
252 return ERROR_OUT_OF_RANGE;
253 }
254
255 mTotalSize += (uint64_t)mNumSampleToChunkOffsets *
256 sizeof(SampleToChunkEntry);
257 if (mTotalSize > kMaxTotalSize) {
258 ALOGE("Sample-to-chunk table size would make sample table too large.\n"
259 " Requested sample-to-chunk table size = %llu\n"
260 " Eventual sample table size >= %llu\n"
261 " Allowed sample table size = %llu\n",
262 (unsigned long long)mNumSampleToChunkOffsets *
263 sizeof(SampleToChunkEntry),
264 (unsigned long long)mTotalSize,
265 (unsigned long long)kMaxTotalSize);
266 return ERROR_OUT_OF_RANGE;
267 }
268
269 mSampleToChunkEntries =
270 new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets];
271 if (!mSampleToChunkEntries) {
272 ALOGE("Cannot allocate sample-to-chunk table with %llu entries.",
273 (unsigned long long)mNumSampleToChunkOffsets);
274 return ERROR_OUT_OF_RANGE;
275 }
276
277 if (mNumSampleToChunkOffsets == 0) {
278 return OK;
279 }
280
281 if ((off64_t)(kMaxOffset - 8 -
282 ((mNumSampleToChunkOffsets - 1) * sizeof(SampleToChunkEntry)))
283 < mSampleToChunkOffset) {
284 return ERROR_MALFORMED;
285 }
286
287 for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
288 uint8_t buffer[sizeof(SampleToChunkEntry)];
289
290 if (mDataSource->readAt(
291 mSampleToChunkOffset + 8 + i * sizeof(SampleToChunkEntry),
292 buffer,
293 sizeof(buffer))
294 != (ssize_t)sizeof(buffer)) {
295 return ERROR_IO;
296 }
297 // chunk index is 1 based in the spec.
298 if (U32_AT(buffer) < 1) {
299 ALOGE("b/23534160");
300 return ERROR_OUT_OF_RANGE;
301 }
302
303 // We want the chunk index to be 0-based.
304 mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
305 mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
306 mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
307 }
308
309 return OK;
310 }
311
setSampleSizeParams(uint32_t type,off64_t data_offset,size_t data_size)312 status_t SampleTable::setSampleSizeParams(
313 uint32_t type, off64_t data_offset, size_t data_size) {
314 if (mSampleSizeOffset >= 0) {
315 return ERROR_MALFORMED;
316 }
317
318 CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
319
320 mSampleSizeOffset = data_offset;
321
322 if (data_size < 12) {
323 return ERROR_MALFORMED;
324 }
325
326 uint8_t header[12];
327 if (mDataSource->readAt(
328 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
329 return ERROR_IO;
330 }
331
332 if (U32_AT(header) != 0) {
333 // Expected version = 0, flags = 0.
334 return ERROR_MALFORMED;
335 }
336
337 mDefaultSampleSize = U32_AT(&header[4]);
338 mNumSampleSizes = U32_AT(&header[8]);
339 if (mNumSampleSizes > (UINT32_MAX - 12) / 16) {
340 ALOGE("b/23247055, mNumSampleSizes(%u)", mNumSampleSizes);
341 return ERROR_MALFORMED;
342 }
343
344 if (type == kSampleSizeType32) {
345 mSampleSizeFieldSize = 32;
346
347 if (mDefaultSampleSize != 0) {
348 return OK;
349 }
350
351 if (data_size < 12 + mNumSampleSizes * 4) {
352 return ERROR_MALFORMED;
353 }
354 } else {
355 if ((mDefaultSampleSize & 0xffffff00) != 0) {
356 // The high 24 bits are reserved and must be 0.
357 return ERROR_MALFORMED;
358 }
359
360 mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
361 mDefaultSampleSize = 0;
362
363 if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
364 && mSampleSizeFieldSize != 16) {
365 return ERROR_MALFORMED;
366 }
367
368 if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
369 return ERROR_MALFORMED;
370 }
371 }
372
373 return OK;
374 }
375
setTimeToSampleParams(off64_t data_offset,size_t data_size)376 status_t SampleTable::setTimeToSampleParams(
377 off64_t data_offset, size_t data_size) {
378 if (mHasTimeToSample || data_size < 8) {
379 return ERROR_MALFORMED;
380 }
381
382 uint8_t header[8];
383 if (mDataSource->readAt(
384 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
385 return ERROR_IO;
386 }
387
388 if (U32_AT(header) != 0) {
389 // Expected version = 0, flags = 0.
390 return ERROR_MALFORMED;
391 }
392
393 mTimeToSampleCount = U32_AT(&header[4]);
394 if (mTimeToSampleCount > UINT32_MAX / (2 * sizeof(uint32_t))) {
395 // Choose this bound because
396 // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
397 // time-to-sample entry in the time-to-sample table.
398 // 2) mTimeToSampleCount is the number of entries of the time-to-sample
399 // table.
400 // 3) We hope that the table size does not exceed UINT32_MAX.
401 ALOGE("Time-to-sample table size too large.");
402 return ERROR_OUT_OF_RANGE;
403 }
404
405 // Note: At this point, we know that mTimeToSampleCount * 2 will not
406 // overflow because of the above condition.
407
408 uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t);
409 mTotalSize += allocSize;
410 if (mTotalSize > kMaxTotalSize) {
411 ALOGE("Time-to-sample table size would make sample table too large.\n"
412 " Requested time-to-sample table size = %llu\n"
413 " Eventual sample table size >= %llu\n"
414 " Allowed sample table size = %llu\n",
415 (unsigned long long)allocSize,
416 (unsigned long long)mTotalSize,
417 (unsigned long long)kMaxTotalSize);
418 return ERROR_OUT_OF_RANGE;
419 }
420
421 mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2];
422 if (!mTimeToSample) {
423 ALOGE("Cannot allocate time-to-sample table with %llu entries.",
424 (unsigned long long)mTimeToSampleCount);
425 return ERROR_OUT_OF_RANGE;
426 }
427
428 if (mDataSource->readAt(data_offset + 8, mTimeToSample,
429 (size_t)allocSize) < (ssize_t)allocSize) {
430 ALOGE("Incomplete data read for time-to-sample table.");
431 return ERROR_IO;
432 }
433
434 for (size_t i = 0; i < mTimeToSampleCount * 2; ++i) {
435 mTimeToSample[i] = ntohl(mTimeToSample[i]);
436 }
437
438 mHasTimeToSample = true;
439 return OK;
440 }
441
442 // NOTE: per 14996-12, version 0 ctts contains unsigned values, while version 1
443 // contains signed values, however some software creates version 0 files that
444 // contain signed values, so we're always treating the values as signed,
445 // regardless of version.
setCompositionTimeToSampleParams(off64_t data_offset,size_t data_size)446 status_t SampleTable::setCompositionTimeToSampleParams(
447 off64_t data_offset, size_t data_size) {
448 ALOGI("There are reordered frames present.");
449
450 if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
451 return ERROR_MALFORMED;
452 }
453
454 uint8_t header[8];
455 if (mDataSource->readAt(
456 data_offset, header, sizeof(header))
457 < (ssize_t)sizeof(header)) {
458 return ERROR_IO;
459 }
460
461 uint32_t flags = U32_AT(header);
462 uint32_t version = flags >> 24;
463 flags &= 0xffffff;
464
465 if ((version != 0 && version != 1) || flags != 0) {
466 // Expected version = 0 or 1, flags = 0.
467 return ERROR_MALFORMED;
468 }
469
470 size_t numEntries = U32_AT(&header[4]);
471
472 if (((SIZE_MAX / 8) - 1 < numEntries) || (data_size != (numEntries + 1) * 8)) {
473 return ERROR_MALFORMED;
474 }
475
476 mNumCompositionTimeDeltaEntries = numEntries;
477 uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(int32_t);
478 if (allocSize > kMaxTotalSize) {
479 ALOGE("Composition-time-to-sample table size too large.");
480 return ERROR_OUT_OF_RANGE;
481 }
482
483 mTotalSize += allocSize;
484 if (mTotalSize > kMaxTotalSize) {
485 ALOGE("Composition-time-to-sample table would make sample table too large.\n"
486 " Requested composition-time-to-sample table size = %llu\n"
487 " Eventual sample table size >= %llu\n"
488 " Allowed sample table size = %llu\n",
489 (unsigned long long)allocSize,
490 (unsigned long long)mTotalSize,
491 (unsigned long long)kMaxTotalSize);
492 return ERROR_OUT_OF_RANGE;
493 }
494
495 mCompositionTimeDeltaEntries = new (std::nothrow) int32_t[2 * numEntries];
496 if (!mCompositionTimeDeltaEntries) {
497 ALOGE("Cannot allocate composition-time-to-sample table with %llu "
498 "entries.", (unsigned long long)numEntries);
499 return ERROR_OUT_OF_RANGE;
500 }
501
502 if (mDataSource->readAt(data_offset + 8, mCompositionTimeDeltaEntries,
503 (size_t)allocSize) < (ssize_t)allocSize) {
504 delete[] mCompositionTimeDeltaEntries;
505 mCompositionTimeDeltaEntries = NULL;
506
507 return ERROR_IO;
508 }
509
510 for (size_t i = 0; i < 2 * numEntries; ++i) {
511 mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
512 }
513
514 mCompositionDeltaLookup->setEntries(
515 mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
516
517 return OK;
518 }
519
setSyncSampleParams(off64_t data_offset,size_t data_size)520 status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
521 if (mSyncSampleOffset >= 0 || data_size < 8) {
522 return ERROR_MALFORMED;
523 }
524
525 uint8_t header[8];
526 if (mDataSource->readAt(
527 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
528 return ERROR_IO;
529 }
530
531 if (U32_AT(header) != 0) {
532 // Expected version = 0, flags = 0.
533 return ERROR_MALFORMED;
534 }
535
536 uint32_t numSyncSamples = U32_AT(&header[4]);
537
538 if (numSyncSamples < 2) {
539 ALOGV("Table of sync samples is empty or has only a single entry!");
540 }
541
542 uint64_t allocSize = (uint64_t)numSyncSamples * sizeof(uint32_t);
543 if (allocSize > kMaxTotalSize) {
544 ALOGE("Sync sample table size too large.");
545 return ERROR_OUT_OF_RANGE;
546 }
547
548 mTotalSize += allocSize;
549 if (mTotalSize > kMaxTotalSize) {
550 ALOGE("Sync sample table size would make sample table too large.\n"
551 " Requested sync sample table size = %llu\n"
552 " Eventual sample table size >= %llu\n"
553 " Allowed sample table size = %llu\n",
554 (unsigned long long)allocSize,
555 (unsigned long long)mTotalSize,
556 (unsigned long long)kMaxTotalSize);
557 return ERROR_OUT_OF_RANGE;
558 }
559
560 mSyncSamples = new (std::nothrow) uint32_t[numSyncSamples];
561 if (!mSyncSamples) {
562 ALOGE("Cannot allocate sync sample table with %llu entries.",
563 (unsigned long long)numSyncSamples);
564 return ERROR_OUT_OF_RANGE;
565 }
566
567 if (mDataSource->readAt(data_offset + 8, mSyncSamples,
568 (size_t)allocSize) != (ssize_t)allocSize) {
569 delete[] mSyncSamples;
570 mSyncSamples = NULL;
571 return ERROR_IO;
572 }
573
574 for (size_t i = 0; i < numSyncSamples; ++i) {
575 if (mSyncSamples[i] == 0) {
576 ALOGE("b/32423862, unexpected zero value in stss");
577 continue;
578 }
579 mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
580 }
581
582 mSyncSampleOffset = data_offset;
583 mNumSyncSamples = numSyncSamples;
584
585 return OK;
586 }
587
countChunkOffsets() const588 uint32_t SampleTable::countChunkOffsets() const {
589 return mNumChunkOffsets;
590 }
591
countSamples() const592 uint32_t SampleTable::countSamples() const {
593 return mNumSampleSizes;
594 }
595
getMaxSampleSize(size_t * max_size)596 status_t SampleTable::getMaxSampleSize(size_t *max_size) {
597 Mutex::Autolock autoLock(mLock);
598
599 *max_size = 0;
600
601 for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
602 size_t sample_size;
603 status_t err = getSampleSize_l(i, &sample_size);
604
605 if (err != OK) {
606 return err;
607 }
608
609 if (sample_size > *max_size) {
610 *max_size = sample_size;
611 }
612 }
613
614 return OK;
615 }
616
abs_difference(uint32_t time1,uint32_t time2)617 uint32_t abs_difference(uint32_t time1, uint32_t time2) {
618 return time1 > time2 ? time1 - time2 : time2 - time1;
619 }
620
621 // static
CompareIncreasingTime(const void * _a,const void * _b)622 int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
623 const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
624 const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
625
626 if (a->mCompositionTime < b->mCompositionTime) {
627 return -1;
628 } else if (a->mCompositionTime > b->mCompositionTime) {
629 return 1;
630 }
631
632 return 0;
633 }
634
buildSampleEntriesTable()635 void SampleTable::buildSampleEntriesTable() {
636 Mutex::Autolock autoLock(mLock);
637
638 if (mSampleTimeEntries != NULL || mNumSampleSizes == 0) {
639 if (mNumSampleSizes == 0) {
640 ALOGE("b/23247055, mNumSampleSizes(%u)", mNumSampleSizes);
641 }
642 return;
643 }
644
645 mTotalSize += (uint64_t)mNumSampleSizes * sizeof(SampleTimeEntry);
646 if (mTotalSize > kMaxTotalSize) {
647 ALOGE("Sample entry table size would make sample table too large.\n"
648 " Requested sample entry table size = %llu\n"
649 " Eventual sample table size >= %llu\n"
650 " Allowed sample table size = %llu\n",
651 (unsigned long long)mNumSampleSizes * sizeof(SampleTimeEntry),
652 (unsigned long long)mTotalSize,
653 (unsigned long long)kMaxTotalSize);
654 return;
655 }
656
657 mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
658 if (!mSampleTimeEntries) {
659 ALOGE("Cannot allocate sample entry table with %llu entries.",
660 (unsigned long long)mNumSampleSizes);
661 return;
662 }
663
664 uint32_t sampleIndex = 0;
665 uint32_t sampleTime = 0;
666
667 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
668 uint32_t n = mTimeToSample[2 * i];
669 uint32_t delta = mTimeToSample[2 * i + 1];
670
671 for (uint32_t j = 0; j < n; ++j) {
672 if (sampleIndex < mNumSampleSizes) {
673 // Technically this should always be the case if the file
674 // is well-formed, but you know... there's (gasp) malformed
675 // content out there.
676
677 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
678
679 int32_t compTimeDelta =
680 mCompositionDeltaLookup->getCompositionTimeOffset(
681 sampleIndex);
682
683 if ((compTimeDelta < 0 && sampleTime <
684 (compTimeDelta == INT32_MIN ?
685 INT32_MAX : uint32_t(-compTimeDelta)))
686 || (compTimeDelta > 0 &&
687 sampleTime > UINT32_MAX - compTimeDelta)) {
688 ALOGE("%u + %d would overflow, clamping",
689 sampleTime, compTimeDelta);
690 if (compTimeDelta < 0) {
691 sampleTime = 0;
692 } else {
693 sampleTime = UINT32_MAX;
694 }
695 compTimeDelta = 0;
696 }
697
698 mSampleTimeEntries[sampleIndex].mCompositionTime =
699 compTimeDelta > 0 ? sampleTime + compTimeDelta:
700 sampleTime - (-compTimeDelta);
701 }
702
703 ++sampleIndex;
704 if (sampleTime > UINT32_MAX - delta) {
705 ALOGE("%u + %u would overflow, clamping",
706 sampleTime, delta);
707 sampleTime = UINT32_MAX;
708 } else {
709 sampleTime += delta;
710 }
711 }
712 }
713
714 qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
715 CompareIncreasingTime);
716 }
717
findSampleAtTime(uint64_t req_time,uint64_t scale_num,uint64_t scale_den,uint32_t * sample_index,uint32_t flags)718 status_t SampleTable::findSampleAtTime(
719 uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
720 uint32_t *sample_index, uint32_t flags) {
721 buildSampleEntriesTable();
722
723 if (mSampleTimeEntries == NULL) {
724 return ERROR_OUT_OF_RANGE;
725 }
726
727 if (flags == kFlagFrameIndex) {
728 if (req_time >= mNumSampleSizes) {
729 return ERROR_OUT_OF_RANGE;
730 }
731 *sample_index = mSampleTimeEntries[req_time].mSampleIndex;
732 return OK;
733 }
734
735 uint32_t left = 0;
736 uint32_t right_plus_one = mNumSampleSizes;
737 while (left < right_plus_one) {
738 uint32_t center = left + (right_plus_one - left) / 2;
739 uint64_t centerTime =
740 getSampleTime(center, scale_num, scale_den);
741
742 if (req_time < centerTime) {
743 right_plus_one = center;
744 } else if (req_time > centerTime) {
745 left = center + 1;
746 } else {
747 *sample_index = mSampleTimeEntries[center].mSampleIndex;
748 return OK;
749 }
750 }
751
752 uint32_t closestIndex = left;
753
754 if (closestIndex == mNumSampleSizes) {
755 if (flags == kFlagAfter) {
756 return ERROR_OUT_OF_RANGE;
757 }
758 flags = kFlagBefore;
759 } else if (closestIndex == 0) {
760 if (flags == kFlagBefore) {
761 // normally we should return out of range, but that is
762 // treated as end-of-stream. instead return first sample
763 //
764 // return ERROR_OUT_OF_RANGE;
765 }
766 flags = kFlagAfter;
767 }
768
769 switch (flags) {
770 case kFlagBefore:
771 {
772 --closestIndex;
773 break;
774 }
775
776 case kFlagAfter:
777 {
778 // nothing to do
779 break;
780 }
781
782 default:
783 {
784 CHECK(flags == kFlagClosest);
785 // pick closest based on timestamp. use abs_difference for safety
786 if (abs_difference(
787 getSampleTime(closestIndex, scale_num, scale_den), req_time) >
788 abs_difference(
789 req_time, getSampleTime(closestIndex - 1, scale_num, scale_den))) {
790 --closestIndex;
791 }
792 break;
793 }
794 }
795
796 *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
797 return OK;
798 }
799
findSyncSampleNear(uint32_t start_sample_index,uint32_t * sample_index,uint32_t flags)800 status_t SampleTable::findSyncSampleNear(
801 uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
802 Mutex::Autolock autoLock(mLock);
803
804 *sample_index = 0;
805
806 if (mSyncSampleOffset < 0) {
807 // All samples are sync-samples.
808 *sample_index = start_sample_index;
809 return OK;
810 }
811
812 if (mNumSyncSamples == 0) {
813 *sample_index = 0;
814 return OK;
815 }
816
817 uint32_t left = 0;
818 uint32_t right_plus_one = mNumSyncSamples;
819 while (left < right_plus_one) {
820 uint32_t center = left + (right_plus_one - left) / 2;
821 uint32_t x = mSyncSamples[center];
822
823 if (start_sample_index < x) {
824 right_plus_one = center;
825 } else if (start_sample_index > x) {
826 left = center + 1;
827 } else {
828 *sample_index = x;
829 return OK;
830 }
831 }
832
833 if (left == mNumSyncSamples) {
834 if (flags == kFlagAfter) {
835 ALOGE("tried to find a sync frame after the last one: %d", left);
836 return ERROR_OUT_OF_RANGE;
837 }
838 flags = kFlagBefore;
839 }
840 else if (left == 0) {
841 if (flags == kFlagBefore) {
842 ALOGE("tried to find a sync frame before the first one: %d", left);
843
844 // normally we should return out of range, but that is
845 // treated as end-of-stream. instead seek to first sync
846 //
847 // return ERROR_OUT_OF_RANGE;
848 }
849 flags = kFlagAfter;
850 }
851
852 // Now ssi[left - 1] <(=) start_sample_index <= ssi[left]
853 switch (flags) {
854 case kFlagBefore:
855 {
856 --left;
857 break;
858 }
859 case kFlagAfter:
860 {
861 // nothing to do
862 break;
863 }
864 default:
865 {
866 // this route is not used, but implement it nonetheless
867 CHECK(flags == kFlagClosest);
868
869 status_t err = mSampleIterator->seekTo(start_sample_index);
870 if (err != OK) {
871 return err;
872 }
873 uint32_t sample_time = mSampleIterator->getSampleTime();
874
875 err = mSampleIterator->seekTo(mSyncSamples[left]);
876 if (err != OK) {
877 return err;
878 }
879 uint32_t upper_time = mSampleIterator->getSampleTime();
880
881 err = mSampleIterator->seekTo(mSyncSamples[left - 1]);
882 if (err != OK) {
883 return err;
884 }
885 uint32_t lower_time = mSampleIterator->getSampleTime();
886
887 // use abs_difference for safety
888 if (abs_difference(upper_time, sample_time) >
889 abs_difference(sample_time, lower_time)) {
890 --left;
891 }
892 break;
893 }
894 }
895
896 *sample_index = mSyncSamples[left];
897 return OK;
898 }
899
findThumbnailSample(uint32_t * sample_index)900 status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
901 Mutex::Autolock autoLock(mLock);
902
903 if (mSyncSampleOffset < 0) {
904 // All samples are sync-samples.
905 *sample_index = 0;
906 return OK;
907 }
908
909 uint32_t bestSampleIndex = 0;
910 size_t maxSampleSize = 0;
911
912 static const size_t kMaxNumSyncSamplesToScan = 20;
913
914 // Consider the first kMaxNumSyncSamplesToScan sync samples and
915 // pick the one with the largest (compressed) size as the thumbnail.
916
917 size_t numSamplesToScan = mNumSyncSamples;
918 if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
919 numSamplesToScan = kMaxNumSyncSamplesToScan;
920 }
921
922 for (size_t i = 0; i < numSamplesToScan; ++i) {
923 uint32_t x = mSyncSamples[i];
924
925 // Now x is a sample index.
926 size_t sampleSize;
927 status_t err = getSampleSize_l(x, &sampleSize);
928 if (err != OK) {
929 return err;
930 }
931
932 if (i == 0 || sampleSize > maxSampleSize) {
933 bestSampleIndex = x;
934 maxSampleSize = sampleSize;
935 }
936 }
937
938 *sample_index = bestSampleIndex;
939
940 return OK;
941 }
942
getSampleSize_l(uint32_t sampleIndex,size_t * sampleSize)943 status_t SampleTable::getSampleSize_l(
944 uint32_t sampleIndex, size_t *sampleSize) {
945 return mSampleIterator->getSampleSizeDirect(
946 sampleIndex, sampleSize);
947 }
948
getMetaDataForSample(uint32_t sampleIndex,off64_t * offset,size_t * size,uint32_t * compositionTime,bool * isSyncSample,uint32_t * sampleDuration)949 status_t SampleTable::getMetaDataForSample(
950 uint32_t sampleIndex,
951 off64_t *offset,
952 size_t *size,
953 uint32_t *compositionTime,
954 bool *isSyncSample,
955 uint32_t *sampleDuration) {
956 Mutex::Autolock autoLock(mLock);
957
958 status_t err;
959 if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
960 return err;
961 }
962
963 if (offset) {
964 *offset = mSampleIterator->getSampleOffset();
965 }
966
967 if (size) {
968 *size = mSampleIterator->getSampleSize();
969 }
970
971 if (compositionTime) {
972 *compositionTime = mSampleIterator->getSampleTime();
973 }
974
975 if (isSyncSample) {
976 *isSyncSample = false;
977 if (mSyncSampleOffset < 0) {
978 // Every sample is a sync sample.
979 *isSyncSample = true;
980 } else {
981 size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
982 && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
983 ? mLastSyncSampleIndex : 0;
984
985 while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
986 ++i;
987 }
988
989 if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
990 *isSyncSample = true;
991 }
992
993 mLastSyncSampleIndex = i;
994 }
995 }
996
997 if (sampleDuration) {
998 *sampleDuration = mSampleIterator->getSampleDuration();
999 }
1000
1001 return OK;
1002 }
1003
getCompositionTimeOffset(uint32_t sampleIndex)1004 int32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
1005 return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
1006 }
1007
1008 } // namespace android
1009