blob: 733de92bf6b12fbeca6aa9bfa33d68bee5d5c04d [file] [log] [blame]
Andreas Huber072f5242010-05-20 14:56:53 -07001/*
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
Andreas Huber0f624582010-11-15 15:10:34 -080025#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/foundation/hexdump.h>
Andreas Huber072f5242010-05-20 14:56:53 -070027#include <media/stagefright/DataSource.h>
28#include <media/stagefright/MediaBuffer.h>
Andreas Huber072f5242010-05-20 14:56:53 -070029#include <media/stagefright/MediaDefs.h>
30#include <media/stagefright/MediaErrors.h>
31#include <media/stagefright/MediaSource.h>
32#include <media/stagefright/MetaData.h>
Andreas Huber0f624582010-11-15 15:10:34 -080033#include <media/stagefright/Utils.h>
Andreas Huber072f5242010-05-20 14:56:53 -070034#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) {
James Dongb1262a82010-11-16 14:04:54 -080061 off64_t size;
Andreas Huber072f5242010-05-20 14:56:53 -070062 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
77private:
78 sp<DataSource> mSource;
79
80 DataSourceReader(const DataSourceReader &);
81 DataSourceReader &operator=(const DataSourceReader &);
82};
83
84////////////////////////////////////////////////////////////////////////////////
85
Andreas Huber6bdf2ed2010-05-25 13:35:02 -070086struct 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
98private:
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
Andreas Huber072f5242010-05-20 14:56:53 -0700109struct 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
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800121protected:
122 virtual ~MatroskaSource();
123
Andreas Huber072f5242010-05-20 14:56:53 -0700124private:
125 enum Type {
126 AVC,
127 AAC,
128 OTHER
129 };
130
131 sp<MatroskaExtractor> mExtractor;
132 size_t mTrackIndex;
Andreas Huber072f5242010-05-20 14:56:53 -0700133 Type mType;
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700134 BlockIterator mBlockIter;
Andreas Huber0f624582010-11-15 15:10:34 -0800135 size_t mNALSizeLen; // for type AVC
Andreas Huber072f5242010-05-20 14:56:53 -0700136
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800137 List<MediaBuffer *> mPendingFrames;
138
Andreas Huber072f5242010-05-20 14:56:53 -0700139 status_t advance();
140
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800141 status_t readBlock();
142 void clearPendingFrames();
143
Andreas Huber072f5242010-05-20 14:56:53 -0700144 MatroskaSource(const MatroskaSource &);
145 MatroskaSource &operator=(const MatroskaSource &);
146};
147
148MatroskaSource::MatroskaSource(
149 const sp<MatroskaExtractor> &extractor, size_t index)
150 : mExtractor(extractor),
151 mTrackIndex(index),
152 mType(OTHER),
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700153 mBlockIter(mExtractor->mSegment,
Andreas Huber0f624582010-11-15 15:10:34 -0800154 mExtractor->mTracks.itemAt(index).mTrackNum),
155 mNALSizeLen(0) {
156 sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
157
Andreas Huber072f5242010-05-20 14:56:53 -0700158 const char *mime;
Andreas Huber0f624582010-11-15 15:10:34 -0800159 CHECK(meta->findCString(kKeyMIMEType, &mime));
Andreas Huber072f5242010-05-20 14:56:53 -0700160
161 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
162 mType = AVC;
Andreas Huber0f624582010-11-15 15:10:34 -0800163
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);
Andreas Huber072f5242010-05-20 14:56:53 -0700174 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
175 mType = AAC;
176 }
177}
178
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800179MatroskaSource::~MatroskaSource() {
180 clearPendingFrames();
181}
182
Andreas Huber072f5242010-05-20 14:56:53 -0700183status_t MatroskaSource::start(MetaData *params) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700184 mBlockIter.reset();
Andreas Huber072f5242010-05-20 14:56:53 -0700185
186 return OK;
187}
188
189status_t MatroskaSource::stop() {
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800190 clearPendingFrames();
191
Andreas Huber072f5242010-05-20 14:56:53 -0700192 return OK;
193}
194
195sp<MetaData> MatroskaSource::getFormat() {
196 return mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
197}
198
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700199////////////////////////////////////////////////////////////////////////////////
200
201BlockIterator::BlockIterator(
202 mkvparser::Segment *segment, unsigned long trackNum)
203 : mSegment(segment),
204 mTrackNum(trackNum),
205 mCluster(NULL),
206 mBlockEntry(NULL) {
207 reset();
208}
209
210bool BlockIterator::eos() const {
211 return mCluster == NULL || mCluster->EOS();
212}
213
214void 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;
Andreas Huber072f5242010-05-20 14:56:53 -0700223 }
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700224
Andreas Huber072f5242010-05-20 14:56:53 -0700225 mBlockEntry = mCluster->GetFirst();
226 }
227
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700228 if (mBlockEntry != NULL
229 && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
230 break;
Andreas Huber072f5242010-05-20 14:56:53 -0700231 }
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700232 }
233}
Andreas Huber072f5242010-05-20 14:56:53 -0700234
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700235void BlockIterator::reset() {
236 mCluster = mSegment->GetFirst();
237 mBlockEntry = mCluster->GetFirst();
238
239 while (!eos() && block()->GetTrackNumber() != mTrackNum) {
240 advance();
241 }
242}
243
244void BlockIterator::seek(int64_t seekTimeUs) {
Andreas Huber4b844452010-10-28 10:50:47 -0700245 mCluster = mSegment->FindCluster(seekTimeUs * 1000ll);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700246 mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL;
247
248 while (!eos() && block()->GetTrackNumber() != mTrackNum) {
249 advance();
Andreas Huber072f5242010-05-20 14:56:53 -0700250 }
251
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700252 while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
253 advance();
254 }
Andreas Huber072f5242010-05-20 14:56:53 -0700255}
256
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700257const mkvparser::Block *BlockIterator::block() const {
258 CHECK(!eos());
259
260 return mBlockEntry->GetBlock();
261}
262
263int64_t BlockIterator::blockTimeUs() const {
264 return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
265}
266
267////////////////////////////////////////////////////////////////////////////////
268
Andreas Huber0f624582010-11-15 15:10:34 -0800269static unsigned U24_AT(const uint8_t *ptr) {
270 return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
271}
272
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800273static 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
284void 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
304status_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
Andreas Huber072f5242010-05-20 14:56:53 -0700481status_t MatroskaSource::read(
482 MediaBuffer **out, const ReadOptions *options) {
483 *out = NULL;
484
485 int64_t seekTimeUs;
Andreas Huber6624c9f2010-07-20 15:04:28 -0700486 ReadOptions::SeekMode mode;
487 if (options && options->getSeekTo(&seekTimeUs, &mode)) {
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800488 clearPendingFrames();
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700489 mBlockIter.seek(seekTimeUs);
Andreas Huber072f5242010-05-20 14:56:53 -0700490 }
491
Andreas Huber0f624582010-11-15 15:10:34 -0800492again:
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800493 while (mPendingFrames.empty()) {
494 status_t err = readBlock();
495
496 if (err != OK) {
497 clearPendingFrames();
498
499 return err;
500 }
Andreas Huber072f5242010-05-20 14:56:53 -0700501 }
502
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800503 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 }
Andreas Huber072f5242010-05-20 14:56:53 -0700520
Andreas Huber0f624582010-11-15 15:10:34 -0800521 // 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);
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800529
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
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700535 buffer->meta_data()->setInt64(kKeyTime, timeUs);
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800536 buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
Andreas Huber072f5242010-05-20 14:56:53 -0700537
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800538 memcpy((uint8_t *)buffer->data() + kPadding,
539 (const uint8_t *)frame->data() + frame->range_offset(),
540 size);
Andreas Huber072f5242010-05-20 14:56:53 -0700541
Andreas Huber0f624582010-11-15 15:10:34 -0800542 buffer->set_range(kPadding, size);
Andreas Huber072f5242010-05-20 14:56:53 -0700543
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800544 frame->release();
545 frame = NULL;
Andreas Huber072f5242010-05-20 14:56:53 -0700546
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800547 uint8_t *data = (uint8_t *)buffer->data();
Andreas Huber072f5242010-05-20 14:56:53 -0700548
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800549 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();
Andreas Huber072f5242010-05-20 14:56:53 -0700557 }
558
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800559 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
Andreas Huber072f5242010-05-20 14:56:53 -0700575 *out = buffer;
576
Andreas Huber072f5242010-05-20 14:56:53 -0700577 return OK;
578}
579
580////////////////////////////////////////////////////////////////////////////////
581
582MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
583 : mDataSource(source),
584 mReader(new DataSourceReader(mDataSource)),
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700585 mSegment(NULL),
586 mExtractedThumbnails(false) {
Andreas Huber072f5242010-05-20 14:56:53 -0700587 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
612MatroskaExtractor::~MatroskaExtractor() {
613 delete mSegment;
614 mSegment = NULL;
615
616 delete mReader;
617 mReader = NULL;
618}
619
620size_t MatroskaExtractor::countTracks() {
621 return mTracks.size();
622}
623
624sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
625 if (index >= mTracks.size()) {
626 return NULL;
627 }
628
629 return new MatroskaSource(this, index);
630}
631
632sp<MetaData> MatroskaExtractor::getTrackMetaData(
633 size_t index, uint32_t flags) {
634 if (index >= mTracks.size()) {
635 return NULL;
636 }
637
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700638 if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) {
639 findThumbnails();
640 mExtractedThumbnails = true;
641 }
642
Andreas Huber072f5242010-05-20 14:56:53 -0700643 return mTracks.itemAt(index).mMeta;
644}
645
646static 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
677void 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
704void 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
Andreas Huberdfe8d9b2011-01-24 12:46:12 -0800710 if (track == NULL) {
711 // Apparently this is currently valid (if unexpected) behaviour
712 // of the mkv parser lib.
713 continue;
714 }
715
Andreas Huber072f5242010-05-20 14:56:53 -0700716 const char *const codecID = track->GetCodecId();
717 LOGV("codec id = %s", codecID);
718 LOGV("codec name = %s", track->GetCodecNameAsUTF8());
719
720 size_t codecPrivateSize;
721 const unsigned char *codecPrivate =
Andreas Huber4b844452010-10-28 10:50:47 -0700722 track->GetCodecPrivate(codecPrivateSize);
Andreas Huber072f5242010-05-20 14:56:53 -0700723
724 enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
725
726 sp<MetaData> meta = new MetaData;
727
728 switch (track->GetType()) {
729 case VIDEO_TRACK:
730 {
731 const mkvparser::VideoTrack *vtrack =
732 static_cast<const mkvparser::VideoTrack *>(track);
733
734 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
735 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
736 meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
737 } else if (!strcmp("V_VP8", codecID)) {
738 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX);
739 } else {
740 continue;
741 }
742
743 meta->setInt32(kKeyWidth, vtrack->GetWidth());
744 meta->setInt32(kKeyHeight, vtrack->GetHeight());
745 break;
746 }
747
748 case AUDIO_TRACK:
749 {
750 const mkvparser::AudioTrack *atrack =
751 static_cast<const mkvparser::AudioTrack *>(track);
752
753 if (!strcmp("A_AAC", codecID)) {
754 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
755 CHECK(codecPrivateSize >= 2);
756
757 addESDSFromAudioSpecificInfo(
758 meta, codecPrivate, codecPrivateSize);
759 } else if (!strcmp("A_VORBIS", codecID)) {
760 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
761
762 addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize);
763 } else {
764 continue;
765 }
766
767 meta->setInt32(kKeySampleRate, atrack->GetSamplingRate());
768 meta->setInt32(kKeyChannelCount, atrack->GetChannels());
769 break;
770 }
771
772 default:
773 continue;
774 }
775
776 long long durationNs = mSegment->GetDuration();
777 meta->setInt64(kKeyDuration, (durationNs + 500) / 1000);
778
779 mTracks.push();
780 TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
781 trackInfo->mTrackNum = track->GetNumber();
782 trackInfo->mMeta = meta;
783 }
784}
785
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700786void MatroskaExtractor::findThumbnails() {
787 for (size_t i = 0; i < mTracks.size(); ++i) {
788 TrackInfo *info = &mTracks.editItemAt(i);
789
790 const char *mime;
791 CHECK(info->mMeta->findCString(kKeyMIMEType, &mime));
792
793 if (strncasecmp(mime, "video/", 6)) {
794 continue;
795 }
796
797 BlockIterator iter(mSegment, info->mTrackNum);
798 int32_t i = 0;
799 int64_t thumbnailTimeUs = 0;
800 size_t maxBlockSize = 0;
801 while (!iter.eos() && i < 20) {
802 if (iter.block()->IsKey()) {
803 ++i;
804
805 size_t blockSize = iter.block()->GetSize();
806 if (blockSize > maxBlockSize) {
807 maxBlockSize = blockSize;
808 thumbnailTimeUs = iter.blockTimeUs();
809 }
810 }
811 iter.advance();
812 }
813 info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
814 }
815}
816
Andreas Huber072f5242010-05-20 14:56:53 -0700817sp<MetaData> MatroskaExtractor::getMetaData() {
818 sp<MetaData> meta = new MetaData;
819 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA);
820
821 return meta;
822}
823
824bool SniffMatroska(
Andreas Huberefdd0882010-08-25 11:09:41 -0700825 const sp<DataSource> &source, String8 *mimeType, float *confidence,
826 sp<AMessage> *) {
Andreas Huber072f5242010-05-20 14:56:53 -0700827 DataSourceReader reader(source);
828 mkvparser::EBMLHeader ebmlHeader;
829 long long pos;
830 if (ebmlHeader.Parse(&reader, pos) < 0) {
831 return false;
832 }
833
834 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA);
835 *confidence = 0.6;
836
837 return true;
838}
839
840} // namespace android