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