blob: d9858d76464d6bc5432c95bf7a86ceaf8cfdbe21 [file] [log] [blame]
Andreas Huber20111aa2009-07-14 16:56:47 -07001/*
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"
Andreas Huberc57b6792010-01-19 10:39:21 -080018//#define LOG_NDEBUG 0
Andreas Huber20111aa2009-07-14 16:56:47 -070019#include <utils/Log.h>
20
Andreas Huber89e69da2009-10-13 10:22:55 -070021#include "include/SampleTable.h"
Andreas Huberc57b6792010-01-19 10:39:21 -080022#include "include/SampleIterator.h"
Andreas Huber89e69da2009-10-13 10:22:55 -070023
Andreas Huber20111aa2009-07-14 16:56:47 -070024#include <arpa/inet.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070025
Andreas Huber89aa8fe2011-09-19 12:18:47 -070026#include <media/stagefright/foundation/ADebug.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070027#include <media/stagefright/DataSource.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070028#include <media/stagefright/Utils.h>
29
30namespace android {
31
Andreas Huberc57b6792010-01-19 10:39:21 -080032// static
33const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
34// static
35const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
36// static
37const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
38// static
39const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
40
41////////////////////////////////////////////////////////////////////////////////
Andreas Huber20111aa2009-07-14 16:56:47 -070042
Andreas Huber89aa8fe2011-09-19 12:18:47 -070043struct 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
51private:
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
63SampleTable::CompositionDeltaLookup::CompositionDeltaLookup()
64 : mDeltaEntries(NULL),
65 mNumDeltaEntries(0),
66 mCurrentDeltaEntry(0),
67 mCurrentEntrySampleIndex(0) {
68}
69
70void 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
80uint32_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
Andreas Huber693d2712009-08-14 14:37:10 -0700108SampleTable::SampleTable(const sp<DataSource> &source)
Andreas Huber20111aa2009-07-14 16:56:47 -0700109 : 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),
Andreas Huber4678a6d2011-04-15 11:52:29 -0700121 mSampleTimeEntries(NULL),
Andreas Huber4931bb52011-02-03 13:18:16 -0800122 mCompositionTimeDeltaEntries(NULL),
123 mNumCompositionTimeDeltaEntries(0),
Andreas Huber89aa8fe2011-09-19 12:18:47 -0700124 mCompositionDeltaLookup(new CompositionDeltaLookup),
Andreas Huber20111aa2009-07-14 16:56:47 -0700125 mSyncSampleOffset(-1),
Andreas Huberc57b6792010-01-19 10:39:21 -0800126 mNumSyncSamples(0),
Andreas Huber8bf59e72010-08-06 14:13:10 -0700127 mSyncSamples(NULL),
128 mLastSyncSampleIndex(0),
Andreas Huberc57b6792010-01-19 10:39:21 -0800129 mSampleToChunkEntries(NULL) {
130 mSampleIterator = new SampleIterator(this);
Andreas Huber20111aa2009-07-14 16:56:47 -0700131}
132
133SampleTable::~SampleTable() {
Andreas Huberc57b6792010-01-19 10:39:21 -0800134 delete[] mSampleToChunkEntries;
135 mSampleToChunkEntries = NULL;
136
Andreas Huber8bf59e72010-08-06 14:13:10 -0700137 delete[] mSyncSamples;
138 mSyncSamples = NULL;
139
Andreas Huber89aa8fe2011-09-19 12:18:47 -0700140 delete mCompositionDeltaLookup;
141 mCompositionDeltaLookup = NULL;
142
Andreas Huber4931bb52011-02-03 13:18:16 -0800143 delete[] mCompositionTimeDeltaEntries;
144 mCompositionTimeDeltaEntries = NULL;
145
Andreas Huber4678a6d2011-04-15 11:52:29 -0700146 delete[] mSampleTimeEntries;
147 mSampleTimeEntries = NULL;
148
Andreas Huber20111aa2009-07-14 16:56:47 -0700149 delete[] mTimeToSample;
150 mTimeToSample = NULL;
Andreas Huberc57b6792010-01-19 10:39:21 -0800151
152 delete mSampleIterator;
153 mSampleIterator = NULL;
Andreas Huber20111aa2009-07-14 16:56:47 -0700154}
155
Andreas Huber169c2862011-08-17 13:03:51 -0700156bool SampleTable::isValid() const {
157 return mChunkOffsetOffset >= 0
158 && mSampleToChunkOffset >= 0
159 && mSampleSizeOffset >= 0
160 && mTimeToSample != NULL;
161}
162
Andreas Huber20111aa2009-07-14 16:56:47 -0700163status_t SampleTable::setChunkOffsetParams(
James Dongc7fc37a2010-11-16 14:04:54 -0800164 uint32_t type, off64_t data_offset, size_t data_size) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700165 if (mChunkOffsetOffset >= 0) {
166 return ERROR_MALFORMED;
167 }
168
Andreas Huber0c891992009-08-26 14:48:20 -0700169 CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
Andreas Huber20111aa2009-07-14 16:56:47 -0700170
171 mChunkOffsetOffset = data_offset;
172 mChunkOffsetType = type;
173
174 if (data_size < 8) {
175 return ERROR_MALFORMED;
176 }
177
178 uint8_t header[8];
Andreas Huber34769bc2009-10-23 10:22:30 -0700179 if (mDataSource->readAt(
Andreas Huber20111aa2009-07-14 16:56:47 -0700180 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
204status_t SampleTable::setSampleToChunkParams(
James Dongc7fc37a2010-11-16 14:04:54 -0800205 off64_t data_offset, size_t data_size) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700206 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];
Andreas Huber34769bc2009-10-23 10:22:30 -0700217 if (mDataSource->readAt(
Andreas Huber20111aa2009-07-14 16:56:47 -0700218 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
Andreas Huberc57b6792010-01-19 10:39:21 -0800233 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
Andreas Huber20111aa2009-07-14 16:56:47 -0700252 return OK;
253}
254
255status_t SampleTable::setSampleSizeParams(
James Dongc7fc37a2010-11-16 14:04:54 -0800256 uint32_t type, off64_t data_offset, size_t data_size) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700257 if (mSampleSizeOffset >= 0) {
258 return ERROR_MALFORMED;
259 }
260
Andreas Huber0c891992009-08-26 14:48:20 -0700261 CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
Andreas Huber20111aa2009-07-14 16:56:47 -0700262
263 mSampleSizeOffset = data_offset;
264
265 if (data_size < 12) {
266 return ERROR_MALFORMED;
267 }
268
269 uint8_t header[12];
Andreas Huber34769bc2009-10-23 10:22:30 -0700270 if (mDataSource->readAt(
Andreas Huber20111aa2009-07-14 16:56:47 -0700271 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
Andreas Huber9f753df2011-05-12 13:38:20 -0700299 mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
Andreas Huber20111aa2009-07-14 16:56:47 -0700300 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
315status_t SampleTable::setTimeToSampleParams(
James Dongc7fc37a2010-11-16 14:04:54 -0800316 off64_t data_offset, size_t data_size) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700317 if (mTimeToSample != NULL || data_size < 8) {
318 return ERROR_MALFORMED;
319 }
320
321 uint8_t header[8];
Andreas Huber34769bc2009-10-23 10:22:30 -0700322 if (mDataSource->readAt(
Andreas Huber20111aa2009-07-14 16:56:47 -0700323 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;
Andreas Huber34769bc2009-10-23 10:22:30 -0700336 if (mDataSource->readAt(
Andreas Huber20111aa2009-07-14 16:56:47 -0700337 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
Andreas Huber4931bb52011-02-03 13:18:16 -0800348status_t SampleTable::setCompositionTimeToSampleParams(
349 off64_t data_offset, size_t data_size) {
Steve Blockdf64d152012-01-04 20:05:49 +0000350 ALOGI("There are reordered frames present.");
Andreas Huber4931bb52011-02-03 13:18:16 -0800351
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
Andreas Huber89aa8fe2011-09-19 12:18:47 -0700390 mCompositionDeltaLookup->setEntries(
391 mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
392
Andreas Huber4931bb52011-02-03 13:18:16 -0800393 return OK;
394}
395
James Dongc7fc37a2010-11-16 14:04:54 -0800396status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700397 if (mSyncSampleOffset >= 0 || data_size < 8) {
398 return ERROR_MALFORMED;
399 }
400
401 mSyncSampleOffset = data_offset;
402
403 uint8_t header[8];
Andreas Huber34769bc2009-10-23 10:22:30 -0700404 if (mDataSource->readAt(
Andreas Huber20111aa2009-07-14 16:56:47 -0700405 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) {
Steve Block3856b092011-10-20 11:56:00 +0100417 ALOGV("Table of sync samples is empty or has only a single entry!");
Andreas Huber20111aa2009-07-14 16:56:47 -0700418 }
Andreas Huber8bf59e72010-08-06 14:13:10 -0700419
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
Andreas Huber20111aa2009-07-14 16:56:47 -0700431 return OK;
432}
433
434uint32_t SampleTable::countChunkOffsets() const {
435 return mNumChunkOffsets;
436}
437
Andreas Huber20111aa2009-07-14 16:56:47 -0700438uint32_t SampleTable::countSamples() const {
439 return mNumSampleSizes;
440}
441
Andreas Huber20111aa2009-07-14 16:56:47 -0700442status_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;
Andreas Huberc57b6792010-01-19 10:39:21 -0800449 status_t err = getSampleSize_l(i, &sample_size);
Andreas Huberda76c642010-01-14 11:36:45 -0800450
Andreas Huber20111aa2009-07-14 16:56:47 -0700451 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
Andreas Huberda76c642010-01-14 11:36:45 -0800463uint32_t abs_difference(uint32_t time1, uint32_t time2) {
464 return time1 > time2 ? time1 - time2 : time2 - time1;
465}
466
Andreas Huber4678a6d2011-04-15 11:52:29 -0700467// static
468int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
469 const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
470 const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
Andreas Huber4931bb52011-02-03 13:18:16 -0800471
Andreas Huber4678a6d2011-04-15 11:52:29 -0700472 if (a->mCompositionTime < b->mCompositionTime) {
473 return -1;
474 } else if (a->mCompositionTime > b->mCompositionTime) {
475 return 1;
476 }
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700477
Andreas Huber4678a6d2011-04-15 11:52:29 -0700478 return 0;
479}
480
481void SampleTable::buildSampleEntriesTable() {
Andreas Huber20111aa2009-07-14 16:56:47 -0700482 Mutex::Autolock autoLock(mLock);
483
Andreas Huber4678a6d2011-04-15 11:52:29 -0700484 if (mSampleTimeEntries != NULL) {
485 return;
486 }
487
488 mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
489
490 uint32_t sampleIndex = 0;
491 uint32_t sampleTime = 0;
492
Andreas Huber20111aa2009-07-14 16:56:47 -0700493 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
494 uint32_t n = mTimeToSample[2 * i];
495 uint32_t delta = mTimeToSample[2 * i + 1];
496
Andreas Huber4678a6d2011-04-15 11:52:29 -0700497 for (uint32_t j = 0; j < n; ++j) {
Andreas Huber65a26702011-06-21 11:38:01 -0700498 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.
Andreas Huber20111aa2009-07-14 16:56:47 -0700502
Andreas Huber65a26702011-06-21 11:38:01 -0700503 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
Andreas Huberda76c642010-01-14 11:36:45 -0800504
Andreas Huber89aa8fe2011-09-19 12:18:47 -0700505 uint32_t compTimeDelta =
506 mCompositionDeltaLookup->getCompositionTimeOffset(
507 sampleIndex);
508
Andreas Huber65a26702011-06-21 11:38:01 -0700509 mSampleTimeEntries[sampleIndex].mCompositionTime =
Andreas Huber89aa8fe2011-09-19 12:18:47 -0700510 sampleTime + compTimeDelta;
Andreas Huber65a26702011-06-21 11:38:01 -0700511 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700512
Andreas Huber4678a6d2011-04-15 11:52:29 -0700513 ++sampleIndex;
514 sampleTime += delta;
Andreas Huber20111aa2009-07-14 16:56:47 -0700515 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700516 }
517
Andreas Huber4678a6d2011-04-15 11:52:29 -0700518 qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
519 CompareIncreasingTime);
520}
521
522status_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) {
Andreas Hubera488c7d2011-04-27 15:00:29 -0700543 if (flags == kFlagAfter) {
544 return ERROR_OUT_OF_RANGE;
545 }
546
Andreas Huber4678a6d2011-04-15 11:52:29 -0700547 --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;
Andreas Huber20111aa2009-07-14 16:56:47 -0700601}
602
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700603status_t SampleTable::findSyncSampleNear(
604 uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
605 Mutex::Autolock autoLock(mLock);
606
Andreas Huber20111aa2009-07-14 16:56:47 -0700607 *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
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700615 if (mNumSyncSamples == 0) {
616 *sample_index = 0;
617 return OK;
618 }
Andreas Huberda76c642010-01-14 11:36:45 -0800619
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700620 uint32_t left = 0;
Andreas Huber8f76ebf2011-11-07 11:38:14 -0800621 uint32_t right = mNumSyncSamples;
622 while (left < right) {
623 uint32_t center = left + (right - left) / 2;
624 uint32_t x = mSyncSamples[center];
Andreas Huber20111aa2009-07-14 16:56:47 -0700625
Andreas Huber8f76ebf2011-11-07 11:38:14 -0800626 if (start_sample_index < x) {
627 right = center;
628 } else if (start_sample_index > x) {
629 left = center + 1;
630 } else {
631 left = center;
Andreas Huber20111aa2009-07-14 16:56:47 -0700632 break;
633 }
James Dongf53263a2010-11-19 18:24:48 -0800634 }
Hong Teng8d0dd8b2011-12-15 16:56:49 -0800635 if (left == mNumSyncSamples) {
636 if (flags == kFlagAfter) {
Steve Block29357bc2012-01-06 19:20:56 +0000637 ALOGE("tried to find a sync frame after the last one: %d", left);
Hong Teng8d0dd8b2011-12-15 16:56:49 -0800638 return ERROR_OUT_OF_RANGE;
639 }
640 left = left - 1;
641 }
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700642
Andreas Huber8f76ebf2011-11-07 11:38:14 -0800643 // 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.
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700646
Andreas Huber8f76ebf2011-11-07 11:38:14 -0800647 uint32_t x = mSyncSamples[left];
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700648
649 if (left + 1 < mNumSyncSamples) {
Andreas Huber8bf59e72010-08-06 14:13:10 -0700650 uint32_t y = mSyncSamples[left + 1];
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700651
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 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700680 }
681
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700682 switch (flags) {
683 case kFlagBefore:
684 {
685 if (x > start_sample_index) {
686 CHECK(left > 0);
687
Andreas Huber8f76ebf2011-11-07 11:38:14 -0800688 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;
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700694 }
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700695 }
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
Andreas Huber8bf59e72010-08-06 14:13:10 -0700706 x = mSyncSamples[left + 1];
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700707
Andreas Huber8f76ebf2011-11-07 11:38:14 -0800708 if (x < start_sample_index) {
709 // The table of sync sample indices was not sorted
710 // properly.
711 return ERROR_MALFORMED;
712 }
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700713 }
714
715 break;
716 }
717
718 default:
719 break;
720 }
721
722 *sample_index = x;
Andreas Huber20111aa2009-07-14 16:56:47 -0700723
724 return OK;
725}
726
Andreas Huber7e04dcf2009-10-22 13:49:30 -0700727status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
Andreas Huberc57b6792010-01-19 10:39:21 -0800728 Mutex::Autolock autoLock(mLock);
729
Andreas Huber7e04dcf2009-10-22 13:49:30 -0700730 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) {
Andreas Huber8bf59e72010-08-06 14:13:10 -0700750 uint32_t x = mSyncSamples[i];
Andreas Huber7e04dcf2009-10-22 13:49:30 -0700751
752 // Now x is a sample index.
753 size_t sampleSize;
Andreas Huberc57b6792010-01-19 10:39:21 -0800754 status_t err = getSampleSize_l(x, &sampleSize);
Andreas Huber7e04dcf2009-10-22 13:49:30 -0700755 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
Andreas Huberc57b6792010-01-19 10:39:21 -0800770status_t SampleTable::getSampleSize_l(
771 uint32_t sampleIndex, size_t *sampleSize) {
772 return mSampleIterator->getSampleSizeDirect(
773 sampleIndex, sampleSize);
774}
775
776status_t SampleTable::getMetaDataForSample(
777 uint32_t sampleIndex,
James Dongc7fc37a2010-11-16 14:04:54 -0800778 off64_t *offset,
Andreas Huberc57b6792010-01-19 10:39:21 -0800779 size_t *size,
Andreas Huber4678a6d2011-04-15 11:52:29 -0700780 uint32_t *compositionTime,
Andreas Huber8bf59e72010-08-06 14:13:10 -0700781 bool *isSyncSample) {
Andreas Huberc57b6792010-01-19 10:39:21 -0800782 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
Andreas Huber4678a6d2011-04-15 11:52:29 -0700797 if (compositionTime) {
798 *compositionTime = mSampleIterator->getSampleTime();
Andreas Huberc57b6792010-01-19 10:39:21 -0800799 }
800
Andreas Huber8bf59e72010-08-06 14:13:10 -0700801 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
Andreas Huberc57b6792010-01-19 10:39:21 -0800823 return OK;
824}
825
Andreas Huber89aa8fe2011-09-19 12:18:47 -0700826uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
827 return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
Andreas Huber4931bb52011-02-03 13:18:16 -0800828}
829
Andreas Huber20111aa2009-07-14 16:56:47 -0700830} // namespace android
831