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