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