blob: e1b9991983a510eea29f41298452ab03df5af47c [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();
96 void seek(int64_t seekTimeUs);
97
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 Huber6bdf2ed2010-05-25 13:35:02 -0700140 BlockIterator mBlockIter;
Andreas Huber0f624582010-11-15 15:10:34 -0800141 size_t mNALSizeLen; // for type AVC
Andreas Huber072f5242010-05-20 14:56:53 -0700142
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800143 List<MediaBuffer *> mPendingFrames;
144
Andreas Huber072f5242010-05-20 14:56:53 -0700145 status_t advance();
146
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800147 status_t readBlock();
148 void clearPendingFrames();
149
Andreas Huber072f5242010-05-20 14:56:53 -0700150 MatroskaSource(const MatroskaSource &);
151 MatroskaSource &operator=(const MatroskaSource &);
152};
153
154MatroskaSource::MatroskaSource(
155 const sp<MatroskaExtractor> &extractor, size_t index)
156 : mExtractor(extractor),
157 mTrackIndex(index),
158 mType(OTHER),
Andreas Huber8885e672011-03-18 14:38:56 -0700159 mBlockIter(mExtractor.get(),
Andreas Huber0f624582010-11-15 15:10:34 -0800160 mExtractor->mTracks.itemAt(index).mTrackNum),
161 mNALSizeLen(0) {
162 sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
163
Andreas Huber072f5242010-05-20 14:56:53 -0700164 const char *mime;
Andreas Huber0f624582010-11-15 15:10:34 -0800165 CHECK(meta->findCString(kKeyMIMEType, &mime));
Andreas Huber072f5242010-05-20 14:56:53 -0700166
167 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
168 mType = AVC;
Andreas Huber0f624582010-11-15 15:10:34 -0800169
170 uint32_t dummy;
171 const uint8_t *avcc;
172 size_t avccSize;
173 CHECK(meta->findData(
174 kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
175
176 CHECK_GE(avccSize, 5u);
177
178 mNALSizeLen = 1 + (avcc[4] & 3);
179 LOGV("mNALSizeLen = %d", mNALSizeLen);
Andreas Huber072f5242010-05-20 14:56:53 -0700180 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
181 mType = AAC;
182 }
183}
184
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800185MatroskaSource::~MatroskaSource() {
186 clearPendingFrames();
187}
188
Andreas Huber072f5242010-05-20 14:56:53 -0700189status_t MatroskaSource::start(MetaData *params) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700190 mBlockIter.reset();
Andreas Huber072f5242010-05-20 14:56:53 -0700191
192 return OK;
193}
194
195status_t MatroskaSource::stop() {
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800196 clearPendingFrames();
197
Andreas Huber072f5242010-05-20 14:56:53 -0700198 return OK;
199}
200
201sp<MetaData> MatroskaSource::getFormat() {
202 return mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
203}
204
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700205////////////////////////////////////////////////////////////////////////////////
206
207BlockIterator::BlockIterator(
Andreas Huber8885e672011-03-18 14:38:56 -0700208 MatroskaExtractor *extractor, unsigned long trackNum)
209 : mExtractor(extractor),
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700210 mTrackNum(trackNum),
211 mCluster(NULL),
Andreas Huber8885e672011-03-18 14:38:56 -0700212 mBlockEntry(NULL),
213 mBlockEntryIndex(0) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700214 reset();
215}
216
217bool BlockIterator::eos() const {
218 return mCluster == NULL || mCluster->EOS();
219}
220
221void BlockIterator::advance() {
Andreas Huber8885e672011-03-18 14:38:56 -0700222 Mutex::Autolock autoLock(mExtractor->mLock);
223 advance_l();
224}
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700225
Andreas Huber8885e672011-03-18 14:38:56 -0700226void BlockIterator::advance_l() {
227 for (;;) {
228 long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry);
229 LOGV("GetEntry returned %ld", res);
230
231 long long pos;
232 long len;
233 if (res < 0) {
234 // Need to parse this cluster some more
235
236 CHECK_EQ(res, mkvparser::E_BUFFER_NOT_FULL);
237
238 res = mCluster->Parse(pos, len);
239 LOGV("Parse returned %ld", res);
240
241 if (res < 0) {
242 // I/O error
243
244 LOGE("Cluster::Parse returned result %ld", res);
245
246 mCluster = NULL;
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700247 break;
Andreas Huber072f5242010-05-20 14:56:53 -0700248 }
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700249
Andreas Huber8885e672011-03-18 14:38:56 -0700250 continue;
251 } else if (res == 0) {
252 // We're done with this cluster
253
254 const mkvparser::Cluster *nextCluster;
255 res = mExtractor->mSegment->ParseNext(
256 mCluster, nextCluster, pos, len);
257 LOGV("ParseNext returned %ld", res);
258
259 if (res > 0) {
260 // EOF
261
262 mCluster = NULL;
263 break;
264 }
265
266 CHECK_EQ(res, 0);
267 CHECK(nextCluster != NULL);
268 CHECK(!nextCluster->EOS());
269
270 mCluster = nextCluster;
271
272 res = mCluster->Parse(pos, len);
273 LOGV("Parse (2) returned %ld", res);
274 CHECK_GE(res, 0);
275
276 mBlockEntryIndex = 0;
277 continue;
Andreas Huber072f5242010-05-20 14:56:53 -0700278 }
279
Andreas Huber8885e672011-03-18 14:38:56 -0700280 CHECK(mBlockEntry != NULL);
281 CHECK(mBlockEntry->GetBlock() != NULL);
282 ++mBlockEntryIndex;
283
284 if (mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700285 break;
Andreas Huber072f5242010-05-20 14:56:53 -0700286 }
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700287 }
288}
Andreas Huber072f5242010-05-20 14:56:53 -0700289
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700290void BlockIterator::reset() {
Andreas Huber8885e672011-03-18 14:38:56 -0700291 Mutex::Autolock autoLock(mExtractor->mLock);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700292
Andreas Huber8885e672011-03-18 14:38:56 -0700293 mCluster = mExtractor->mSegment->GetFirst();
Andreas Huber21796922011-04-01 13:36:53 -0700294 mBlockEntry = NULL;
Andreas Huber8885e672011-03-18 14:38:56 -0700295 mBlockEntryIndex = 0;
296
297 do {
298 advance_l();
299 } while (!eos() && block()->GetTrackNumber() != mTrackNum);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700300}
301
302void BlockIterator::seek(int64_t seekTimeUs) {
Andreas Huber8885e672011-03-18 14:38:56 -0700303 Mutex::Autolock autoLock(mExtractor->mLock);
304
305 mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
Andreas Huber21796922011-04-01 13:36:53 -0700306 mBlockEntry = NULL;
Andreas Huber8885e672011-03-18 14:38:56 -0700307 mBlockEntryIndex = 0;
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700308
Andreas Huber21796922011-04-01 13:36:53 -0700309 do {
Andreas Huber8885e672011-03-18 14:38:56 -0700310 advance_l();
Andreas Huber072f5242010-05-20 14:56:53 -0700311 }
Andreas Huber21796922011-04-01 13:36:53 -0700312 while (!eos() && block()->GetTrackNumber() != mTrackNum);
Andreas Huber072f5242010-05-20 14:56:53 -0700313
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700314 while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
Andreas Huber8885e672011-03-18 14:38:56 -0700315 advance_l();
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700316 }
Andreas Huber072f5242010-05-20 14:56:53 -0700317}
318
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700319const mkvparser::Block *BlockIterator::block() const {
320 CHECK(!eos());
321
322 return mBlockEntry->GetBlock();
323}
324
325int64_t BlockIterator::blockTimeUs() const {
326 return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
327}
328
329////////////////////////////////////////////////////////////////////////////////
330
Andreas Huber0f624582010-11-15 15:10:34 -0800331static unsigned U24_AT(const uint8_t *ptr) {
332 return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
333}
334
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800335static size_t clz(uint8_t x) {
336 size_t numLeadingZeroes = 0;
337
338 while (!(x & 0x80)) {
339 ++numLeadingZeroes;
340 x = x << 1;
341 }
342
343 return numLeadingZeroes;
344}
345
346void MatroskaSource::clearPendingFrames() {
347 while (!mPendingFrames.empty()) {
348 MediaBuffer *frame = *mPendingFrames.begin();
349 mPendingFrames.erase(mPendingFrames.begin());
350
351 frame->release();
352 frame = NULL;
353 }
354}
355
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800356status_t MatroskaSource::readBlock() {
357 CHECK(mPendingFrames.empty());
358
359 if (mBlockIter.eos()) {
360 return ERROR_END_OF_STREAM;
361 }
362
363 const mkvparser::Block *block = mBlockIter.block();
364
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800365 int64_t timeUs = mBlockIter.blockTimeUs();
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800366
Andreas Huber8885e672011-03-18 14:38:56 -0700367 for (int i = 0; i < block->GetFrameCount(); ++i) {
368 const mkvparser::Block::Frame &frame = block->GetFrame(i);
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800369
Andreas Huber8885e672011-03-18 14:38:56 -0700370 MediaBuffer *mbuf = new MediaBuffer(frame.len);
371 mbuf->meta_data()->setInt64(kKeyTime, timeUs);
372 mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800373
Andreas Huber8885e672011-03-18 14:38:56 -0700374 long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data());
375 if (n != 0) {
376 mPendingFrames.clear();
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800377
Andreas Huber8885e672011-03-18 14:38:56 -0700378 mBlockIter.advance();
379 return ERROR_IO;
380 }
381
382 mPendingFrames.push_back(mbuf);
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800383 }
384
385 mBlockIter.advance();
386
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800387 return OK;
388}
389
Andreas Huber072f5242010-05-20 14:56:53 -0700390status_t MatroskaSource::read(
391 MediaBuffer **out, const ReadOptions *options) {
392 *out = NULL;
393
394 int64_t seekTimeUs;
Andreas Huber6624c9f2010-07-20 15:04:28 -0700395 ReadOptions::SeekMode mode;
Andreas Huber8885e672011-03-18 14:38:56 -0700396 if (options && options->getSeekTo(&seekTimeUs, &mode)
397 && !mExtractor->isLiveStreaming()) {
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800398 clearPendingFrames();
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700399 mBlockIter.seek(seekTimeUs);
Andreas Huber072f5242010-05-20 14:56:53 -0700400 }
401
Andreas Huber0f624582010-11-15 15:10:34 -0800402again:
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800403 while (mPendingFrames.empty()) {
404 status_t err = readBlock();
405
406 if (err != OK) {
407 clearPendingFrames();
408
409 return err;
410 }
Andreas Huber072f5242010-05-20 14:56:53 -0700411 }
412
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800413 MediaBuffer *frame = *mPendingFrames.begin();
414 mPendingFrames.erase(mPendingFrames.begin());
415
416 size_t size = frame->range_length();
417
418 if (mType != AVC) {
419 *out = frame;
420
421 return OK;
422 }
423
424 if (size < mNALSizeLen) {
425 frame->release();
426 frame = NULL;
427
428 return ERROR_MALFORMED;
429 }
Andreas Huber072f5242010-05-20 14:56:53 -0700430
Andreas Huber0f624582010-11-15 15:10:34 -0800431 // In the case of AVC content, each NAL unit is prefixed by
432 // mNALSizeLen bytes of length. We want to prefix the data with
433 // a four-byte 0x00000001 startcode instead of the length prefix.
434 // mNALSizeLen ranges from 1 through 4 bytes, so add an extra
435 // 3 bytes of padding to the buffer start.
436 static const size_t kPadding = 3;
437
438 MediaBuffer *buffer = new MediaBuffer(size + kPadding);
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800439
440 int64_t timeUs;
441 CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
442 int32_t isSync;
443 CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync));
444
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700445 buffer->meta_data()->setInt64(kKeyTime, timeUs);
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800446 buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
Andreas Huber072f5242010-05-20 14:56:53 -0700447
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800448 memcpy((uint8_t *)buffer->data() + kPadding,
449 (const uint8_t *)frame->data() + frame->range_offset(),
450 size);
Andreas Huber072f5242010-05-20 14:56:53 -0700451
Andreas Huber0f624582010-11-15 15:10:34 -0800452 buffer->set_range(kPadding, size);
Andreas Huber072f5242010-05-20 14:56:53 -0700453
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800454 frame->release();
455 frame = NULL;
Andreas Huber072f5242010-05-20 14:56:53 -0700456
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800457 uint8_t *data = (uint8_t *)buffer->data();
Andreas Huber072f5242010-05-20 14:56:53 -0700458
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800459 size_t NALsize;
460 switch (mNALSizeLen) {
461 case 1: NALsize = data[kPadding]; break;
462 case 2: NALsize = U16_AT(&data[kPadding]); break;
463 case 3: NALsize = U24_AT(&data[kPadding]); break;
464 case 4: NALsize = U32_AT(&data[kPadding]); break;
465 default:
466 TRESPASS();
Andreas Huber072f5242010-05-20 14:56:53 -0700467 }
468
Andreas Huber6fe6b4c2011-01-11 11:56:06 -0800469 if (size < NALsize + mNALSizeLen) {
470 buffer->release();
471 buffer = NULL;
472
473 return ERROR_MALFORMED;
474 }
475
476 if (size > NALsize + mNALSizeLen) {
477 LOGW("discarding %d bytes of data.", size - NALsize - mNALSizeLen);
478 }
479
480 // actual data starts at &data[kPadding + mNALSizeLen]
481
482 memcpy(&data[mNALSizeLen - 1], "\x00\x00\x00\x01", 4);
483 buffer->set_range(mNALSizeLen - 1, NALsize + 4);
484
Andreas Huber072f5242010-05-20 14:56:53 -0700485 *out = buffer;
486
Andreas Huber072f5242010-05-20 14:56:53 -0700487 return OK;
488}
489
490////////////////////////////////////////////////////////////////////////////////
491
492MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
493 : mDataSource(source),
494 mReader(new DataSourceReader(mDataSource)),
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700495 mSegment(NULL),
496 mExtractedThumbnails(false) {
Andreas Huber8885e672011-03-18 14:38:56 -0700497 off64_t size;
498 mIsLiveStreaming =
499 (mDataSource->flags()
500 & (DataSource::kWantsPrefetching
501 | DataSource::kIsCachingDataSource))
502 && mDataSource->getSize(&size) != OK;
503
Andreas Huber072f5242010-05-20 14:56:53 -0700504 mkvparser::EBMLHeader ebmlHeader;
505 long long pos;
506 if (ebmlHeader.Parse(mReader, pos) < 0) {
507 return;
508 }
509
510 long long ret =
511 mkvparser::Segment::CreateInstance(mReader, pos, mSegment);
512
513 if (ret) {
514 CHECK(mSegment == NULL);
515 return;
516 }
517
Andreas Huber8885e672011-03-18 14:38:56 -0700518 if (isLiveStreaming()) {
519 ret = mSegment->ParseHeaders();
520 CHECK_EQ(ret, 0);
521
522 long len;
523 ret = mSegment->LoadCluster(pos, len);
524 CHECK_EQ(ret, 0);
525 } else {
526 ret = mSegment->Load();
527 }
Andreas Huber072f5242010-05-20 14:56:53 -0700528
529 if (ret < 0) {
530 delete mSegment;
531 mSegment = NULL;
532 return;
533 }
534
535 addTracks();
536}
537
538MatroskaExtractor::~MatroskaExtractor() {
539 delete mSegment;
540 mSegment = NULL;
541
542 delete mReader;
543 mReader = NULL;
544}
545
546size_t MatroskaExtractor::countTracks() {
547 return mTracks.size();
548}
549
550sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
551 if (index >= mTracks.size()) {
552 return NULL;
553 }
554
555 return new MatroskaSource(this, index);
556}
557
558sp<MetaData> MatroskaExtractor::getTrackMetaData(
559 size_t index, uint32_t flags) {
560 if (index >= mTracks.size()) {
561 return NULL;
562 }
563
Andreas Huber8885e672011-03-18 14:38:56 -0700564 if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails
565 && !isLiveStreaming()) {
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700566 findThumbnails();
567 mExtractedThumbnails = true;
568 }
569
Andreas Huber072f5242010-05-20 14:56:53 -0700570 return mTracks.itemAt(index).mMeta;
571}
572
Andreas Huber8885e672011-03-18 14:38:56 -0700573bool MatroskaExtractor::isLiveStreaming() const {
574 return mIsLiveStreaming;
575}
576
Andreas Huber072f5242010-05-20 14:56:53 -0700577static void addESDSFromAudioSpecificInfo(
578 const sp<MetaData> &meta, const void *asi, size_t asiSize) {
579 static const uint8_t kStaticESDS[] = {
580 0x03, 22,
581 0x00, 0x00, // ES_ID
582 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
583
584 0x04, 17,
585 0x40, // Audio ISO/IEC 14496-3
586 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x00, 0x00, 0x00,
589
590 0x05,
591 // AudioSpecificInfo (with size prefix) follows
592 };
593
Andreas Huber65b96052011-05-04 09:48:46 -0700594 // Make sure all sizes can be coded in a single byte.
595 CHECK(asiSize + 22 - 2 < 128);
Andreas Huber072f5242010-05-20 14:56:53 -0700596 size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1;
597 uint8_t *esds = new uint8_t[esdsSize];
598 memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
599 uint8_t *ptr = esds + sizeof(kStaticESDS);
600 *ptr++ = asiSize;
601 memcpy(ptr, asi, asiSize);
602
Andreas Huber65b96052011-05-04 09:48:46 -0700603 // Increment by codecPrivateSize less 2 bytes that are accounted for
604 // already in lengths of 22/17
605 esds[1] += asiSize - 2;
606 esds[6] += asiSize - 2;
607
Andreas Huber072f5242010-05-20 14:56:53 -0700608 meta->setData(kKeyESDS, 0, esds, esdsSize);
609
610 delete[] esds;
611 esds = NULL;
612}
613
614void addVorbisCodecInfo(
615 const sp<MetaData> &meta,
616 const void *_codecPrivate, size_t codecPrivateSize) {
617 // printf("vorbis private data follows:\n");
618 // hexdump(_codecPrivate, codecPrivateSize);
619
620 CHECK(codecPrivateSize >= 3);
621
622 const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate;
623 CHECK(codecPrivate[0] == 0x02);
624
625 size_t len1 = codecPrivate[1];
626 size_t len2 = codecPrivate[2];
627
628 CHECK(codecPrivateSize > 3 + len1 + len2);
629
630 CHECK(codecPrivate[3] == 0x01);
631 meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1);
632
633 CHECK(codecPrivate[len1 + 3] == 0x03);
634
635 CHECK(codecPrivate[len1 + len2 + 3] == 0x05);
636 meta->setData(
637 kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3],
638 codecPrivateSize - len1 - len2 - 3);
639}
640
641void MatroskaExtractor::addTracks() {
642 const mkvparser::Tracks *tracks = mSegment->GetTracks();
643
644 for (size_t index = 0; index < tracks->GetTracksCount(); ++index) {
645 const mkvparser::Track *track = tracks->GetTrackByIndex(index);
646
Andreas Huberdfe8d9b2011-01-24 12:46:12 -0800647 if (track == NULL) {
648 // Apparently this is currently valid (if unexpected) behaviour
649 // of the mkv parser lib.
650 continue;
651 }
652
Andreas Huber072f5242010-05-20 14:56:53 -0700653 const char *const codecID = track->GetCodecId();
654 LOGV("codec id = %s", codecID);
655 LOGV("codec name = %s", track->GetCodecNameAsUTF8());
656
657 size_t codecPrivateSize;
658 const unsigned char *codecPrivate =
Andreas Huber4b844452010-10-28 10:50:47 -0700659 track->GetCodecPrivate(codecPrivateSize);
Andreas Huber072f5242010-05-20 14:56:53 -0700660
661 enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
662
663 sp<MetaData> meta = new MetaData;
664
665 switch (track->GetType()) {
666 case VIDEO_TRACK:
667 {
668 const mkvparser::VideoTrack *vtrack =
669 static_cast<const mkvparser::VideoTrack *>(track);
670
671 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
672 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
673 meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
674 } else if (!strcmp("V_VP8", codecID)) {
675 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX);
676 } else {
677 continue;
678 }
679
680 meta->setInt32(kKeyWidth, vtrack->GetWidth());
681 meta->setInt32(kKeyHeight, vtrack->GetHeight());
682 break;
683 }
684
685 case AUDIO_TRACK:
686 {
687 const mkvparser::AudioTrack *atrack =
688 static_cast<const mkvparser::AudioTrack *>(track);
689
690 if (!strcmp("A_AAC", codecID)) {
691 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
692 CHECK(codecPrivateSize >= 2);
693
694 addESDSFromAudioSpecificInfo(
695 meta, codecPrivate, codecPrivateSize);
696 } else if (!strcmp("A_VORBIS", codecID)) {
697 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
698
699 addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize);
700 } else {
701 continue;
702 }
703
704 meta->setInt32(kKeySampleRate, atrack->GetSamplingRate());
705 meta->setInt32(kKeyChannelCount, atrack->GetChannels());
706 break;
707 }
708
709 default:
710 continue;
711 }
712
713 long long durationNs = mSegment->GetDuration();
714 meta->setInt64(kKeyDuration, (durationNs + 500) / 1000);
715
716 mTracks.push();
717 TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
718 trackInfo->mTrackNum = track->GetNumber();
719 trackInfo->mMeta = meta;
720 }
721}
722
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700723void MatroskaExtractor::findThumbnails() {
724 for (size_t i = 0; i < mTracks.size(); ++i) {
725 TrackInfo *info = &mTracks.editItemAt(i);
726
727 const char *mime;
728 CHECK(info->mMeta->findCString(kKeyMIMEType, &mime));
729
730 if (strncasecmp(mime, "video/", 6)) {
731 continue;
732 }
733
Andreas Huber8885e672011-03-18 14:38:56 -0700734 BlockIterator iter(this, info->mTrackNum);
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700735 int32_t i = 0;
736 int64_t thumbnailTimeUs = 0;
737 size_t maxBlockSize = 0;
738 while (!iter.eos() && i < 20) {
739 if (iter.block()->IsKey()) {
740 ++i;
741
Andreas Huber8885e672011-03-18 14:38:56 -0700742 size_t blockSize = 0;
743 for (int i = 0; i < iter.block()->GetFrameCount(); ++i) {
744 blockSize += iter.block()->GetFrame(i).len;
745 }
746
Andreas Huber6bdf2ed2010-05-25 13:35:02 -0700747 if (blockSize > maxBlockSize) {
748 maxBlockSize = blockSize;
749 thumbnailTimeUs = iter.blockTimeUs();
750 }
751 }
752 iter.advance();
753 }
754 info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
755 }
756}
757
Andreas Huber072f5242010-05-20 14:56:53 -0700758sp<MetaData> MatroskaExtractor::getMetaData() {
759 sp<MetaData> meta = new MetaData;
760 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA);
761
762 return meta;
763}
764
Andreas Huber8885e672011-03-18 14:38:56 -0700765uint32_t MatroskaExtractor::flags() const {
766 uint32_t x = CAN_PAUSE;
767 if (!isLiveStreaming()) {
768 x |= CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK;
769 }
770
771 return x;
772}
773
Andreas Huber072f5242010-05-20 14:56:53 -0700774bool SniffMatroska(
Andreas Huberefdd0882010-08-25 11:09:41 -0700775 const sp<DataSource> &source, String8 *mimeType, float *confidence,
776 sp<AMessage> *) {
Andreas Huber072f5242010-05-20 14:56:53 -0700777 DataSourceReader reader(source);
778 mkvparser::EBMLHeader ebmlHeader;
779 long long pos;
780 if (ebmlHeader.Parse(&reader, pos) < 0) {
781 return false;
782 }
783
784 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA);
785 *confidence = 0.6;
786
787 return true;
788}
789
790} // namespace android