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