MatroskaExtractor.cpp revision ff1df9951d09f1a1a8ae2dbc42b82b0f9c164e5e
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/DataSource.h> 26#include <media/stagefright/MediaBuffer.h> 27#include <media/stagefright/MediaDebug.h> 28#include <media/stagefright/MediaDefs.h> 29#include <media/stagefright/MediaErrors.h> 30#include <media/stagefright/MediaSource.h> 31#include <media/stagefright/MetaData.h> 32#include <utils/String8.h> 33 34namespace android { 35 36struct DataSourceReader : public mkvparser::IMkvReader { 37 DataSourceReader(const sp<DataSource> &source) 38 : mSource(source) { 39 } 40 41 virtual int Read(long long position, long length, unsigned char* buffer) { 42 CHECK(position >= 0); 43 CHECK(length >= 0); 44 45 if (length == 0) { 46 return 0; 47 } 48 49 ssize_t n = mSource->readAt(position, buffer, length); 50 51 if (n <= 0) { 52 return -1; 53 } 54 55 return 0; 56 } 57 58 virtual int Length(long long* total, long long* available) { 59 off_t size; 60 if (mSource->getSize(&size) != OK) { 61 return -1; 62 } 63 64 if (total) { 65 *total = size; 66 } 67 68 if (available) { 69 *available = size; 70 } 71 72 return 0; 73 } 74 75private: 76 sp<DataSource> mSource; 77 78 DataSourceReader(const DataSourceReader &); 79 DataSourceReader &operator=(const DataSourceReader &); 80}; 81 82//////////////////////////////////////////////////////////////////////////////// 83 84#include <ctype.h> 85static void hexdump(const void *_data, size_t size) { 86 const uint8_t *data = (const uint8_t *)_data; 87 size_t offset = 0; 88 while (offset < size) { 89 printf("0x%04x ", offset); 90 91 size_t n = size - offset; 92 if (n > 16) { 93 n = 16; 94 } 95 96 for (size_t i = 0; i < 16; ++i) { 97 if (i == 8) { 98 printf(" "); 99 } 100 101 if (offset + i < size) { 102 printf("%02x ", data[offset + i]); 103 } else { 104 printf(" "); 105 } 106 } 107 108 printf(" "); 109 110 for (size_t i = 0; i < n; ++i) { 111 if (isprint(data[offset + i])) { 112 printf("%c", data[offset + i]); 113 } else { 114 printf("."); 115 } 116 } 117 118 printf("\n"); 119 120 offset += 16; 121 } 122} 123 124struct BlockIterator { 125 BlockIterator(mkvparser::Segment *segment, unsigned long trackNum); 126 127 bool eos() const; 128 129 void advance(); 130 void reset(); 131 void seek(int64_t seekTimeUs); 132 133 const mkvparser::Block *block() const; 134 int64_t blockTimeUs() const; 135 136private: 137 mkvparser::Segment *mSegment; 138 unsigned long mTrackNum; 139 140 mkvparser::Cluster *mCluster; 141 const mkvparser::BlockEntry *mBlockEntry; 142 143 BlockIterator(const BlockIterator &); 144 BlockIterator &operator=(const BlockIterator &); 145}; 146 147struct MatroskaSource : public MediaSource { 148 MatroskaSource( 149 const sp<MatroskaExtractor> &extractor, size_t index); 150 151 virtual status_t start(MetaData *params); 152 virtual status_t stop(); 153 154 virtual sp<MetaData> getFormat(); 155 156 virtual status_t read( 157 MediaBuffer **buffer, const ReadOptions *options); 158 159private: 160 enum Type { 161 AVC, 162 AAC, 163 OTHER 164 }; 165 166 sp<MatroskaExtractor> mExtractor; 167 size_t mTrackIndex; 168 Type mType; 169 BlockIterator mBlockIter; 170 171 status_t advance(); 172 173 MatroskaSource(const MatroskaSource &); 174 MatroskaSource &operator=(const MatroskaSource &); 175}; 176 177MatroskaSource::MatroskaSource( 178 const sp<MatroskaExtractor> &extractor, size_t index) 179 : mExtractor(extractor), 180 mTrackIndex(index), 181 mType(OTHER), 182 mBlockIter(mExtractor->mSegment, 183 mExtractor->mTracks.itemAt(index).mTrackNum) { 184 const char *mime; 185 CHECK(mExtractor->mTracks.itemAt(index).mMeta-> 186 findCString(kKeyMIMEType, &mime)); 187 188 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 189 mType = AVC; 190 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 191 mType = AAC; 192 } 193} 194 195status_t MatroskaSource::start(MetaData *params) { 196 mBlockIter.reset(); 197 198 return OK; 199} 200 201status_t MatroskaSource::stop() { 202 return OK; 203} 204 205sp<MetaData> MatroskaSource::getFormat() { 206 return mExtractor->mTracks.itemAt(mTrackIndex).mMeta; 207} 208 209//////////////////////////////////////////////////////////////////////////////// 210 211BlockIterator::BlockIterator( 212 mkvparser::Segment *segment, unsigned long trackNum) 213 : mSegment(segment), 214 mTrackNum(trackNum), 215 mCluster(NULL), 216 mBlockEntry(NULL) { 217 reset(); 218} 219 220bool BlockIterator::eos() const { 221 return mCluster == NULL || mCluster->EOS(); 222} 223 224void BlockIterator::advance() { 225 while (!eos()) { 226 if (mBlockEntry != NULL) { 227 mBlockEntry = mCluster->GetNext(mBlockEntry); 228 } else if (mCluster != NULL) { 229 mCluster = mSegment->GetNext(mCluster); 230 231 if (eos()) { 232 break; 233 } 234 235 mBlockEntry = mCluster->GetFirst(); 236 } 237 238 if (mBlockEntry != NULL 239 && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) { 240 break; 241 } 242 } 243} 244 245void BlockIterator::reset() { 246 mCluster = mSegment->GetFirst(); 247 mBlockEntry = mCluster->GetFirst(); 248 249 while (!eos() && block()->GetTrackNumber() != mTrackNum) { 250 advance(); 251 } 252} 253 254void BlockIterator::seek(int64_t seekTimeUs) { 255 mCluster = mSegment->FindCluster(seekTimeUs * 1000ll); 256 mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL; 257 258 while (!eos() && block()->GetTrackNumber() != mTrackNum) { 259 advance(); 260 } 261 262 while (!eos() && !mBlockEntry->GetBlock()->IsKey()) { 263 advance(); 264 } 265} 266 267const mkvparser::Block *BlockIterator::block() const { 268 CHECK(!eos()); 269 270 return mBlockEntry->GetBlock(); 271} 272 273int64_t BlockIterator::blockTimeUs() const { 274 return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll; 275} 276 277//////////////////////////////////////////////////////////////////////////////// 278 279status_t MatroskaSource::read( 280 MediaBuffer **out, const ReadOptions *options) { 281 *out = NULL; 282 283 int64_t seekTimeUs; 284 ReadOptions::SeekMode mode; 285 if (options && options->getSeekTo(&seekTimeUs, &mode)) { 286 mBlockIter.seek(seekTimeUs); 287 } 288 289 if (mBlockIter.eos()) { 290 return ERROR_END_OF_STREAM; 291 } 292 293 const mkvparser::Block *block = mBlockIter.block(); 294 size_t size = block->GetSize(); 295 int64_t timeUs = mBlockIter.blockTimeUs(); 296 297 MediaBuffer *buffer = new MediaBuffer(size + 2); 298 buffer->meta_data()->setInt64(kKeyTime, timeUs); 299 buffer->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey()); 300 301 long res = block->Read( 302 mExtractor->mReader, (unsigned char *)buffer->data() + 2); 303 304 if (res != 0) { 305 return ERROR_END_OF_STREAM; 306 } 307 308 buffer->set_range(2, size); 309 310 if (mType == AVC) { 311 CHECK(size >= 2); 312 313 uint8_t *data = (uint8_t *)buffer->data(); 314 315 unsigned NALsize = data[2] << 8 | data[3]; 316 CHECK_EQ(size, NALsize + 2); 317 318 memcpy(data, "\x00\x00\x00\x01", 4); 319 buffer->set_range(0, size + 2); 320 } else if (mType == AAC) { 321 // There's strange junk at the beginning... 322 323 const uint8_t *data = (const uint8_t *)buffer->data() + 2; 324 size_t offset = 0; 325 while (offset < size && data[offset] != 0x21) { 326 ++offset; 327 } 328 buffer->set_range(2 + offset, size - offset); 329 } 330 331 *out = buffer; 332 333#if 0 334 hexdump((const uint8_t *)buffer->data() + buffer->range_offset(), 335 buffer->range_length()); 336#endif 337 338 mBlockIter.advance(); 339 340 return OK; 341} 342 343//////////////////////////////////////////////////////////////////////////////// 344 345MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) 346 : mDataSource(source), 347 mReader(new DataSourceReader(mDataSource)), 348 mSegment(NULL), 349 mExtractedThumbnails(false) { 350 mkvparser::EBMLHeader ebmlHeader; 351 long long pos; 352 if (ebmlHeader.Parse(mReader, pos) < 0) { 353 return; 354 } 355 356 long long ret = 357 mkvparser::Segment::CreateInstance(mReader, pos, mSegment); 358 359 if (ret) { 360 CHECK(mSegment == NULL); 361 return; 362 } 363 364 ret = mSegment->Load(); 365 366 if (ret < 0) { 367 delete mSegment; 368 mSegment = NULL; 369 return; 370 } 371 372 addTracks(); 373} 374 375MatroskaExtractor::~MatroskaExtractor() { 376 delete mSegment; 377 mSegment = NULL; 378 379 delete mReader; 380 mReader = NULL; 381} 382 383size_t MatroskaExtractor::countTracks() { 384 return mTracks.size(); 385} 386 387sp<MediaSource> MatroskaExtractor::getTrack(size_t index) { 388 if (index >= mTracks.size()) { 389 return NULL; 390 } 391 392 return new MatroskaSource(this, index); 393} 394 395sp<MetaData> MatroskaExtractor::getTrackMetaData( 396 size_t index, uint32_t flags) { 397 if (index >= mTracks.size()) { 398 return NULL; 399 } 400 401 if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) { 402 findThumbnails(); 403 mExtractedThumbnails = true; 404 } 405 406 return mTracks.itemAt(index).mMeta; 407} 408 409static void addESDSFromAudioSpecificInfo( 410 const sp<MetaData> &meta, const void *asi, size_t asiSize) { 411 static const uint8_t kStaticESDS[] = { 412 0x03, 22, 413 0x00, 0x00, // ES_ID 414 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag 415 416 0x04, 17, 417 0x40, // Audio ISO/IEC 14496-3 418 0x00, 0x00, 0x00, 0x00, 419 0x00, 0x00, 0x00, 0x00, 420 0x00, 0x00, 0x00, 0x00, 421 422 0x05, 423 // AudioSpecificInfo (with size prefix) follows 424 }; 425 426 CHECK(asiSize < 128); 427 size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1; 428 uint8_t *esds = new uint8_t[esdsSize]; 429 memcpy(esds, kStaticESDS, sizeof(kStaticESDS)); 430 uint8_t *ptr = esds + sizeof(kStaticESDS); 431 *ptr++ = asiSize; 432 memcpy(ptr, asi, asiSize); 433 434 meta->setData(kKeyESDS, 0, esds, esdsSize); 435 436 delete[] esds; 437 esds = NULL; 438} 439 440void addVorbisCodecInfo( 441 const sp<MetaData> &meta, 442 const void *_codecPrivate, size_t codecPrivateSize) { 443 // printf("vorbis private data follows:\n"); 444 // hexdump(_codecPrivate, codecPrivateSize); 445 446 CHECK(codecPrivateSize >= 3); 447 448 const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate; 449 CHECK(codecPrivate[0] == 0x02); 450 451 size_t len1 = codecPrivate[1]; 452 size_t len2 = codecPrivate[2]; 453 454 CHECK(codecPrivateSize > 3 + len1 + len2); 455 456 CHECK(codecPrivate[3] == 0x01); 457 meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1); 458 459 CHECK(codecPrivate[len1 + 3] == 0x03); 460 461 CHECK(codecPrivate[len1 + len2 + 3] == 0x05); 462 meta->setData( 463 kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3], 464 codecPrivateSize - len1 - len2 - 3); 465} 466 467void MatroskaExtractor::addTracks() { 468 const mkvparser::Tracks *tracks = mSegment->GetTracks(); 469 470 for (size_t index = 0; index < tracks->GetTracksCount(); ++index) { 471 const mkvparser::Track *track = tracks->GetTrackByIndex(index); 472 473 const char *const codecID = track->GetCodecId(); 474 LOGV("codec id = %s", codecID); 475 LOGV("codec name = %s", track->GetCodecNameAsUTF8()); 476 477 size_t codecPrivateSize; 478 const unsigned char *codecPrivate = 479 track->GetCodecPrivate(codecPrivateSize); 480 481 enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 }; 482 483 sp<MetaData> meta = new MetaData; 484 485 switch (track->GetType()) { 486 case VIDEO_TRACK: 487 { 488 const mkvparser::VideoTrack *vtrack = 489 static_cast<const mkvparser::VideoTrack *>(track); 490 491 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) { 492 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 493 meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize); 494 } else if (!strcmp("V_VP8", codecID)) { 495 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX); 496 } else { 497 continue; 498 } 499 500 meta->setInt32(kKeyWidth, vtrack->GetWidth()); 501 meta->setInt32(kKeyHeight, vtrack->GetHeight()); 502 break; 503 } 504 505 case AUDIO_TRACK: 506 { 507 const mkvparser::AudioTrack *atrack = 508 static_cast<const mkvparser::AudioTrack *>(track); 509 510 if (!strcmp("A_AAC", codecID)) { 511 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); 512 CHECK(codecPrivateSize >= 2); 513 514 addESDSFromAudioSpecificInfo( 515 meta, codecPrivate, codecPrivateSize); 516 } else if (!strcmp("A_VORBIS", codecID)) { 517 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); 518 519 addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize); 520 } else { 521 continue; 522 } 523 524 meta->setInt32(kKeySampleRate, atrack->GetSamplingRate()); 525 meta->setInt32(kKeyChannelCount, atrack->GetChannels()); 526 break; 527 } 528 529 default: 530 continue; 531 } 532 533 long long durationNs = mSegment->GetDuration(); 534 meta->setInt64(kKeyDuration, (durationNs + 500) / 1000); 535 536 mTracks.push(); 537 TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1); 538 trackInfo->mTrackNum = track->GetNumber(); 539 trackInfo->mMeta = meta; 540 } 541} 542 543void MatroskaExtractor::findThumbnails() { 544 for (size_t i = 0; i < mTracks.size(); ++i) { 545 TrackInfo *info = &mTracks.editItemAt(i); 546 547 const char *mime; 548 CHECK(info->mMeta->findCString(kKeyMIMEType, &mime)); 549 550 if (strncasecmp(mime, "video/", 6)) { 551 continue; 552 } 553 554 BlockIterator iter(mSegment, info->mTrackNum); 555 int32_t i = 0; 556 int64_t thumbnailTimeUs = 0; 557 size_t maxBlockSize = 0; 558 while (!iter.eos() && i < 20) { 559 if (iter.block()->IsKey()) { 560 ++i; 561 562 size_t blockSize = iter.block()->GetSize(); 563 if (blockSize > maxBlockSize) { 564 maxBlockSize = blockSize; 565 thumbnailTimeUs = iter.blockTimeUs(); 566 } 567 } 568 iter.advance(); 569 } 570 info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs); 571 } 572} 573 574sp<MetaData> MatroskaExtractor::getMetaData() { 575 sp<MetaData> meta = new MetaData; 576 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA); 577 578 return meta; 579} 580 581bool SniffMatroska( 582 const sp<DataSource> &source, String8 *mimeType, float *confidence, 583 sp<AMessage> *) { 584 DataSourceReader reader(source); 585 mkvparser::EBMLHeader ebmlHeader; 586 long long pos; 587 if (ebmlHeader.Parse(&reader, pos) < 0) { 588 return false; 589 } 590 591 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA); 592 *confidence = 0.6; 593 594 return true; 595} 596 597} // namespace android 598