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