SampleTable.cpp revision 9a12baf929ea803915d7ab626b200ffefb4fbac7
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#include <utils/Log.h> 19 20#include "include/SampleTable.h" 21 22#include <arpa/inet.h> 23 24#include <media/stagefright/DataSource.h> 25#include <media/stagefright/MediaDebug.h> 26#include <media/stagefright/Utils.h> 27 28namespace android { 29 30static const uint32_t kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o'); 31static const uint32_t kChunkOffsetType64 = FOURCC('c', 'o', '6', '4'); 32static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z'); 33static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); 34 35SampleTable::SampleTable(const sp<DataSource> &source) 36 : mDataSource(source), 37 mChunkOffsetOffset(-1), 38 mChunkOffsetType(0), 39 mNumChunkOffsets(0), 40 mSampleToChunkOffset(-1), 41 mNumSampleToChunkOffsets(0), 42 mSampleSizeOffset(-1), 43 mSampleSizeFieldSize(0), 44 mDefaultSampleSize(0), 45 mNumSampleSizes(0), 46 mTimeToSampleCount(0), 47 mTimeToSample(NULL), 48 mSyncSampleOffset(-1), 49 mNumSyncSamples(0) { 50} 51 52SampleTable::~SampleTable() { 53 delete[] mTimeToSample; 54 mTimeToSample = NULL; 55} 56 57status_t SampleTable::setChunkOffsetParams( 58 uint32_t type, off_t data_offset, size_t data_size) { 59 if (mChunkOffsetOffset >= 0) { 60 return ERROR_MALFORMED; 61 } 62 63 CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64); 64 65 mChunkOffsetOffset = data_offset; 66 mChunkOffsetType = type; 67 68 if (data_size < 8) { 69 return ERROR_MALFORMED; 70 } 71 72 uint8_t header[8]; 73 if (mDataSource->readAt( 74 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 75 return ERROR_IO; 76 } 77 78 if (U32_AT(header) != 0) { 79 // Expected version = 0, flags = 0. 80 return ERROR_MALFORMED; 81 } 82 83 mNumChunkOffsets = U32_AT(&header[4]); 84 85 if (mChunkOffsetType == kChunkOffsetType32) { 86 if (data_size < 8 + mNumChunkOffsets * 4) { 87 return ERROR_MALFORMED; 88 } 89 } else { 90 if (data_size < 8 + mNumChunkOffsets * 8) { 91 return ERROR_MALFORMED; 92 } 93 } 94 95 return OK; 96} 97 98status_t SampleTable::setSampleToChunkParams( 99 off_t data_offset, size_t data_size) { 100 if (mSampleToChunkOffset >= 0) { 101 return ERROR_MALFORMED; 102 } 103 104 mSampleToChunkOffset = data_offset; 105 106 if (data_size < 8) { 107 return ERROR_MALFORMED; 108 } 109 110 uint8_t header[8]; 111 if (mDataSource->readAt( 112 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 113 return ERROR_IO; 114 } 115 116 if (U32_AT(header) != 0) { 117 // Expected version = 0, flags = 0. 118 return ERROR_MALFORMED; 119 } 120 121 mNumSampleToChunkOffsets = U32_AT(&header[4]); 122 123 if (data_size < 8 + mNumSampleToChunkOffsets * 12) { 124 return ERROR_MALFORMED; 125 } 126 127 return OK; 128} 129 130status_t SampleTable::setSampleSizeParams( 131 uint32_t type, off_t data_offset, size_t data_size) { 132 if (mSampleSizeOffset >= 0) { 133 return ERROR_MALFORMED; 134 } 135 136 CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); 137 138 mSampleSizeOffset = data_offset; 139 140 if (data_size < 12) { 141 return ERROR_MALFORMED; 142 } 143 144 uint8_t header[12]; 145 if (mDataSource->readAt( 146 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 147 return ERROR_IO; 148 } 149 150 if (U32_AT(header) != 0) { 151 // Expected version = 0, flags = 0. 152 return ERROR_MALFORMED; 153 } 154 155 mDefaultSampleSize = U32_AT(&header[4]); 156 mNumSampleSizes = U32_AT(&header[8]); 157 158 if (type == kSampleSizeType32) { 159 mSampleSizeFieldSize = 32; 160 161 if (mDefaultSampleSize != 0) { 162 return OK; 163 } 164 165 if (data_size < 12 + mNumSampleSizes * 4) { 166 return ERROR_MALFORMED; 167 } 168 } else { 169 if ((mDefaultSampleSize & 0xffffff00) != 0) { 170 // The high 24 bits are reserved and must be 0. 171 return ERROR_MALFORMED; 172 } 173 174 mSampleSizeFieldSize = mDefaultSampleSize & 0xf; 175 mDefaultSampleSize = 0; 176 177 if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8 178 && mSampleSizeFieldSize != 16) { 179 return ERROR_MALFORMED; 180 } 181 182 if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) { 183 return ERROR_MALFORMED; 184 } 185 } 186 187 return OK; 188} 189 190status_t SampleTable::setTimeToSampleParams( 191 off_t data_offset, size_t data_size) { 192 if (mTimeToSample != NULL || data_size < 8) { 193 return ERROR_MALFORMED; 194 } 195 196 uint8_t header[8]; 197 if (mDataSource->readAt( 198 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 199 return ERROR_IO; 200 } 201 202 if (U32_AT(header) != 0) { 203 // Expected version = 0, flags = 0. 204 return ERROR_MALFORMED; 205 } 206 207 mTimeToSampleCount = U32_AT(&header[4]); 208 mTimeToSample = new uint32_t[mTimeToSampleCount * 2]; 209 210 size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; 211 if (mDataSource->readAt( 212 data_offset + 8, mTimeToSample, size) < (ssize_t)size) { 213 return ERROR_IO; 214 } 215 216 for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) { 217 mTimeToSample[i] = ntohl(mTimeToSample[i]); 218 } 219 220 return OK; 221} 222 223status_t SampleTable::setSyncSampleParams(off_t data_offset, size_t data_size) { 224 if (mSyncSampleOffset >= 0 || data_size < 8) { 225 return ERROR_MALFORMED; 226 } 227 228 mSyncSampleOffset = data_offset; 229 230 uint8_t header[8]; 231 if (mDataSource->readAt( 232 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 233 return ERROR_IO; 234 } 235 236 if (U32_AT(header) != 0) { 237 // Expected version = 0, flags = 0. 238 return ERROR_MALFORMED; 239 } 240 241 mNumSyncSamples = U32_AT(&header[4]); 242 243 if (mNumSyncSamples < 2) { 244 LOGW("Table of sync samples is empty or has only a single entry!"); 245 } 246 return OK; 247} 248 249uint32_t SampleTable::countChunkOffsets() const { 250 return mNumChunkOffsets; 251} 252 253status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) { 254 *offset = 0; 255 256 if (mChunkOffsetOffset < 0) { 257 return ERROR_MALFORMED; 258 } 259 260 if (chunk_index >= mNumChunkOffsets) { 261 return ERROR_OUT_OF_RANGE; 262 } 263 264 if (mChunkOffsetType == kChunkOffsetType32) { 265 uint32_t offset32; 266 267 if (mDataSource->readAt( 268 mChunkOffsetOffset + 8 + 4 * chunk_index, 269 &offset32, 270 sizeof(offset32)) < (ssize_t)sizeof(offset32)) { 271 return ERROR_IO; 272 } 273 274 *offset = ntohl(offset32); 275 } else { 276 CHECK_EQ(mChunkOffsetType, kChunkOffsetType64); 277 278 uint64_t offset64; 279 if (mDataSource->readAt( 280 mChunkOffsetOffset + 8 + 8 * chunk_index, 281 &offset64, 282 sizeof(offset64)) < (ssize_t)sizeof(offset64)) { 283 return ERROR_IO; 284 } 285 286 *offset = ntoh64(offset64); 287 } 288 289 return OK; 290} 291 292status_t SampleTable::getChunkForSample( 293 uint32_t sample_index, 294 uint32_t *chunk_index, 295 uint32_t *chunk_relative_sample_index, 296 uint32_t *desc_index) { 297 *chunk_index = 0; 298 *chunk_relative_sample_index = 0; 299 *desc_index = 0; 300 301 if (mSampleToChunkOffset < 0) { 302 return ERROR_MALFORMED; 303 } 304 305 if (sample_index >= countSamples()) { 306 return ERROR_END_OF_STREAM; 307 } 308 309 uint32_t first_chunk = 0; 310 uint32_t samples_per_chunk = 0; 311 uint32_t chunk_desc_index = 0; 312 313 uint32_t index = 0; 314 while (index < mNumSampleToChunkOffsets) { 315 uint8_t buffer[12]; 316 if (mDataSource->readAt(mSampleToChunkOffset + 8 + index * 12, 317 buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) { 318 return ERROR_IO; 319 } 320 321 uint32_t stop_chunk = U32_AT(buffer); 322 if (sample_index < (stop_chunk - first_chunk) * samples_per_chunk) { 323 break; 324 } 325 326 sample_index -= (stop_chunk - first_chunk) * samples_per_chunk; 327 first_chunk = stop_chunk; 328 samples_per_chunk = U32_AT(&buffer[4]); 329 chunk_desc_index = U32_AT(&buffer[8]); 330 331 ++index; 332 } 333 334 *chunk_index = sample_index / samples_per_chunk + first_chunk - 1; 335 *chunk_relative_sample_index = sample_index % samples_per_chunk; 336 *desc_index = chunk_desc_index; 337 338 return OK; 339} 340 341uint32_t SampleTable::countSamples() const { 342 return mNumSampleSizes; 343} 344 345status_t SampleTable::getSampleSize( 346 uint32_t sample_index, size_t *sample_size) { 347 *sample_size = 0; 348 349 if (mSampleSizeOffset < 0) { 350 return ERROR_MALFORMED; 351 } 352 353 if (sample_index >= mNumSampleSizes) { 354 return ERROR_OUT_OF_RANGE; 355 } 356 357 if (mDefaultSampleSize > 0) { 358 *sample_size = mDefaultSampleSize; 359 return OK; 360 } 361 362 switch (mSampleSizeFieldSize) { 363 case 32: 364 { 365 if (mDataSource->readAt( 366 mSampleSizeOffset + 12 + 4 * sample_index, 367 sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) { 368 return ERROR_IO; 369 } 370 371 *sample_size = ntohl(*sample_size); 372 break; 373 } 374 375 case 16: 376 { 377 uint16_t x; 378 if (mDataSource->readAt( 379 mSampleSizeOffset + 12 + 2 * sample_index, 380 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 381 return ERROR_IO; 382 } 383 384 *sample_size = ntohs(x); 385 break; 386 } 387 388 case 8: 389 { 390 uint8_t x; 391 if (mDataSource->readAt( 392 mSampleSizeOffset + 12 + sample_index, 393 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 394 return ERROR_IO; 395 } 396 397 *sample_size = x; 398 break; 399 } 400 401 default: 402 { 403 CHECK_EQ(mSampleSizeFieldSize, 4); 404 405 uint8_t x; 406 if (mDataSource->readAt( 407 mSampleSizeOffset + 12 + sample_index / 2, 408 &x, sizeof(x)) < (ssize_t)sizeof(x)) { 409 return ERROR_IO; 410 } 411 412 *sample_size = (sample_index & 1) ? x & 0x0f : x >> 4; 413 break; 414 } 415 } 416 417 return OK; 418} 419 420status_t SampleTable::getSampleOffsetAndSize( 421 uint32_t sample_index, off_t *offset, size_t *size) { 422 Mutex::Autolock autoLock(mLock); 423 424 *offset = 0; 425 *size = 0; 426 427 uint32_t chunk_index; 428 uint32_t chunk_relative_sample_index; 429 uint32_t desc_index; 430 status_t err = getChunkForSample( 431 sample_index, &chunk_index, &chunk_relative_sample_index, 432 &desc_index); 433 434 if (err != OK) { 435 return err; 436 } 437 438 err = getChunkOffset(chunk_index, offset); 439 440 if (err != OK) { 441 return err; 442 } 443 444 for (uint32_t j = 0; j < chunk_relative_sample_index; ++j) { 445 size_t sample_size; 446 err = getSampleSize(sample_index - j - 1, &sample_size); 447 448 if (err != OK) { 449 return err; 450 } 451 452 *offset += sample_size; 453 } 454 455 err = getSampleSize(sample_index, size); 456 457 if (err != OK) { 458 return err; 459 } 460 461 return OK; 462} 463 464status_t SampleTable::getMaxSampleSize(size_t *max_size) { 465 Mutex::Autolock autoLock(mLock); 466 467 *max_size = 0; 468 469 for (uint32_t i = 0; i < mNumSampleSizes; ++i) { 470 size_t sample_size; 471 status_t err = getSampleSize(i, &sample_size); 472 473 if (err != OK) { 474 return err; 475 } 476 477 if (sample_size > *max_size) { 478 *max_size = sample_size; 479 } 480 } 481 482 return OK; 483} 484 485status_t SampleTable::getDecodingTime(uint32_t sample_index, uint32_t *time) { 486 // XXX FIXME idiotic (for the common use-case) O(n) algorithm below... 487 488 Mutex::Autolock autoLock(mLock); 489 490 if (sample_index >= mNumSampleSizes) { 491 return ERROR_OUT_OF_RANGE; 492 } 493 494 uint32_t cur_sample = 0; 495 *time = 0; 496 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { 497 uint32_t n = mTimeToSample[2 * i]; 498 uint32_t delta = mTimeToSample[2 * i + 1]; 499 500 if (sample_index < cur_sample + n) { 501 *time += delta * (sample_index - cur_sample); 502 503 return OK; 504 } 505 506 *time += delta * n; 507 cur_sample += n; 508 } 509 510 return ERROR_OUT_OF_RANGE; 511} 512 513status_t SampleTable::findClosestSample( 514 uint32_t req_time, uint32_t *sample_index, uint32_t flags) { 515 Mutex::Autolock autoLock(mLock); 516 517 uint32_t cur_sample = 0; 518 uint32_t time = 0; 519 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { 520 uint32_t n = mTimeToSample[2 * i]; 521 uint32_t delta = mTimeToSample[2 * i + 1]; 522 523 if (req_time < time + n * delta) { 524 int j = (req_time - time) / delta; 525 526 *sample_index = cur_sample + j; 527 528 if (flags & kSyncSample_Flag) { 529 return findClosestSyncSample(*sample_index, sample_index); 530 } 531 532 return OK; 533 } 534 535 time += delta * n; 536 cur_sample += n; 537 } 538 539 return ERROR_OUT_OF_RANGE; 540} 541 542status_t SampleTable::findClosestSyncSample( 543 uint32_t start_sample_index, uint32_t *sample_index) { 544 *sample_index = 0; 545 546 if (mSyncSampleOffset < 0) { 547 // All samples are sync-samples. 548 *sample_index = start_sample_index; 549 return OK; 550 } 551 552 uint32_t x; 553 uint32_t left = 0; 554 uint32_t right = mNumSyncSamples; 555 while (left < right) { 556 uint32_t mid = (left + right) / 2; 557 if (mDataSource->readAt( 558 mSyncSampleOffset + 8 + (mid - 1) * 4, &x, 4) != 4) { 559 return ERROR_IO; 560 } 561 562 x = ntohl(x); 563 564 if (x < (start_sample_index + 1)) { 565 left = mid + 1; 566 } else if (x > (start_sample_index + 1)) { 567 right = mid; 568 } else { 569 break; 570 } 571 } 572 573 *sample_index = x - 1; 574 575 return OK; 576} 577 578status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { 579 if (mSyncSampleOffset < 0) { 580 // All samples are sync-samples. 581 *sample_index = 0; 582 return OK; 583 } 584 585 uint32_t bestSampleIndex = 0; 586 size_t maxSampleSize = 0; 587 588 static const size_t kMaxNumSyncSamplesToScan = 20; 589 590 // Consider the first kMaxNumSyncSamplesToScan sync samples and 591 // pick the one with the largest (compressed) size as the thumbnail. 592 593 size_t numSamplesToScan = mNumSyncSamples; 594 if (numSamplesToScan > kMaxNumSyncSamplesToScan) { 595 numSamplesToScan = kMaxNumSyncSamplesToScan; 596 } 597 598 for (size_t i = 0; i < numSamplesToScan; ++i) { 599 uint32_t x; 600 if (mDataSource->readAt( 601 mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) { 602 return ERROR_IO; 603 } 604 x = ntohl(x); 605 --x; 606 607 // Now x is a sample index. 608 size_t sampleSize; 609 status_t err = getSampleSize(x, &sampleSize); 610 if (err != OK) { 611 return err; 612 } 613 614 if (i == 0 || sampleSize > maxSampleSize) { 615 bestSampleIndex = x; 616 maxSampleSize = sampleSize; 617 } 618 } 619 620 *sample_index = bestSampleIndex; 621 622 return OK; 623} 624 625} // namespace android 626 627