AVIExtractor.cpp revision 7de73f4eb68f3aa478e19ba05a13bc84296f9894
1/* 2 * Copyright (C) 2011 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_NDEBUG 0 18#define LOG_TAG "AVIExtractor" 19#include <utils/Log.h> 20 21#include "include/AVIExtractor.h" 22 23#include <binder/ProcessState.h> 24#include <media/stagefright/foundation/hexdump.h> 25#include <media/stagefright/foundation/ABuffer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/DataSource.h> 28#include <media/stagefright/MediaBuffer.h> 29#include <media/stagefright/MediaBufferGroup.h> 30#include <media/stagefright/MediaDefs.h> 31#include <media/stagefright/MediaErrors.h> 32#include <media/stagefright/MetaData.h> 33#include <media/stagefright/Utils.h> 34 35namespace android { 36 37struct AVIExtractor::AVISource : public MediaSource { 38 AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex); 39 40 virtual status_t start(MetaData *params); 41 virtual status_t stop(); 42 43 virtual sp<MetaData> getFormat(); 44 45 virtual status_t read( 46 MediaBuffer **buffer, const ReadOptions *options); 47 48protected: 49 virtual ~AVISource(); 50 51private: 52 sp<AVIExtractor> mExtractor; 53 size_t mTrackIndex; 54 const AVIExtractor::Track &mTrack; 55 MediaBufferGroup *mBufferGroup; 56 size_t mSampleIndex; 57 58 DISALLOW_EVIL_CONSTRUCTORS(AVISource); 59}; 60 61//////////////////////////////////////////////////////////////////////////////// 62 63AVIExtractor::AVISource::AVISource( 64 const sp<AVIExtractor> &extractor, size_t trackIndex) 65 : mExtractor(extractor), 66 mTrackIndex(trackIndex), 67 mTrack(mExtractor->mTracks.itemAt(trackIndex)), 68 mBufferGroup(NULL) { 69} 70 71AVIExtractor::AVISource::~AVISource() { 72 if (mBufferGroup) { 73 stop(); 74 } 75} 76 77status_t AVIExtractor::AVISource::start(MetaData *params) { 78 CHECK(!mBufferGroup); 79 80 mBufferGroup = new MediaBufferGroup; 81 82 mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize)); 83 mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize)); 84 mSampleIndex = 0; 85 86 return OK; 87} 88 89status_t AVIExtractor::AVISource::stop() { 90 CHECK(mBufferGroup); 91 92 delete mBufferGroup; 93 mBufferGroup = NULL; 94 95 return OK; 96} 97 98sp<MetaData> AVIExtractor::AVISource::getFormat() { 99 return mTrack.mMeta; 100} 101 102status_t AVIExtractor::AVISource::read( 103 MediaBuffer **buffer, const ReadOptions *options) { 104 CHECK(mBufferGroup); 105 106 *buffer = NULL; 107 108 int64_t seekTimeUs; 109 ReadOptions::SeekMode seekMode; 110 if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { 111 status_t err = 112 mExtractor->getSampleIndexAtTime( 113 mTrackIndex, seekTimeUs, seekMode, &mSampleIndex); 114 115 if (err != OK) { 116 return ERROR_END_OF_STREAM; 117 } 118 } 119 120 off64_t offset; 121 size_t size; 122 bool isKey; 123 int64_t timeUs; 124 status_t err = mExtractor->getSampleInfo( 125 mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs); 126 127 ++mSampleIndex; 128 129 if (err != OK) { 130 return ERROR_END_OF_STREAM; 131 } 132 133 MediaBuffer *out; 134 CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK); 135 136 ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size); 137 138 if (n < (ssize_t)size) { 139 return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED; 140 } 141 142 out->set_range(0, size); 143 144 out->meta_data()->setInt64(kKeyTime, timeUs); 145 146 if (isKey) { 147 out->meta_data()->setInt32(kKeyIsSyncFrame, 1); 148 } 149 150 *buffer = out; 151 152 return OK; 153} 154 155//////////////////////////////////////////////////////////////////////////////// 156 157AVIExtractor::AVIExtractor(const sp<DataSource> &dataSource) 158 : mDataSource(dataSource) { 159 mInitCheck = parseHeaders(); 160 161 if (mInitCheck != OK) { 162 mTracks.clear(); 163 } 164} 165 166AVIExtractor::~AVIExtractor() { 167} 168 169size_t AVIExtractor::countTracks() { 170 return mTracks.size(); 171} 172 173sp<MediaSource> AVIExtractor::getTrack(size_t index) { 174 return index < mTracks.size() ? new AVISource(this, index) : NULL; 175} 176 177sp<MetaData> AVIExtractor::getTrackMetaData( 178 size_t index, uint32_t flags) { 179 return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL; 180} 181 182sp<MetaData> AVIExtractor::getMetaData() { 183 sp<MetaData> meta = new MetaData; 184 185 if (mInitCheck == OK) { 186 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI); 187 } 188 189 return meta; 190} 191 192status_t AVIExtractor::parseHeaders() { 193 mTracks.clear(); 194 mMovieOffset = 0; 195 mFoundIndex = false; 196 mOffsetsAreAbsolute = false; 197 198 ssize_t res = parseChunk(0ll, -1ll); 199 200 if (res < 0) { 201 return (status_t)res; 202 } 203 204 if (mMovieOffset == 0ll || !mFoundIndex) { 205 return ERROR_MALFORMED; 206 } 207 208 return OK; 209} 210 211ssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) { 212 if (size >= 0 && size < 8) { 213 return ERROR_MALFORMED; 214 } 215 216 uint8_t tmp[12]; 217 ssize_t n = mDataSource->readAt(offset, tmp, 8); 218 219 if (n < 8) { 220 return (n < 0) ? n : (ssize_t)ERROR_MALFORMED; 221 } 222 223 uint32_t fourcc = U32_AT(tmp); 224 uint32_t chunkSize = U32LE_AT(&tmp[4]); 225 226 if (size >= 0 && chunkSize + 8 > size) { 227 return ERROR_MALFORMED; 228 } 229 230 static const char kPrefix[] = " "; 231 const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth]; 232 233 if (fourcc == FOURCC('L', 'I', 'S', 'T') 234 || fourcc == FOURCC('R', 'I', 'F', 'F')) { 235 // It's a list of chunks 236 237 if (size >= 0 && size < 12) { 238 return ERROR_MALFORMED; 239 } 240 241 n = mDataSource->readAt(offset + 8, &tmp[8], 4); 242 243 if (n < 4) { 244 return (n < 0) ? n : (ssize_t)ERROR_MALFORMED; 245 } 246 247 uint32_t subFourcc = U32_AT(&tmp[8]); 248 249 LOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d", 250 prefix, 251 offset, 252 (char)(subFourcc >> 24), 253 (char)((subFourcc >> 16) & 0xff), 254 (char)((subFourcc >> 8) & 0xff), 255 (char)(subFourcc & 0xff), 256 chunkSize - 4); 257 258 if (subFourcc == FOURCC('m', 'o', 'v', 'i')) { 259 // We're not going to parse this, but will take note of the 260 // offset. 261 262 mMovieOffset = offset; 263 } else { 264 off64_t subOffset = offset + 12; 265 off64_t subOffsetLimit = subOffset + chunkSize - 4; 266 while (subOffset < subOffsetLimit) { 267 ssize_t res = 268 parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1); 269 270 if (res < 0) { 271 return res; 272 } 273 274 subOffset += res; 275 } 276 } 277 } else { 278 LOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'", 279 prefix, 280 offset, 281 (char)(fourcc >> 24), 282 (char)((fourcc >> 16) & 0xff), 283 (char)((fourcc >> 8) & 0xff), 284 (char)(fourcc & 0xff)); 285 286 status_t err = OK; 287 288 switch (fourcc) { 289 case FOURCC('s', 't', 'r', 'h'): 290 { 291 err = parseStreamHeader(offset + 8, chunkSize); 292 break; 293 } 294 295 case FOURCC('s', 't', 'r', 'f'): 296 { 297 err = parseStreamFormat(offset + 8, chunkSize); 298 break; 299 } 300 301 case FOURCC('i', 'd', 'x', '1'): 302 { 303 err = parseIndex(offset + 8, chunkSize); 304 break; 305 } 306 307 default: 308 break; 309 } 310 311 if (err != OK) { 312 return err; 313 } 314 } 315 316 if (chunkSize & 1) { 317 ++chunkSize; 318 } 319 320 return chunkSize + 8; 321} 322 323static const char *GetMIMETypeForHandler(uint32_t handler) { 324 switch (handler) { 325 // Wow... shamelessly copied from 326 // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4 327 328 case FOURCC('3', 'I', 'V', '2'): 329 case FOURCC('3', 'i', 'v', '2'): 330 case FOURCC('B', 'L', 'Z', '0'): 331 case FOURCC('D', 'I', 'G', 'I'): 332 case FOURCC('D', 'I', 'V', '1'): 333 case FOURCC('d', 'i', 'v', '1'): 334 case FOURCC('D', 'I', 'V', 'X'): 335 case FOURCC('d', 'i', 'v', 'x'): 336 case FOURCC('D', 'X', '5', '0'): 337 case FOURCC('d', 'x', '5', '0'): 338 case FOURCC('D', 'X', 'G', 'M'): 339 case FOURCC('E', 'M', '4', 'A'): 340 case FOURCC('E', 'P', 'H', 'V'): 341 case FOURCC('F', 'M', 'P', '4'): 342 case FOURCC('f', 'm', 'p', '4'): 343 case FOURCC('F', 'V', 'F', 'W'): 344 case FOURCC('H', 'D', 'X', '4'): 345 case FOURCC('h', 'd', 'x', '4'): 346 case FOURCC('M', '4', 'C', 'C'): 347 case FOURCC('M', '4', 'S', '2'): 348 case FOURCC('m', '4', 's', '2'): 349 case FOURCC('M', 'P', '4', 'S'): 350 case FOURCC('m', 'p', '4', 's'): 351 case FOURCC('M', 'P', '4', 'V'): 352 case FOURCC('m', 'p', '4', 'v'): 353 case FOURCC('M', 'V', 'X', 'M'): 354 case FOURCC('R', 'M', 'P', '4'): 355 case FOURCC('S', 'E', 'D', 'G'): 356 case FOURCC('S', 'M', 'P', '4'): 357 case FOURCC('U', 'M', 'P', '4'): 358 case FOURCC('W', 'V', '1', 'F'): 359 case FOURCC('X', 'V', 'I', 'D'): 360 case FOURCC('X', 'v', 'i', 'D'): 361 case FOURCC('x', 'v', 'i', 'd'): 362 case FOURCC('X', 'V', 'I', 'X'): 363 return MEDIA_MIMETYPE_VIDEO_MPEG4; 364 365 default: 366 return NULL; 367 } 368} 369 370status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) { 371 if (size != 56) { 372 return ERROR_MALFORMED; 373 } 374 375 if (mTracks.size() > 99) { 376 return -ERANGE; 377 } 378 379 sp<ABuffer> buffer = new ABuffer(size); 380 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); 381 382 if (n < (ssize_t)size) { 383 return n < 0 ? (status_t)n : ERROR_MALFORMED; 384 } 385 386 const uint8_t *data = buffer->data(); 387 388 uint32_t type = U32_AT(data); 389 uint32_t handler = U32_AT(&data[4]); 390 uint32_t flags = U32LE_AT(&data[8]); 391 392 sp<MetaData> meta = new MetaData; 393 394 uint32_t rate = U32LE_AT(&data[20]); 395 uint32_t scale = U32LE_AT(&data[24]); 396 397 uint32_t sampleSize = U32LE_AT(&data[44]); 398 399 const char *mime = NULL; 400 Track::Kind kind = Track::OTHER; 401 402 if (type == FOURCC('v', 'i', 'd', 's')) { 403 mime = GetMIMETypeForHandler(handler); 404 405 if (mime && strncasecmp(mime, "video/", 6)) { 406 return ERROR_MALFORMED; 407 } 408 409 kind = Track::VIDEO; 410 } else if (type == FOURCC('a', 'u', 'd', 's')) { 411 if (mime && strncasecmp(mime, "audio/", 6)) { 412 return ERROR_MALFORMED; 413 } 414 415 kind = Track::AUDIO; 416 } 417 418 if (!mime) { 419 mime = "application/octet-stream"; 420 } 421 422 meta->setCString(kKeyMIMEType, mime); 423 424 mTracks.push(); 425 Track *track = &mTracks.editItemAt(mTracks.size() - 1); 426 427 track->mMeta = meta; 428 track->mRate = rate; 429 track->mScale = scale; 430 track->mBytesPerSample = sampleSize; 431 track->mKind = kind; 432 track->mNumSyncSamples = 0; 433 track->mThumbnailSampleSize = 0; 434 track->mThumbnailSampleIndex = -1; 435 track->mMaxSampleSize = 0; 436 437 return OK; 438} 439 440status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) { 441 if (mTracks.isEmpty()) { 442 return ERROR_MALFORMED; 443 } 444 445 Track *track = &mTracks.editItemAt(mTracks.size() - 1); 446 447 if (track->mKind == Track::OTHER) { 448 // We don't support this content, but that's not a parsing error. 449 return OK; 450 } 451 452 bool isVideo = (track->mKind == Track::VIDEO); 453 454 if ((isVideo && size < 40) || (!isVideo && size < 18)) { 455 // Expected a BITMAPINFO or WAVEFORMATEX structure, respectively. 456 return ERROR_MALFORMED; 457 } 458 459 sp<ABuffer> buffer = new ABuffer(size); 460 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); 461 462 if (n < (ssize_t)size) { 463 return n < 0 ? (status_t)n : ERROR_MALFORMED; 464 } 465 466 const uint8_t *data = buffer->data(); 467 468 if (isVideo) { 469 uint32_t width = U32LE_AT(&data[4]); 470 uint32_t height = U32LE_AT(&data[8]); 471 472 track->mMeta->setInt32(kKeyWidth, width); 473 track->mMeta->setInt32(kKeyHeight, height); 474 } else { 475 uint32_t format = U16LE_AT(data); 476 if (format == 0x55) { 477 track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); 478 } 479 480 uint32_t numChannels = U16LE_AT(&data[2]); 481 uint32_t sampleRate = U32LE_AT(&data[4]); 482 483 track->mMeta->setInt32(kKeyChannelCount, numChannels); 484 track->mMeta->setInt32(kKeySampleRate, sampleRate); 485 } 486 487 return OK; 488} 489 490// static 491bool AVIExtractor::IsCorrectChunkType( 492 ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) { 493 uint32_t chunkBase = chunkType & 0xffff; 494 495 switch (kind) { 496 case Track::VIDEO: 497 { 498 if (chunkBase != FOURCC(0, 0, 'd', 'c') 499 && chunkBase != FOURCC(0, 0, 'd', 'b')) { 500 return false; 501 } 502 break; 503 } 504 505 case Track::AUDIO: 506 { 507 if (chunkBase != FOURCC(0, 0, 'w', 'b')) { 508 return false; 509 } 510 break; 511 } 512 513 default: 514 break; 515 } 516 517 if (trackIndex < 0) { 518 return true; 519 } 520 521 uint8_t hi = chunkType >> 24; 522 uint8_t lo = (chunkType >> 16) & 0xff; 523 524 if (hi < '0' || hi > '9' || lo < '0' || lo > '9') { 525 return false; 526 } 527 528 if (trackIndex != (10 * (hi - '0') + (lo - '0'))) { 529 return false; 530 } 531 532 return true; 533} 534 535status_t AVIExtractor::parseIndex(off64_t offset, size_t size) { 536 if ((size % 16) != 0) { 537 return ERROR_MALFORMED; 538 } 539 540 sp<ABuffer> buffer = new ABuffer(size); 541 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); 542 543 if (n < (ssize_t)size) { 544 return n < 0 ? (status_t)n : ERROR_MALFORMED; 545 } 546 547 const uint8_t *data = buffer->data(); 548 549 while (size > 0) { 550 uint32_t chunkType = U32_AT(data); 551 552 uint8_t hi = chunkType >> 24; 553 uint8_t lo = (chunkType >> 16) & 0xff; 554 555 if (hi < '0' || hi > '9' || lo < '0' || lo > '9') { 556 return ERROR_MALFORMED; 557 } 558 559 size_t trackIndex = 10 * (hi - '0') + (lo - '0'); 560 561 if (trackIndex >= mTracks.size()) { 562 return ERROR_MALFORMED; 563 } 564 565 Track *track = &mTracks.editItemAt(trackIndex); 566 567 if (!IsCorrectChunkType(-1, track->mKind, chunkType)) { 568 return ERROR_MALFORMED; 569 } 570 571 if (track->mKind == Track::OTHER) { 572 data += 16; 573 size -= 16; 574 continue; 575 } 576 577 uint32_t flags = U32LE_AT(&data[4]); 578 uint32_t offset = U32LE_AT(&data[8]); 579 uint32_t chunkSize = U32LE_AT(&data[12]); 580 581 if (chunkSize > track->mMaxSampleSize) { 582 track->mMaxSampleSize = chunkSize; 583 } 584 585 track->mSamples.push(); 586 587 SampleInfo *info = 588 &track->mSamples.editItemAt(track->mSamples.size() - 1); 589 590 info->mOffset = offset; 591 info->mIsKey = (flags & 0x10) != 0; 592 593 if (info->mIsKey) { 594 static const size_t kMaxNumSyncSamplesToScan = 20; 595 596 if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) { 597 if (chunkSize > track->mThumbnailSampleSize) { 598 track->mThumbnailSampleSize = chunkSize; 599 600 track->mThumbnailSampleIndex = 601 track->mSamples.size() - 1; 602 } 603 } 604 605 ++track->mNumSyncSamples; 606 } 607 608 data += 16; 609 size -= 16; 610 } 611 612 if (!mTracks.isEmpty()) { 613 off64_t offset; 614 size_t size; 615 bool isKey; 616 int64_t timeUs; 617 status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs); 618 619 if (err != OK) { 620 mOffsetsAreAbsolute = !mOffsetsAreAbsolute; 621 err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs); 622 623 if (err != OK) { 624 return err; 625 } 626 } 627 628 LOGV("Chunk offsets are %s", 629 mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative"); 630 } 631 632 for (size_t i = 0; i < mTracks.size(); ++i) { 633 Track *track = &mTracks.editItemAt(i); 634 635 int64_t durationUs; 636 CHECK_EQ((status_t)OK, 637 getSampleTime(i, track->mSamples.size() - 1, &durationUs)); 638 639 LOGV("track %d duration = %.2f secs", i, durationUs / 1E6); 640 641 track->mMeta->setInt64(kKeyDuration, durationUs); 642 track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize); 643 644 const char *tmp; 645 CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp)); 646 647 AString mime = tmp; 648 649 if (!strncasecmp("video/", mime.c_str(), 6) 650 && track->mThumbnailSampleIndex >= 0) { 651 int64_t thumbnailTimeUs; 652 CHECK_EQ((status_t)OK, 653 getSampleTime(i, track->mThumbnailSampleIndex, 654 &thumbnailTimeUs)); 655 656 track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs); 657 658 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) { 659 status_t err = addMPEG4CodecSpecificData(i); 660 661 if (err != OK) { 662 return err; 663 } 664 } 665 } 666 667 if (track->mBytesPerSample != 0) { 668 // Assume all chunks are the same size for now. 669 670 off64_t offset; 671 size_t size; 672 bool isKey; 673 int64_t sampleTimeUs; 674 CHECK_EQ((status_t)OK, 675 getSampleInfo( 676 i, 0, 677 &offset, &size, &isKey, &sampleTimeUs)); 678 679 track->mRate *= size / track->mBytesPerSample; 680 } 681 } 682 683 mFoundIndex = true; 684 685 return OK; 686} 687 688static size_t GetSizeWidth(size_t x) { 689 size_t n = 1; 690 while (x > 127) { 691 ++n; 692 x >>= 7; 693 } 694 return n; 695} 696 697static uint8_t *EncodeSize(uint8_t *dst, size_t x) { 698 while (x > 127) { 699 *dst++ = (x & 0x7f) | 0x80; 700 x >>= 7; 701 } 702 *dst++ = x; 703 return dst; 704} 705 706sp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) { 707 size_t len1 = config->size() + GetSizeWidth(config->size()) + 1; 708 size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13; 709 size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3; 710 711 sp<ABuffer> csd = new ABuffer(len3); 712 uint8_t *dst = csd->data(); 713 *dst++ = 0x03; 714 dst = EncodeSize(dst, len2 + 3); 715 *dst++ = 0x00; // ES_ID 716 *dst++ = 0x00; 717 *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag 718 719 *dst++ = 0x04; 720 dst = EncodeSize(dst, len1 + 13); 721 *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile 722 for (size_t i = 0; i < 12; ++i) { 723 *dst++ = 0x00; 724 } 725 726 *dst++ = 0x05; 727 dst = EncodeSize(dst, config->size()); 728 memcpy(dst, config->data(), config->size()); 729 dst += config->size(); 730 731 // hexdump(csd->data(), csd->size()); 732 733 return csd; 734} 735 736status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) { 737 Track *track = &mTracks.editItemAt(trackIndex); 738 739 off64_t offset; 740 size_t size; 741 bool isKey; 742 int64_t timeUs; 743 status_t err = 744 getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs); 745 746 if (err != OK) { 747 return err; 748 } 749 750 sp<ABuffer> buffer = new ABuffer(size); 751 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); 752 753 if (n < (ssize_t)size) { 754 return n < 0 ? (status_t)n : ERROR_MALFORMED; 755 } 756 757 // Extract everything up to the first VOP start code from the first 758 // frame's encoded data and use it to construct an ESDS with the 759 // codec specific data. 760 761 size_t i = 0; 762 bool found = false; 763 while (i + 3 < buffer->size()) { 764 if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) { 765 found = true; 766 break; 767 } 768 769 ++i; 770 } 771 772 if (!found) { 773 return ERROR_MALFORMED; 774 } 775 776 buffer->setRange(0, i); 777 778 sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer); 779 track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size()); 780 781 return OK; 782} 783 784status_t AVIExtractor::getSampleInfo( 785 size_t trackIndex, size_t sampleIndex, 786 off64_t *offset, size_t *size, bool *isKey, 787 int64_t *sampleTimeUs) { 788 if (trackIndex >= mTracks.size()) { 789 return -ERANGE; 790 } 791 792 const Track &track = mTracks.itemAt(trackIndex); 793 794 if (sampleIndex >= track.mSamples.size()) { 795 return -ERANGE; 796 } 797 798 const SampleInfo &info = track.mSamples.itemAt(sampleIndex); 799 800 if (!mOffsetsAreAbsolute) { 801 *offset = info.mOffset + mMovieOffset + 8; 802 } else { 803 *offset = info.mOffset; 804 } 805 806 *size = 0; 807 808 uint8_t tmp[8]; 809 ssize_t n = mDataSource->readAt(*offset, tmp, 8); 810 811 if (n < 8) { 812 return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED; 813 } 814 815 uint32_t chunkType = U32_AT(tmp); 816 817 if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) { 818 return ERROR_MALFORMED; 819 } 820 821 *offset += 8; 822 *size = U32LE_AT(&tmp[4]); 823 824 *isKey = info.mIsKey; 825 826 *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale; 827 828 return OK; 829} 830 831status_t AVIExtractor::getSampleTime( 832 size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) { 833 off64_t offset; 834 size_t size; 835 bool isKey; 836 return getSampleInfo( 837 trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs); 838} 839 840status_t AVIExtractor::getSampleIndexAtTime( 841 size_t trackIndex, 842 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode, 843 size_t *sampleIndex) const { 844 if (trackIndex >= mTracks.size()) { 845 return -ERANGE; 846 } 847 848 const Track &track = mTracks.itemAt(trackIndex); 849 850 ssize_t closestSampleIndex = 851 timeUs / track.mRate * track.mScale / 1000000ll; 852 853 ssize_t numSamples = track.mSamples.size(); 854 855 if (closestSampleIndex < 0) { 856 closestSampleIndex = 0; 857 } else if (closestSampleIndex >= numSamples) { 858 closestSampleIndex = numSamples - 1; 859 } 860 861 if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) { 862 *sampleIndex = closestSampleIndex; 863 864 return OK; 865 } 866 867 ssize_t prevSyncSampleIndex = closestSampleIndex; 868 while (prevSyncSampleIndex >= 0) { 869 const SampleInfo &info = 870 track.mSamples.itemAt(prevSyncSampleIndex); 871 872 if (info.mIsKey) { 873 break; 874 } 875 876 --prevSyncSampleIndex; 877 } 878 879 ssize_t nextSyncSampleIndex = closestSampleIndex; 880 while (nextSyncSampleIndex < numSamples) { 881 const SampleInfo &info = 882 track.mSamples.itemAt(nextSyncSampleIndex); 883 884 if (info.mIsKey) { 885 break; 886 } 887 888 ++nextSyncSampleIndex; 889 } 890 891 switch (mode) { 892 case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: 893 { 894 *sampleIndex = prevSyncSampleIndex; 895 896 return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR; 897 } 898 899 case MediaSource::ReadOptions::SEEK_NEXT_SYNC: 900 { 901 *sampleIndex = nextSyncSampleIndex; 902 903 return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR; 904 } 905 906 case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC: 907 { 908 if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) { 909 return UNKNOWN_ERROR; 910 } 911 912 if (prevSyncSampleIndex < 0) { 913 *sampleIndex = nextSyncSampleIndex; 914 return OK; 915 } 916 917 if (nextSyncSampleIndex >= numSamples) { 918 *sampleIndex = prevSyncSampleIndex; 919 return OK; 920 } 921 922 size_t dist1 = closestSampleIndex - prevSyncSampleIndex; 923 size_t dist2 = nextSyncSampleIndex - closestSampleIndex; 924 925 *sampleIndex = 926 (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex; 927 928 return OK; 929 } 930 931 default: 932 TRESPASS(); 933 break; 934 } 935} 936 937bool SniffAVI( 938 const sp<DataSource> &source, String8 *mimeType, float *confidence, 939 sp<AMessage> *) { 940 char tmp[12]; 941 if (source->readAt(0, tmp, 12) < 12) { 942 return false; 943 } 944 945 if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) { 946 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI); 947 948 // Just a tad over the mp3 extractor's confidence, since 949 // these .avi files may contain .mp3 content that otherwise would 950 // mistakenly lead to us identifying the entire file as a .mp3 file. 951 *confidence = 0.21; 952 953 return true; 954 } 955 956 return false; 957} 958 959} // namespace android 960