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