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