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