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