• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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