1 /* 2 * Copyright (C) 2010 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 "MatroskaExtractor" 19 #include <utils/Log.h> 20 21 #include "MatroskaExtractor.h" 22 23 #include "mkvparser.hpp" 24 25 #include <media/stagefright/foundation/ADebug.h> 26 #include <media/stagefright/foundation/hexdump.h> 27 #include <media/stagefright/DataSource.h> 28 #include <media/stagefright/MediaBuffer.h> 29 #include <media/stagefright/MediaDefs.h> 30 #include <media/stagefright/MediaErrors.h> 31 #include <media/stagefright/MediaSource.h> 32 #include <media/stagefright/MetaData.h> 33 #include <media/stagefright/Utils.h> 34 #include <utils/String8.h> 35 36 namespace android { 37 38 struct DataSourceReader : public mkvparser::IMkvReader { 39 DataSourceReader(const sp<DataSource> &source) 40 : mSource(source) { 41 } 42 43 virtual int Read(long long position, long length, unsigned char* buffer) { 44 CHECK(position >= 0); 45 CHECK(length >= 0); 46 47 if (length == 0) { 48 return 0; 49 } 50 51 ssize_t n = mSource->readAt(position, buffer, length); 52 53 if (n <= 0) { 54 return -1; 55 } 56 57 return 0; 58 } 59 60 virtual int Length(long long* total, long long* available) { 61 off_t size; 62 if (mSource->getSize(&size) != OK) { 63 return -1; 64 } 65 66 if (total) { 67 *total = size; 68 } 69 70 if (available) { 71 *available = size; 72 } 73 74 return 0; 75 } 76 77 private: 78 sp<DataSource> mSource; 79 80 DataSourceReader(const DataSourceReader &); 81 DataSourceReader &operator=(const DataSourceReader &); 82 }; 83 84 //////////////////////////////////////////////////////////////////////////////// 85 86 struct BlockIterator { 87 BlockIterator(mkvparser::Segment *segment, unsigned long trackNum); 88 89 bool eos() const; 90 91 void advance(); 92 void reset(); 93 void seek(int64_t seekTimeUs); 94 95 const mkvparser::Block *block() const; 96 int64_t blockTimeUs() const; 97 98 private: 99 mkvparser::Segment *mSegment; 100 unsigned long mTrackNum; 101 102 mkvparser::Cluster *mCluster; 103 const mkvparser::BlockEntry *mBlockEntry; 104 105 BlockIterator(const BlockIterator &); 106 BlockIterator &operator=(const BlockIterator &); 107 }; 108 109 struct MatroskaSource : public MediaSource { 110 MatroskaSource( 111 const sp<MatroskaExtractor> &extractor, size_t index); 112 113 virtual status_t start(MetaData *params); 114 virtual status_t stop(); 115 116 virtual sp<MetaData> getFormat(); 117 118 virtual status_t read( 119 MediaBuffer **buffer, const ReadOptions *options); 120 121 protected: 122 virtual ~MatroskaSource(); 123 124 private: 125 enum Type { 126 AVC, 127 AAC, 128 OTHER 129 }; 130 131 sp<MatroskaExtractor> mExtractor; 132 size_t mTrackIndex; 133 Type mType; 134 BlockIterator mBlockIter; 135 size_t mNALSizeLen; // for type AVC 136 137 List<MediaBuffer *> mPendingFrames; 138 139 status_t advance(); 140 141 status_t readBlock(); 142 void clearPendingFrames(); 143 144 MatroskaSource(const MatroskaSource &); 145 MatroskaSource &operator=(const MatroskaSource &); 146 }; 147 148 MatroskaSource::MatroskaSource( 149 const sp<MatroskaExtractor> &extractor, size_t index) 150 : mExtractor(extractor), 151 mTrackIndex(index), 152 mType(OTHER), 153 mBlockIter(mExtractor->mSegment, 154 mExtractor->mTracks.itemAt(index).mTrackNum), 155 mNALSizeLen(0) { 156 sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta; 157 158 const char *mime; 159 CHECK(meta->findCString(kKeyMIMEType, &mime)); 160 161 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 162 mType = AVC; 163 164 uint32_t dummy; 165 const uint8_t *avcc; 166 size_t avccSize; 167 CHECK(meta->findData( 168 kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)); 169 170 CHECK_GE(avccSize, 5u); 171 172 mNALSizeLen = 1 + (avcc[4] & 3); 173 LOGV("mNALSizeLen = %d", mNALSizeLen); 174 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 175 mType = AAC; 176 } 177 } 178 179 MatroskaSource::~MatroskaSource() { 180 clearPendingFrames(); 181 } 182 183 status_t MatroskaSource::start(MetaData *params) { 184 mBlockIter.reset(); 185 186 return OK; 187 } 188 189 status_t MatroskaSource::stop() { 190 clearPendingFrames(); 191 192 return OK; 193 } 194 195 sp<MetaData> MatroskaSource::getFormat() { 196 return mExtractor->mTracks.itemAt(mTrackIndex).mMeta; 197 } 198 199 //////////////////////////////////////////////////////////////////////////////// 200 201 BlockIterator::BlockIterator( 202 mkvparser::Segment *segment, unsigned long trackNum) 203 : mSegment(segment), 204 mTrackNum(trackNum), 205 mCluster(NULL), 206 mBlockEntry(NULL) { 207 reset(); 208 } 209 210 bool BlockIterator::eos() const { 211 return mCluster == NULL || mCluster->EOS(); 212 } 213 214 void BlockIterator::advance() { 215 while (!eos()) { 216 if (mBlockEntry != NULL) { 217 mBlockEntry = mCluster->GetNext(mBlockEntry); 218 } else if (mCluster != NULL) { 219 mCluster = mSegment->GetNext(mCluster); 220 221 if (eos()) { 222 break; 223 } 224 225 mBlockEntry = mCluster->GetFirst(); 226 } 227 228 if (mBlockEntry != NULL 229 && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) { 230 break; 231 } 232 } 233 } 234 235 void BlockIterator::reset() { 236 mCluster = mSegment->GetFirst(); 237 mBlockEntry = mCluster->GetFirst(); 238 239 while (!eos() && block()->GetTrackNumber() != mTrackNum) { 240 advance(); 241 } 242 } 243 244 void BlockIterator::seek(int64_t seekTimeUs) { 245 mCluster = mSegment->FindCluster(seekTimeUs * 1000ll); 246 mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL; 247 248 while (!eos() && block()->GetTrackNumber() != mTrackNum) { 249 advance(); 250 } 251 252 while (!eos() && !mBlockEntry->GetBlock()->IsKey()) { 253 advance(); 254 } 255 } 256 257 const mkvparser::Block *BlockIterator::block() const { 258 CHECK(!eos()); 259 260 return mBlockEntry->GetBlock(); 261 } 262 263 int64_t BlockIterator::blockTimeUs() const { 264 return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll; 265 } 266 267 //////////////////////////////////////////////////////////////////////////////// 268 269 static unsigned U24_AT(const uint8_t *ptr) { 270 return ptr[0] << 16 | ptr[1] << 8 | ptr[2]; 271 } 272 273 static size_t clz(uint8_t x) { 274 size_t numLeadingZeroes = 0; 275 276 while (!(x & 0x80)) { 277 ++numLeadingZeroes; 278 x = x << 1; 279 } 280 281 return numLeadingZeroes; 282 } 283 284 void MatroskaSource::clearPendingFrames() { 285 while (!mPendingFrames.empty()) { 286 MediaBuffer *frame = *mPendingFrames.begin(); 287 mPendingFrames.erase(mPendingFrames.begin()); 288 289 frame->release(); 290 frame = NULL; 291 } 292 } 293 294 #define BAIL(err) \ 295 do { \ 296 if (bigbuf) { \ 297 bigbuf->release(); \ 298 bigbuf = NULL; \ 299 } \ 300 \ 301 return err; \ 302 } while (0) 303 304 status_t MatroskaSource::readBlock() { 305 CHECK(mPendingFrames.empty()); 306 307 if (mBlockIter.eos()) { 308 return ERROR_END_OF_STREAM; 309 } 310 311 const mkvparser::Block *block = mBlockIter.block(); 312 313 size_t size = block->GetSize(); 314 int64_t timeUs = mBlockIter.blockTimeUs(); 315 int32_t isSync = block->IsKey(); 316 317 MediaBuffer *bigbuf = new MediaBuffer(size); 318 319 long res = block->Read( 320 mExtractor->mReader, (unsigned char *)bigbuf->data()); 321 322 if (res != 0) { 323 bigbuf->release(); 324 bigbuf = NULL; 325 326 return ERROR_END_OF_STREAM; 327 } 328 329 mBlockIter.advance(); 330 331 bigbuf->meta_data()->setInt64(kKeyTime, timeUs); 332 bigbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync); 333 334 unsigned lacing = (block->Flags() >> 1) & 3; 335 336 if (lacing == 0) { 337 mPendingFrames.push_back(bigbuf); 338 return OK; 339 } 340 341 LOGV("lacing = %u, size = %d", lacing, size); 342 343 const uint8_t *data = (const uint8_t *)bigbuf->data(); 344 // hexdump(data, size); 345 346 if (size == 0) { 347 BAIL(ERROR_MALFORMED); 348 } 349 350 unsigned numFrames = (unsigned)data[0] + 1; 351 ++data; 352 --size; 353 354 Vector<uint64_t> frameSizes; 355 356 switch (lacing) { 357 case 1: // Xiph 358 { 359 for (size_t i = 0; i < numFrames - 1; ++i) { 360 size_t frameSize = 0; 361 uint8_t byte; 362 do { 363 if (size == 0) { 364 BAIL(ERROR_MALFORMED); 365 } 366 byte = data[0]; 367 ++data; 368 --size; 369 370 frameSize += byte; 371 } while (byte == 0xff); 372 373 frameSizes.push(frameSize); 374 } 375 376 break; 377 } 378 379 case 2: // fixed-size 380 { 381 if ((size % numFrames) != 0) { 382 BAIL(ERROR_MALFORMED); 383 } 384 385 size_t frameSize = size / numFrames; 386 for (size_t i = 0; i < numFrames - 1; ++i) { 387 frameSizes.push(frameSize); 388 } 389 390 break; 391 } 392 393 case 3: // EBML 394 { 395 uint64_t lastFrameSize = 0; 396 for (size_t i = 0; i < numFrames - 1; ++i) { 397 uint8_t byte; 398 399 if (size == 0) { 400 BAIL(ERROR_MALFORMED); 401 } 402 byte = data[0]; 403 ++data; 404 --size; 405 406 size_t numLeadingZeroes = clz(byte); 407 408 uint64_t frameSize = byte & ~(0x80 >> numLeadingZeroes); 409 for (size_t j = 0; j < numLeadingZeroes; ++j) { 410 if (size == 0) { 411 BAIL(ERROR_MALFORMED); 412 } 413 414 frameSize = frameSize << 8; 415 frameSize |= data[0]; 416 ++data; 417 --size; 418 } 419 420 if (i == 0) { 421 frameSizes.push(frameSize); 422 } else { 423 size_t shift = 424 7 - numLeadingZeroes + 8 * numLeadingZeroes; 425 426 int64_t delta = 427 (int64_t)frameSize - (1ll << (shift - 1)) + 1; 428 429 frameSize = lastFrameSize + delta; 430 431 frameSizes.push(frameSize); 432 } 433 434 lastFrameSize = frameSize; 435 } 436 break; 437 } 438 439 default: 440 TRESPASS(); 441 } 442 443 #if 0 444 AString out; 445 for (size_t i = 0; i < frameSizes.size(); ++i) { 446 if (i > 0) { 447 out.append(", "); 448 } 449 out.append(StringPrintf("%llu", frameSizes.itemAt(i))); 450 } 451 LOGV("sizes = [%s]", out.c_str()); 452 #endif 453 454 for (size_t i = 0; i < frameSizes.size(); ++i) { 455 uint64_t frameSize = frameSizes.itemAt(i); 456 457 if (size < frameSize) { 458 BAIL(ERROR_MALFORMED); 459 } 460 461 MediaBuffer *mbuf = new MediaBuffer(frameSize); 462 mbuf->meta_data()->setInt64(kKeyTime, timeUs); 463 mbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync); 464 memcpy(mbuf->data(), data, frameSize); 465 mPendingFrames.push_back(mbuf); 466 467 data += frameSize; 468 size -= frameSize; 469 } 470 471 size_t offset = bigbuf->range_length() - size; 472 bigbuf->set_range(offset, size); 473 474 mPendingFrames.push_back(bigbuf); 475 476 return OK; 477 } 478 479 #undef BAIL 480 481 status_t MatroskaSource::read( 482 MediaBuffer **out, const ReadOptions *options) { 483 *out = NULL; 484 485 int64_t seekTimeUs; 486 ReadOptions::SeekMode mode; 487 if (options && options->getSeekTo(&seekTimeUs, &mode)) { 488 clearPendingFrames(); 489 mBlockIter.seek(seekTimeUs); 490 } 491 492 again: 493 while (mPendingFrames.empty()) { 494 status_t err = readBlock(); 495 496 if (err != OK) { 497 clearPendingFrames(); 498 499 return err; 500 } 501 } 502 503 MediaBuffer *frame = *mPendingFrames.begin(); 504 mPendingFrames.erase(mPendingFrames.begin()); 505 506 size_t size = frame->range_length(); 507 508 if (mType != AVC) { 509 *out = frame; 510 511 return OK; 512 } 513 514 if (size < mNALSizeLen) { 515 frame->release(); 516 frame = NULL; 517 518 return ERROR_MALFORMED; 519 } 520 521 // In the case of AVC content, each NAL unit is prefixed by 522 // mNALSizeLen bytes of length. We want to prefix the data with 523 // a four-byte 0x00000001 startcode instead of the length prefix. 524 // mNALSizeLen ranges from 1 through 4 bytes, so add an extra 525 // 3 bytes of padding to the buffer start. 526 static const size_t kPadding = 3; 527 528 MediaBuffer *buffer = new MediaBuffer(size + kPadding); 529 530 int64_t timeUs; 531 CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs)); 532 int32_t isSync; 533 CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)); 534 535 buffer->meta_data()->setInt64(kKeyTime, timeUs); 536 buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync); 537 538 memcpy((uint8_t *)buffer->data() + kPadding, 539 (const uint8_t *)frame->data() + frame->range_offset(), 540 size); 541 542 buffer->set_range(kPadding, size); 543 544 frame->release(); 545 frame = NULL; 546 547 uint8_t *data = (uint8_t *)buffer->data(); 548 549 size_t NALsize; 550 switch (mNALSizeLen) { 551 case 1: NALsize = data[kPadding]; break; 552 case 2: NALsize = U16_AT(&data[kPadding]); break; 553 case 3: NALsize = U24_AT(&data[kPadding]); break; 554 case 4: NALsize = U32_AT(&data[kPadding]); break; 555 default: 556 TRESPASS(); 557 } 558 559 if (size < NALsize + mNALSizeLen) { 560 buffer->release(); 561 buffer = NULL; 562 563 return ERROR_MALFORMED; 564 } 565 566 if (size > NALsize + mNALSizeLen) { 567 LOGW("discarding %d bytes of data.", size - NALsize - mNALSizeLen); 568 } 569 570 // actual data starts at &data[kPadding + mNALSizeLen] 571 572 memcpy(&data[mNALSizeLen - 1], "\x00\x00\x00\x01", 4); 573 buffer->set_range(mNALSizeLen - 1, NALsize + 4); 574 575 *out = buffer; 576 577 return OK; 578 } 579 580 //////////////////////////////////////////////////////////////////////////////// 581 582 MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) 583 : mDataSource(source), 584 mReader(new DataSourceReader(mDataSource)), 585 mSegment(NULL), 586 mExtractedThumbnails(false) { 587 mkvparser::EBMLHeader ebmlHeader; 588 long long pos; 589 if (ebmlHeader.Parse(mReader, pos) < 0) { 590 return; 591 } 592 593 long long ret = 594 mkvparser::Segment::CreateInstance(mReader, pos, mSegment); 595 596 if (ret) { 597 CHECK(mSegment == NULL); 598 return; 599 } 600 601 ret = mSegment->Load(); 602 603 if (ret < 0) { 604 delete mSegment; 605 mSegment = NULL; 606 return; 607 } 608 609 addTracks(); 610 } 611 612 MatroskaExtractor::~MatroskaExtractor() { 613 delete mSegment; 614 mSegment = NULL; 615 616 delete mReader; 617 mReader = NULL; 618 } 619 620 size_t MatroskaExtractor::countTracks() { 621 return mTracks.size(); 622 } 623 624 sp<MediaSource> MatroskaExtractor::getTrack(size_t index) { 625 if (index >= mTracks.size()) { 626 return NULL; 627 } 628 629 return new MatroskaSource(this, index); 630 } 631 632 sp<MetaData> MatroskaExtractor::getTrackMetaData( 633 size_t index, uint32_t flags) { 634 if (index >= mTracks.size()) { 635 return NULL; 636 } 637 638 if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) { 639 findThumbnails(); 640 mExtractedThumbnails = true; 641 } 642 643 return mTracks.itemAt(index).mMeta; 644 } 645 646 static void addESDSFromAudioSpecificInfo( 647 const sp<MetaData> &meta, const void *asi, size_t asiSize) { 648 static const uint8_t kStaticESDS[] = { 649 0x03, 22, 650 0x00, 0x00, // ES_ID 651 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag 652 653 0x04, 17, 654 0x40, // Audio ISO/IEC 14496-3 655 0x00, 0x00, 0x00, 0x00, 656 0x00, 0x00, 0x00, 0x00, 657 0x00, 0x00, 0x00, 0x00, 658 659 0x05, 660 // AudioSpecificInfo (with size prefix) follows 661 }; 662 663 CHECK(asiSize < 128); 664 size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1; 665 uint8_t *esds = new uint8_t[esdsSize]; 666 memcpy(esds, kStaticESDS, sizeof(kStaticESDS)); 667 uint8_t *ptr = esds + sizeof(kStaticESDS); 668 *ptr++ = asiSize; 669 memcpy(ptr, asi, asiSize); 670 671 meta->setData(kKeyESDS, 0, esds, esdsSize); 672 673 delete[] esds; 674 esds = NULL; 675 } 676 677 void addVorbisCodecInfo( 678 const sp<MetaData> &meta, 679 const void *_codecPrivate, size_t codecPrivateSize) { 680 // printf("vorbis private data follows:\n"); 681 // hexdump(_codecPrivate, codecPrivateSize); 682 683 CHECK(codecPrivateSize >= 3); 684 685 const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate; 686 CHECK(codecPrivate[0] == 0x02); 687 688 size_t len1 = codecPrivate[1]; 689 size_t len2 = codecPrivate[2]; 690 691 CHECK(codecPrivateSize > 3 + len1 + len2); 692 693 CHECK(codecPrivate[3] == 0x01); 694 meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1); 695 696 CHECK(codecPrivate[len1 + 3] == 0x03); 697 698 CHECK(codecPrivate[len1 + len2 + 3] == 0x05); 699 meta->setData( 700 kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3], 701 codecPrivateSize - len1 - len2 - 3); 702 } 703 704 void MatroskaExtractor::addTracks() { 705 const mkvparser::Tracks *tracks = mSegment->GetTracks(); 706 707 for (size_t index = 0; index < tracks->GetTracksCount(); ++index) { 708 const mkvparser::Track *track = tracks->GetTrackByIndex(index); 709 710 const char *const codecID = track->GetCodecId(); 711 LOGV("codec id = %s", codecID); 712 LOGV("codec name = %s", track->GetCodecNameAsUTF8()); 713 714 size_t codecPrivateSize; 715 const unsigned char *codecPrivate = 716 track->GetCodecPrivate(codecPrivateSize); 717 718 enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 }; 719 720 sp<MetaData> meta = new MetaData; 721 722 switch (track->GetType()) { 723 case VIDEO_TRACK: 724 { 725 const mkvparser::VideoTrack *vtrack = 726 static_cast<const mkvparser::VideoTrack *>(track); 727 728 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) { 729 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 730 meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize); 731 } else if (!strcmp("V_VP8", codecID)) { 732 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX); 733 } else { 734 continue; 735 } 736 737 meta->setInt32(kKeyWidth, vtrack->GetWidth()); 738 meta->setInt32(kKeyHeight, vtrack->GetHeight()); 739 break; 740 } 741 742 case AUDIO_TRACK: 743 { 744 const mkvparser::AudioTrack *atrack = 745 static_cast<const mkvparser::AudioTrack *>(track); 746 747 if (!strcmp("A_AAC", codecID)) { 748 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); 749 CHECK(codecPrivateSize >= 2); 750 751 addESDSFromAudioSpecificInfo( 752 meta, codecPrivate, codecPrivateSize); 753 } else if (!strcmp("A_VORBIS", codecID)) { 754 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); 755 756 addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize); 757 } else { 758 continue; 759 } 760 761 meta->setInt32(kKeySampleRate, atrack->GetSamplingRate()); 762 meta->setInt32(kKeyChannelCount, atrack->GetChannels()); 763 break; 764 } 765 766 default: 767 continue; 768 } 769 770 long long durationNs = mSegment->GetDuration(); 771 meta->setInt64(kKeyDuration, (durationNs + 500) / 1000); 772 773 mTracks.push(); 774 TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1); 775 trackInfo->mTrackNum = track->GetNumber(); 776 trackInfo->mMeta = meta; 777 } 778 } 779 780 void MatroskaExtractor::findThumbnails() { 781 for (size_t i = 0; i < mTracks.size(); ++i) { 782 TrackInfo *info = &mTracks.editItemAt(i); 783 784 const char *mime; 785 CHECK(info->mMeta->findCString(kKeyMIMEType, &mime)); 786 787 if (strncasecmp(mime, "video/", 6)) { 788 continue; 789 } 790 791 BlockIterator iter(mSegment, info->mTrackNum); 792 int32_t i = 0; 793 int64_t thumbnailTimeUs = 0; 794 size_t maxBlockSize = 0; 795 while (!iter.eos() && i < 20) { 796 if (iter.block()->IsKey()) { 797 ++i; 798 799 size_t blockSize = iter.block()->GetSize(); 800 if (blockSize > maxBlockSize) { 801 maxBlockSize = blockSize; 802 thumbnailTimeUs = iter.blockTimeUs(); 803 } 804 } 805 iter.advance(); 806 } 807 info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs); 808 } 809 } 810 811 sp<MetaData> MatroskaExtractor::getMetaData() { 812 sp<MetaData> meta = new MetaData; 813 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA); 814 815 return meta; 816 } 817 818 bool SniffMatroska( 819 const sp<DataSource> &source, String8 *mimeType, float *confidence, 820 sp<AMessage> *) { 821 DataSourceReader reader(source); 822 mkvparser::EBMLHeader ebmlHeader; 823 long long pos; 824 if (ebmlHeader.Parse(&reader, pos) < 0) { 825 return false; 826 } 827 828 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA); 829 *confidence = 0.6; 830 831 return true; 832 } 833 834 } // namespace android 835