SampleTable.cpp revision 1cb23b033987e86827a4fa96550c6a3670b688f1
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) / 4 < mNumChunkOffsets) { 198 return ERROR_MALFORMED; 199 } 200 } else { 201 if ((data_size - 8) / 8 < mNumChunkOffsets) { 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 // already set 213 return ERROR_MALFORMED; 214 } 215 216 if (data_offset < 0) { 217 return ERROR_MALFORMED; 218 } 219 220 mSampleToChunkOffset = data_offset; 221 222 if (data_size < 8) { 223 return ERROR_MALFORMED; 224 } 225 226 uint8_t header[8]; 227 if (mDataSource->readAt( 228 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 229 return ERROR_IO; 230 } 231 232 if (U32_AT(header) != 0) { 233 // Expected version = 0, flags = 0. 234 return ERROR_MALFORMED; 235 } 236 237 mNumSampleToChunkOffsets = U32_AT(&header[4]); 238 239 if ((data_size - 8) / 12 < mNumSampleToChunkOffsets) { 240 return ERROR_MALFORMED; 241 } 242 243 if (SIZE_MAX / sizeof(SampleToChunkEntry) <= (size_t)mNumSampleToChunkOffsets) 244 return ERROR_OUT_OF_RANGE; 245 246 mSampleToChunkEntries = 247 new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets]; 248 if (!mSampleToChunkEntries) 249 return ERROR_OUT_OF_RANGE; 250 251 for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { 252 uint8_t buffer[12]; 253 254 if ((SIZE_MAX - 8 - (i * 12)) < (size_t)mSampleToChunkOffset) { 255 return ERROR_MALFORMED; 256 } 257 258 if (mDataSource->readAt( 259 mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) 260 != (ssize_t)sizeof(buffer)) { 261 return ERROR_IO; 262 } 263 264 CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. 265 266 // We want the chunk index to be 0-based. 267 mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; 268 mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]); 269 mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]); 270 } 271 272 return OK; 273} 274 275status_t SampleTable::setSampleSizeParams( 276 uint32_t type, off64_t data_offset, size_t data_size) { 277 if (mSampleSizeOffset >= 0) { 278 return ERROR_MALFORMED; 279 } 280 281 CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); 282 283 mSampleSizeOffset = data_offset; 284 285 if (data_size < 12) { 286 return ERROR_MALFORMED; 287 } 288 289 uint8_t header[12]; 290 if (mDataSource->readAt( 291 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 292 return ERROR_IO; 293 } 294 295 if (U32_AT(header) != 0) { 296 // Expected version = 0, flags = 0. 297 return ERROR_MALFORMED; 298 } 299 300 mDefaultSampleSize = U32_AT(&header[4]); 301 mNumSampleSizes = U32_AT(&header[8]); 302 if (mNumSampleSizes > (UINT32_MAX - 12) / 16) { 303 return ERROR_MALFORMED; 304 } 305 306 if (type == kSampleSizeType32) { 307 mSampleSizeFieldSize = 32; 308 309 if (mDefaultSampleSize != 0) { 310 return OK; 311 } 312 313 if (data_size < 12 + mNumSampleSizes * 4) { 314 return ERROR_MALFORMED; 315 } 316 } else { 317 if ((mDefaultSampleSize & 0xffffff00) != 0) { 318 // The high 24 bits are reserved and must be 0. 319 return ERROR_MALFORMED; 320 } 321 322 mSampleSizeFieldSize = mDefaultSampleSize & 0xff; 323 mDefaultSampleSize = 0; 324 325 if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8 326 && mSampleSizeFieldSize != 16) { 327 return ERROR_MALFORMED; 328 } 329 330 if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) { 331 return ERROR_MALFORMED; 332 } 333 } 334 335 return OK; 336} 337 338status_t SampleTable::setTimeToSampleParams( 339 off64_t data_offset, size_t data_size) { 340 if (mTimeToSample != NULL || data_size < 8) { 341 return ERROR_MALFORMED; 342 } 343 344 uint8_t header[8]; 345 if (mDataSource->readAt( 346 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 347 return ERROR_IO; 348 } 349 350 if (U32_AT(header) != 0) { 351 // Expected version = 0, flags = 0. 352 return ERROR_MALFORMED; 353 } 354 355 mTimeToSampleCount = U32_AT(&header[4]); 356 uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t); 357 if (allocSize > UINT32_MAX) { 358 return ERROR_OUT_OF_RANGE; 359 } 360 mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2]; 361 if (!mTimeToSample) 362 return ERROR_OUT_OF_RANGE; 363 364 size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; 365 if (mDataSource->readAt( 366 data_offset + 8, mTimeToSample, size) < (ssize_t)size) { 367 return ERROR_IO; 368 } 369 370 for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) { 371 mTimeToSample[i] = ntohl(mTimeToSample[i]); 372 } 373 374 return OK; 375} 376 377status_t SampleTable::setCompositionTimeToSampleParams( 378 off64_t data_offset, size_t data_size) { 379 ALOGI("There are reordered frames present."); 380 381 if (mCompositionTimeDeltaEntries != NULL || data_size < 8) { 382 return ERROR_MALFORMED; 383 } 384 385 uint8_t header[8]; 386 if (mDataSource->readAt( 387 data_offset, header, sizeof(header)) 388 < (ssize_t)sizeof(header)) { 389 return ERROR_IO; 390 } 391 392 if (U32_AT(header) != 0) { 393 // Expected version = 0, flags = 0. 394 return ERROR_MALFORMED; 395 } 396 397 size_t numEntries = U32_AT(&header[4]); 398 399 if (((SIZE_MAX / 8) - 1 < numEntries) || (data_size != (numEntries + 1) * 8)) { 400 return ERROR_MALFORMED; 401 } 402 403 mNumCompositionTimeDeltaEntries = numEntries; 404 uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t); 405 if (allocSize > UINT32_MAX) { 406 return ERROR_OUT_OF_RANGE; 407 } 408 409 mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries]; 410 if (!mCompositionTimeDeltaEntries) 411 return ERROR_OUT_OF_RANGE; 412 413 if (mDataSource->readAt( 414 data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8) 415 < (ssize_t)numEntries * 8) { 416 delete[] mCompositionTimeDeltaEntries; 417 mCompositionTimeDeltaEntries = NULL; 418 419 return ERROR_IO; 420 } 421 422 for (size_t i = 0; i < 2 * numEntries; ++i) { 423 mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]); 424 } 425 426 mCompositionDeltaLookup->setEntries( 427 mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries); 428 429 return OK; 430} 431 432status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) { 433 if (mSyncSampleOffset >= 0 || data_size < 8) { 434 return ERROR_MALFORMED; 435 } 436 437 mSyncSampleOffset = data_offset; 438 439 uint8_t header[8]; 440 if (mDataSource->readAt( 441 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 442 return ERROR_IO; 443 } 444 445 if (U32_AT(header) != 0) { 446 // Expected version = 0, flags = 0. 447 return ERROR_MALFORMED; 448 } 449 450 mNumSyncSamples = U32_AT(&header[4]); 451 452 if (mNumSyncSamples < 2) { 453 ALOGV("Table of sync samples is empty or has only a single entry!"); 454 } 455 456 uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t); 457 if (allocSize > SIZE_MAX) { 458 return ERROR_OUT_OF_RANGE; 459 } 460 461 mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples]; 462 if (!mSyncSamples) 463 return ERROR_OUT_OF_RANGE; 464 465 size_t size = mNumSyncSamples * sizeof(uint32_t); 466 if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size) 467 != (ssize_t)size) { 468 return ERROR_IO; 469 } 470 471 for (size_t i = 0; i < mNumSyncSamples; ++i) { 472 mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1; 473 } 474 475 return OK; 476} 477 478uint32_t SampleTable::countChunkOffsets() const { 479 return mNumChunkOffsets; 480} 481 482uint32_t SampleTable::countSamples() const { 483 return mNumSampleSizes; 484} 485 486status_t SampleTable::getMaxSampleSize(size_t *max_size) { 487 Mutex::Autolock autoLock(mLock); 488 489 *max_size = 0; 490 491 for (uint32_t i = 0; i < mNumSampleSizes; ++i) { 492 size_t sample_size; 493 status_t err = getSampleSize_l(i, &sample_size); 494 495 if (err != OK) { 496 return err; 497 } 498 499 if (sample_size > *max_size) { 500 *max_size = sample_size; 501 } 502 } 503 504 return OK; 505} 506 507uint32_t abs_difference(uint32_t time1, uint32_t time2) { 508 return time1 > time2 ? time1 - time2 : time2 - time1; 509} 510 511// static 512int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) { 513 const SampleTimeEntry *a = (const SampleTimeEntry *)_a; 514 const SampleTimeEntry *b = (const SampleTimeEntry *)_b; 515 516 if (a->mCompositionTime < b->mCompositionTime) { 517 return -1; 518 } else if (a->mCompositionTime > b->mCompositionTime) { 519 return 1; 520 } 521 522 return 0; 523} 524 525void SampleTable::buildSampleEntriesTable() { 526 Mutex::Autolock autoLock(mLock); 527 528 if (mSampleTimeEntries != NULL || mNumSampleSizes == 0) { 529 return; 530 } 531 532 mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes]; 533 if (!mSampleTimeEntries) 534 return; 535 536 uint32_t sampleIndex = 0; 537 uint32_t sampleTime = 0; 538 539 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { 540 uint32_t n = mTimeToSample[2 * i]; 541 uint32_t delta = mTimeToSample[2 * i + 1]; 542 543 for (uint32_t j = 0; j < n; ++j) { 544 if (sampleIndex < mNumSampleSizes) { 545 // Technically this should always be the case if the file 546 // is well-formed, but you know... there's (gasp) malformed 547 // content out there. 548 549 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; 550 551 uint32_t compTimeDelta = 552 mCompositionDeltaLookup->getCompositionTimeOffset( 553 sampleIndex); 554 555 mSampleTimeEntries[sampleIndex].mCompositionTime = 556 sampleTime + compTimeDelta; 557 } 558 559 ++sampleIndex; 560 sampleTime += delta; 561 } 562 } 563 564 qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry), 565 CompareIncreasingTime); 566} 567 568status_t SampleTable::findSampleAtTime( 569 uint64_t req_time, uint64_t scale_num, uint64_t scale_den, 570 uint32_t *sample_index, uint32_t flags) { 571 buildSampleEntriesTable(); 572 573 if (mSampleTimeEntries == NULL) { 574 return ERROR_OUT_OF_RANGE; 575 } 576 577 uint32_t left = 0; 578 uint32_t right_plus_one = mNumSampleSizes; 579 while (left < right_plus_one) { 580 uint32_t center = left + (right_plus_one - left) / 2; 581 uint64_t centerTime = 582 getSampleTime(center, scale_num, scale_den); 583 584 if (req_time < centerTime) { 585 right_plus_one = center; 586 } else if (req_time > centerTime) { 587 left = center + 1; 588 } else { 589 *sample_index = mSampleTimeEntries[center].mSampleIndex; 590 return OK; 591 } 592 } 593 594 uint32_t closestIndex = left; 595 596 if (closestIndex == mNumSampleSizes) { 597 if (flags == kFlagAfter) { 598 return ERROR_OUT_OF_RANGE; 599 } 600 flags = kFlagBefore; 601 } else if (closestIndex == 0) { 602 if (flags == kFlagBefore) { 603 // normally we should return out of range, but that is 604 // treated as end-of-stream. instead return first sample 605 // 606 // return ERROR_OUT_OF_RANGE; 607 } 608 flags = kFlagAfter; 609 } 610 611 switch (flags) { 612 case kFlagBefore: 613 { 614 --closestIndex; 615 break; 616 } 617 618 case kFlagAfter: 619 { 620 // nothing to do 621 break; 622 } 623 624 default: 625 { 626 CHECK(flags == kFlagClosest); 627 // pick closest based on timestamp. use abs_difference for safety 628 if (abs_difference( 629 getSampleTime(closestIndex, scale_num, scale_den), req_time) > 630 abs_difference( 631 req_time, getSampleTime(closestIndex - 1, scale_num, scale_den))) { 632 --closestIndex; 633 } 634 break; 635 } 636 } 637 638 *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; 639 return OK; 640} 641 642status_t SampleTable::findSyncSampleNear( 643 uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) { 644 Mutex::Autolock autoLock(mLock); 645 646 *sample_index = 0; 647 648 if (mSyncSampleOffset < 0) { 649 // All samples are sync-samples. 650 *sample_index = start_sample_index; 651 return OK; 652 } 653 654 if (mNumSyncSamples == 0) { 655 *sample_index = 0; 656 return OK; 657 } 658 659 uint32_t left = 0; 660 uint32_t right_plus_one = mNumSyncSamples; 661 while (left < right_plus_one) { 662 uint32_t center = left + (right_plus_one - left) / 2; 663 uint32_t x = mSyncSamples[center]; 664 665 if (start_sample_index < x) { 666 right_plus_one = center; 667 } else if (start_sample_index > x) { 668 left = center + 1; 669 } else { 670 *sample_index = x; 671 return OK; 672 } 673 } 674 675 if (left == mNumSyncSamples) { 676 if (flags == kFlagAfter) { 677 ALOGE("tried to find a sync frame after the last one: %d", left); 678 return ERROR_OUT_OF_RANGE; 679 } 680 flags = kFlagBefore; 681 } 682 else if (left == 0) { 683 if (flags == kFlagBefore) { 684 ALOGE("tried to find a sync frame before the first one: %d", left); 685 686 // normally we should return out of range, but that is 687 // treated as end-of-stream. instead seek to first sync 688 // 689 // return ERROR_OUT_OF_RANGE; 690 } 691 flags = kFlagAfter; 692 } 693 694 // Now ssi[left - 1] <(=) start_sample_index <= ssi[left] 695 switch (flags) { 696 case kFlagBefore: 697 { 698 --left; 699 break; 700 } 701 case kFlagAfter: 702 { 703 // nothing to do 704 break; 705 } 706 default: 707 { 708 // this route is not used, but implement it nonetheless 709 CHECK(flags == kFlagClosest); 710 711 status_t err = mSampleIterator->seekTo(start_sample_index); 712 if (err != OK) { 713 return err; 714 } 715 uint32_t sample_time = mSampleIterator->getSampleTime(); 716 717 err = mSampleIterator->seekTo(mSyncSamples[left]); 718 if (err != OK) { 719 return err; 720 } 721 uint32_t upper_time = mSampleIterator->getSampleTime(); 722 723 err = mSampleIterator->seekTo(mSyncSamples[left - 1]); 724 if (err != OK) { 725 return err; 726 } 727 uint32_t lower_time = mSampleIterator->getSampleTime(); 728 729 // use abs_difference for safety 730 if (abs_difference(upper_time, sample_time) > 731 abs_difference(sample_time, lower_time)) { 732 --left; 733 } 734 break; 735 } 736 } 737 738 *sample_index = mSyncSamples[left]; 739 return OK; 740} 741 742status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { 743 Mutex::Autolock autoLock(mLock); 744 745 if (mSyncSampleOffset < 0) { 746 // All samples are sync-samples. 747 *sample_index = 0; 748 return OK; 749 } 750 751 uint32_t bestSampleIndex = 0; 752 size_t maxSampleSize = 0; 753 754 static const size_t kMaxNumSyncSamplesToScan = 20; 755 756 // Consider the first kMaxNumSyncSamplesToScan sync samples and 757 // pick the one with the largest (compressed) size as the thumbnail. 758 759 size_t numSamplesToScan = mNumSyncSamples; 760 if (numSamplesToScan > kMaxNumSyncSamplesToScan) { 761 numSamplesToScan = kMaxNumSyncSamplesToScan; 762 } 763 764 for (size_t i = 0; i < numSamplesToScan; ++i) { 765 uint32_t x = mSyncSamples[i]; 766 767 // Now x is a sample index. 768 size_t sampleSize; 769 status_t err = getSampleSize_l(x, &sampleSize); 770 if (err != OK) { 771 return err; 772 } 773 774 if (i == 0 || sampleSize > maxSampleSize) { 775 bestSampleIndex = x; 776 maxSampleSize = sampleSize; 777 } 778 } 779 780 *sample_index = bestSampleIndex; 781 782 return OK; 783} 784 785status_t SampleTable::getSampleSize_l( 786 uint32_t sampleIndex, size_t *sampleSize) { 787 return mSampleIterator->getSampleSizeDirect( 788 sampleIndex, sampleSize); 789} 790 791status_t SampleTable::getMetaDataForSample( 792 uint32_t sampleIndex, 793 off64_t *offset, 794 size_t *size, 795 uint32_t *compositionTime, 796 bool *isSyncSample, 797 uint32_t *sampleDuration) { 798 Mutex::Autolock autoLock(mLock); 799 800 status_t err; 801 if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) { 802 return err; 803 } 804 805 if (offset) { 806 *offset = mSampleIterator->getSampleOffset(); 807 } 808 809 if (size) { 810 *size = mSampleIterator->getSampleSize(); 811 } 812 813 if (compositionTime) { 814 *compositionTime = mSampleIterator->getSampleTime(); 815 } 816 817 if (isSyncSample) { 818 *isSyncSample = false; 819 if (mSyncSampleOffset < 0) { 820 // Every sample is a sync sample. 821 *isSyncSample = true; 822 } else { 823 size_t i = (mLastSyncSampleIndex < mNumSyncSamples) 824 && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex) 825 ? mLastSyncSampleIndex : 0; 826 827 while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) { 828 ++i; 829 } 830 831 if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) { 832 *isSyncSample = true; 833 } 834 835 mLastSyncSampleIndex = i; 836 } 837 } 838 839 if (sampleDuration) { 840 *sampleDuration = mSampleIterator->getSampleDuration(); 841 } 842 843 return OK; 844} 845 846uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { 847 return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex); 848} 849 850} // namespace android 851 852