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