MatroskaExtractor.cpp revision 10f0fe7bcd60bdb0eceb905e84ac11555e8c1b9d
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/foundation/ADebug.h>
26#include <media/stagefright/foundation/hexdump.h>
27#include <media/stagefright/DataSource.h>
28#include <media/stagefright/MediaBuffer.h>
29#include <media/stagefright/MediaDefs.h>
30#include <media/stagefright/MediaErrors.h>
31#include <media/stagefright/MediaSource.h>
32#include <media/stagefright/MetaData.h>
33#include <media/stagefright/Utils.h>
34#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) {
61        off64_t size;
62        if (mSource->getSize(&size) != OK) {
63            *total = -1;
64            *available = (long long)((1ull << 63) - 1);
65
66            return 0;
67        }
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
89struct BlockIterator {
90    BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum);
91
92    bool eos() const;
93
94    void advance();
95    void reset();
96
97    void seek(
98            int64_t seekTimeUs, bool seekToKeyFrame,
99            int64_t *actualFrameTimeUs);
100
101    const mkvparser::Block *block() const;
102    int64_t blockTimeUs() const;
103
104private:
105    MatroskaExtractor *mExtractor;
106    unsigned long mTrackNum;
107
108    const mkvparser::Cluster *mCluster;
109    const mkvparser::BlockEntry *mBlockEntry;
110    long mBlockEntryIndex;
111
112    void advance_l();
113
114    BlockIterator(const BlockIterator &);
115    BlockIterator &operator=(const BlockIterator &);
116};
117
118struct MatroskaSource : public MediaSource {
119    MatroskaSource(
120            const sp<MatroskaExtractor> &extractor, size_t index);
121
122    virtual status_t start(MetaData *params);
123    virtual status_t stop();
124
125    virtual sp<MetaData> getFormat();
126
127    virtual status_t read(
128            MediaBuffer **buffer, const ReadOptions *options);
129
130protected:
131    virtual ~MatroskaSource();
132
133private:
134    enum Type {
135        AVC,
136        AAC,
137        OTHER
138    };
139
140    sp<MatroskaExtractor> mExtractor;
141    size_t mTrackIndex;
142    Type mType;
143    bool mIsAudio;
144    BlockIterator mBlockIter;
145    size_t mNALSizeLen;  // for type AVC
146
147    List<MediaBuffer *> mPendingFrames;
148
149    status_t advance();
150
151    status_t readBlock();
152    void clearPendingFrames();
153
154    MatroskaSource(const MatroskaSource &);
155    MatroskaSource &operator=(const MatroskaSource &);
156};
157
158MatroskaSource::MatroskaSource(
159        const sp<MatroskaExtractor> &extractor, size_t index)
160    : mExtractor(extractor),
161      mTrackIndex(index),
162      mType(OTHER),
163      mIsAudio(false),
164      mBlockIter(mExtractor.get(),
165                 mExtractor->mTracks.itemAt(index).mTrackNum),
166      mNALSizeLen(0) {
167    sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
168
169    const char *mime;
170    CHECK(meta->findCString(kKeyMIMEType, &mime));
171
172    mIsAudio = !strncasecmp("audio/", mime, 6);
173
174    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
175        mType = AVC;
176
177        uint32_t dummy;
178        const uint8_t *avcc;
179        size_t avccSize;
180        CHECK(meta->findData(
181                    kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
182
183        CHECK_GE(avccSize, 5u);
184
185        mNALSizeLen = 1 + (avcc[4] & 3);
186        ALOGV("mNALSizeLen = %d", mNALSizeLen);
187    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
188        mType = AAC;
189    }
190}
191
192MatroskaSource::~MatroskaSource() {
193    clearPendingFrames();
194}
195
196status_t MatroskaSource::start(MetaData *params) {
197    mBlockIter.reset();
198
199    return OK;
200}
201
202status_t MatroskaSource::stop() {
203    clearPendingFrames();
204
205    return OK;
206}
207
208sp<MetaData> MatroskaSource::getFormat() {
209    return mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
210}
211
212////////////////////////////////////////////////////////////////////////////////
213
214BlockIterator::BlockIterator(
215        MatroskaExtractor *extractor, unsigned long trackNum)
216    : mExtractor(extractor),
217      mTrackNum(trackNum),
218      mCluster(NULL),
219      mBlockEntry(NULL),
220      mBlockEntryIndex(0) {
221    reset();
222}
223
224bool BlockIterator::eos() const {
225    return mCluster == NULL || mCluster->EOS();
226}
227
228void BlockIterator::advance() {
229    Mutex::Autolock autoLock(mExtractor->mLock);
230    advance_l();
231}
232
233void BlockIterator::advance_l() {
234    for (;;) {
235        long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry);
236        ALOGV("GetEntry returned %ld", res);
237
238        long long pos;
239        long len;
240        if (res < 0) {
241            // Need to parse this cluster some more
242
243            CHECK_EQ(res, mkvparser::E_BUFFER_NOT_FULL);
244
245            res = mCluster->Parse(pos, len);
246            ALOGV("Parse returned %ld", res);
247
248            if (res < 0) {
249                // I/O error
250
251                ALOGE("Cluster::Parse returned result %ld", res);
252
253                mCluster = NULL;
254                break;
255            }
256
257            continue;
258        } else if (res == 0) {
259            // We're done with this cluster
260
261            const mkvparser::Cluster *nextCluster;
262            res = mExtractor->mSegment->ParseNext(
263                    mCluster, nextCluster, pos, len);
264            ALOGV("ParseNext returned %ld", res);
265
266            if (res > 0) {
267                // EOF
268
269                mCluster = NULL;
270                break;
271            }
272
273            CHECK_EQ(res, 0);
274            CHECK(nextCluster != NULL);
275            CHECK(!nextCluster->EOS());
276
277            mCluster = nextCluster;
278
279            res = mCluster->Parse(pos, len);
280            ALOGV("Parse (2) returned %ld", res);
281            CHECK_GE(res, 0);
282
283            mBlockEntryIndex = 0;
284            continue;
285        }
286
287        CHECK(mBlockEntry != NULL);
288        CHECK(mBlockEntry->GetBlock() != NULL);
289        ++mBlockEntryIndex;
290
291        if (mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
292            break;
293        }
294    }
295}
296
297void BlockIterator::reset() {
298    Mutex::Autolock autoLock(mExtractor->mLock);
299
300    mCluster = mExtractor->mSegment->GetFirst();
301    mBlockEntry = NULL;
302    mBlockEntryIndex = 0;
303
304    do {
305        advance_l();
306    } while (!eos() && block()->GetTrackNumber() != mTrackNum);
307}
308
309void BlockIterator::seek(
310        int64_t seekTimeUs, bool seekToKeyFrame,
311        int64_t *actualFrameTimeUs) {
312    Mutex::Autolock autoLock(mExtractor->mLock);
313
314    *actualFrameTimeUs = -1ll;
315
316    const int64_t seekTimeNs = seekTimeUs * 1000ll;
317
318    mkvparser::Segment* const pSegment = mExtractor->mSegment;
319
320    // Special case the 0 seek to avoid loading Cues when the application
321    // extraneously seeks to 0 before playing.
322    if (seekTimeNs <= 0) {
323        ALOGV("Seek to beginning: %lld", seekTimeUs);
324        mCluster = pSegment->GetFirst();
325        mBlockEntryIndex = 0;
326        do {
327            advance_l();
328        } while (!eos() && block()->GetTrackNumber() != mTrackNum);
329        return;
330    }
331
332    ALOGV("Seeking to: %lld", seekTimeUs);
333
334    // If the Cues have not been located then find them.
335    const mkvparser::Cues* pCues = pSegment->GetCues();
336    const mkvparser::SeekHead* pSH = pSegment->GetSeekHead();
337    if (!pCues && pSH) {
338        const size_t count = pSH->GetCount();
339        const mkvparser::SeekHead::Entry* pEntry;
340        ALOGV("No Cues yet");
341
342        for (size_t index = 0; index < count; index++) {
343            pEntry = pSH->GetEntry(index);
344
345            if (pEntry->id == 0x0C53BB6B) { // Cues ID
346                long len; long long pos;
347                pSegment->ParseCues(pEntry->pos, pos, len);
348                pCues = pSegment->GetCues();
349                // Pull one cue point to fix loop below
350                ALOGV("Loading Cue points");
351                pCues->LoadCuePoint();
352                break;
353            }
354        }
355
356        if (!pCues) {
357            ALOGE("No Cues in file");
358            return;
359        }
360    }
361    else if (!pSH) {
362        ALOGE("No SeekHead");
363        return;
364    }
365
366    const mkvparser::CuePoint* pCP;
367    while (!pCues->DoneParsing()) {
368        // Make sure we don't have the necessary Cue already.
369        // If one Cue hadn't been loaded it would need to pre-emptively
370        // load one every time (until they are all loaded).
371        pCP = pCues->GetLast();
372        if (pCP->GetTime(pSegment) >= seekTimeNs) {
373            ALOGV("Located segment");
374            break;
375        }
376
377        pCues->LoadCuePoint();
378    }
379
380    // Find the video track for seeking. It doesn't make sense to search the
381    // audio track because we'd still want to make sure we're jumping to a
382    // keyframe in the video track.
383    mkvparser::Tracks const *pTracks = pSegment->GetTracks();
384    const mkvparser::Track *pTrack = NULL;
385    for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) {
386        pTrack = pTracks->GetTrackByIndex(index);
387        if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK
388            ALOGV("Video track located at %d", index);
389            break;
390        }
391    }
392
393    const mkvparser::CuePoint::TrackPosition* pTP;
394    if (pTrack) {
395        pCues->Find(seekTimeNs, pTrack, pCP, pTP);
396    } else {
397        ALOGE("Did not locate a VIDEO_TRACK");
398        return;
399    }
400
401    mCluster = pSegment->FindOrPreloadCluster(pTP->m_pos);
402    if (pTP->m_block > 0) {
403        // m_block starts at 1, but mBlockEntryIndex is expected to start at 0
404        mBlockEntryIndex = pTP->m_block - 1;
405    } else {
406        ALOGE("m_block must be > 0");
407        return;
408    }
409
410    long prevKeyFrameBlockEntryIndex = -1;
411
412    for (;;) {
413        advance_l();
414
415        if (eos()) {
416            break;
417        }
418
419        if (block()->GetTrackNumber() != mTrackNum) {
420            continue;
421        }
422
423        if (block()->IsKey()) {
424            prevKeyFrameBlockEntryIndex = mBlockEntryIndex - 1;
425        }
426
427        int64_t timeNs = block()->GetTime(mCluster);
428
429        if (timeNs >= seekTimeNs) {
430            *actualFrameTimeUs = (timeNs + 500ll) / 1000ll;
431            break;
432        }
433    }
434
435    if (eos()) {
436        return;
437    }
438
439    if (seekToKeyFrame && !block()->IsKey()) {
440        CHECK_GE(prevKeyFrameBlockEntryIndex, 0);
441        mBlockEntryIndex = prevKeyFrameBlockEntryIndex;
442        advance_l();
443    }
444}
445
446const mkvparser::Block *BlockIterator::block() const {
447    CHECK(!eos());
448
449    return mBlockEntry->GetBlock();
450}
451
452int64_t BlockIterator::blockTimeUs() const {
453    return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
454}
455
456////////////////////////////////////////////////////////////////////////////////
457
458static unsigned U24_AT(const uint8_t *ptr) {
459    return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
460}
461
462static size_t clz(uint8_t x) {
463    size_t numLeadingZeroes = 0;
464
465    while (!(x & 0x80)) {
466        ++numLeadingZeroes;
467        x = x << 1;
468    }
469
470    return numLeadingZeroes;
471}
472
473void MatroskaSource::clearPendingFrames() {
474    while (!mPendingFrames.empty()) {
475        MediaBuffer *frame = *mPendingFrames.begin();
476        mPendingFrames.erase(mPendingFrames.begin());
477
478        frame->release();
479        frame = NULL;
480    }
481}
482
483status_t MatroskaSource::readBlock() {
484    CHECK(mPendingFrames.empty());
485
486    if (mBlockIter.eos()) {
487        return ERROR_END_OF_STREAM;
488    }
489
490    const mkvparser::Block *block = mBlockIter.block();
491
492    int64_t timeUs = mBlockIter.blockTimeUs();
493
494    for (int i = 0; i < block->GetFrameCount(); ++i) {
495        const mkvparser::Block::Frame &frame = block->GetFrame(i);
496
497        MediaBuffer *mbuf = new MediaBuffer(frame.len);
498        mbuf->meta_data()->setInt64(kKeyTime, timeUs);
499        mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
500
501        long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data());
502        if (n != 0) {
503            mPendingFrames.clear();
504
505            mBlockIter.advance();
506            return ERROR_IO;
507        }
508
509        mPendingFrames.push_back(mbuf);
510    }
511
512    mBlockIter.advance();
513
514    return OK;
515}
516
517status_t MatroskaSource::read(
518        MediaBuffer **out, const ReadOptions *options) {
519    *out = NULL;
520
521    int64_t targetSampleTimeUs = -1ll;
522
523    int64_t seekTimeUs;
524    ReadOptions::SeekMode mode;
525    if (options && options->getSeekTo(&seekTimeUs, &mode)
526            && !mExtractor->isLiveStreaming()) {
527        clearPendingFrames();
528
529        // Apparently keyframe indication in audio tracks is unreliable,
530        // fortunately in all our currently supported audio encodings every
531        // frame is effectively a keyframe.
532        int64_t actualFrameTimeUs;
533        mBlockIter.seek(seekTimeUs, !mIsAudio, &actualFrameTimeUs);
534
535        if (mode == ReadOptions::SEEK_CLOSEST) {
536            targetSampleTimeUs = actualFrameTimeUs;
537        }
538    }
539
540    while (mPendingFrames.empty()) {
541        status_t err = readBlock();
542
543        if (err != OK) {
544            clearPendingFrames();
545
546            return err;
547        }
548    }
549
550    MediaBuffer *frame = *mPendingFrames.begin();
551    mPendingFrames.erase(mPendingFrames.begin());
552
553    if (mType != AVC) {
554        if (targetSampleTimeUs >= 0ll) {
555            frame->meta_data()->setInt64(
556                    kKeyTargetTime, targetSampleTimeUs);
557        }
558
559        *out = frame;
560
561        return OK;
562    }
563
564    // Each input frame contains one or more NAL fragments, each fragment
565    // is prefixed by mNALSizeLen bytes giving the fragment length,
566    // followed by a corresponding number of bytes containing the fragment.
567    // We output all these fragments into a single large buffer separated
568    // by startcodes (0x00 0x00 0x00 0x01).
569
570    const uint8_t *srcPtr =
571        (const uint8_t *)frame->data() + frame->range_offset();
572
573    size_t srcSize = frame->range_length();
574
575    size_t dstSize = 0;
576    MediaBuffer *buffer = NULL;
577    uint8_t *dstPtr = NULL;
578
579    for (int32_t pass = 0; pass < 2; ++pass) {
580        size_t srcOffset = 0;
581        size_t dstOffset = 0;
582        while (srcOffset + mNALSizeLen <= srcSize) {
583            size_t NALsize;
584            switch (mNALSizeLen) {
585                case 1: NALsize = srcPtr[srcOffset]; break;
586                case 2: NALsize = U16_AT(srcPtr + srcOffset); break;
587                case 3: NALsize = U24_AT(srcPtr + srcOffset); break;
588                case 4: NALsize = U32_AT(srcPtr + srcOffset); break;
589                default:
590                    TRESPASS();
591            }
592
593            if (srcOffset + mNALSizeLen + NALsize > srcSize) {
594                break;
595            }
596
597            if (pass == 1) {
598                memcpy(&dstPtr[dstOffset], "\x00\x00\x00\x01", 4);
599
600                memcpy(&dstPtr[dstOffset + 4],
601                       &srcPtr[srcOffset + mNALSizeLen],
602                       NALsize);
603            }
604
605            dstOffset += 4;  // 0x00 00 00 01
606            dstOffset += NALsize;
607
608            srcOffset += mNALSizeLen + NALsize;
609        }
610
611        if (srcOffset < srcSize) {
612            // There were trailing bytes or not enough data to complete
613            // a fragment.
614
615            frame->release();
616            frame = NULL;
617
618            return ERROR_MALFORMED;
619        }
620
621        if (pass == 0) {
622            dstSize = dstOffset;
623
624            buffer = new MediaBuffer(dstSize);
625
626            int64_t timeUs;
627            CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
628            int32_t isSync;
629            CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync));
630
631            buffer->meta_data()->setInt64(kKeyTime, timeUs);
632            buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
633
634            dstPtr = (uint8_t *)buffer->data();
635        }
636    }
637
638    frame->release();
639    frame = NULL;
640
641    if (targetSampleTimeUs >= 0ll) {
642        buffer->meta_data()->setInt64(
643                kKeyTargetTime, targetSampleTimeUs);
644    }
645
646    *out = buffer;
647
648    return OK;
649}
650
651////////////////////////////////////////////////////////////////////////////////
652
653MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
654    : mDataSource(source),
655      mReader(new DataSourceReader(mDataSource)),
656      mSegment(NULL),
657      mExtractedThumbnails(false),
658      mIsWebm(false) {
659    off64_t size;
660    mIsLiveStreaming =
661        (mDataSource->flags()
662            & (DataSource::kWantsPrefetching
663                | DataSource::kIsCachingDataSource))
664        && mDataSource->getSize(&size) != OK;
665
666    mkvparser::EBMLHeader ebmlHeader;
667    long long pos;
668    if (ebmlHeader.Parse(mReader, pos) < 0) {
669        return;
670    }
671
672    if (ebmlHeader.m_docType && !strcmp("webm", ebmlHeader.m_docType)) {
673        mIsWebm = true;
674    }
675
676    long long ret =
677        mkvparser::Segment::CreateInstance(mReader, pos, mSegment);
678
679    if (ret) {
680        CHECK(mSegment == NULL);
681        return;
682    }
683
684    ret = mSegment->ParseHeaders();
685    CHECK_EQ(ret, 0);
686
687    long len;
688    ret = mSegment->LoadCluster(pos, len);
689    CHECK_EQ(ret, 0);
690
691    if (ret < 0) {
692        delete mSegment;
693        mSegment = NULL;
694        return;
695    }
696
697#if 0
698    const mkvparser::SegmentInfo *info = mSegment->GetInfo();
699    ALOGI("muxing app: %s, writing app: %s",
700         info->GetMuxingAppAsUTF8(),
701         info->GetWritingAppAsUTF8());
702#endif
703
704    addTracks();
705}
706
707MatroskaExtractor::~MatroskaExtractor() {
708    delete mSegment;
709    mSegment = NULL;
710
711    delete mReader;
712    mReader = NULL;
713}
714
715size_t MatroskaExtractor::countTracks() {
716    return mTracks.size();
717}
718
719sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
720    if (index >= mTracks.size()) {
721        return NULL;
722    }
723
724    return new MatroskaSource(this, index);
725}
726
727sp<MetaData> MatroskaExtractor::getTrackMetaData(
728        size_t index, uint32_t flags) {
729    if (index >= mTracks.size()) {
730        return NULL;
731    }
732
733    if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails
734            && !isLiveStreaming()) {
735        findThumbnails();
736        mExtractedThumbnails = true;
737    }
738
739    return mTracks.itemAt(index).mMeta;
740}
741
742bool MatroskaExtractor::isLiveStreaming() const {
743    return mIsLiveStreaming;
744}
745
746static void addESDSFromCodecPrivate(
747        const sp<MetaData> &meta,
748        bool isAudio, const void *priv, size_t privSize) {
749    static const uint8_t kStaticESDS[] = {
750        0x03, 22,
751        0x00, 0x00,     // ES_ID
752        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
753
754        0x04, 17,
755        0x40,           // ObjectTypeIndication
756        0x00, 0x00, 0x00, 0x00,
757        0x00, 0x00, 0x00, 0x00,
758        0x00, 0x00, 0x00, 0x00,
759
760        0x05,
761        // CodecSpecificInfo (with size prefix) follows
762    };
763
764    // Make sure all sizes can be coded in a single byte.
765    CHECK(privSize + 22 - 2 < 128);
766    size_t esdsSize = sizeof(kStaticESDS) + privSize + 1;
767    uint8_t *esds = new uint8_t[esdsSize];
768    memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
769    uint8_t *ptr = esds + sizeof(kStaticESDS);
770    *ptr++ = privSize;
771    memcpy(ptr, priv, privSize);
772
773    // Increment by codecPrivateSize less 2 bytes that are accounted for
774    // already in lengths of 22/17
775    esds[1] += privSize - 2;
776    esds[6] += privSize - 2;
777
778    // Set ObjectTypeIndication.
779    esds[7] = isAudio ? 0x40   // Audio ISO/IEC 14496-3
780                      : 0x20;  // Visual ISO/IEC 14496-2
781
782    meta->setData(kKeyESDS, 0, esds, esdsSize);
783
784    delete[] esds;
785    esds = NULL;
786}
787
788void addVorbisCodecInfo(
789        const sp<MetaData> &meta,
790        const void *_codecPrivate, size_t codecPrivateSize) {
791    // printf("vorbis private data follows:\n");
792    // hexdump(_codecPrivate, codecPrivateSize);
793
794    CHECK(codecPrivateSize >= 3);
795
796    const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate;
797    CHECK(codecPrivate[0] == 0x02);
798
799    size_t len1 = codecPrivate[1];
800    size_t len2 = codecPrivate[2];
801
802    CHECK(codecPrivateSize > 3 + len1 + len2);
803
804    CHECK(codecPrivate[3] == 0x01);
805    meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1);
806
807    CHECK(codecPrivate[len1 + 3] == 0x03);
808
809    CHECK(codecPrivate[len1 + len2 + 3] == 0x05);
810    meta->setData(
811            kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3],
812            codecPrivateSize - len1 - len2 - 3);
813}
814
815void MatroskaExtractor::addTracks() {
816    const mkvparser::Tracks *tracks = mSegment->GetTracks();
817
818    for (size_t index = 0; index < tracks->GetTracksCount(); ++index) {
819        const mkvparser::Track *track = tracks->GetTrackByIndex(index);
820
821        if (track == NULL) {
822            // Apparently this is currently valid (if unexpected) behaviour
823            // of the mkv parser lib.
824            continue;
825        }
826
827        const char *const codecID = track->GetCodecId();
828        ALOGV("codec id = %s", codecID);
829        ALOGV("codec name = %s", track->GetCodecNameAsUTF8());
830
831        size_t codecPrivateSize;
832        const unsigned char *codecPrivate =
833            track->GetCodecPrivate(codecPrivateSize);
834
835        enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
836
837        sp<MetaData> meta = new MetaData;
838
839        switch (track->GetType()) {
840            case VIDEO_TRACK:
841            {
842                const mkvparser::VideoTrack *vtrack =
843                    static_cast<const mkvparser::VideoTrack *>(track);
844
845                if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
846                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
847                    meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
848                } else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
849                    if (codecPrivateSize > 0) {
850                        meta->setCString(
851                                kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
852                        addESDSFromCodecPrivate(
853                                meta, false, codecPrivate, codecPrivateSize);
854                    } else {
855                        ALOGW("%s is detected, but does not have configuration.",
856                                codecID);
857                        continue;
858                    }
859                } else if (!strcmp("V_VP8", codecID)) {
860                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX);
861                } else {
862                    ALOGW("%s is not supported.", codecID);
863                    continue;
864                }
865
866                meta->setInt32(kKeyWidth, vtrack->GetWidth());
867                meta->setInt32(kKeyHeight, vtrack->GetHeight());
868                break;
869            }
870
871            case AUDIO_TRACK:
872            {
873                const mkvparser::AudioTrack *atrack =
874                    static_cast<const mkvparser::AudioTrack *>(track);
875
876                if (!strcmp("A_AAC", codecID)) {
877                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
878                    CHECK(codecPrivateSize >= 2);
879
880                    addESDSFromCodecPrivate(
881                            meta, true, codecPrivate, codecPrivateSize);
882                } else if (!strcmp("A_VORBIS", codecID)) {
883                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
884
885                    addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize);
886                } else if (!strcmp("A_MPEG/L3", codecID)) {
887                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
888                } else {
889                    ALOGW("%s is not supported.", codecID);
890                    continue;
891                }
892
893                meta->setInt32(kKeySampleRate, atrack->GetSamplingRate());
894                meta->setInt32(kKeyChannelCount, atrack->GetChannels());
895                break;
896            }
897
898            default:
899                continue;
900        }
901
902        long long durationNs = mSegment->GetDuration();
903        meta->setInt64(kKeyDuration, (durationNs + 500) / 1000);
904
905        mTracks.push();
906        TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
907        trackInfo->mTrackNum = track->GetNumber();
908        trackInfo->mMeta = meta;
909    }
910}
911
912void MatroskaExtractor::findThumbnails() {
913    for (size_t i = 0; i < mTracks.size(); ++i) {
914        TrackInfo *info = &mTracks.editItemAt(i);
915
916        const char *mime;
917        CHECK(info->mMeta->findCString(kKeyMIMEType, &mime));
918
919        if (strncasecmp(mime, "video/", 6)) {
920            continue;
921        }
922
923        BlockIterator iter(this, info->mTrackNum);
924        int32_t i = 0;
925        int64_t thumbnailTimeUs = 0;
926        size_t maxBlockSize = 0;
927        while (!iter.eos() && i < 20) {
928            if (iter.block()->IsKey()) {
929                ++i;
930
931                size_t blockSize = 0;
932                for (int i = 0; i < iter.block()->GetFrameCount(); ++i) {
933                    blockSize += iter.block()->GetFrame(i).len;
934                }
935
936                if (blockSize > maxBlockSize) {
937                    maxBlockSize = blockSize;
938                    thumbnailTimeUs = iter.blockTimeUs();
939                }
940            }
941            iter.advance();
942        }
943        info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
944    }
945}
946
947sp<MetaData> MatroskaExtractor::getMetaData() {
948    sp<MetaData> meta = new MetaData;
949
950    meta->setCString(
951            kKeyMIMEType,
952            mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA);
953
954    return meta;
955}
956
957uint32_t MatroskaExtractor::flags() const {
958    uint32_t x = CAN_PAUSE;
959    if (!isLiveStreaming()) {
960        x |= CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK;
961    }
962
963    return x;
964}
965
966bool SniffMatroska(
967        const sp<DataSource> &source, String8 *mimeType, float *confidence,
968        sp<AMessage> *) {
969    DataSourceReader reader(source);
970    mkvparser::EBMLHeader ebmlHeader;
971    long long pos;
972    if (ebmlHeader.Parse(&reader, pos) < 0) {
973        return false;
974    }
975
976    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA);
977    *confidence = 0.6;
978
979    return true;
980}
981
982}  // namespace android
983