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