• Home
  • History
  • Annotate
  • 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     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