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