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