blob: f215f52a61a66e16ca444b9aa4056db753a65e71 [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) {
Andreas Huber8885e672011-03-18 14:38:56 -070063 *total = -1;
64 *available = (long long)((1ull << 63) - 1);
65
66 return 0;
Andreas Huber072f5242010-05-20 14:56:53 -070067 }
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
Andreas Huber6bdf2ed2010-05-25 13:35:02 -070089struct BlockIterator {
Andreas Huber8885e672011-03-18 14:38:56 -070090 BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -070091
92 bool eos() const;
93
94 void advance();
95 void reset();
Andreas Huber089d3e32011-09-07 11:05:43 -070096 void seek(int64_t seekTimeUs, bool seekToKeyFrame);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -070097
98 const mkvparser::Block *block() const;
99 int64_t blockTimeUs() const;
100
101private:
Andreas Huber8885e672011-03-18 14:38:56 -0700102 MatroskaExtractor *mExtractor;
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700103 unsigned long mTrackNum;
104
Andreas Huber8885e672011-03-18 14:38:56 -0700105 const mkvparser::Cluster *mCluster;
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700106 const mkvparser::BlockEntry *mBlockEntry;
Andreas Huber8885e672011-03-18 14:38:56 -0700107 long mBlockEntryIndex;
108
109 void advance_l();
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700110
111 BlockIterator(const BlockIterator &);
112 BlockIterator &operator=(const BlockIterator &);
113};
114
Andreas Huber072f5242010-05-20 14:56:53 -0700115struct MatroskaSource : public MediaSource {
116 MatroskaSource(
117 const sp<MatroskaExtractor> &extractor, size_t index);
118
119 virtual status_t start(MetaData *params);
120 virtual status_t stop();
121
122 virtual sp<MetaData> getFormat();
123
124 virtual status_t read(
125 MediaBuffer **buffer, const ReadOptions *options);
126
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800127protected:
128 virtual ~MatroskaSource();
129
Andreas Huber072f5242010-05-20 14:56:53 -0700130private:
131 enum Type {
132 AVC,
133 AAC,
134 OTHER
135 };
136
137 sp<MatroskaExtractor> mExtractor;
138 size_t mTrackIndex;
Andreas Huber072f5242010-05-20 14:56:53 -0700139 Type mType;
Andreas Huber089d3e32011-09-07 11:05:43 -0700140 bool mIsAudio;
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700141 BlockIterator mBlockIter;
Andreas Huber0f624582010-11-15 15:10:34 -0800142 size_t mNALSizeLen; // for type AVC
Andreas Huber072f5242010-05-20 14:56:53 -0700143
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800144 List<MediaBuffer *> mPendingFrames;
145
Andreas Huber072f5242010-05-20 14:56:53 -0700146 status_t advance();
147
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800148 status_t readBlock();
149 void clearPendingFrames();
150
Andreas Huber072f5242010-05-20 14:56:53 -0700151 MatroskaSource(const MatroskaSource &);
152 MatroskaSource &operator=(const MatroskaSource &);
153};
154
155MatroskaSource::MatroskaSource(
156 const sp<MatroskaExtractor> &extractor, size_t index)
157 : mExtractor(extractor),
158 mTrackIndex(index),
159 mType(OTHER),
Andreas Huber089d3e32011-09-07 11:05:43 -0700160 mIsAudio(false),
Andreas Huber8885e672011-03-18 14:38:56 -0700161 mBlockIter(mExtractor.get(),
Andreas Huber0f624582010-11-15 15:10:34 -0800162 mExtractor->mTracks.itemAt(index).mTrackNum),
163 mNALSizeLen(0) {
164 sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
165
Andreas Huber072f5242010-05-20 14:56:53 -0700166 const char *mime;
Andreas Huber0f624582010-11-15 15:10:34 -0800167 CHECK(meta->findCString(kKeyMIMEType, &mime));
Andreas Huber072f5242010-05-20 14:56:53 -0700168
Andreas Huber089d3e32011-09-07 11:05:43 -0700169 mIsAudio = !strncasecmp("audio/", mime, 6);
170
Andreas Huber072f5242010-05-20 14:56:53 -0700171 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
172 mType = AVC;
Andreas Huber0f624582010-11-15 15:10:34 -0800173
174 uint32_t dummy;
175 const uint8_t *avcc;
176 size_t avccSize;
177 CHECK(meta->findData(
178 kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
179
180 CHECK_GE(avccSize, 5u);
181
182 mNALSizeLen = 1 + (avcc[4] & 3);
Steve Block71f2cf12011-10-20 11:56:00 +0100183 ALOGV("mNALSizeLen = %d", mNALSizeLen);
Andreas Huber072f5242010-05-20 14:56:53 -0700184 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
185 mType = AAC;
186 }
187}
188
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800189MatroskaSource::~MatroskaSource() {
190 clearPendingFrames();
191}
192
Andreas Huber072f5242010-05-20 14:56:53 -0700193status_t MatroskaSource::start(MetaData *params) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700194 mBlockIter.reset();
Andreas Huber072f5242010-05-20 14:56:53 -0700195
196 return OK;
197}
198
199status_t MatroskaSource::stop() {
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800200 clearPendingFrames();
201
Andreas Huber072f5242010-05-20 14:56:53 -0700202 return OK;
203}
204
205sp<MetaData> MatroskaSource::getFormat() {
206 return mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
207}
208
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700209////////////////////////////////////////////////////////////////////////////////
210
211BlockIterator::BlockIterator(
Andreas Huber8885e672011-03-18 14:38:56 -0700212 MatroskaExtractor *extractor, unsigned long trackNum)
213 : mExtractor(extractor),
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700214 mTrackNum(trackNum),
215 mCluster(NULL),
Andreas Huber8885e672011-03-18 14:38:56 -0700216 mBlockEntry(NULL),
217 mBlockEntryIndex(0) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700218 reset();
219}
220
221bool BlockIterator::eos() const {
222 return mCluster == NULL || mCluster->EOS();
223}
224
225void BlockIterator::advance() {
Andreas Huber8885e672011-03-18 14:38:56 -0700226 Mutex::Autolock autoLock(mExtractor->mLock);
227 advance_l();
228}
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700229
Andreas Huber8885e672011-03-18 14:38:56 -0700230void BlockIterator::advance_l() {
231 for (;;) {
232 long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry);
Steve Block71f2cf12011-10-20 11:56:00 +0100233 ALOGV("GetEntry returned %ld", res);
Andreas Huber8885e672011-03-18 14:38:56 -0700234
235 long long pos;
236 long len;
237 if (res < 0) {
238 // Need to parse this cluster some more
239
240 CHECK_EQ(res, mkvparser::E_BUFFER_NOT_FULL);
241
242 res = mCluster->Parse(pos, len);
Steve Block71f2cf12011-10-20 11:56:00 +0100243 ALOGV("Parse returned %ld", res);
Andreas Huber8885e672011-03-18 14:38:56 -0700244
245 if (res < 0) {
246 // I/O error
247
248 LOGE("Cluster::Parse returned result %ld", res);
249
250 mCluster = NULL;
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700251 break;
Andreas Huber072f5242010-05-20 14:56:53 -0700252 }
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700253
Andreas Huber8885e672011-03-18 14:38:56 -0700254 continue;
255 } else if (res == 0) {
256 // We're done with this cluster
257
258 const mkvparser::Cluster *nextCluster;
259 res = mExtractor->mSegment->ParseNext(
260 mCluster, nextCluster, pos, len);
Steve Block71f2cf12011-10-20 11:56:00 +0100261 ALOGV("ParseNext returned %ld", res);
Andreas Huber8885e672011-03-18 14:38:56 -0700262
263 if (res > 0) {
264 // EOF
265
266 mCluster = NULL;
267 break;
268 }
269
270 CHECK_EQ(res, 0);
271 CHECK(nextCluster != NULL);
272 CHECK(!nextCluster->EOS());
273
274 mCluster = nextCluster;
275
276 res = mCluster->Parse(pos, len);
Steve Block71f2cf12011-10-20 11:56:00 +0100277 ALOGV("Parse (2) returned %ld", res);
Andreas Huber8885e672011-03-18 14:38:56 -0700278 CHECK_GE(res, 0);
279
280 mBlockEntryIndex = 0;
281 continue;
Andreas Huber072f5242010-05-20 14:56:53 -0700282 }
283
Andreas Huber8885e672011-03-18 14:38:56 -0700284 CHECK(mBlockEntry != NULL);
285 CHECK(mBlockEntry->GetBlock() != NULL);
286 ++mBlockEntryIndex;
287
288 if (mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700289 break;
Andreas Huber072f5242010-05-20 14:56:53 -0700290 }
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700291 }
292}
Andreas Huber072f5242010-05-20 14:56:53 -0700293
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700294void BlockIterator::reset() {
Andreas Huber8885e672011-03-18 14:38:56 -0700295 Mutex::Autolock autoLock(mExtractor->mLock);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700296
Andreas Huber8885e672011-03-18 14:38:56 -0700297 mCluster = mExtractor->mSegment->GetFirst();
Andreas Huber21796922011-04-01 13:36:53 -0700298 mBlockEntry = NULL;
Andreas Huber8885e672011-03-18 14:38:56 -0700299 mBlockEntryIndex = 0;
300
301 do {
302 advance_l();
303 } while (!eos() && block()->GetTrackNumber() != mTrackNum);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700304}
305
Andreas Huber089d3e32011-09-07 11:05:43 -0700306void BlockIterator::seek(int64_t seekTimeUs, bool seekToKeyFrame) {
Andreas Huber8885e672011-03-18 14:38:56 -0700307 Mutex::Autolock autoLock(mExtractor->mLock);
308
309 mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
Andreas Huber21796922011-04-01 13:36:53 -0700310 mBlockEntry = NULL;
Andreas Huber8885e672011-03-18 14:38:56 -0700311 mBlockEntryIndex = 0;
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700312
Andreas Huber21796922011-04-01 13:36:53 -0700313 do {
Andreas Huber8885e672011-03-18 14:38:56 -0700314 advance_l();
Andreas Huber072f5242010-05-20 14:56:53 -0700315 }
Andreas Huber21796922011-04-01 13:36:53 -0700316 while (!eos() && block()->GetTrackNumber() != mTrackNum);
Andreas Huber072f5242010-05-20 14:56:53 -0700317
Andreas Huber089d3e32011-09-07 11:05:43 -0700318 if (seekToKeyFrame) {
319 while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
320 advance_l();
321 }
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700322 }
Andreas Huber072f5242010-05-20 14:56:53 -0700323}
324
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700325const mkvparser::Block *BlockIterator::block() const {
326 CHECK(!eos());
327
328 return mBlockEntry->GetBlock();
329}
330
331int64_t BlockIterator::blockTimeUs() const {
332 return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
333}
334
335////////////////////////////////////////////////////////////////////////////////
336
Andreas Huber0f624582010-11-15 15:10:34 -0800337static unsigned U24_AT(const uint8_t *ptr) {
338 return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
339}
340
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800341static size_t clz(uint8_t x) {
342 size_t numLeadingZeroes = 0;
343
344 while (!(x & 0x80)) {
345 ++numLeadingZeroes;
346 x = x << 1;
347 }
348
349 return numLeadingZeroes;
350}
351
352void MatroskaSource::clearPendingFrames() {
353 while (!mPendingFrames.empty()) {
354 MediaBuffer *frame = *mPendingFrames.begin();
355 mPendingFrames.erase(mPendingFrames.begin());
356
357 frame->release();
358 frame = NULL;
359 }
360}
361
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800362status_t MatroskaSource::readBlock() {
363 CHECK(mPendingFrames.empty());
364
365 if (mBlockIter.eos()) {
366 return ERROR_END_OF_STREAM;
367 }
368
369 const mkvparser::Block *block = mBlockIter.block();
370
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800371 int64_t timeUs = mBlockIter.blockTimeUs();
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800372
Andreas Huber8885e672011-03-18 14:38:56 -0700373 for (int i = 0; i < block->GetFrameCount(); ++i) {
374 const mkvparser::Block::Frame &frame = block->GetFrame(i);
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800375
Andreas Huber8885e672011-03-18 14:38:56 -0700376 MediaBuffer *mbuf = new MediaBuffer(frame.len);
377 mbuf->meta_data()->setInt64(kKeyTime, timeUs);
378 mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800379
Andreas Huber8885e672011-03-18 14:38:56 -0700380 long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data());
381 if (n != 0) {
382 mPendingFrames.clear();
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800383
Andreas Huber8885e672011-03-18 14:38:56 -0700384 mBlockIter.advance();
385 return ERROR_IO;
386 }
387
388 mPendingFrames.push_back(mbuf);
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800389 }
390
391 mBlockIter.advance();
392
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800393 return OK;
394}
395
Andreas Huber072f5242010-05-20 14:56:53 -0700396status_t MatroskaSource::read(
397 MediaBuffer **out, const ReadOptions *options) {
398 *out = NULL;
399
400 int64_t seekTimeUs;
Andreas Huber6624c9f2010-07-20 15:04:28 -0700401 ReadOptions::SeekMode mode;
Andreas Huber8885e672011-03-18 14:38:56 -0700402 if (options && options->getSeekTo(&seekTimeUs, &mode)
403 && !mExtractor->isLiveStreaming()) {
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800404 clearPendingFrames();
Andreas Huber089d3e32011-09-07 11:05:43 -0700405
406 // Apparently keyframe indication in audio tracks is unreliable,
407 // fortunately in all our currently supported audio encodings every
408 // frame is effectively a keyframe.
409 mBlockIter.seek(seekTimeUs, !mIsAudio);
Andreas Huber072f5242010-05-20 14:56:53 -0700410 }
411
Andreas Huber0f624582010-11-15 15:10:34 -0800412again:
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800413 while (mPendingFrames.empty()) {
414 status_t err = readBlock();
415
416 if (err != OK) {
417 clearPendingFrames();
418
419 return err;
420 }
Andreas Huber072f5242010-05-20 14:56:53 -0700421 }
422
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800423 MediaBuffer *frame = *mPendingFrames.begin();
424 mPendingFrames.erase(mPendingFrames.begin());
425
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800426 if (mType != AVC) {
427 *out = frame;
428
429 return OK;
430 }
431
Andreas Huber23783412011-09-28 15:06:46 -0700432 // Each input frame contains one or more NAL fragments, each fragment
433 // is prefixed by mNALSizeLen bytes giving the fragment length,
434 // followed by a corresponding number of bytes containing the fragment.
435 // We output all these fragments into a single large buffer separated
436 // by startcodes (0x00 0x00 0x00 0x01).
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800437
Andreas Huber23783412011-09-28 15:06:46 -0700438 const uint8_t *srcPtr =
439 (const uint8_t *)frame->data() + frame->range_offset();
440
441 size_t srcSize = frame->range_length();
442
443 size_t dstSize = 0;
444 MediaBuffer *buffer = NULL;
445 uint8_t *dstPtr = NULL;
446
447 for (int32_t pass = 0; pass < 2; ++pass) {
448 size_t srcOffset = 0;
449 size_t dstOffset = 0;
450 while (srcOffset + mNALSizeLen <= srcSize) {
451 size_t NALsize;
452 switch (mNALSizeLen) {
453 case 1: NALsize = srcPtr[srcOffset]; break;
454 case 2: NALsize = U16_AT(srcPtr + srcOffset); break;
455 case 3: NALsize = U24_AT(srcPtr + srcOffset); break;
456 case 4: NALsize = U32_AT(srcPtr + srcOffset); break;
457 default:
458 TRESPASS();
459 }
460
461 if (srcOffset + mNALSizeLen + NALsize > srcSize) {
462 break;
463 }
464
465 if (pass == 1) {
466 memcpy(&dstPtr[dstOffset], "\x00\x00\x00\x01", 4);
467
468 memcpy(&dstPtr[dstOffset + 4],
469 &srcPtr[srcOffset + mNALSizeLen],
470 NALsize);
471 }
472
473 dstOffset += 4; // 0x00 00 00 01
474 dstOffset += NALsize;
475
476 srcOffset += mNALSizeLen + NALsize;
477 }
478
479 if (srcOffset < srcSize) {
480 // There were trailing bytes or not enough data to complete
481 // a fragment.
482
483 frame->release();
484 frame = NULL;
485
486 return ERROR_MALFORMED;
487 }
488
489 if (pass == 0) {
490 dstSize = dstOffset;
491
492 buffer = new MediaBuffer(dstSize);
493
494 int64_t timeUs;
495 CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
496 int32_t isSync;
497 CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync));
498
499 buffer->meta_data()->setInt64(kKeyTime, timeUs);
500 buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
501
502 dstPtr = (uint8_t *)buffer->data();
503 }
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800504 }
Andreas Huber072f5242010-05-20 14:56:53 -0700505
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800506 frame->release();
507 frame = NULL;
Andreas Huber072f5242010-05-20 14:56:53 -0700508
Andreas Huber072f5242010-05-20 14:56:53 -0700509 *out = buffer;
510
Andreas Huber072f5242010-05-20 14:56:53 -0700511 return OK;
512}
513
514////////////////////////////////////////////////////////////////////////////////
515
516MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
517 : mDataSource(source),
518 mReader(new DataSourceReader(mDataSource)),
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700519 mSegment(NULL),
Andreas Huber6e37cf92011-08-22 13:21:26 -0700520 mExtractedThumbnails(false),
521 mIsWebm(false) {
Andreas Huber8885e672011-03-18 14:38:56 -0700522 off64_t size;
523 mIsLiveStreaming =
524 (mDataSource->flags()
525 & (DataSource::kWantsPrefetching
526 | DataSource::kIsCachingDataSource))
527 && mDataSource->getSize(&size) != OK;
528
Andreas Huber072f5242010-05-20 14:56:53 -0700529 mkvparser::EBMLHeader ebmlHeader;
530 long long pos;
531 if (ebmlHeader.Parse(mReader, pos) < 0) {
532 return;
533 }
534
Andreas Huber6e37cf92011-08-22 13:21:26 -0700535 if (ebmlHeader.m_docType && !strcmp("webm", ebmlHeader.m_docType)) {
536 mIsWebm = true;
537 }
538
Andreas Huber072f5242010-05-20 14:56:53 -0700539 long long ret =
540 mkvparser::Segment::CreateInstance(mReader, pos, mSegment);
541
542 if (ret) {
543 CHECK(mSegment == NULL);
544 return;
545 }
546
Andreas Huber8885e672011-03-18 14:38:56 -0700547 if (isLiveStreaming()) {
548 ret = mSegment->ParseHeaders();
549 CHECK_EQ(ret, 0);
550
551 long len;
552 ret = mSegment->LoadCluster(pos, len);
553 CHECK_EQ(ret, 0);
554 } else {
555 ret = mSegment->Load();
556 }
Andreas Huber072f5242010-05-20 14:56:53 -0700557
558 if (ret < 0) {
559 delete mSegment;
560 mSegment = NULL;
561 return;
562 }
563
Andreas Huber089d3e32011-09-07 11:05:43 -0700564#if 0
565 const mkvparser::SegmentInfo *info = mSegment->GetInfo();
Steve Block6215d3f2012-01-04 20:05:49 +0000566 ALOGI("muxing app: %s, writing app: %s",
Andreas Huber089d3e32011-09-07 11:05:43 -0700567 info->GetMuxingAppAsUTF8(),
568 info->GetWritingAppAsUTF8());
569#endif
570
Andreas Huber072f5242010-05-20 14:56:53 -0700571 addTracks();
572}
573
574MatroskaExtractor::~MatroskaExtractor() {
575 delete mSegment;
576 mSegment = NULL;
577
578 delete mReader;
579 mReader = NULL;
580}
581
582size_t MatroskaExtractor::countTracks() {
583 return mTracks.size();
584}
585
586sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
587 if (index >= mTracks.size()) {
588 return NULL;
589 }
590
591 return new MatroskaSource(this, index);
592}
593
594sp<MetaData> MatroskaExtractor::getTrackMetaData(
595 size_t index, uint32_t flags) {
596 if (index >= mTracks.size()) {
597 return NULL;
598 }
599
Andreas Huber8885e672011-03-18 14:38:56 -0700600 if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails
601 && !isLiveStreaming()) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700602 findThumbnails();
603 mExtractedThumbnails = true;
604 }
605
Andreas Huber072f5242010-05-20 14:56:53 -0700606 return mTracks.itemAt(index).mMeta;
607}
608
Andreas Huber8885e672011-03-18 14:38:56 -0700609bool MatroskaExtractor::isLiveStreaming() const {
610 return mIsLiveStreaming;
611}
612
Andreas Huber072f5242010-05-20 14:56:53 -0700613static void addESDSFromAudioSpecificInfo(
614 const sp<MetaData> &meta, const void *asi, size_t asiSize) {
615 static const uint8_t kStaticESDS[] = {
616 0x03, 22,
617 0x00, 0x00, // ES_ID
618 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
619
620 0x04, 17,
621 0x40, // Audio ISO/IEC 14496-3
622 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x00, 0x00,
624 0x00, 0x00, 0x00, 0x00,
625
626 0x05,
627 // AudioSpecificInfo (with size prefix) follows
628 };
629
Andreas Huber65b96052011-05-04 09:48:46 -0700630 // Make sure all sizes can be coded in a single byte.
631 CHECK(asiSize + 22 - 2 < 128);
Andreas Huber072f5242010-05-20 14:56:53 -0700632 size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1;
633 uint8_t *esds = new uint8_t[esdsSize];
634 memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
635 uint8_t *ptr = esds + sizeof(kStaticESDS);
636 *ptr++ = asiSize;
637 memcpy(ptr, asi, asiSize);
638
Andreas Huber65b96052011-05-04 09:48:46 -0700639 // Increment by codecPrivateSize less 2 bytes that are accounted for
640 // already in lengths of 22/17
641 esds[1] += asiSize - 2;
642 esds[6] += asiSize - 2;
643
Andreas Huber072f5242010-05-20 14:56:53 -0700644 meta->setData(kKeyESDS, 0, esds, esdsSize);
645
646 delete[] esds;
647 esds = NULL;
648}
649
650void addVorbisCodecInfo(
651 const sp<MetaData> &meta,
652 const void *_codecPrivate, size_t codecPrivateSize) {
653 // printf("vorbis private data follows:\n");
654 // hexdump(_codecPrivate, codecPrivateSize);
655
656 CHECK(codecPrivateSize >= 3);
657
658 const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate;
659 CHECK(codecPrivate[0] == 0x02);
660
661 size_t len1 = codecPrivate[1];
662 size_t len2 = codecPrivate[2];
663
664 CHECK(codecPrivateSize > 3 + len1 + len2);
665
666 CHECK(codecPrivate[3] == 0x01);
667 meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1);
668
669 CHECK(codecPrivate[len1 + 3] == 0x03);
670
671 CHECK(codecPrivate[len1 + len2 + 3] == 0x05);
672 meta->setData(
673 kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3],
674 codecPrivateSize - len1 - len2 - 3);
675}
676
677void MatroskaExtractor::addTracks() {
678 const mkvparser::Tracks *tracks = mSegment->GetTracks();
679
680 for (size_t index = 0; index < tracks->GetTracksCount(); ++index) {
681 const mkvparser::Track *track = tracks->GetTrackByIndex(index);
682
Andreas Huberdfe8d9b2011-01-24 12:46:12 -0800683 if (track == NULL) {
684 // Apparently this is currently valid (if unexpected) behaviour
685 // of the mkv parser lib.
686 continue;
687 }
688
Andreas Huber072f5242010-05-20 14:56:53 -0700689 const char *const codecID = track->GetCodecId();
Steve Block71f2cf12011-10-20 11:56:00 +0100690 ALOGV("codec id = %s", codecID);
691 ALOGV("codec name = %s", track->GetCodecNameAsUTF8());
Andreas Huber072f5242010-05-20 14:56:53 -0700692
693 size_t codecPrivateSize;
694 const unsigned char *codecPrivate =
Andreas Huber4b844452010-10-28 10:50:47 -0700695 track->GetCodecPrivate(codecPrivateSize);
Andreas Huber072f5242010-05-20 14:56:53 -0700696
697 enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
698
699 sp<MetaData> meta = new MetaData;
700
701 switch (track->GetType()) {
702 case VIDEO_TRACK:
703 {
704 const mkvparser::VideoTrack *vtrack =
705 static_cast<const mkvparser::VideoTrack *>(track);
706
707 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
708 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
709 meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
710 } else if (!strcmp("V_VP8", codecID)) {
711 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX);
712 } else {
713 continue;
714 }
715
716 meta->setInt32(kKeyWidth, vtrack->GetWidth());
717 meta->setInt32(kKeyHeight, vtrack->GetHeight());
718 break;
719 }
720
721 case AUDIO_TRACK:
722 {
723 const mkvparser::AudioTrack *atrack =
724 static_cast<const mkvparser::AudioTrack *>(track);
725
726 if (!strcmp("A_AAC", codecID)) {
727 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
728 CHECK(codecPrivateSize >= 2);
729
730 addESDSFromAudioSpecificInfo(
731 meta, codecPrivate, codecPrivateSize);
732 } else if (!strcmp("A_VORBIS", codecID)) {
733 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
734
735 addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize);
736 } else {
737 continue;
738 }
739
740 meta->setInt32(kKeySampleRate, atrack->GetSamplingRate());
741 meta->setInt32(kKeyChannelCount, atrack->GetChannels());
742 break;
743 }
744
745 default:
746 continue;
747 }
748
749 long long durationNs = mSegment->GetDuration();
750 meta->setInt64(kKeyDuration, (durationNs + 500) / 1000);
751
752 mTracks.push();
753 TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
754 trackInfo->mTrackNum = track->GetNumber();
755 trackInfo->mMeta = meta;
756 }
757}
758
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700759void MatroskaExtractor::findThumbnails() {
760 for (size_t i = 0; i < mTracks.size(); ++i) {
761 TrackInfo *info = &mTracks.editItemAt(i);
762
763 const char *mime;
764 CHECK(info->mMeta->findCString(kKeyMIMEType, &mime));
765
766 if (strncasecmp(mime, "video/", 6)) {
767 continue;
768 }
769
Andreas Huber8885e672011-03-18 14:38:56 -0700770 BlockIterator iter(this, info->mTrackNum);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700771 int32_t i = 0;
772 int64_t thumbnailTimeUs = 0;
773 size_t maxBlockSize = 0;
774 while (!iter.eos() && i < 20) {
775 if (iter.block()->IsKey()) {
776 ++i;
777
Andreas Huber8885e672011-03-18 14:38:56 -0700778 size_t blockSize = 0;
779 for (int i = 0; i < iter.block()->GetFrameCount(); ++i) {
780 blockSize += iter.block()->GetFrame(i).len;
781 }
782
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700783 if (blockSize > maxBlockSize) {
784 maxBlockSize = blockSize;
785 thumbnailTimeUs = iter.blockTimeUs();
786 }
787 }
788 iter.advance();
789 }
790 info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
791 }
792}
793
Andreas Huber072f5242010-05-20 14:56:53 -0700794sp<MetaData> MatroskaExtractor::getMetaData() {
795 sp<MetaData> meta = new MetaData;
Andreas Huber6e37cf92011-08-22 13:21:26 -0700796
797 meta->setCString(
798 kKeyMIMEType,
799 mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA);
Andreas Huber072f5242010-05-20 14:56:53 -0700800
801 return meta;
802}
803
Andreas Huber8885e672011-03-18 14:38:56 -0700804uint32_t MatroskaExtractor::flags() const {
805 uint32_t x = CAN_PAUSE;
806 if (!isLiveStreaming()) {
807 x |= CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK;
808 }
809
810 return x;
811}
812
Andreas Huber072f5242010-05-20 14:56:53 -0700813bool SniffMatroska(
Andreas Huberefdd0882010-08-25 11:09:41 -0700814 const sp<DataSource> &source, String8 *mimeType, float *confidence,
815 sp<AMessage> *) {
Andreas Huber072f5242010-05-20 14:56:53 -0700816 DataSourceReader reader(source);
817 mkvparser::EBMLHeader ebmlHeader;
818 long long pos;
819 if (ebmlHeader.Parse(&reader, pos) < 0) {
820 return false;
821 }
822
823 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA);
824 *confidence = 0.6;
825
826 return true;
827}
828
829} // namespace android