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