SampleTable.cpp revision c57b67905c2128ddadfeca96785ee1f593b6605a
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/DataSource.h> 27#include <media/stagefright/MediaDebug.h> 28#include <media/stagefright/Utils.h> 29 30namespace android { 31 32// static 33const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o'); 34// static 35const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4'); 36// static 37const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z'); 38// static 39const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); 40 41//////////////////////////////////////////////////////////////////////////////// 42 43SampleTable::SampleTable(const sp<DataSource> &source) 44 : mDataSource(source), 45 mChunkOffsetOffset(-1), 46 mChunkOffsetType(0), 47 mNumChunkOffsets(0), 48 mSampleToChunkOffset(-1), 49 mNumSampleToChunkOffsets(0), 50 mSampleSizeOffset(-1), 51 mSampleSizeFieldSize(0), 52 mDefaultSampleSize(0), 53 mNumSampleSizes(0), 54 mTimeToSampleCount(0), 55 mTimeToSample(NULL), 56 mSyncSampleOffset(-1), 57 mNumSyncSamples(0), 58 mSampleToChunkEntries(NULL) { 59 mSampleIterator = new SampleIterator(this); 60} 61 62SampleTable::~SampleTable() { 63 delete[] mSampleToChunkEntries; 64 mSampleToChunkEntries = NULL; 65 66 delete[] mTimeToSample; 67 mTimeToSample = NULL; 68 69 delete mSampleIterator; 70 mSampleIterator = NULL; 71} 72 73status_t SampleTable::setChunkOffsetParams( 74 uint32_t type, off_t data_offset, size_t data_size) { 75 if (mChunkOffsetOffset >= 0) { 76 return ERROR_MALFORMED; 77 } 78 79 CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64); 80 81 mChunkOffsetOffset = data_offset; 82 mChunkOffsetType = type; 83 84 if (data_size < 8) { 85 return ERROR_MALFORMED; 86 } 87 88 uint8_t header[8]; 89 if (mDataSource->readAt( 90 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 91 return ERROR_IO; 92 } 93 94 if (U32_AT(header) != 0) { 95 // Expected version = 0, flags = 0. 96 return ERROR_MALFORMED; 97 } 98 99 mNumChunkOffsets = U32_AT(&header[4]); 100 101 if (mChunkOffsetType == kChunkOffsetType32) { 102 if (data_size < 8 + mNumChunkOffsets * 4) { 103 return ERROR_MALFORMED; 104 } 105 } else { 106 if (data_size < 8 + mNumChunkOffsets * 8) { 107 return ERROR_MALFORMED; 108 } 109 } 110 111 return OK; 112} 113 114status_t SampleTable::setSampleToChunkParams( 115 off_t data_offset, size_t data_size) { 116 if (mSampleToChunkOffset >= 0) { 117 return ERROR_MALFORMED; 118 } 119 120 mSampleToChunkOffset = data_offset; 121 122 if (data_size < 8) { 123 return ERROR_MALFORMED; 124 } 125 126 uint8_t header[8]; 127 if (mDataSource->readAt( 128 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 129 return ERROR_IO; 130 } 131 132 if (U32_AT(header) != 0) { 133 // Expected version = 0, flags = 0. 134 return ERROR_MALFORMED; 135 } 136 137 mNumSampleToChunkOffsets = U32_AT(&header[4]); 138 139 if (data_size < 8 + mNumSampleToChunkOffsets * 12) { 140 return ERROR_MALFORMED; 141 } 142 143 mSampleToChunkEntries = 144 new SampleToChunkEntry[mNumSampleToChunkOffsets]; 145 146 for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { 147 uint8_t buffer[12]; 148 if (mDataSource->readAt( 149 mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) 150 != (ssize_t)sizeof(buffer)) { 151 return ERROR_IO; 152 } 153 154 CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. 155 156 // We want the chunk index to be 0-based. 157 mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; 158 mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]); 159 mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]); 160 } 161 162 return OK; 163} 164 165status_t SampleTable::setSampleSizeParams( 166 uint32_t type, off_t data_offset, size_t data_size) { 167 if (mSampleSizeOffset >= 0) { 168 return ERROR_MALFORMED; 169 } 170 171 CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); 172 173 mSampleSizeOffset = data_offset; 174 175 if (data_size < 12) { 176 return ERROR_MALFORMED; 177 } 178 179 uint8_t header[12]; 180 if (mDataSource->readAt( 181 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 182 return ERROR_IO; 183 } 184 185 if (U32_AT(header) != 0) { 186 // Expected version = 0, flags = 0. 187 return ERROR_MALFORMED; 188 } 189 190 mDefaultSampleSize = U32_AT(&header[4]); 191 mNumSampleSizes = U32_AT(&header[8]); 192 193 if (type == kSampleSizeType32) { 194 mSampleSizeFieldSize = 32; 195 196 if (mDefaultSampleSize != 0) { 197 return OK; 198 } 199 200 if (data_size < 12 + mNumSampleSizes * 4) { 201 return ERROR_MALFORMED; 202 } 203 } else { 204 if ((mDefaultSampleSize & 0xffffff00) != 0) { 205 // The high 24 bits are reserved and must be 0. 206 return ERROR_MALFORMED; 207 } 208 209 mSampleSizeFieldSize = mDefaultSampleSize & 0xf; 210 mDefaultSampleSize = 0; 211 212 if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8 213 && mSampleSizeFieldSize != 16) { 214 return ERROR_MALFORMED; 215 } 216 217 if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) { 218 return ERROR_MALFORMED; 219 } 220 } 221 222 return OK; 223} 224 225status_t SampleTable::setTimeToSampleParams( 226 off_t data_offset, size_t data_size) { 227 if (mTimeToSample != NULL || data_size < 8) { 228 return ERROR_MALFORMED; 229 } 230 231 uint8_t header[8]; 232 if (mDataSource->readAt( 233 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 234 return ERROR_IO; 235 } 236 237 if (U32_AT(header) != 0) { 238 // Expected version = 0, flags = 0. 239 return ERROR_MALFORMED; 240 } 241 242 mTimeToSampleCount = U32_AT(&header[4]); 243 mTimeToSample = new uint32_t[mTimeToSampleCount * 2]; 244 245 size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; 246 if (mDataSource->readAt( 247 data_offset + 8, mTimeToSample, size) < (ssize_t)size) { 248 return ERROR_IO; 249 } 250 251 for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) { 252 mTimeToSample[i] = ntohl(mTimeToSample[i]); 253 } 254 255 return OK; 256} 257 258status_t SampleTable::setSyncSampleParams(off_t data_offset, size_t data_size) { 259 if (mSyncSampleOffset >= 0 || data_size < 8) { 260 return ERROR_MALFORMED; 261 } 262 263 mSyncSampleOffset = data_offset; 264 265 uint8_t header[8]; 266 if (mDataSource->readAt( 267 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { 268 return ERROR_IO; 269 } 270 271 if (U32_AT(header) != 0) { 272 // Expected version = 0, flags = 0. 273 return ERROR_MALFORMED; 274 } 275 276 mNumSyncSamples = U32_AT(&header[4]); 277 278 if (mNumSyncSamples < 2) { 279 LOGW("Table of sync samples is empty or has only a single entry!"); 280 } 281 return OK; 282} 283 284uint32_t SampleTable::countChunkOffsets() const { 285 return mNumChunkOffsets; 286} 287 288uint32_t SampleTable::countSamples() const { 289 return mNumSampleSizes; 290} 291 292status_t SampleTable::getMaxSampleSize(size_t *max_size) { 293 Mutex::Autolock autoLock(mLock); 294 295 *max_size = 0; 296 297 for (uint32_t i = 0; i < mNumSampleSizes; ++i) { 298 size_t sample_size; 299 status_t err = getSampleSize_l(i, &sample_size); 300 301 if (err != OK) { 302 return err; 303 } 304 305 if (sample_size > *max_size) { 306 *max_size = sample_size; 307 } 308 } 309 310 return OK; 311} 312 313uint32_t abs_difference(uint32_t time1, uint32_t time2) { 314 return time1 > time2 ? time1 - time2 : time2 - time1; 315} 316 317status_t SampleTable::findClosestSample( 318 uint32_t req_time, uint32_t *sample_index, uint32_t flags) { 319 Mutex::Autolock autoLock(mLock); 320 321 uint32_t cur_sample = 0; 322 uint32_t time = 0; 323 for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { 324 uint32_t n = mTimeToSample[2 * i]; 325 uint32_t delta = mTimeToSample[2 * i + 1]; 326 327 if (req_time < time + n * delta) { 328 int j = (req_time - time) / delta; 329 330 uint32_t time1 = time + j * delta; 331 uint32_t time2 = time1 + delta; 332 333 if (i+1 == mTimeToSampleCount 334 || (abs_difference(req_time, time1) 335 < abs_difference(req_time, time2))) { 336 *sample_index = cur_sample + j; 337 } else { 338 *sample_index = cur_sample + j + 1; 339 } 340 341 if (flags & kSyncSample_Flag) { 342 return findClosestSyncSample_l(*sample_index, sample_index); 343 } 344 345 return OK; 346 } 347 348 time += delta * n; 349 cur_sample += n; 350 } 351 352 return ERROR_OUT_OF_RANGE; 353} 354 355status_t SampleTable::findClosestSyncSample_l( 356 uint32_t start_sample_index, uint32_t *sample_index) { 357 *sample_index = 0; 358 359 if (mSyncSampleOffset < 0) { 360 // All samples are sync-samples. 361 *sample_index = start_sample_index; 362 return OK; 363 } 364 365 uint32_t x; 366 uint32_t left = 0; 367 uint32_t right = mNumSyncSamples; 368 while (left < right) { 369 uint32_t mid = (left + right) / 2; 370 371 if (mDataSource->readAt( 372 mSyncSampleOffset + 8 + mid * 4, &x, 4) != 4) { 373 return ERROR_IO; 374 } 375 376 x = ntohl(x); 377 378 if (x < (start_sample_index + 1)) { 379 left = mid + 1; 380 } else if (x > (start_sample_index + 1)) { 381 right = mid; 382 } else { 383 break; 384 } 385 } 386 387 *sample_index = x - 1; 388 389 return OK; 390} 391 392status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { 393 Mutex::Autolock autoLock(mLock); 394 395 if (mSyncSampleOffset < 0) { 396 // All samples are sync-samples. 397 *sample_index = 0; 398 return OK; 399 } 400 401 uint32_t bestSampleIndex = 0; 402 size_t maxSampleSize = 0; 403 404 static const size_t kMaxNumSyncSamplesToScan = 20; 405 406 // Consider the first kMaxNumSyncSamplesToScan sync samples and 407 // pick the one with the largest (compressed) size as the thumbnail. 408 409 size_t numSamplesToScan = mNumSyncSamples; 410 if (numSamplesToScan > kMaxNumSyncSamplesToScan) { 411 numSamplesToScan = kMaxNumSyncSamplesToScan; 412 } 413 414 for (size_t i = 0; i < numSamplesToScan; ++i) { 415 uint32_t x; 416 if (mDataSource->readAt( 417 mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) { 418 return ERROR_IO; 419 } 420 x = ntohl(x); 421 --x; 422 423 // Now x is a sample index. 424 size_t sampleSize; 425 status_t err = getSampleSize_l(x, &sampleSize); 426 if (err != OK) { 427 return err; 428 } 429 430 if (i == 0 || sampleSize > maxSampleSize) { 431 bestSampleIndex = x; 432 maxSampleSize = sampleSize; 433 } 434 } 435 436 *sample_index = bestSampleIndex; 437 438 return OK; 439} 440 441status_t SampleTable::getSampleSize_l( 442 uint32_t sampleIndex, size_t *sampleSize) { 443 return mSampleIterator->getSampleSizeDirect( 444 sampleIndex, sampleSize); 445} 446 447status_t SampleTable::getMetaDataForSample( 448 uint32_t sampleIndex, 449 off_t *offset, 450 size_t *size, 451 uint32_t *decodingTime) { 452 Mutex::Autolock autoLock(mLock); 453 454 status_t err; 455 if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) { 456 return err; 457 } 458 459 if (offset) { 460 *offset = mSampleIterator->getSampleOffset(); 461 } 462 463 if (size) { 464 *size = mSampleIterator->getSampleSize(); 465 } 466 467 if (decodingTime) { 468 *decodingTime = mSampleIterator->getSampleTime(); 469 } 470 471 return OK; 472} 473 474} // namespace android 475 476