blob: eb135abd0a24524cb7babb12a903e4a045caafd5 [file] [log] [blame]
Andreas Hubere46b7be2009-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 Huber1faa92a2010-01-19 10:39:21 -080018//#define LOG_NDEBUG 0
Andreas Hubere46b7be2009-07-14 16:56:47 -070019#include <utils/Log.h>
20
Andreas Huberbd7b43b2009-10-13 10:22:55 -070021#include "include/SampleTable.h"
Andreas Huber1faa92a2010-01-19 10:39:21 -080022#include "include/SampleIterator.h"
Andreas Huberbd7b43b2009-10-13 10:22:55 -070023
Andreas Hubere46b7be2009-07-14 16:56:47 -070024#include <arpa/inet.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070025
26#include <media/stagefright/DataSource.h>
Andreas Huberb5ceb9e2009-08-26 14:48:20 -070027#include <media/stagefright/MediaDebug.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070028#include <media/stagefright/Utils.h>
29
30namespace android {
31
Andreas Huber1faa92a2010-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 Hubere46b7be2009-07-14 16:56:47 -070042
Andreas Huberbe06d262009-08-14 14:37:10 -070043SampleTable::SampleTable(const sp<DataSource> &source)
Andreas Hubere46b7be2009-07-14 16:56:47 -070044 : mDataSource(source),
45 mChunkOffsetOffset(-1),
46 mChunkOffsetType(0),
47 mNumChunkOffsets(0),
48 mSampleToChunkOffset(-1),
49 mNumSampleToChunkOffsets(0),
50 mSampleSizeOffset(-1),
51 mSampleSizeFieldSize(0),
52 mDefaultSampleSize(0),
53 mNumSampleSizes(0),
54 mTimeToSampleCount(0),
55 mTimeToSample(NULL),
Andreas Huber44fdac02011-04-15 11:52:29 -070056 mSampleTimeEntries(NULL),
Andreas Huberbd352c32011-02-03 13:18:16 -080057 mCompositionTimeDeltaEntries(NULL),
58 mNumCompositionTimeDeltaEntries(0),
Andreas Hubere46b7be2009-07-14 16:56:47 -070059 mSyncSampleOffset(-1),
Andreas Huber1faa92a2010-01-19 10:39:21 -080060 mNumSyncSamples(0),
Andreas Huberad98d382010-08-06 14:13:10 -070061 mSyncSamples(NULL),
62 mLastSyncSampleIndex(0),
Andreas Huber1faa92a2010-01-19 10:39:21 -080063 mSampleToChunkEntries(NULL) {
64 mSampleIterator = new SampleIterator(this);
Andreas Hubere46b7be2009-07-14 16:56:47 -070065}
66
67SampleTable::~SampleTable() {
Andreas Huber1faa92a2010-01-19 10:39:21 -080068 delete[] mSampleToChunkEntries;
69 mSampleToChunkEntries = NULL;
70
Andreas Huberad98d382010-08-06 14:13:10 -070071 delete[] mSyncSamples;
72 mSyncSamples = NULL;
73
Andreas Huberbd352c32011-02-03 13:18:16 -080074 delete[] mCompositionTimeDeltaEntries;
75 mCompositionTimeDeltaEntries = NULL;
76
Andreas Huber44fdac02011-04-15 11:52:29 -070077 delete[] mSampleTimeEntries;
78 mSampleTimeEntries = NULL;
79
Andreas Hubere46b7be2009-07-14 16:56:47 -070080 delete[] mTimeToSample;
81 mTimeToSample = NULL;
Andreas Huber1faa92a2010-01-19 10:39:21 -080082
83 delete mSampleIterator;
84 mSampleIterator = NULL;
Andreas Hubere46b7be2009-07-14 16:56:47 -070085}
86
87status_t SampleTable::setChunkOffsetParams(
James Dongb1262a82010-11-16 14:04:54 -080088 uint32_t type, off64_t data_offset, size_t data_size) {
Andreas Hubere46b7be2009-07-14 16:56:47 -070089 if (mChunkOffsetOffset >= 0) {
90 return ERROR_MALFORMED;
91 }
92
Andreas Huberb5ceb9e2009-08-26 14:48:20 -070093 CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
Andreas Hubere46b7be2009-07-14 16:56:47 -070094
95 mChunkOffsetOffset = data_offset;
96 mChunkOffsetType = type;
97
98 if (data_size < 8) {
99 return ERROR_MALFORMED;
100 }
101
102 uint8_t header[8];
Andreas Huber9a12baf2009-10-23 10:22:30 -0700103 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700104 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
105 return ERROR_IO;
106 }
107
108 if (U32_AT(header) != 0) {
109 // Expected version = 0, flags = 0.
110 return ERROR_MALFORMED;
111 }
112
113 mNumChunkOffsets = U32_AT(&header[4]);
114
115 if (mChunkOffsetType == kChunkOffsetType32) {
116 if (data_size < 8 + mNumChunkOffsets * 4) {
117 return ERROR_MALFORMED;
118 }
119 } else {
120 if (data_size < 8 + mNumChunkOffsets * 8) {
121 return ERROR_MALFORMED;
122 }
123 }
124
125 return OK;
126}
127
128status_t SampleTable::setSampleToChunkParams(
James Dongb1262a82010-11-16 14:04:54 -0800129 off64_t data_offset, size_t data_size) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700130 if (mSampleToChunkOffset >= 0) {
131 return ERROR_MALFORMED;
132 }
133
134 mSampleToChunkOffset = data_offset;
135
136 if (data_size < 8) {
137 return ERROR_MALFORMED;
138 }
139
140 uint8_t header[8];
Andreas Huber9a12baf2009-10-23 10:22:30 -0700141 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700142 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
143 return ERROR_IO;
144 }
145
146 if (U32_AT(header) != 0) {
147 // Expected version = 0, flags = 0.
148 return ERROR_MALFORMED;
149 }
150
151 mNumSampleToChunkOffsets = U32_AT(&header[4]);
152
153 if (data_size < 8 + mNumSampleToChunkOffsets * 12) {
154 return ERROR_MALFORMED;
155 }
156
Andreas Huber1faa92a2010-01-19 10:39:21 -0800157 mSampleToChunkEntries =
158 new SampleToChunkEntry[mNumSampleToChunkOffsets];
159
160 for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
161 uint8_t buffer[12];
162 if (mDataSource->readAt(
163 mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
164 != (ssize_t)sizeof(buffer)) {
165 return ERROR_IO;
166 }
167
168 CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec.
169
170 // We want the chunk index to be 0-based.
171 mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
172 mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
173 mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
174 }
175
Andreas Hubere46b7be2009-07-14 16:56:47 -0700176 return OK;
177}
178
179status_t SampleTable::setSampleSizeParams(
James Dongb1262a82010-11-16 14:04:54 -0800180 uint32_t type, off64_t data_offset, size_t data_size) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700181 if (mSampleSizeOffset >= 0) {
182 return ERROR_MALFORMED;
183 }
184
Andreas Huberb5ceb9e2009-08-26 14:48:20 -0700185 CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700186
187 mSampleSizeOffset = data_offset;
188
189 if (data_size < 12) {
190 return ERROR_MALFORMED;
191 }
192
193 uint8_t header[12];
Andreas Huber9a12baf2009-10-23 10:22:30 -0700194 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700195 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
196 return ERROR_IO;
197 }
198
199 if (U32_AT(header) != 0) {
200 // Expected version = 0, flags = 0.
201 return ERROR_MALFORMED;
202 }
203
204 mDefaultSampleSize = U32_AT(&header[4]);
205 mNumSampleSizes = U32_AT(&header[8]);
206
207 if (type == kSampleSizeType32) {
208 mSampleSizeFieldSize = 32;
209
210 if (mDefaultSampleSize != 0) {
211 return OK;
212 }
213
214 if (data_size < 12 + mNumSampleSizes * 4) {
215 return ERROR_MALFORMED;
216 }
217 } else {
218 if ((mDefaultSampleSize & 0xffffff00) != 0) {
219 // The high 24 bits are reserved and must be 0.
220 return ERROR_MALFORMED;
221 }
222
Andreas Huber0a6f09e2011-05-12 13:38:20 -0700223 mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700224 mDefaultSampleSize = 0;
225
226 if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
227 && mSampleSizeFieldSize != 16) {
228 return ERROR_MALFORMED;
229 }
230
231 if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
232 return ERROR_MALFORMED;
233 }
234 }
235
236 return OK;
237}
238
239status_t SampleTable::setTimeToSampleParams(
James Dongb1262a82010-11-16 14:04:54 -0800240 off64_t data_offset, size_t data_size) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700241 if (mTimeToSample != NULL || data_size < 8) {
242 return ERROR_MALFORMED;
243 }
244
245 uint8_t header[8];
Andreas Huber9a12baf2009-10-23 10:22:30 -0700246 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700247 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
248 return ERROR_IO;
249 }
250
251 if (U32_AT(header) != 0) {
252 // Expected version = 0, flags = 0.
253 return ERROR_MALFORMED;
254 }
255
256 mTimeToSampleCount = U32_AT(&header[4]);
257 mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
258
259 size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
Andreas Huber9a12baf2009-10-23 10:22:30 -0700260 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700261 data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
262 return ERROR_IO;
263 }
264
265 for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
266 mTimeToSample[i] = ntohl(mTimeToSample[i]);
267 }
268
269 return OK;
270}
271
Andreas Huberbd352c32011-02-03 13:18:16 -0800272status_t SampleTable::setCompositionTimeToSampleParams(
273 off64_t data_offset, size_t data_size) {
274 LOGI("There are reordered frames present.");
275
276 if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
277 return ERROR_MALFORMED;
278 }
279
280 uint8_t header[8];
281 if (mDataSource->readAt(
282 data_offset, header, sizeof(header))
283 < (ssize_t)sizeof(header)) {
284 return ERROR_IO;
285 }
286
287 if (U32_AT(header) != 0) {
288 // Expected version = 0, flags = 0.
289 return ERROR_MALFORMED;
290 }
291
292 size_t numEntries = U32_AT(&header[4]);
293
294 if (data_size != (numEntries + 1) * 8) {
295 return ERROR_MALFORMED;
296 }
297
298 mNumCompositionTimeDeltaEntries = numEntries;
299 mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries];
300
301 if (mDataSource->readAt(
302 data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
303 < (ssize_t)numEntries * 8) {
304 delete[] mCompositionTimeDeltaEntries;
305 mCompositionTimeDeltaEntries = NULL;
306
307 return ERROR_IO;
308 }
309
310 for (size_t i = 0; i < 2 * numEntries; ++i) {
311 mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
312 }
313
314 return OK;
315}
316
James Dongb1262a82010-11-16 14:04:54 -0800317status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700318 if (mSyncSampleOffset >= 0 || data_size < 8) {
319 return ERROR_MALFORMED;
320 }
321
322 mSyncSampleOffset = data_offset;
323
324 uint8_t header[8];
Andreas Huber9a12baf2009-10-23 10:22:30 -0700325 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700326 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
327 return ERROR_IO;
328 }
329
330 if (U32_AT(header) != 0) {
331 // Expected version = 0, flags = 0.
332 return ERROR_MALFORMED;
333 }
334
335 mNumSyncSamples = U32_AT(&header[4]);
336
337 if (mNumSyncSamples < 2) {
Andreas Huberc69b9d32010-10-27 10:25:44 -0700338 LOGV("Table of sync samples is empty or has only a single entry!");
Andreas Hubere46b7be2009-07-14 16:56:47 -0700339 }
Andreas Huberad98d382010-08-06 14:13:10 -0700340
341 mSyncSamples = new uint32_t[mNumSyncSamples];
342 size_t size = mNumSyncSamples * sizeof(uint32_t);
343 if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
344 != (ssize_t)size) {
345 return ERROR_IO;
346 }
347
348 for (size_t i = 0; i < mNumSyncSamples; ++i) {
349 mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
350 }
351
Andreas Hubere46b7be2009-07-14 16:56:47 -0700352 return OK;
353}
354
355uint32_t SampleTable::countChunkOffsets() const {
356 return mNumChunkOffsets;
357}
358
Andreas Hubere46b7be2009-07-14 16:56:47 -0700359uint32_t SampleTable::countSamples() const {
360 return mNumSampleSizes;
361}
362
Andreas Hubere46b7be2009-07-14 16:56:47 -0700363status_t SampleTable::getMaxSampleSize(size_t *max_size) {
364 Mutex::Autolock autoLock(mLock);
365
366 *max_size = 0;
367
368 for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
369 size_t sample_size;
Andreas Huber1faa92a2010-01-19 10:39:21 -0800370 status_t err = getSampleSize_l(i, &sample_size);
Andreas Huber140d4ed2010-01-14 11:36:45 -0800371
Andreas Hubere46b7be2009-07-14 16:56:47 -0700372 if (err != OK) {
373 return err;
374 }
375
376 if (sample_size > *max_size) {
377 *max_size = sample_size;
378 }
379 }
380
381 return OK;
382}
383
Andreas Huber140d4ed2010-01-14 11:36:45 -0800384uint32_t abs_difference(uint32_t time1, uint32_t time2) {
385 return time1 > time2 ? time1 - time2 : time2 - time1;
386}
387
Andreas Huber44fdac02011-04-15 11:52:29 -0700388// static
389int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
390 const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
391 const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
Andreas Huberbd352c32011-02-03 13:18:16 -0800392
Andreas Huber44fdac02011-04-15 11:52:29 -0700393 if (a->mCompositionTime < b->mCompositionTime) {
394 return -1;
395 } else if (a->mCompositionTime > b->mCompositionTime) {
396 return 1;
397 }
Andreas Huber6624c9f2010-07-20 15:04:28 -0700398
Andreas Huber44fdac02011-04-15 11:52:29 -0700399 return 0;
400}
401
402void SampleTable::buildSampleEntriesTable() {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700403 Mutex::Autolock autoLock(mLock);
404
Andreas Huber44fdac02011-04-15 11:52:29 -0700405 if (mSampleTimeEntries != NULL) {
406 return;
407 }
408
409 mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
410
411 uint32_t sampleIndex = 0;
412 uint32_t sampleTime = 0;
413
Andreas Hubere46b7be2009-07-14 16:56:47 -0700414 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
415 uint32_t n = mTimeToSample[2 * i];
416 uint32_t delta = mTimeToSample[2 * i + 1];
417
Andreas Huber44fdac02011-04-15 11:52:29 -0700418 for (uint32_t j = 0; j < n; ++j) {
419 CHECK(sampleIndex < mNumSampleSizes);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700420
Andreas Huber44fdac02011-04-15 11:52:29 -0700421 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
Andreas Huber140d4ed2010-01-14 11:36:45 -0800422
Andreas Huber44fdac02011-04-15 11:52:29 -0700423 mSampleTimeEntries[sampleIndex].mCompositionTime =
424 sampleTime + getCompositionTimeOffset(sampleIndex);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700425
Andreas Huber44fdac02011-04-15 11:52:29 -0700426 ++sampleIndex;
427 sampleTime += delta;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700428 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700429 }
430
Andreas Huber44fdac02011-04-15 11:52:29 -0700431 qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
432 CompareIncreasingTime);
433}
434
435status_t SampleTable::findSampleAtTime(
436 uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
437 buildSampleEntriesTable();
438
439 uint32_t left = 0;
440 uint32_t right = mNumSampleSizes;
441 while (left < right) {
442 uint32_t center = (left + right) / 2;
443 uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
444
445 if (req_time < centerTime) {
446 right = center;
447 } else if (req_time > centerTime) {
448 left = center + 1;
449 } else {
450 left = center;
451 break;
452 }
453 }
454
455 if (left == mNumSampleSizes) {
Andreas Hubere23a3922011-04-27 15:00:29 -0700456 if (flags == kFlagAfter) {
457 return ERROR_OUT_OF_RANGE;
458 }
459
Andreas Huber44fdac02011-04-15 11:52:29 -0700460 --left;
461 }
462
463 uint32_t closestIndex = left;
464
465 switch (flags) {
466 case kFlagBefore:
467 {
468 while (closestIndex > 0
469 && mSampleTimeEntries[closestIndex].mCompositionTime
470 > req_time) {
471 --closestIndex;
472 }
473 break;
474 }
475
476 case kFlagAfter:
477 {
478 while (closestIndex + 1 < mNumSampleSizes
479 && mSampleTimeEntries[closestIndex].mCompositionTime
480 < req_time) {
481 ++closestIndex;
482 }
483 break;
484 }
485
486 default:
487 {
488 CHECK(flags == kFlagClosest);
489
490 if (closestIndex > 0) {
491 // Check left neighbour and pick closest.
492 uint32_t absdiff1 =
493 abs_difference(
494 mSampleTimeEntries[closestIndex].mCompositionTime,
495 req_time);
496
497 uint32_t absdiff2 =
498 abs_difference(
499 mSampleTimeEntries[closestIndex - 1].mCompositionTime,
500 req_time);
501
502 if (absdiff1 > absdiff2) {
503 closestIndex = closestIndex - 1;
504 }
505 }
506
507 break;
508 }
509 }
510
511 *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
512
513 return OK;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700514}
515
Andreas Huber6624c9f2010-07-20 15:04:28 -0700516status_t SampleTable::findSyncSampleNear(
517 uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
518 Mutex::Autolock autoLock(mLock);
519
Andreas Hubere46b7be2009-07-14 16:56:47 -0700520 *sample_index = 0;
521
522 if (mSyncSampleOffset < 0) {
523 // All samples are sync-samples.
524 *sample_index = start_sample_index;
525 return OK;
526 }
527
Andreas Huber6624c9f2010-07-20 15:04:28 -0700528 if (mNumSyncSamples == 0) {
529 *sample_index = 0;
530 return OK;
531 }
Andreas Huber140d4ed2010-01-14 11:36:45 -0800532
Andreas Huber6624c9f2010-07-20 15:04:28 -0700533 uint32_t left = 0;
534 while (left < mNumSyncSamples) {
Andreas Huberad98d382010-08-06 14:13:10 -0700535 uint32_t x = mSyncSamples[left];
Andreas Hubere46b7be2009-07-14 16:56:47 -0700536
Andreas Huber6624c9f2010-07-20 15:04:28 -0700537 if (x >= start_sample_index) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700538 break;
539 }
Andreas Huber6624c9f2010-07-20 15:04:28 -0700540
541 ++left;
542 }
James Dong0950b4b2010-11-19 18:24:48 -0800543 if (left > 0) {
544 --left;
545 }
Andreas Huber6624c9f2010-07-20 15:04:28 -0700546
Andreas Huber6624c9f2010-07-20 15:04:28 -0700547 uint32_t x;
548 if (mDataSource->readAt(
549 mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) {
550 return ERROR_IO;
551 }
552
553 x = ntohl(x);
554 --x;
555
556 if (left + 1 < mNumSyncSamples) {
Andreas Huberad98d382010-08-06 14:13:10 -0700557 uint32_t y = mSyncSamples[left + 1];
Andreas Huber6624c9f2010-07-20 15:04:28 -0700558
559 // our sample lies between sync samples x and y.
560
561 status_t err = mSampleIterator->seekTo(start_sample_index);
562 if (err != OK) {
563 return err;
564 }
565
566 uint32_t sample_time = mSampleIterator->getSampleTime();
567
568 err = mSampleIterator->seekTo(x);
569 if (err != OK) {
570 return err;
571 }
572 uint32_t x_time = mSampleIterator->getSampleTime();
573
574 err = mSampleIterator->seekTo(y);
575 if (err != OK) {
576 return err;
577 }
578
579 uint32_t y_time = mSampleIterator->getSampleTime();
580
581 if (abs_difference(x_time, sample_time)
582 > abs_difference(y_time, sample_time)) {
583 // Pick the sync sample closest (timewise) to the start-sample.
584 x = y;
585 ++left;
586 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700587 }
588
Andreas Huber6624c9f2010-07-20 15:04:28 -0700589 switch (flags) {
590 case kFlagBefore:
591 {
592 if (x > start_sample_index) {
593 CHECK(left > 0);
594
595 if (mDataSource->readAt(
596 mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) {
597 return ERROR_IO;
598 }
599
600 x = ntohl(x);
601 --x;
602
603 CHECK(x <= start_sample_index);
604 }
605 break;
606 }
607
608 case kFlagAfter:
609 {
610 if (x < start_sample_index) {
611 if (left + 1 >= mNumSyncSamples) {
612 return ERROR_OUT_OF_RANGE;
613 }
614
Andreas Huberad98d382010-08-06 14:13:10 -0700615 x = mSyncSamples[left + 1];
Andreas Huber6624c9f2010-07-20 15:04:28 -0700616
617 CHECK(x >= start_sample_index);
618 }
619
620 break;
621 }
622
623 default:
624 break;
625 }
626
627 *sample_index = x;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700628
629 return OK;
630}
631
Andreas Hubere981c332009-10-22 13:49:30 -0700632status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
Andreas Huber1faa92a2010-01-19 10:39:21 -0800633 Mutex::Autolock autoLock(mLock);
634
Andreas Hubere981c332009-10-22 13:49:30 -0700635 if (mSyncSampleOffset < 0) {
636 // All samples are sync-samples.
637 *sample_index = 0;
638 return OK;
639 }
640
641 uint32_t bestSampleIndex = 0;
642 size_t maxSampleSize = 0;
643
644 static const size_t kMaxNumSyncSamplesToScan = 20;
645
646 // Consider the first kMaxNumSyncSamplesToScan sync samples and
647 // pick the one with the largest (compressed) size as the thumbnail.
648
649 size_t numSamplesToScan = mNumSyncSamples;
650 if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
651 numSamplesToScan = kMaxNumSyncSamplesToScan;
652 }
653
654 for (size_t i = 0; i < numSamplesToScan; ++i) {
Andreas Huberad98d382010-08-06 14:13:10 -0700655 uint32_t x = mSyncSamples[i];
Andreas Hubere981c332009-10-22 13:49:30 -0700656
657 // Now x is a sample index.
658 size_t sampleSize;
Andreas Huber1faa92a2010-01-19 10:39:21 -0800659 status_t err = getSampleSize_l(x, &sampleSize);
Andreas Hubere981c332009-10-22 13:49:30 -0700660 if (err != OK) {
661 return err;
662 }
663
664 if (i == 0 || sampleSize > maxSampleSize) {
665 bestSampleIndex = x;
666 maxSampleSize = sampleSize;
667 }
668 }
669
670 *sample_index = bestSampleIndex;
671
672 return OK;
673}
674
Andreas Huber1faa92a2010-01-19 10:39:21 -0800675status_t SampleTable::getSampleSize_l(
676 uint32_t sampleIndex, size_t *sampleSize) {
677 return mSampleIterator->getSampleSizeDirect(
678 sampleIndex, sampleSize);
679}
680
681status_t SampleTable::getMetaDataForSample(
682 uint32_t sampleIndex,
James Dongb1262a82010-11-16 14:04:54 -0800683 off64_t *offset,
Andreas Huber1faa92a2010-01-19 10:39:21 -0800684 size_t *size,
Andreas Huber44fdac02011-04-15 11:52:29 -0700685 uint32_t *compositionTime,
Andreas Huberad98d382010-08-06 14:13:10 -0700686 bool *isSyncSample) {
Andreas Huber1faa92a2010-01-19 10:39:21 -0800687 Mutex::Autolock autoLock(mLock);
688
689 status_t err;
690 if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
691 return err;
692 }
693
694 if (offset) {
695 *offset = mSampleIterator->getSampleOffset();
696 }
697
698 if (size) {
699 *size = mSampleIterator->getSampleSize();
700 }
701
Andreas Huber44fdac02011-04-15 11:52:29 -0700702 if (compositionTime) {
703 *compositionTime = mSampleIterator->getSampleTime();
Andreas Huber1faa92a2010-01-19 10:39:21 -0800704 }
705
Andreas Huberad98d382010-08-06 14:13:10 -0700706 if (isSyncSample) {
707 *isSyncSample = false;
708 if (mSyncSampleOffset < 0) {
709 // Every sample is a sync sample.
710 *isSyncSample = true;
711 } else {
712 size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
713 && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
714 ? mLastSyncSampleIndex : 0;
715
716 while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
717 ++i;
718 }
719
720 if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
721 *isSyncSample = true;
722 }
723
724 mLastSyncSampleIndex = i;
725 }
726 }
727
Andreas Huber1faa92a2010-01-19 10:39:21 -0800728 return OK;
729}
730
Andreas Huberbd352c32011-02-03 13:18:16 -0800731uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) const {
732 if (mCompositionTimeDeltaEntries == NULL) {
733 return 0;
734 }
735
736 uint32_t curSample = 0;
737 for (size_t i = 0; i < mNumCompositionTimeDeltaEntries; ++i) {
738 uint32_t sampleCount = mCompositionTimeDeltaEntries[2 * i];
739
740 if (sampleIndex < curSample + sampleCount) {
741 uint32_t sampleDelta = mCompositionTimeDeltaEntries[2 * i + 1];
742
743 return sampleDelta;
744 }
745
746 curSample += sampleCount;
747 }
748
749 return 0;
750}
751
Andreas Hubere46b7be2009-07-14 16:56:47 -0700752} // namespace android
753