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