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