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 uint64_t allocSize = mTimeToSampleCount * 2 * sizeof(uint32_t);
334 if (allocSize > SIZE_MAX) {
335 return ERROR_OUT_OF_RANGE;
336 }
337 mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
338
339 size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
340 if (mDataSource->readAt(
341 data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
342 return ERROR_IO;
343 }
344
345 for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
346 mTimeToSample[i] = ntohl(mTimeToSample[i]);
347 }
348
349 return OK;
350 }
351
setCompositionTimeToSampleParams(off64_t data_offset,size_t data_size)352 status_t SampleTable::setCompositionTimeToSampleParams(
353 off64_t data_offset, size_t data_size) {
354 ALOGI("There are reordered frames present.");
355
356 if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
357 return ERROR_MALFORMED;
358 }
359
360 uint8_t header[8];
361 if (mDataSource->readAt(
362 data_offset, header, sizeof(header))
363 < (ssize_t)sizeof(header)) {
364 return ERROR_IO;
365 }
366
367 if (U32_AT(header) != 0) {
368 // Expected version = 0, flags = 0.
369 return ERROR_MALFORMED;
370 }
371
372 size_t numEntries = U32_AT(&header[4]);
373
374 if (data_size != (numEntries + 1) * 8) {
375 return ERROR_MALFORMED;
376 }
377
378 mNumCompositionTimeDeltaEntries = numEntries;
379 uint64_t allocSize = numEntries * 2 * sizeof(uint32_t);
380 if (allocSize > SIZE_MAX) {
381 return ERROR_OUT_OF_RANGE;
382 }
383
384 mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries];
385
386 if (mDataSource->readAt(
387 data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
388 < (ssize_t)numEntries * 8) {
389 delete[] mCompositionTimeDeltaEntries;
390 mCompositionTimeDeltaEntries = NULL;
391
392 return ERROR_IO;
393 }
394
395 for (size_t i = 0; i < 2 * numEntries; ++i) {
396 mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
397 }
398
399 mCompositionDeltaLookup->setEntries(
400 mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
401
402 return OK;
403 }
404
setSyncSampleParams(off64_t data_offset,size_t data_size)405 status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
406 if (mSyncSampleOffset >= 0 || data_size < 8) {
407 return ERROR_MALFORMED;
408 }
409
410 mSyncSampleOffset = data_offset;
411
412 uint8_t header[8];
413 if (mDataSource->readAt(
414 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
415 return ERROR_IO;
416 }
417
418 if (U32_AT(header) != 0) {
419 // Expected version = 0, flags = 0.
420 return ERROR_MALFORMED;
421 }
422
423 mNumSyncSamples = U32_AT(&header[4]);
424
425 if (mNumSyncSamples < 2) {
426 ALOGV("Table of sync samples is empty or has only a single entry!");
427 }
428
429 uint64_t allocSize = mNumSyncSamples * sizeof(uint32_t);
430 if (allocSize > SIZE_MAX) {
431 return ERROR_OUT_OF_RANGE;
432 }
433
434 mSyncSamples = new uint32_t[mNumSyncSamples];
435 size_t size = mNumSyncSamples * sizeof(uint32_t);
436 if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
437 != (ssize_t)size) {
438 return ERROR_IO;
439 }
440
441 for (size_t i = 0; i < mNumSyncSamples; ++i) {
442 mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
443 }
444
445 return OK;
446 }
447
countChunkOffsets() const448 uint32_t SampleTable::countChunkOffsets() const {
449 return mNumChunkOffsets;
450 }
451
countSamples() const452 uint32_t SampleTable::countSamples() const {
453 return mNumSampleSizes;
454 }
455
getMaxSampleSize(size_t * max_size)456 status_t SampleTable::getMaxSampleSize(size_t *max_size) {
457 Mutex::Autolock autoLock(mLock);
458
459 *max_size = 0;
460
461 for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
462 size_t sample_size;
463 status_t err = getSampleSize_l(i, &sample_size);
464
465 if (err != OK) {
466 return err;
467 }
468
469 if (sample_size > *max_size) {
470 *max_size = sample_size;
471 }
472 }
473
474 return OK;
475 }
476
abs_difference(uint32_t time1,uint32_t time2)477 uint32_t abs_difference(uint32_t time1, uint32_t time2) {
478 return time1 > time2 ? time1 - time2 : time2 - time1;
479 }
480
481 // static
CompareIncreasingTime(const void * _a,const void * _b)482 int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
483 const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
484 const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
485
486 if (a->mCompositionTime < b->mCompositionTime) {
487 return -1;
488 } else if (a->mCompositionTime > b->mCompositionTime) {
489 return 1;
490 }
491
492 return 0;
493 }
494
buildSampleEntriesTable()495 void SampleTable::buildSampleEntriesTable() {
496 Mutex::Autolock autoLock(mLock);
497
498 if (mSampleTimeEntries != NULL) {
499 return;
500 }
501
502 mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
503
504 uint32_t sampleIndex = 0;
505 uint32_t sampleTime = 0;
506
507 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
508 uint32_t n = mTimeToSample[2 * i];
509 uint32_t delta = mTimeToSample[2 * i + 1];
510
511 for (uint32_t j = 0; j < n; ++j) {
512 if (sampleIndex < mNumSampleSizes) {
513 // Technically this should always be the case if the file
514 // is well-formed, but you know... there's (gasp) malformed
515 // content out there.
516
517 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
518
519 uint32_t compTimeDelta =
520 mCompositionDeltaLookup->getCompositionTimeOffset(
521 sampleIndex);
522
523 mSampleTimeEntries[sampleIndex].mCompositionTime =
524 sampleTime + compTimeDelta;
525 }
526
527 ++sampleIndex;
528 sampleTime += delta;
529 }
530 }
531
532 qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
533 CompareIncreasingTime);
534 }
535
findSampleAtTime(uint64_t req_time,uint64_t scale_num,uint64_t scale_den,uint32_t * sample_index,uint32_t flags)536 status_t SampleTable::findSampleAtTime(
537 uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
538 uint32_t *sample_index, uint32_t flags) {
539 buildSampleEntriesTable();
540
541 uint32_t left = 0;
542 uint32_t right_plus_one = mNumSampleSizes;
543 while (left < right_plus_one) {
544 uint32_t center = left + (right_plus_one - left) / 2;
545 uint64_t centerTime =
546 getSampleTime(center, scale_num, scale_den);
547
548 if (req_time < centerTime) {
549 right_plus_one = center;
550 } else if (req_time > centerTime) {
551 left = center + 1;
552 } else {
553 *sample_index = mSampleTimeEntries[center].mSampleIndex;
554 return OK;
555 }
556 }
557
558 uint32_t closestIndex = left;
559
560 if (closestIndex == mNumSampleSizes) {
561 if (flags == kFlagAfter) {
562 return ERROR_OUT_OF_RANGE;
563 }
564 flags = kFlagBefore;
565 } else if (closestIndex == 0) {
566 if (flags == kFlagBefore) {
567 // normally we should return out of range, but that is
568 // treated as end-of-stream. instead return first sample
569 //
570 // return ERROR_OUT_OF_RANGE;
571 }
572 flags = kFlagAfter;
573 }
574
575 switch (flags) {
576 case kFlagBefore:
577 {
578 --closestIndex;
579 break;
580 }
581
582 case kFlagAfter:
583 {
584 // nothing to do
585 break;
586 }
587
588 default:
589 {
590 CHECK(flags == kFlagClosest);
591 // pick closest based on timestamp. use abs_difference for safety
592 if (abs_difference(
593 getSampleTime(closestIndex, scale_num, scale_den), req_time) >
594 abs_difference(
595 req_time, getSampleTime(closestIndex - 1, scale_num, scale_den))) {
596 --closestIndex;
597 }
598 break;
599 }
600 }
601
602 *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
603 return OK;
604 }
605
findSyncSampleNear(uint32_t start_sample_index,uint32_t * sample_index,uint32_t flags)606 status_t SampleTable::findSyncSampleNear(
607 uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
608 Mutex::Autolock autoLock(mLock);
609
610 *sample_index = 0;
611
612 if (mSyncSampleOffset < 0) {
613 // All samples are sync-samples.
614 *sample_index = start_sample_index;
615 return OK;
616 }
617
618 if (mNumSyncSamples == 0) {
619 *sample_index = 0;
620 return OK;
621 }
622
623 uint32_t left = 0;
624 uint32_t right_plus_one = mNumSyncSamples;
625 while (left < right_plus_one) {
626 uint32_t center = left + (right_plus_one - left) / 2;
627 uint32_t x = mSyncSamples[center];
628
629 if (start_sample_index < x) {
630 right_plus_one = center;
631 } else if (start_sample_index > x) {
632 left = center + 1;
633 } else {
634 *sample_index = x;
635 return OK;
636 }
637 }
638
639 if (left == mNumSyncSamples) {
640 if (flags == kFlagAfter) {
641 ALOGE("tried to find a sync frame after the last one: %d", left);
642 return ERROR_OUT_OF_RANGE;
643 }
644 flags = kFlagBefore;
645 }
646 else if (left == 0) {
647 if (flags == kFlagBefore) {
648 ALOGE("tried to find a sync frame before the first one: %d", left);
649
650 // normally we should return out of range, but that is
651 // treated as end-of-stream. instead seek to first sync
652 //
653 // return ERROR_OUT_OF_RANGE;
654 }
655 flags = kFlagAfter;
656 }
657
658 // Now ssi[left - 1] <(=) start_sample_index <= ssi[left]
659 switch (flags) {
660 case kFlagBefore:
661 {
662 --left;
663 break;
664 }
665 case kFlagAfter:
666 {
667 // nothing to do
668 break;
669 }
670 default:
671 {
672 // this route is not used, but implement it nonetheless
673 CHECK(flags == kFlagClosest);
674
675 status_t err = mSampleIterator->seekTo(start_sample_index);
676 if (err != OK) {
677 return err;
678 }
679 uint32_t sample_time = mSampleIterator->getSampleTime();
680
681 err = mSampleIterator->seekTo(mSyncSamples[left]);
682 if (err != OK) {
683 return err;
684 }
685 uint32_t upper_time = mSampleIterator->getSampleTime();
686
687 err = mSampleIterator->seekTo(mSyncSamples[left - 1]);
688 if (err != OK) {
689 return err;
690 }
691 uint32_t lower_time = mSampleIterator->getSampleTime();
692
693 // use abs_difference for safety
694 if (abs_difference(upper_time, sample_time) >
695 abs_difference(sample_time, lower_time)) {
696 --left;
697 }
698 break;
699 }
700 }
701
702 *sample_index = mSyncSamples[left];
703 return OK;
704 }
705
findThumbnailSample(uint32_t * sample_index)706 status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
707 Mutex::Autolock autoLock(mLock);
708
709 if (mSyncSampleOffset < 0) {
710 // All samples are sync-samples.
711 *sample_index = 0;
712 return OK;
713 }
714
715 uint32_t bestSampleIndex = 0;
716 size_t maxSampleSize = 0;
717
718 static const size_t kMaxNumSyncSamplesToScan = 20;
719
720 // Consider the first kMaxNumSyncSamplesToScan sync samples and
721 // pick the one with the largest (compressed) size as the thumbnail.
722
723 size_t numSamplesToScan = mNumSyncSamples;
724 if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
725 numSamplesToScan = kMaxNumSyncSamplesToScan;
726 }
727
728 for (size_t i = 0; i < numSamplesToScan; ++i) {
729 uint32_t x = mSyncSamples[i];
730
731 // Now x is a sample index.
732 size_t sampleSize;
733 status_t err = getSampleSize_l(x, &sampleSize);
734 if (err != OK) {
735 return err;
736 }
737
738 if (i == 0 || sampleSize > maxSampleSize) {
739 bestSampleIndex = x;
740 maxSampleSize = sampleSize;
741 }
742 }
743
744 *sample_index = bestSampleIndex;
745
746 return OK;
747 }
748
getSampleSize_l(uint32_t sampleIndex,size_t * sampleSize)749 status_t SampleTable::getSampleSize_l(
750 uint32_t sampleIndex, size_t *sampleSize) {
751 return mSampleIterator->getSampleSizeDirect(
752 sampleIndex, sampleSize);
753 }
754
getMetaDataForSample(uint32_t sampleIndex,off64_t * offset,size_t * size,uint32_t * compositionTime,bool * isSyncSample,uint32_t * sampleDuration)755 status_t SampleTable::getMetaDataForSample(
756 uint32_t sampleIndex,
757 off64_t *offset,
758 size_t *size,
759 uint32_t *compositionTime,
760 bool *isSyncSample,
761 uint32_t *sampleDuration) {
762 Mutex::Autolock autoLock(mLock);
763
764 status_t err;
765 if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
766 return err;
767 }
768
769 if (offset) {
770 *offset = mSampleIterator->getSampleOffset();
771 }
772
773 if (size) {
774 *size = mSampleIterator->getSampleSize();
775 }
776
777 if (compositionTime) {
778 *compositionTime = mSampleIterator->getSampleTime();
779 }
780
781 if (isSyncSample) {
782 *isSyncSample = false;
783 if (mSyncSampleOffset < 0) {
784 // Every sample is a sync sample.
785 *isSyncSample = true;
786 } else {
787 size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
788 && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
789 ? mLastSyncSampleIndex : 0;
790
791 while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
792 ++i;
793 }
794
795 if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
796 *isSyncSample = true;
797 }
798
799 mLastSyncSampleIndex = i;
800 }
801 }
802
803 if (sampleDuration) {
804 *sampleDuration = mSampleIterator->getSampleDuration();
805 }
806
807 return OK;
808 }
809
getCompositionTimeOffset(uint32_t sampleIndex)810 uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
811 return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
812 }
813
814 } // namespace android
815
816