MatroskaExtractor.cpp revision be7ac3d682729048af27871311808a76c618abdb
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 36namespace android { 37 38struct 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 off64_t size; 62 if (mSource->getSize(&size) != OK) { 63 *total = -1; 64 *available = (long long)((1ull << 63) - 1); 65 66 return 0; 67 } 68 69 if (total) { 70 *total = size; 71 } 72 73 if (available) { 74 *available = size; 75 } 76 77 return 0; 78 } 79 80private: 81 sp<DataSource> mSource; 82 83 DataSourceReader(const DataSourceReader &); 84 DataSourceReader &operator=(const DataSourceReader &); 85}; 86 87//////////////////////////////////////////////////////////////////////////////// 88 89struct BlockIterator { 90 BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum); 91 92 bool eos() const; 93 94 void advance(); 95 void reset(); 96 97 void seek( 98 int64_t seekTimeUs, bool seekToKeyFrame, 99 int64_t *actualFrameTimeUs); 100 101 const mkvparser::Block *block() const; 102 int64_t blockTimeUs() const; 103 104private: 105 MatroskaExtractor *mExtractor; 106 unsigned long mTrackNum; 107 108 const mkvparser::Cluster *mCluster; 109 const mkvparser::BlockEntry *mBlockEntry; 110 long mBlockEntryIndex; 111 112 void advance_l(); 113 114 BlockIterator(const BlockIterator &); 115 BlockIterator &operator=(const BlockIterator &); 116}; 117 118struct MatroskaSource : public MediaSource { 119 MatroskaSource( 120 const sp<MatroskaExtractor> &extractor, size_t index); 121 122 virtual status_t start(MetaData *params); 123 virtual status_t stop(); 124 125 virtual sp<MetaData> getFormat(); 126 127 virtual status_t read( 128 MediaBuffer **buffer, const ReadOptions *options); 129 130protected: 131 virtual ~MatroskaSource(); 132 133private: 134 enum Type { 135 AVC, 136 AAC, 137 OTHER 138 }; 139 140 sp<MatroskaExtractor> mExtractor; 141 size_t mTrackIndex; 142 Type mType; 143 bool mIsAudio; 144 BlockIterator mBlockIter; 145 size_t mNALSizeLen; // for type AVC 146 147 List<MediaBuffer *> mPendingFrames; 148 149 status_t advance(); 150 151 status_t readBlock(); 152 void clearPendingFrames(); 153 154 MatroskaSource(const MatroskaSource &); 155 MatroskaSource &operator=(const MatroskaSource &); 156}; 157 158MatroskaSource::MatroskaSource( 159 const sp<MatroskaExtractor> &extractor, size_t index) 160 : mExtractor(extractor), 161 mTrackIndex(index), 162 mType(OTHER), 163 mIsAudio(false), 164 mBlockIter(mExtractor.get(), 165 mExtractor->mTracks.itemAt(index).mTrackNum), 166 mNALSizeLen(0) { 167 sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta; 168 169 const char *mime; 170 CHECK(meta->findCString(kKeyMIMEType, &mime)); 171 172 mIsAudio = !strncasecmp("audio/", mime, 6); 173 174 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 175 mType = AVC; 176 177 uint32_t dummy; 178 const uint8_t *avcc; 179 size_t avccSize; 180 CHECK(meta->findData( 181 kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)); 182 183 CHECK_GE(avccSize, 5u); 184 185 mNALSizeLen = 1 + (avcc[4] & 3); 186 ALOGV("mNALSizeLen = %d", mNALSizeLen); 187 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 188 mType = AAC; 189 } 190} 191 192MatroskaSource::~MatroskaSource() { 193 clearPendingFrames(); 194} 195 196status_t MatroskaSource::start(MetaData *params) { 197 mBlockIter.reset(); 198 199 return OK; 200} 201 202status_t MatroskaSource::stop() { 203 clearPendingFrames(); 204 205 return OK; 206} 207 208sp<MetaData> MatroskaSource::getFormat() { 209 return mExtractor->mTracks.itemAt(mTrackIndex).mMeta; 210} 211 212//////////////////////////////////////////////////////////////////////////////// 213 214BlockIterator::BlockIterator( 215 MatroskaExtractor *extractor, unsigned long trackNum) 216 : mExtractor(extractor), 217 mTrackNum(trackNum), 218 mCluster(NULL), 219 mBlockEntry(NULL), 220 mBlockEntryIndex(0) { 221 reset(); 222} 223 224bool BlockIterator::eos() const { 225 return mCluster == NULL || mCluster->EOS(); 226} 227 228void BlockIterator::advance() { 229 Mutex::Autolock autoLock(mExtractor->mLock); 230 advance_l(); 231} 232 233void BlockIterator::advance_l() { 234 for (;;) { 235 long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry); 236 ALOGV("GetEntry returned %ld", res); 237 238 long long pos; 239 long len; 240 if (res < 0) { 241 // Need to parse this cluster some more 242 243 CHECK_EQ(res, mkvparser::E_BUFFER_NOT_FULL); 244 245 res = mCluster->Parse(pos, len); 246 ALOGV("Parse returned %ld", res); 247 248 if (res < 0) { 249 // I/O error 250 251 ALOGE("Cluster::Parse returned result %ld", res); 252 253 mCluster = NULL; 254 break; 255 } 256 257 continue; 258 } else if (res == 0) { 259 // We're done with this cluster 260 261 const mkvparser::Cluster *nextCluster; 262 res = mExtractor->mSegment->ParseNext( 263 mCluster, nextCluster, pos, len); 264 ALOGV("ParseNext returned %ld", res); 265 266 if (res > 0) { 267 // EOF 268 269 mCluster = NULL; 270 break; 271 } 272 273 CHECK_EQ(res, 0); 274 CHECK(nextCluster != NULL); 275 CHECK(!nextCluster->EOS()); 276 277 mCluster = nextCluster; 278 279 res = mCluster->Parse(pos, len); 280 ALOGV("Parse (2) returned %ld", res); 281 CHECK_GE(res, 0); 282 283 mBlockEntryIndex = 0; 284 continue; 285 } 286 287 CHECK(mBlockEntry != NULL); 288 CHECK(mBlockEntry->GetBlock() != NULL); 289 ++mBlockEntryIndex; 290 291 if (mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) { 292 break; 293 } 294 } 295} 296 297void BlockIterator::reset() { 298 Mutex::Autolock autoLock(mExtractor->mLock); 299 300 mCluster = mExtractor->mSegment->GetFirst(); 301 mBlockEntry = NULL; 302 mBlockEntryIndex = 0; 303 304 do { 305 advance_l(); 306 } while (!eos() && block()->GetTrackNumber() != mTrackNum); 307} 308 309void BlockIterator::seek( 310 int64_t seekTimeUs, bool seekToKeyFrame, 311 int64_t *actualFrameTimeUs) { 312 Mutex::Autolock autoLock(mExtractor->mLock); 313 314 *actualFrameTimeUs = -1ll; 315 316 const int64_t seekTimeNs = seekTimeUs * 1000ll; 317 318 mkvparser::Segment* const pSegment = mExtractor->mSegment; 319 320 // Special case the 0 seek to avoid loading Cues when the application 321 // extraneously seeks to 0 before playing. 322 if (seekTimeNs <= 0) { 323 ALOGV("Seek to beginning: %lld", seekTimeUs); 324 mCluster = pSegment->GetFirst(); 325 mBlockEntryIndex = 0; 326 do { 327 advance_l(); 328 } while (!eos() && block()->GetTrackNumber() != mTrackNum); 329 return; 330 } 331 332 ALOGV("Seeking to: %lld", seekTimeUs); 333 334 // If the Cues have not been located then find them. 335 const mkvparser::Cues* pCues = pSegment->GetCues(); 336 const mkvparser::SeekHead* pSH = pSegment->GetSeekHead(); 337 if (!pCues && pSH) { 338 const size_t count = pSH->GetCount(); 339 const mkvparser::SeekHead::Entry* pEntry; 340 ALOGV("No Cues yet"); 341 342 for (size_t index = 0; index < count; index++) { 343 pEntry = pSH->GetEntry(index); 344 345 if (pEntry->id == 0x0C53BB6B) { // Cues ID 346 long len; long long pos; 347 pSegment->ParseCues(pEntry->pos, pos, len); 348 pCues = pSegment->GetCues(); 349 ALOGV("Cues found"); 350 break; 351 } 352 } 353 354 if (!pCues) { 355 ALOGE("No Cues in file"); 356 return; 357 } 358 } 359 else if (!pSH) { 360 ALOGE("No SeekHead"); 361 return; 362 } 363 364 const mkvparser::CuePoint* pCP; 365 while (!pCues->DoneParsing()) { 366 pCues->LoadCuePoint(); 367 pCP = pCues->GetLast(); 368 369 if (pCP->GetTime(pSegment) >= seekTimeNs) { 370 ALOGV("Parsed past relevant Cue"); 371 break; 372 } 373 } 374 375 // Find the video track for seeking. It doesn't make sense to search the 376 // audio track because we'd still want to make sure we're jumping to a 377 // keyframe in the video track. 378 mkvparser::Tracks const *pTracks = pSegment->GetTracks(); 379 const mkvparser::Track *pTrack = NULL; 380 for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) { 381 pTrack = pTracks->GetTrackByIndex(index); 382 if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK 383 ALOGV("Video track located at %d", index); 384 break; 385 } 386 } 387 388 const mkvparser::CuePoint::TrackPosition* pTP; 389 if (pTrack) { 390 pCues->Find(seekTimeNs, pTrack, pCP, pTP); 391 } else { 392 ALOGE("Did not locate a VIDEO_TRACK"); 393 return; 394 } 395 396 mCluster = pSegment->FindOrPreloadCluster(pTP->m_pos); 397 if (pTP->m_block > 0) { 398 // m_block starts at 1, but mBlockEntryIndex is expected to start at 0 399 mBlockEntryIndex = pTP->m_block - 1; 400 } else { 401 ALOGE("m_block must be > 0"); 402 return; 403 } 404 405 long prevKeyFrameBlockEntryIndex = -1; 406 407 for (;;) { 408 advance_l(); 409 410 if (eos()) { 411 break; 412 } 413 414 if (block()->GetTrackNumber() != mTrackNum) { 415 continue; 416 } 417 418 if (block()->IsKey()) { 419 prevKeyFrameBlockEntryIndex = mBlockEntryIndex - 1; 420 } 421 422 int64_t timeNs = block()->GetTime(mCluster); 423 424 if (timeNs >= seekTimeNs) { 425 *actualFrameTimeUs = (timeNs + 500ll) / 1000ll; 426 break; 427 } 428 } 429 430 if (eos()) { 431 return; 432 } 433 434 if (seekToKeyFrame && !block()->IsKey()) { 435 CHECK_GE(prevKeyFrameBlockEntryIndex, 0); 436 mBlockEntryIndex = prevKeyFrameBlockEntryIndex; 437 advance_l(); 438 } 439} 440 441const mkvparser::Block *BlockIterator::block() const { 442 CHECK(!eos()); 443 444 return mBlockEntry->GetBlock(); 445} 446 447int64_t BlockIterator::blockTimeUs() const { 448 return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll; 449} 450 451//////////////////////////////////////////////////////////////////////////////// 452 453static unsigned U24_AT(const uint8_t *ptr) { 454 return ptr[0] << 16 | ptr[1] << 8 | ptr[2]; 455} 456 457static size_t clz(uint8_t x) { 458 size_t numLeadingZeroes = 0; 459 460 while (!(x & 0x80)) { 461 ++numLeadingZeroes; 462 x = x << 1; 463 } 464 465 return numLeadingZeroes; 466} 467 468void MatroskaSource::clearPendingFrames() { 469 while (!mPendingFrames.empty()) { 470 MediaBuffer *frame = *mPendingFrames.begin(); 471 mPendingFrames.erase(mPendingFrames.begin()); 472 473 frame->release(); 474 frame = NULL; 475 } 476} 477 478status_t MatroskaSource::readBlock() { 479 CHECK(mPendingFrames.empty()); 480 481 if (mBlockIter.eos()) { 482 return ERROR_END_OF_STREAM; 483 } 484 485 const mkvparser::Block *block = mBlockIter.block(); 486 487 int64_t timeUs = mBlockIter.blockTimeUs(); 488 489 for (int i = 0; i < block->GetFrameCount(); ++i) { 490 const mkvparser::Block::Frame &frame = block->GetFrame(i); 491 492 MediaBuffer *mbuf = new MediaBuffer(frame.len); 493 mbuf->meta_data()->setInt64(kKeyTime, timeUs); 494 mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey()); 495 496 long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data()); 497 if (n != 0) { 498 mPendingFrames.clear(); 499 500 mBlockIter.advance(); 501 return ERROR_IO; 502 } 503 504 mPendingFrames.push_back(mbuf); 505 } 506 507 mBlockIter.advance(); 508 509 return OK; 510} 511 512status_t MatroskaSource::read( 513 MediaBuffer **out, const ReadOptions *options) { 514 *out = NULL; 515 516 int64_t targetSampleTimeUs = -1ll; 517 518 int64_t seekTimeUs; 519 ReadOptions::SeekMode mode; 520 if (options && options->getSeekTo(&seekTimeUs, &mode) 521 && !mExtractor->isLiveStreaming()) { 522 clearPendingFrames(); 523 524 // Apparently keyframe indication in audio tracks is unreliable, 525 // fortunately in all our currently supported audio encodings every 526 // frame is effectively a keyframe. 527 int64_t actualFrameTimeUs; 528 mBlockIter.seek(seekTimeUs, !mIsAudio, &actualFrameTimeUs); 529 530 if (mode == ReadOptions::SEEK_CLOSEST) { 531 targetSampleTimeUs = actualFrameTimeUs; 532 } 533 } 534 535 while (mPendingFrames.empty()) { 536 status_t err = readBlock(); 537 538 if (err != OK) { 539 clearPendingFrames(); 540 541 return err; 542 } 543 } 544 545 MediaBuffer *frame = *mPendingFrames.begin(); 546 mPendingFrames.erase(mPendingFrames.begin()); 547 548 if (mType != AVC) { 549 if (targetSampleTimeUs >= 0ll) { 550 frame->meta_data()->setInt64( 551 kKeyTargetTime, targetSampleTimeUs); 552 } 553 554 *out = frame; 555 556 return OK; 557 } 558 559 // Each input frame contains one or more NAL fragments, each fragment 560 // is prefixed by mNALSizeLen bytes giving the fragment length, 561 // followed by a corresponding number of bytes containing the fragment. 562 // We output all these fragments into a single large buffer separated 563 // by startcodes (0x00 0x00 0x00 0x01). 564 565 const uint8_t *srcPtr = 566 (const uint8_t *)frame->data() + frame->range_offset(); 567 568 size_t srcSize = frame->range_length(); 569 570 size_t dstSize = 0; 571 MediaBuffer *buffer = NULL; 572 uint8_t *dstPtr = NULL; 573 574 for (int32_t pass = 0; pass < 2; ++pass) { 575 size_t srcOffset = 0; 576 size_t dstOffset = 0; 577 while (srcOffset + mNALSizeLen <= srcSize) { 578 size_t NALsize; 579 switch (mNALSizeLen) { 580 case 1: NALsize = srcPtr[srcOffset]; break; 581 case 2: NALsize = U16_AT(srcPtr + srcOffset); break; 582 case 3: NALsize = U24_AT(srcPtr + srcOffset); break; 583 case 4: NALsize = U32_AT(srcPtr + srcOffset); break; 584 default: 585 TRESPASS(); 586 } 587 588 if (srcOffset + mNALSizeLen + NALsize > srcSize) { 589 break; 590 } 591 592 if (pass == 1) { 593 memcpy(&dstPtr[dstOffset], "\x00\x00\x00\x01", 4); 594 595 memcpy(&dstPtr[dstOffset + 4], 596 &srcPtr[srcOffset + mNALSizeLen], 597 NALsize); 598 } 599 600 dstOffset += 4; // 0x00 00 00 01 601 dstOffset += NALsize; 602 603 srcOffset += mNALSizeLen + NALsize; 604 } 605 606 if (srcOffset < srcSize) { 607 // There were trailing bytes or not enough data to complete 608 // a fragment. 609 610 frame->release(); 611 frame = NULL; 612 613 return ERROR_MALFORMED; 614 } 615 616 if (pass == 0) { 617 dstSize = dstOffset; 618 619 buffer = new MediaBuffer(dstSize); 620 621 int64_t timeUs; 622 CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs)); 623 int32_t isSync; 624 CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)); 625 626 buffer->meta_data()->setInt64(kKeyTime, timeUs); 627 buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync); 628 629 dstPtr = (uint8_t *)buffer->data(); 630 } 631 } 632 633 frame->release(); 634 frame = NULL; 635 636 if (targetSampleTimeUs >= 0ll) { 637 buffer->meta_data()->setInt64( 638 kKeyTargetTime, targetSampleTimeUs); 639 } 640 641 *out = buffer; 642 643 return OK; 644} 645 646//////////////////////////////////////////////////////////////////////////////// 647 648MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) 649 : mDataSource(source), 650 mReader(new DataSourceReader(mDataSource)), 651 mSegment(NULL), 652 mExtractedThumbnails(false), 653 mIsWebm(false) { 654 off64_t size; 655 mIsLiveStreaming = 656 (mDataSource->flags() 657 & (DataSource::kWantsPrefetching 658 | DataSource::kIsCachingDataSource)) 659 && mDataSource->getSize(&size) != OK; 660 661 mkvparser::EBMLHeader ebmlHeader; 662 long long pos; 663 if (ebmlHeader.Parse(mReader, pos) < 0) { 664 return; 665 } 666 667 if (ebmlHeader.m_docType && !strcmp("webm", ebmlHeader.m_docType)) { 668 mIsWebm = true; 669 } 670 671 long long ret = 672 mkvparser::Segment::CreateInstance(mReader, pos, mSegment); 673 674 if (ret) { 675 CHECK(mSegment == NULL); 676 return; 677 } 678 679 ret = mSegment->ParseHeaders(); 680 CHECK_EQ(ret, 0); 681 682 long len; 683 ret = mSegment->LoadCluster(pos, len); 684 CHECK_EQ(ret, 0); 685 686 if (ret < 0) { 687 delete mSegment; 688 mSegment = NULL; 689 return; 690 } 691 692#if 0 693 const mkvparser::SegmentInfo *info = mSegment->GetInfo(); 694 ALOGI("muxing app: %s, writing app: %s", 695 info->GetMuxingAppAsUTF8(), 696 info->GetWritingAppAsUTF8()); 697#endif 698 699 addTracks(); 700} 701 702MatroskaExtractor::~MatroskaExtractor() { 703 delete mSegment; 704 mSegment = NULL; 705 706 delete mReader; 707 mReader = NULL; 708} 709 710size_t MatroskaExtractor::countTracks() { 711 return mTracks.size(); 712} 713 714sp<MediaSource> MatroskaExtractor::getTrack(size_t index) { 715 if (index >= mTracks.size()) { 716 return NULL; 717 } 718 719 return new MatroskaSource(this, index); 720} 721 722sp<MetaData> MatroskaExtractor::getTrackMetaData( 723 size_t index, uint32_t flags) { 724 if (index >= mTracks.size()) { 725 return NULL; 726 } 727 728 if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails 729 && !isLiveStreaming()) { 730 findThumbnails(); 731 mExtractedThumbnails = true; 732 } 733 734 return mTracks.itemAt(index).mMeta; 735} 736 737bool MatroskaExtractor::isLiveStreaming() const { 738 return mIsLiveStreaming; 739} 740 741static void addESDSFromCodecPrivate( 742 const sp<MetaData> &meta, 743 bool isAudio, const void *priv, size_t privSize) { 744 static const uint8_t kStaticESDS[] = { 745 0x03, 22, 746 0x00, 0x00, // ES_ID 747 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag 748 749 0x04, 17, 750 0x40, // ObjectTypeIndication 751 0x00, 0x00, 0x00, 0x00, 752 0x00, 0x00, 0x00, 0x00, 753 0x00, 0x00, 0x00, 0x00, 754 755 0x05, 756 // CodecSpecificInfo (with size prefix) follows 757 }; 758 759 // Make sure all sizes can be coded in a single byte. 760 CHECK(privSize + 22 - 2 < 128); 761 size_t esdsSize = sizeof(kStaticESDS) + privSize + 1; 762 uint8_t *esds = new uint8_t[esdsSize]; 763 memcpy(esds, kStaticESDS, sizeof(kStaticESDS)); 764 uint8_t *ptr = esds + sizeof(kStaticESDS); 765 *ptr++ = privSize; 766 memcpy(ptr, priv, privSize); 767 768 // Increment by codecPrivateSize less 2 bytes that are accounted for 769 // already in lengths of 22/17 770 esds[1] += privSize - 2; 771 esds[6] += privSize - 2; 772 773 // Set ObjectTypeIndication. 774 esds[7] = isAudio ? 0x40 // Audio ISO/IEC 14496-3 775 : 0x20; // Visual ISO/IEC 14496-2 776 777 meta->setData(kKeyESDS, 0, esds, esdsSize); 778 779 delete[] esds; 780 esds = NULL; 781} 782 783void addVorbisCodecInfo( 784 const sp<MetaData> &meta, 785 const void *_codecPrivate, size_t codecPrivateSize) { 786 // printf("vorbis private data follows:\n"); 787 // hexdump(_codecPrivate, codecPrivateSize); 788 789 CHECK(codecPrivateSize >= 3); 790 791 const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate; 792 CHECK(codecPrivate[0] == 0x02); 793 794 size_t len1 = codecPrivate[1]; 795 size_t len2 = codecPrivate[2]; 796 797 CHECK(codecPrivateSize > 3 + len1 + len2); 798 799 CHECK(codecPrivate[3] == 0x01); 800 meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1); 801 802 CHECK(codecPrivate[len1 + 3] == 0x03); 803 804 CHECK(codecPrivate[len1 + len2 + 3] == 0x05); 805 meta->setData( 806 kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3], 807 codecPrivateSize - len1 - len2 - 3); 808} 809 810void MatroskaExtractor::addTracks() { 811 const mkvparser::Tracks *tracks = mSegment->GetTracks(); 812 813 for (size_t index = 0; index < tracks->GetTracksCount(); ++index) { 814 const mkvparser::Track *track = tracks->GetTrackByIndex(index); 815 816 if (track == NULL) { 817 // Apparently this is currently valid (if unexpected) behaviour 818 // of the mkv parser lib. 819 continue; 820 } 821 822 const char *const codecID = track->GetCodecId(); 823 ALOGV("codec id = %s", codecID); 824 ALOGV("codec name = %s", track->GetCodecNameAsUTF8()); 825 826 size_t codecPrivateSize; 827 const unsigned char *codecPrivate = 828 track->GetCodecPrivate(codecPrivateSize); 829 830 enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 }; 831 832 sp<MetaData> meta = new MetaData; 833 834 switch (track->GetType()) { 835 case VIDEO_TRACK: 836 { 837 const mkvparser::VideoTrack *vtrack = 838 static_cast<const mkvparser::VideoTrack *>(track); 839 840 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) { 841 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 842 meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize); 843 } else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) { 844 if (codecPrivateSize > 0) { 845 meta->setCString( 846 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); 847 addESDSFromCodecPrivate( 848 meta, false, codecPrivate, codecPrivateSize); 849 } else { 850 ALOGW("%s is detected, but does not have configuration.", 851 codecID); 852 continue; 853 } 854 } else if (!strcmp("V_VP8", codecID)) { 855 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX); 856 } else { 857 ALOGW("%s is not supported.", codecID); 858 continue; 859 } 860 861 meta->setInt32(kKeyWidth, vtrack->GetWidth()); 862 meta->setInt32(kKeyHeight, vtrack->GetHeight()); 863 break; 864 } 865 866 case AUDIO_TRACK: 867 { 868 const mkvparser::AudioTrack *atrack = 869 static_cast<const mkvparser::AudioTrack *>(track); 870 871 if (!strcmp("A_AAC", codecID)) { 872 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); 873 CHECK(codecPrivateSize >= 2); 874 875 addESDSFromCodecPrivate( 876 meta, true, codecPrivate, codecPrivateSize); 877 } else if (!strcmp("A_VORBIS", codecID)) { 878 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); 879 880 addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize); 881 } else if (!strcmp("A_MPEG/L3", codecID)) { 882 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); 883 } else { 884 ALOGW("%s is not supported.", codecID); 885 continue; 886 } 887 888 meta->setInt32(kKeySampleRate, atrack->GetSamplingRate()); 889 meta->setInt32(kKeyChannelCount, atrack->GetChannels()); 890 break; 891 } 892 893 default: 894 continue; 895 } 896 897 long long durationNs = mSegment->GetDuration(); 898 meta->setInt64(kKeyDuration, (durationNs + 500) / 1000); 899 900 mTracks.push(); 901 TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1); 902 trackInfo->mTrackNum = track->GetNumber(); 903 trackInfo->mMeta = meta; 904 } 905} 906 907void MatroskaExtractor::findThumbnails() { 908 for (size_t i = 0; i < mTracks.size(); ++i) { 909 TrackInfo *info = &mTracks.editItemAt(i); 910 911 const char *mime; 912 CHECK(info->mMeta->findCString(kKeyMIMEType, &mime)); 913 914 if (strncasecmp(mime, "video/", 6)) { 915 continue; 916 } 917 918 BlockIterator iter(this, info->mTrackNum); 919 int32_t i = 0; 920 int64_t thumbnailTimeUs = 0; 921 size_t maxBlockSize = 0; 922 while (!iter.eos() && i < 20) { 923 if (iter.block()->IsKey()) { 924 ++i; 925 926 size_t blockSize = 0; 927 for (int i = 0; i < iter.block()->GetFrameCount(); ++i) { 928 blockSize += iter.block()->GetFrame(i).len; 929 } 930 931 if (blockSize > maxBlockSize) { 932 maxBlockSize = blockSize; 933 thumbnailTimeUs = iter.blockTimeUs(); 934 } 935 } 936 iter.advance(); 937 } 938 info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs); 939 } 940} 941 942sp<MetaData> MatroskaExtractor::getMetaData() { 943 sp<MetaData> meta = new MetaData; 944 945 meta->setCString( 946 kKeyMIMEType, 947 mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA); 948 949 return meta; 950} 951 952uint32_t MatroskaExtractor::flags() const { 953 uint32_t x = CAN_PAUSE; 954 if (!isLiveStreaming()) { 955 x |= CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK; 956 } 957 958 return x; 959} 960 961bool SniffMatroska( 962 const sp<DataSource> &source, String8 *mimeType, float *confidence, 963 sp<AMessage> *) { 964 DataSourceReader reader(source); 965 mkvparser::EBMLHeader ebmlHeader; 966 long long pos; 967 if (ebmlHeader.Parse(&reader, pos) < 0) { 968 return false; 969 } 970 971 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA); 972 *confidence = 0.6; 973 974 return true; 975} 976 977} // namespace android 978