SampleTable.cpp revision 20dfd1547445eca8853b7cde0a11aa11d28bf8d2
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/* TODO: remove after being merged into other branches */ 31#ifndef UINT32_MAX 32#define UINT32_MAX (4294967295U) 33#endif 34 35namespace android { 36 37// static 38const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o'); 39// static 40const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4'); 41// static 42const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z'); 43// static 44const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); 45 46//////////////////////////////////////////////////////////////////////////////// 47 48struct SampleTable::CompositionDeltaLookup { 49 CompositionDeltaLookup(); 50 51 void setEntries( 52 const uint32_t *deltaEntries, size_t numDeltaEntries); 53 54 uint32_t getCompositionTimeOffset(uint32_t sampleIndex); 55 56private: 57 Mutex mLock; 58 59 const uint32_t *mDeltaEntries; 60 size_t mNumDeltaEntries; 61 62 size_t mCurrentDeltaEntry; 63 size_t mCurrentEntrySampleIndex; 64 65 DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup); 66}; 67 68SampleTable::CompositionDeltaLookup::CompositionDeltaLookup() 69 : mDeltaEntries(NULL), 70 mNumDeltaEntries(0), 71 mCurrentDeltaEntry(0), 72 mCurrentEntrySampleIndex(0) { 73} 74 75void SampleTable::CompositionDeltaLookup::setEntries( 76 const uint32_t *deltaEntries, size_t numDeltaEntries) { 77 Mutex::Autolock autolock(mLock); 78 79 mDeltaEntries = deltaEntries; 80 mNumDeltaEntries = numDeltaEntries; 81 mCurrentDeltaEntry = 0; 82 mCurrentEntrySampleIndex = 0; 83} 84 85uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset( 86 uint32_t sampleIndex) { 87 Mutex::Autolock autolock(mLock); 88 89 if (mDeltaEntries == NULL) { 90 return 0; 91 } 92 93 if (sampleIndex < mCurrentEntrySampleIndex) { 94 mCurrentDeltaEntry = 0; 95 mCurrentEntrySampleIndex = 0; 96 } 97 98 while (mCurrentDeltaEntry < mNumDeltaEntries) { 99 uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry]; 100 if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) { 101 return mDeltaEntries[2 * mCurrentDeltaEntry + 1]; 102 } 103 104 mCurrentEntrySampleIndex += sampleCount; 105 ++mCurrentDeltaEntry; 106 } 107 108 return 0; 109} 110 111//////////////////////////////////////////////////////////////////////////////// 112 113SampleTable::SampleTable(const sp<DataSource> &source) 114 : mDataSource(source), 115 mChunkOffsetOffset(-1), 116 mChunkOffsetType(0), 117 mNumChunkOffsets(0), 118 mSampleToChunkOffset(-1), 119 mNumSampleToChunkOffsets(0), 120 mSampleSizeOffset(-1), 121 mSampleSizeFieldSize(0), 122 mDefaultSampleSize(0), 123 mNumSampleSizes(0), 124 mTimeToSampleCount(0), 125 mTimeToSample(NULL), 126 mSampleTimeEntries(NULL), 127 mCompositionTimeDeltaEntries(NULL), 128 mNumCompositionTimeDeltaEntries(0), 129 mCompositionDeltaLookup(new CompositionDeltaLookup), 130 mSyncSampleOffset(-1), 131 mNumSyncSamples(0), 132 mSyncSamples(NULL), 133 mLastSyncSampleIndex(0), 134 mSampleToChunkEntries(NULL) { 135 mSampleIterator = new SampleIterator(this); 136} 137 138SampleTable::~SampleTable() { 139 delete[] mSampleToChunkEntries; 140 mSampleToChunkEntries = NULL; 141 142 delete[] mSyncSamples; 143 mSyncSamples = NULL; 144 145 delete mCompositionDeltaLookup; 146 mCompositionDeltaLookup = NULL; 147 148 delete[] mCompositionTimeDeltaEntries; 149 mCompositionTimeDeltaEntries = NULL; 150 151 delete[] mSampleTimeEntries; 152 mSampleTimeEntries = NULL; 153 154 delete[] mTimeToSample; 155 mTimeToSample = NULL; 156 157 delete mSampleIterator; 158 mSampleIterator = NULL; 159} 160 161bool SampleTable::isValid() const { 162 return mChunkOffsetOffset >= 0 163 && mSampleToChunkOffset >= 0 164 && mSampleSizeOffset >= 0 165 && mTimeToSample != NULL; 166} 167 168status_t SampleTable::setChunkOffsetParams( 169 uint32_t type, off64_t data_offset, size_t data_size) { 170 if (mChunkOffsetOffset >= 0) { 171 return ERROR_MALFORMED; 172 } 173 174 CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64); 175 176 mChunkOffsetOffset = data_offset; 177 mChunkOffsetType = type; 178 179 if (data_size < 8) { 180 return ERROR_MALFORMED; 181 } 182 183 uint8_t header[8]; 184 if (mDataSource->readAt( 185 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 186 return ERROR_IO; 187 } 188 189 if (U32_AT(header) != 0) { 190 // Expected version = 0, flags = 0. 191 return ERROR_MALFORMED; 192 } 193 194 mNumChunkOffsets = U32_AT(&header[4]); 195 196 if (mChunkOffsetType == kChunkOffsetType32) { 197 if (data_size < 8 + mNumChunkOffsets * 4) { 198 return ERROR_MALFORMED; 199 } 200 } else { 201 if (data_size < 8 + mNumChunkOffsets * 8) { 202 return ERROR_MALFORMED; 203 } 204 } 205 206 return OK; 207} 208 209status_t SampleTable::setSampleToChunkParams( 210 off64_t data_offset, size_t data_size) { 211 if (mSampleToChunkOffset >= 0) { 212 return ERROR_MALFORMED; 213 } 214 215 mSampleToChunkOffset = data_offset; 216 217 if (data_size < 8) { 218 return ERROR_MALFORMED; 219 } 220 221 uint8_t header[8]; 222 if (mDataSource->readAt( 223 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 224 return ERROR_IO; 225 } 226 227 if (U32_AT(header) != 0) { 228 // Expected version = 0, flags = 0. 229 return ERROR_MALFORMED; 230 } 231 232 mNumSampleToChunkOffsets = U32_AT(&header[4]); 233 234 if (data_size < 8 + mNumSampleToChunkOffsets * 12) { 235 return ERROR_MALFORMED; 236 } 237 238 if (SIZE_MAX / sizeof(SampleToChunkEntry) <= (size_t)mNumSampleToChunkOffsets) 239 return ERROR_OUT_OF_RANGE; 240 241 mSampleToChunkEntries = 242 new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets]; 243 if (!mSampleToChunkEntries) 244 return ERROR_OUT_OF_RANGE; 245 246 for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { 247 uint8_t buffer[12]; 248 if (mDataSource->readAt( 249 mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) 250 != (ssize_t)sizeof(buffer)) { 251 return ERROR_IO; 252 } 253 254 CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. 255 256 // We want the chunk index to be 0-based. 257 mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; 258 mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]); 259 mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]); 260 } 261 262 return OK; 263} 264 265status_t SampleTable::setSampleSizeParams( 266 uint32_t type, off64_t data_offset, size_t data_size) { 267 if (mSampleSizeOffset >= 0) { 268 return ERROR_MALFORMED; 269 } 270 271 CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); 272 273 mSampleSizeOffset = data_offset; 274 275 if (data_size < 12) { 276 return ERROR_MALFORMED; 277 } 278 279 uint8_t header[12]; 280 if (mDataSource->readAt( 281 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 282 return ERROR_IO; 283 } 284 285 if (U32_AT(header) != 0) { 286 // Expected version = 0, flags = 0. 287 return ERROR_MALFORMED; 288 } 289 290 mDefaultSampleSize = U32_AT(&header[4]); 291 mNumSampleSizes = U32_AT(&header[8]); 292 if (mNumSampleSizes > (UINT32_MAX - 12) / 16) { 293 ALOGE("b/23247055, mNumSampleSizes(%u)", mNumSampleSizes); 294 return ERROR_MALFORMED; 295 } 296 297 if (type == kSampleSizeType32) { 298 mSampleSizeFieldSize = 32; 299 300 if (mDefaultSampleSize != 0) { 301 return OK; 302 } 303 304 if (data_size < 12 + mNumSampleSizes * 4) { 305 return ERROR_MALFORMED; 306 } 307 } else { 308 if ((mDefaultSampleSize & 0xffffff00) != 0) { 309 // The high 24 bits are reserved and must be 0. 310 return ERROR_MALFORMED; 311 } 312 313 mSampleSizeFieldSize = mDefaultSampleSize & 0xff; 314 mDefaultSampleSize = 0; 315 316 if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8 317 && mSampleSizeFieldSize != 16) { 318 return ERROR_MALFORMED; 319 } 320 321 if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) { 322 return ERROR_MALFORMED; 323 } 324 } 325 326 return OK; 327} 328 329status_t SampleTable::setTimeToSampleParams( 330 off64_t data_offset, size_t data_size) { 331 if (mTimeToSample != NULL || data_size < 8) { 332 return ERROR_MALFORMED; 333 } 334 335 uint8_t header[8]; 336 if (mDataSource->readAt( 337 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 338 return ERROR_IO; 339 } 340 341 if (U32_AT(header) != 0) { 342 // Expected version = 0, flags = 0. 343 return ERROR_MALFORMED; 344 } 345 346 mTimeToSampleCount = U32_AT(&header[4]); 347 uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t); 348 if (allocSize > UINT32_MAX) { 349 return ERROR_OUT_OF_RANGE; 350 } 351 mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2]; 352 if (!mTimeToSample) 353 return ERROR_OUT_OF_RANGE; 354 355 size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; 356 if (mDataSource->readAt( 357 data_offset + 8, mTimeToSample, size) < (ssize_t)size) { 358 return ERROR_IO; 359 } 360 361 for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) { 362 mTimeToSample[i] = ntohl(mTimeToSample[i]); 363 } 364 365 return OK; 366} 367 368status_t SampleTable::setCompositionTimeToSampleParams( 369 off64_t data_offset, size_t data_size) { 370 ALOGI("There are reordered frames present."); 371 372 if (mCompositionTimeDeltaEntries != NULL || data_size < 8) { 373 return ERROR_MALFORMED; 374 } 375 376 uint8_t header[8]; 377 if (mDataSource->readAt( 378 data_offset, header, sizeof(header)) 379 < (ssize_t)sizeof(header)) { 380 return ERROR_IO; 381 } 382 383 if (U32_AT(header) != 0) { 384 // Expected version = 0, flags = 0. 385 return ERROR_MALFORMED; 386 } 387 388 size_t numEntries = U32_AT(&header[4]); 389 390 if (data_size != (numEntries + 1) * 8) { 391 return ERROR_MALFORMED; 392 } 393 394 mNumCompositionTimeDeltaEntries = numEntries; 395 uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t); 396 if (allocSize > UINT32_MAX) { 397 return ERROR_OUT_OF_RANGE; 398 } 399 400 mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries]; 401 if (!mCompositionTimeDeltaEntries) 402 return ERROR_OUT_OF_RANGE; 403 404 if (mDataSource->readAt( 405 data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8) 406 < (ssize_t)numEntries * 8) { 407 delete[] mCompositionTimeDeltaEntries; 408 mCompositionTimeDeltaEntries = NULL; 409 410 return ERROR_IO; 411 } 412 413 for (size_t i = 0; i < 2 * numEntries; ++i) { 414 mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]); 415 } 416 417 mCompositionDeltaLookup->setEntries( 418 mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries); 419 420 return OK; 421} 422 423status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) { 424 if (mSyncSampleOffset >= 0 || data_size < 8) { 425 return ERROR_MALFORMED; 426 } 427 428 mSyncSampleOffset = data_offset; 429 430 uint8_t header[8]; 431 if (mDataSource->readAt( 432 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 433 return ERROR_IO; 434 } 435 436 if (U32_AT(header) != 0) { 437 // Expected version = 0, flags = 0. 438 return ERROR_MALFORMED; 439 } 440 441 mNumSyncSamples = U32_AT(&header[4]); 442 443 if (mNumSyncSamples < 2) { 444 ALOGV("Table of sync samples is empty or has only a single entry!"); 445 } 446 447 uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t); 448 if (allocSize > SIZE_MAX) { 449 return ERROR_OUT_OF_RANGE; 450 } 451 452 mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples]; 453 if (!mSyncSamples) 454 return ERROR_OUT_OF_RANGE; 455 456 size_t size = mNumSyncSamples * sizeof(uint32_t); 457 if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size) 458 != (ssize_t)size) { 459 return ERROR_IO; 460 } 461 462 for (size_t i = 0; i < mNumSyncSamples; ++i) { 463 mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1; 464 } 465 466 return OK; 467} 468 469uint32_t SampleTable::countChunkOffsets() const { 470 return mNumChunkOffsets; 471} 472 473uint32_t SampleTable::countSamples() const { 474 return mNumSampleSizes; 475} 476 477status_t SampleTable::getMaxSampleSize(size_t *max_size) { 478 Mutex::Autolock autoLock(mLock); 479 480 *max_size = 0; 481 482 for (uint32_t i = 0; i < mNumSampleSizes; ++i) { 483 size_t sample_size; 484 status_t err = getSampleSize_l(i, &sample_size); 485 486 if (err != OK) { 487 return err; 488 } 489 490 if (sample_size > *max_size) { 491 *max_size = sample_size; 492 } 493 } 494 495 return OK; 496} 497 498uint32_t abs_difference(uint32_t time1, uint32_t time2) { 499 return time1 > time2 ? time1 - time2 : time2 - time1; 500} 501 502// static 503int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) { 504 const SampleTimeEntry *a = (const SampleTimeEntry *)_a; 505 const SampleTimeEntry *b = (const SampleTimeEntry *)_b; 506 507 if (a->mCompositionTime < b->mCompositionTime) { 508 return -1; 509 } else if (a->mCompositionTime > b->mCompositionTime) { 510 return 1; 511 } 512 513 return 0; 514} 515 516void SampleTable::buildSampleEntriesTable() { 517 Mutex::Autolock autoLock(mLock); 518 519 if (mSampleTimeEntries != NULL || mNumSampleSizes == 0) { 520 ALOGE("b/23247055, mNumSampleSizes(%u), mSampleTimeEntries(%p)", 521 mNumSampleSizes, mSampleTimeEntries); 522 return; 523 } 524 525 mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes]; 526 if (!mSampleTimeEntries) 527 return; 528 529 uint32_t sampleIndex = 0; 530 uint32_t sampleTime = 0; 531 532 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { 533 uint32_t n = mTimeToSample[2 * i]; 534 uint32_t delta = mTimeToSample[2 * i + 1]; 535 536 for (uint32_t j = 0; j < n; ++j) { 537 if (sampleIndex < mNumSampleSizes) { 538 // Technically this should always be the case if the file 539 // is well-formed, but you know... there's (gasp) malformed 540 // content out there. 541 542 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; 543 544 uint32_t compTimeDelta = 545 mCompositionDeltaLookup->getCompositionTimeOffset( 546 sampleIndex); 547 548 mSampleTimeEntries[sampleIndex].mCompositionTime = 549 sampleTime + compTimeDelta; 550 } 551 552 ++sampleIndex; 553 sampleTime += delta; 554 } 555 } 556 557 qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry), 558 CompareIncreasingTime); 559} 560 561status_t SampleTable::findSampleAtTime( 562 uint64_t req_time, uint64_t scale_num, uint64_t scale_den, 563 uint32_t *sample_index, uint32_t flags) { 564 buildSampleEntriesTable(); 565 566 if (mSampleTimeEntries == NULL) { 567 return ERROR_OUT_OF_RANGE; 568 } 569 570 uint32_t left = 0; 571 uint32_t right_plus_one = mNumSampleSizes; 572 while (left < right_plus_one) { 573 uint32_t center = left + (right_plus_one - left) / 2; 574 uint64_t centerTime = 575 getSampleTime(center, scale_num, scale_den); 576 577 if (req_time < centerTime) { 578 right_plus_one = center; 579 } else if (req_time > centerTime) { 580 left = center + 1; 581 } else { 582 *sample_index = mSampleTimeEntries[center].mSampleIndex; 583 return OK; 584 } 585 } 586 587 uint32_t closestIndex = left; 588 589 if (closestIndex == mNumSampleSizes) { 590 if (flags == kFlagAfter) { 591 return ERROR_OUT_OF_RANGE; 592 } 593 flags = kFlagBefore; 594 } else if (closestIndex == 0) { 595 if (flags == kFlagBefore) { 596 // normally we should return out of range, but that is 597 // treated as end-of-stream. instead return first sample 598 // 599 // return ERROR_OUT_OF_RANGE; 600 } 601 flags = kFlagAfter; 602 } 603 604 switch (flags) { 605 case kFlagBefore: 606 { 607 --closestIndex; 608 break; 609 } 610 611 case kFlagAfter: 612 { 613 // nothing to do 614 break; 615 } 616 617 default: 618 { 619 CHECK(flags == kFlagClosest); 620 // pick closest based on timestamp. use abs_difference for safety 621 if (abs_difference( 622 getSampleTime(closestIndex, scale_num, scale_den), req_time) > 623 abs_difference( 624 req_time, getSampleTime(closestIndex - 1, scale_num, scale_den))) { 625 --closestIndex; 626 } 627 break; 628 } 629 } 630 631 *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; 632 return OK; 633} 634 635status_t SampleTable::findSyncSampleNear( 636 uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) { 637 Mutex::Autolock autoLock(mLock); 638 639 *sample_index = 0; 640 641 if (mSyncSampleOffset < 0) { 642 // All samples are sync-samples. 643 *sample_index = start_sample_index; 644 return OK; 645 } 646 647 if (mNumSyncSamples == 0) { 648 *sample_index = 0; 649 return OK; 650 } 651 652 uint32_t left = 0; 653 uint32_t right_plus_one = mNumSyncSamples; 654 while (left < right_plus_one) { 655 uint32_t center = left + (right_plus_one - left) / 2; 656 uint32_t x = mSyncSamples[center]; 657 658 if (start_sample_index < x) { 659 right_plus_one = center; 660 } else if (start_sample_index > x) { 661 left = center + 1; 662 } else { 663 *sample_index = x; 664 return OK; 665 } 666 } 667 668 if (left == mNumSyncSamples) { 669 if (flags == kFlagAfter) { 670 ALOGE("tried to find a sync frame after the last one: %d", left); 671 return ERROR_OUT_OF_RANGE; 672 } 673 flags = kFlagBefore; 674 } 675 else if (left == 0) { 676 if (flags == kFlagBefore) { 677 ALOGE("tried to find a sync frame before the first one: %d", left); 678 679 // normally we should return out of range, but that is 680 // treated as end-of-stream. instead seek to first sync 681 // 682 // return ERROR_OUT_OF_RANGE; 683 } 684 flags = kFlagAfter; 685 } 686 687 // Now ssi[left - 1] <(=) start_sample_index <= ssi[left] 688 switch (flags) { 689 case kFlagBefore: 690 { 691 --left; 692 break; 693 } 694 case kFlagAfter: 695 { 696 // nothing to do 697 break; 698 } 699 default: 700 { 701 // this route is not used, but implement it nonetheless 702 CHECK(flags == kFlagClosest); 703 704 status_t err = mSampleIterator->seekTo(start_sample_index); 705 if (err != OK) { 706 return err; 707 } 708 uint32_t sample_time = mSampleIterator->getSampleTime(); 709 710 err = mSampleIterator->seekTo(mSyncSamples[left]); 711 if (err != OK) { 712 return err; 713 } 714 uint32_t upper_time = mSampleIterator->getSampleTime(); 715 716 err = mSampleIterator->seekTo(mSyncSamples[left - 1]); 717 if (err != OK) { 718 return err; 719 } 720 uint32_t lower_time = mSampleIterator->getSampleTime(); 721 722 // use abs_difference for safety 723 if (abs_difference(upper_time, sample_time) > 724 abs_difference(sample_time, lower_time)) { 725 --left; 726 } 727 break; 728 } 729 } 730 731 *sample_index = mSyncSamples[left]; 732 return OK; 733} 734 735status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { 736 Mutex::Autolock autoLock(mLock); 737 738 if (mSyncSampleOffset < 0) { 739 // All samples are sync-samples. 740 *sample_index = 0; 741 return OK; 742 } 743 744 uint32_t bestSampleIndex = 0; 745 size_t maxSampleSize = 0; 746 747 static const size_t kMaxNumSyncSamplesToScan = 20; 748 749 // Consider the first kMaxNumSyncSamplesToScan sync samples and 750 // pick the one with the largest (compressed) size as the thumbnail. 751 752 size_t numSamplesToScan = mNumSyncSamples; 753 if (numSamplesToScan > kMaxNumSyncSamplesToScan) { 754 numSamplesToScan = kMaxNumSyncSamplesToScan; 755 } 756 757 for (size_t i = 0; i < numSamplesToScan; ++i) { 758 uint32_t x = mSyncSamples[i]; 759 760 // Now x is a sample index. 761 size_t sampleSize; 762 status_t err = getSampleSize_l(x, &sampleSize); 763 if (err != OK) { 764 return err; 765 } 766 767 if (i == 0 || sampleSize > maxSampleSize) { 768 bestSampleIndex = x; 769 maxSampleSize = sampleSize; 770 } 771 } 772 773 *sample_index = bestSampleIndex; 774 775 return OK; 776} 777 778status_t SampleTable::getSampleSize_l( 779 uint32_t sampleIndex, size_t *sampleSize) { 780 return mSampleIterator->getSampleSizeDirect( 781 sampleIndex, sampleSize); 782} 783 784status_t SampleTable::getMetaDataForSample( 785 uint32_t sampleIndex, 786 off64_t *offset, 787 size_t *size, 788 uint32_t *compositionTime, 789 bool *isSyncSample, 790 uint32_t *sampleDuration) { 791 Mutex::Autolock autoLock(mLock); 792 793 status_t err; 794 if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) { 795 return err; 796 } 797 798 if (offset) { 799 *offset = mSampleIterator->getSampleOffset(); 800 } 801 802 if (size) { 803 *size = mSampleIterator->getSampleSize(); 804 } 805 806 if (compositionTime) { 807 *compositionTime = mSampleIterator->getSampleTime(); 808 } 809 810 if (isSyncSample) { 811 *isSyncSample = false; 812 if (mSyncSampleOffset < 0) { 813 // Every sample is a sync sample. 814 *isSyncSample = true; 815 } else { 816 size_t i = (mLastSyncSampleIndex < mNumSyncSamples) 817 && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex) 818 ? mLastSyncSampleIndex : 0; 819 820 while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) { 821 ++i; 822 } 823 824 if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) { 825 *isSyncSample = true; 826 } 827 828 mLastSyncSampleIndex = i; 829 } 830 } 831 832 if (sampleDuration) { 833 *sampleDuration = mSampleIterator->getSampleDuration(); 834 } 835 836 return OK; 837} 838 839uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { 840 return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex); 841} 842 843} // namespace android 844 845