MatroskaExtractor.cpp revision 5279d1d8c19e5fdbb177805db0da8e8aadac3079
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->GetCluster(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 if (options && options->getSeekTo(&seekTimeUs)) { 285 mBlockIter.seek(seekTimeUs); 286 } 287 288 if (mBlockIter.eos()) { 289 return ERROR_END_OF_STREAM; 290 } 291 292 const mkvparser::Block *block = mBlockIter.block(); 293 size_t size = block->GetSize(); 294 int64_t timeUs = mBlockIter.blockTimeUs(); 295 296 MediaBuffer *buffer = new MediaBuffer(size + 2); 297 buffer->meta_data()->setInt64(kKeyTime, timeUs); 298 299 long res = block->Read( 300 mExtractor->mReader, (unsigned char *)buffer->data() + 2); 301 302 if (res != 0) { 303 return ERROR_END_OF_STREAM; 304 } 305 306 buffer->set_range(2, size); 307 308 if (mType == AVC) { 309 CHECK(size >= 2); 310 311 uint8_t *data = (uint8_t *)buffer->data(); 312 313 unsigned NALsize = data[2] << 8 | data[3]; 314 CHECK_EQ(size, NALsize + 2); 315 316 memcpy(data, "\x00\x00\x00\x01", 4); 317 buffer->set_range(0, size + 2); 318 } else if (mType == AAC) { 319 // There's strange junk at the beginning... 320 321 const uint8_t *data = (const uint8_t *)buffer->data() + 2; 322 size_t offset = 0; 323 while (offset < size && data[offset] != 0x21) { 324 ++offset; 325 } 326 buffer->set_range(2 + offset, size - offset); 327 } 328 329 *out = buffer; 330 331#if 0 332 hexdump((const uint8_t *)buffer->data() + buffer->range_offset(), 333 buffer->range_length()); 334#endif 335 336 mBlockIter.advance(); 337 338 return OK; 339} 340 341//////////////////////////////////////////////////////////////////////////////// 342 343MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) 344 : mDataSource(source), 345 mReader(new DataSourceReader(mDataSource)), 346 mSegment(NULL), 347 mExtractedThumbnails(false) { 348 mkvparser::EBMLHeader ebmlHeader; 349 long long pos; 350 if (ebmlHeader.Parse(mReader, pos) < 0) { 351 return; 352 } 353 354 long long ret = 355 mkvparser::Segment::CreateInstance(mReader, pos, mSegment); 356 357 if (ret) { 358 CHECK(mSegment == NULL); 359 return; 360 } 361 362 ret = mSegment->Load(); 363 364 if (ret < 0) { 365 delete mSegment; 366 mSegment = NULL; 367 return; 368 } 369 370 addTracks(); 371} 372 373MatroskaExtractor::~MatroskaExtractor() { 374 delete mSegment; 375 mSegment = NULL; 376 377 delete mReader; 378 mReader = NULL; 379} 380 381size_t MatroskaExtractor::countTracks() { 382 return mTracks.size(); 383} 384 385sp<MediaSource> MatroskaExtractor::getTrack(size_t index) { 386 if (index >= mTracks.size()) { 387 return NULL; 388 } 389 390 return new MatroskaSource(this, index); 391} 392 393sp<MetaData> MatroskaExtractor::getTrackMetaData( 394 size_t index, uint32_t flags) { 395 if (index >= mTracks.size()) { 396 return NULL; 397 } 398 399 if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) { 400 findThumbnails(); 401 mExtractedThumbnails = true; 402 } 403 404 return mTracks.itemAt(index).mMeta; 405} 406 407static void addESDSFromAudioSpecificInfo( 408 const sp<MetaData> &meta, const void *asi, size_t asiSize) { 409 static const uint8_t kStaticESDS[] = { 410 0x03, 22, 411 0x00, 0x00, // ES_ID 412 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag 413 414 0x04, 17, 415 0x40, // Audio ISO/IEC 14496-3 416 0x00, 0x00, 0x00, 0x00, 417 0x00, 0x00, 0x00, 0x00, 418 0x00, 0x00, 0x00, 0x00, 419 420 0x05, 421 // AudioSpecificInfo (with size prefix) follows 422 }; 423 424 CHECK(asiSize < 128); 425 size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1; 426 uint8_t *esds = new uint8_t[esdsSize]; 427 memcpy(esds, kStaticESDS, sizeof(kStaticESDS)); 428 uint8_t *ptr = esds + sizeof(kStaticESDS); 429 *ptr++ = asiSize; 430 memcpy(ptr, asi, asiSize); 431 432 meta->setData(kKeyESDS, 0, esds, esdsSize); 433 434 delete[] esds; 435 esds = NULL; 436} 437 438void addVorbisCodecInfo( 439 const sp<MetaData> &meta, 440 const void *_codecPrivate, size_t codecPrivateSize) { 441 // printf("vorbis private data follows:\n"); 442 // hexdump(_codecPrivate, codecPrivateSize); 443 444 CHECK(codecPrivateSize >= 3); 445 446 const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate; 447 CHECK(codecPrivate[0] == 0x02); 448 449 size_t len1 = codecPrivate[1]; 450 size_t len2 = codecPrivate[2]; 451 452 CHECK(codecPrivateSize > 3 + len1 + len2); 453 454 CHECK(codecPrivate[3] == 0x01); 455 meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1); 456 457 CHECK(codecPrivate[len1 + 3] == 0x03); 458 459 CHECK(codecPrivate[len1 + len2 + 3] == 0x05); 460 meta->setData( 461 kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3], 462 codecPrivateSize - len1 - len2 - 3); 463} 464 465void MatroskaExtractor::addTracks() { 466 const mkvparser::Tracks *tracks = mSegment->GetTracks(); 467 468 for (size_t index = 0; index < tracks->GetTracksCount(); ++index) { 469 const mkvparser::Track *track = tracks->GetTrackByIndex(index); 470 471 const char *const codecID = track->GetCodecId(); 472 LOGV("codec id = %s", codecID); 473 LOGV("codec name = %s", track->GetCodecNameAsUTF8()); 474 475 size_t codecPrivateSize; 476 const unsigned char *codecPrivate = 477 track->GetCodecPrivate(&codecPrivateSize); 478 479 enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 }; 480 481 sp<MetaData> meta = new MetaData; 482 483 switch (track->GetType()) { 484 case VIDEO_TRACK: 485 { 486 const mkvparser::VideoTrack *vtrack = 487 static_cast<const mkvparser::VideoTrack *>(track); 488 489 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) { 490 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 491 meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize); 492 } else if (!strcmp("V_VP8", codecID)) { 493 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX); 494 } else { 495 continue; 496 } 497 498 meta->setInt32(kKeyWidth, vtrack->GetWidth()); 499 meta->setInt32(kKeyHeight, vtrack->GetHeight()); 500 break; 501 } 502 503 case AUDIO_TRACK: 504 { 505 const mkvparser::AudioTrack *atrack = 506 static_cast<const mkvparser::AudioTrack *>(track); 507 508 if (!strcmp("A_AAC", codecID)) { 509 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); 510 CHECK(codecPrivateSize >= 2); 511 512 addESDSFromAudioSpecificInfo( 513 meta, codecPrivate, codecPrivateSize); 514 } else if (!strcmp("A_VORBIS", codecID)) { 515 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); 516 517 addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize); 518 } else { 519 continue; 520 } 521 522 meta->setInt32(kKeySampleRate, atrack->GetSamplingRate()); 523 meta->setInt32(kKeyChannelCount, atrack->GetChannels()); 524 break; 525 } 526 527 default: 528 continue; 529 } 530 531 long long durationNs = mSegment->GetDuration(); 532 meta->setInt64(kKeyDuration, (durationNs + 500) / 1000); 533 534 mTracks.push(); 535 TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1); 536 trackInfo->mTrackNum = track->GetNumber(); 537 trackInfo->mMeta = meta; 538 } 539} 540 541void MatroskaExtractor::findThumbnails() { 542 for (size_t i = 0; i < mTracks.size(); ++i) { 543 TrackInfo *info = &mTracks.editItemAt(i); 544 545 const char *mime; 546 CHECK(info->mMeta->findCString(kKeyMIMEType, &mime)); 547 548 if (strncasecmp(mime, "video/", 6)) { 549 continue; 550 } 551 552 BlockIterator iter(mSegment, info->mTrackNum); 553 int32_t i = 0; 554 int64_t thumbnailTimeUs = 0; 555 size_t maxBlockSize = 0; 556 while (!iter.eos() && i < 20) { 557 if (iter.block()->IsKey()) { 558 ++i; 559 560 size_t blockSize = iter.block()->GetSize(); 561 if (blockSize > maxBlockSize) { 562 maxBlockSize = blockSize; 563 thumbnailTimeUs = iter.blockTimeUs(); 564 } 565 } 566 iter.advance(); 567 } 568 info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs); 569 } 570} 571 572sp<MetaData> MatroskaExtractor::getMetaData() { 573 sp<MetaData> meta = new MetaData; 574 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA); 575 576 return meta; 577} 578 579bool SniffMatroska( 580 const sp<DataSource> &source, String8 *mimeType, float *confidence) { 581 DataSourceReader reader(source); 582 mkvparser::EBMLHeader ebmlHeader; 583 long long pos; 584 if (ebmlHeader.Parse(&reader, pos) < 0) { 585 return false; 586 } 587 588 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA); 589 *confidence = 0.6; 590 591 return true; 592} 593 594} // namespace android 595