diff options
Diffstat (limited to 'media/libstagefright/matroska/MatroskaExtractor.cpp')
-rw-r--r-- | media/libstagefright/matroska/MatroskaExtractor.cpp | 898 |
1 files changed, 0 insertions, 898 deletions
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp deleted file mode 100644 index a0db719..0000000 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ /dev/null @@ -1,898 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "MatroskaExtractor" -#include <utils/Log.h> - -#include "MatroskaExtractor.h" - -#include "mkvparser.hpp" - -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/hexdump.h> -#include <media/stagefright/DataSource.h> -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MediaSource.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/Utils.h> -#include <utils/String8.h> - -namespace android { - -struct DataSourceReader : public mkvparser::IMkvReader { - DataSourceReader(const sp<DataSource> &source) - : mSource(source) { - } - - virtual int Read(long long position, long length, unsigned char* buffer) { - CHECK(position >= 0); - CHECK(length >= 0); - - if (length == 0) { - return 0; - } - - ssize_t n = mSource->readAt(position, buffer, length); - - if (n <= 0) { - return -1; - } - - return 0; - } - - virtual int Length(long long* total, long long* available) { - off64_t size; - if (mSource->getSize(&size) != OK) { - *total = -1; - *available = (long long)((1ull << 63) - 1); - - return 0; - } - - if (total) { - *total = size; - } - - if (available) { - *available = size; - } - - return 0; - } - -private: - sp<DataSource> mSource; - - DataSourceReader(const DataSourceReader &); - DataSourceReader &operator=(const DataSourceReader &); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct BlockIterator { - BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum); - - bool eos() const; - - void advance(); - void reset(); - - void seek( - int64_t seekTimeUs, bool seekToKeyFrame, - int64_t *actualFrameTimeUs); - - const mkvparser::Block *block() const; - int64_t blockTimeUs() const; - -private: - MatroskaExtractor *mExtractor; - unsigned long mTrackNum; - - const mkvparser::Cluster *mCluster; - const mkvparser::BlockEntry *mBlockEntry; - long mBlockEntryIndex; - - void advance_l(); - - BlockIterator(const BlockIterator &); - BlockIterator &operator=(const BlockIterator &); -}; - -struct MatroskaSource : public MediaSource { - MatroskaSource( - const sp<MatroskaExtractor> &extractor, size_t index); - - virtual status_t start(MetaData *params); - virtual status_t stop(); - - virtual sp<MetaData> getFormat(); - - virtual status_t read( - MediaBuffer **buffer, const ReadOptions *options); - -protected: - virtual ~MatroskaSource(); - -private: - enum Type { - AVC, - AAC, - OTHER - }; - - sp<MatroskaExtractor> mExtractor; - size_t mTrackIndex; - Type mType; - bool mIsAudio; - BlockIterator mBlockIter; - size_t mNALSizeLen; // for type AVC - - List<MediaBuffer *> mPendingFrames; - - status_t advance(); - - status_t readBlock(); - void clearPendingFrames(); - - MatroskaSource(const MatroskaSource &); - MatroskaSource &operator=(const MatroskaSource &); -}; - -MatroskaSource::MatroskaSource( - const sp<MatroskaExtractor> &extractor, size_t index) - : mExtractor(extractor), - mTrackIndex(index), - mType(OTHER), - mIsAudio(false), - mBlockIter(mExtractor.get(), - mExtractor->mTracks.itemAt(index).mTrackNum), - mNALSizeLen(0) { - sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta; - - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - mIsAudio = !strncasecmp("audio/", mime, 6); - - if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { - mType = AVC; - - uint32_t dummy; - const uint8_t *avcc; - size_t avccSize; - CHECK(meta->findData( - kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)); - - CHECK_GE(avccSize, 5u); - - mNALSizeLen = 1 + (avcc[4] & 3); - ALOGV("mNALSizeLen = %d", mNALSizeLen); - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { - mType = AAC; - } -} - -MatroskaSource::~MatroskaSource() { - clearPendingFrames(); -} - -status_t MatroskaSource::start(MetaData *params) { - mBlockIter.reset(); - - return OK; -} - -status_t MatroskaSource::stop() { - clearPendingFrames(); - - return OK; -} - -sp<MetaData> MatroskaSource::getFormat() { - return mExtractor->mTracks.itemAt(mTrackIndex).mMeta; -} - -//////////////////////////////////////////////////////////////////////////////// - -BlockIterator::BlockIterator( - MatroskaExtractor *extractor, unsigned long trackNum) - : mExtractor(extractor), - mTrackNum(trackNum), - mCluster(NULL), - mBlockEntry(NULL), - mBlockEntryIndex(0) { - reset(); -} - -bool BlockIterator::eos() const { - return mCluster == NULL || mCluster->EOS(); -} - -void BlockIterator::advance() { - Mutex::Autolock autoLock(mExtractor->mLock); - advance_l(); -} - -void BlockIterator::advance_l() { - for (;;) { - long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry); - ALOGV("GetEntry returned %ld", res); - - long long pos; - long len; - if (res < 0) { - // Need to parse this cluster some more - - CHECK_EQ(res, mkvparser::E_BUFFER_NOT_FULL); - - res = mCluster->Parse(pos, len); - ALOGV("Parse returned %ld", res); - - if (res < 0) { - // I/O error - - ALOGE("Cluster::Parse returned result %ld", res); - - mCluster = NULL; - break; - } - - continue; - } else if (res == 0) { - // We're done with this cluster - - const mkvparser::Cluster *nextCluster; - res = mExtractor->mSegment->ParseNext( - mCluster, nextCluster, pos, len); - ALOGV("ParseNext returned %ld", res); - - if (res > 0) { - // EOF - - mCluster = NULL; - break; - } - - CHECK_EQ(res, 0); - CHECK(nextCluster != NULL); - CHECK(!nextCluster->EOS()); - - mCluster = nextCluster; - - res = mCluster->Parse(pos, len); - ALOGV("Parse (2) returned %ld", res); - CHECK_GE(res, 0); - - mBlockEntryIndex = 0; - continue; - } - - CHECK(mBlockEntry != NULL); - CHECK(mBlockEntry->GetBlock() != NULL); - ++mBlockEntryIndex; - - if (mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) { - break; - } - } -} - -void BlockIterator::reset() { - Mutex::Autolock autoLock(mExtractor->mLock); - - mCluster = mExtractor->mSegment->GetFirst(); - mBlockEntry = NULL; - mBlockEntryIndex = 0; - - do { - advance_l(); - } while (!eos() && block()->GetTrackNumber() != mTrackNum); -} - -void BlockIterator::seek( - int64_t seekTimeUs, bool seekToKeyFrame, - int64_t *actualFrameTimeUs) { - Mutex::Autolock autoLock(mExtractor->mLock); - - *actualFrameTimeUs = -1ll; - - int64_t seekTimeNs = seekTimeUs * 1000ll; - - mCluster = mExtractor->mSegment->FindCluster(seekTimeNs); - mBlockEntry = NULL; - mBlockEntryIndex = 0; - - long prevKeyFrameBlockEntryIndex = -1; - - for (;;) { - advance_l(); - - if (eos()) { - break; - } - - if (block()->GetTrackNumber() != mTrackNum) { - continue; - } - - if (block()->IsKey()) { - prevKeyFrameBlockEntryIndex = mBlockEntryIndex - 1; - } - - int64_t timeNs = block()->GetTime(mCluster); - - if (timeNs >= seekTimeNs) { - *actualFrameTimeUs = (timeNs + 500ll) / 1000ll; - break; - } - } - - if (eos()) { - return; - } - - if (seekToKeyFrame && !block()->IsKey()) { - CHECK_GE(prevKeyFrameBlockEntryIndex, 0); - mBlockEntryIndex = prevKeyFrameBlockEntryIndex; - advance_l(); - } -} - -const mkvparser::Block *BlockIterator::block() const { - CHECK(!eos()); - - return mBlockEntry->GetBlock(); -} - -int64_t BlockIterator::blockTimeUs() const { - return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll; -} - -//////////////////////////////////////////////////////////////////////////////// - -static unsigned U24_AT(const uint8_t *ptr) { - return ptr[0] << 16 | ptr[1] << 8 | ptr[2]; -} - -static size_t clz(uint8_t x) { - size_t numLeadingZeroes = 0; - - while (!(x & 0x80)) { - ++numLeadingZeroes; - x = x << 1; - } - - return numLeadingZeroes; -} - -void MatroskaSource::clearPendingFrames() { - while (!mPendingFrames.empty()) { - MediaBuffer *frame = *mPendingFrames.begin(); - mPendingFrames.erase(mPendingFrames.begin()); - - frame->release(); - frame = NULL; - } -} - -status_t MatroskaSource::readBlock() { - CHECK(mPendingFrames.empty()); - - if (mBlockIter.eos()) { - return ERROR_END_OF_STREAM; - } - - const mkvparser::Block *block = mBlockIter.block(); - - int64_t timeUs = mBlockIter.blockTimeUs(); - - for (int i = 0; i < block->GetFrameCount(); ++i) { - const mkvparser::Block::Frame &frame = block->GetFrame(i); - - MediaBuffer *mbuf = new MediaBuffer(frame.len); - mbuf->meta_data()->setInt64(kKeyTime, timeUs); - mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey()); - - long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data()); - if (n != 0) { - mPendingFrames.clear(); - - mBlockIter.advance(); - return ERROR_IO; - } - - mPendingFrames.push_back(mbuf); - } - - mBlockIter.advance(); - - return OK; -} - -status_t MatroskaSource::read( - MediaBuffer **out, const ReadOptions *options) { - *out = NULL; - - int64_t targetSampleTimeUs = -1ll; - - int64_t seekTimeUs; - ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode) - && !mExtractor->isLiveStreaming()) { - clearPendingFrames(); - - // Apparently keyframe indication in audio tracks is unreliable, - // fortunately in all our currently supported audio encodings every - // frame is effectively a keyframe. - int64_t actualFrameTimeUs; - mBlockIter.seek(seekTimeUs, !mIsAudio, &actualFrameTimeUs); - - if (mode == ReadOptions::SEEK_CLOSEST) { - targetSampleTimeUs = actualFrameTimeUs; - } - } - - while (mPendingFrames.empty()) { - status_t err = readBlock(); - - if (err != OK) { - clearPendingFrames(); - - return err; - } - } - - MediaBuffer *frame = *mPendingFrames.begin(); - mPendingFrames.erase(mPendingFrames.begin()); - - if (mType != AVC) { - if (targetSampleTimeUs >= 0ll) { - frame->meta_data()->setInt64( - kKeyTargetTime, targetSampleTimeUs); - } - - *out = frame; - - return OK; - } - - // Each input frame contains one or more NAL fragments, each fragment - // is prefixed by mNALSizeLen bytes giving the fragment length, - // followed by a corresponding number of bytes containing the fragment. - // We output all these fragments into a single large buffer separated - // by startcodes (0x00 0x00 0x00 0x01). - - const uint8_t *srcPtr = - (const uint8_t *)frame->data() + frame->range_offset(); - - size_t srcSize = frame->range_length(); - - size_t dstSize = 0; - MediaBuffer *buffer = NULL; - uint8_t *dstPtr = NULL; - - for (int32_t pass = 0; pass < 2; ++pass) { - size_t srcOffset = 0; - size_t dstOffset = 0; - while (srcOffset + mNALSizeLen <= srcSize) { - size_t NALsize; - switch (mNALSizeLen) { - case 1: NALsize = srcPtr[srcOffset]; break; - case 2: NALsize = U16_AT(srcPtr + srcOffset); break; - case 3: NALsize = U24_AT(srcPtr + srcOffset); break; - case 4: NALsize = U32_AT(srcPtr + srcOffset); break; - default: - TRESPASS(); - } - - if (srcOffset + mNALSizeLen + NALsize > srcSize) { - break; - } - - if (pass == 1) { - memcpy(&dstPtr[dstOffset], "\x00\x00\x00\x01", 4); - - memcpy(&dstPtr[dstOffset + 4], - &srcPtr[srcOffset + mNALSizeLen], - NALsize); - } - - dstOffset += 4; // 0x00 00 00 01 - dstOffset += NALsize; - - srcOffset += mNALSizeLen + NALsize; - } - - if (srcOffset < srcSize) { - // There were trailing bytes or not enough data to complete - // a fragment. - - frame->release(); - frame = NULL; - - return ERROR_MALFORMED; - } - - if (pass == 0) { - dstSize = dstOffset; - - buffer = new MediaBuffer(dstSize); - - int64_t timeUs; - CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs)); - int32_t isSync; - CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)); - - buffer->meta_data()->setInt64(kKeyTime, timeUs); - buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync); - - dstPtr = (uint8_t *)buffer->data(); - } - } - - frame->release(); - frame = NULL; - - if (targetSampleTimeUs >= 0ll) { - buffer->meta_data()->setInt64( - kKeyTargetTime, targetSampleTimeUs); - } - - *out = buffer; - - return OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) - : mDataSource(source), - mReader(new DataSourceReader(mDataSource)), - mSegment(NULL), - mExtractedThumbnails(false), - mIsWebm(false) { - off64_t size; - mIsLiveStreaming = - (mDataSource->flags() - & (DataSource::kWantsPrefetching - | DataSource::kIsCachingDataSource)) - && mDataSource->getSize(&size) != OK; - - mkvparser::EBMLHeader ebmlHeader; - long long pos; - if (ebmlHeader.Parse(mReader, pos) < 0) { - return; - } - - if (ebmlHeader.m_docType && !strcmp("webm", ebmlHeader.m_docType)) { - mIsWebm = true; - } - - long long ret = - mkvparser::Segment::CreateInstance(mReader, pos, mSegment); - - if (ret) { - CHECK(mSegment == NULL); - return; - } - - if (isLiveStreaming()) { - ret = mSegment->ParseHeaders(); - CHECK_EQ(ret, 0); - - long len; - ret = mSegment->LoadCluster(pos, len); - CHECK_EQ(ret, 0); - } else { - ret = mSegment->Load(); - } - - if (ret < 0) { - delete mSegment; - mSegment = NULL; - return; - } - -#if 0 - const mkvparser::SegmentInfo *info = mSegment->GetInfo(); - ALOGI("muxing app: %s, writing app: %s", - info->GetMuxingAppAsUTF8(), - info->GetWritingAppAsUTF8()); -#endif - - addTracks(); -} - -MatroskaExtractor::~MatroskaExtractor() { - delete mSegment; - mSegment = NULL; - - delete mReader; - mReader = NULL; -} - -size_t MatroskaExtractor::countTracks() { - return mTracks.size(); -} - -sp<MediaSource> MatroskaExtractor::getTrack(size_t index) { - if (index >= mTracks.size()) { - return NULL; - } - - return new MatroskaSource(this, index); -} - -sp<MetaData> MatroskaExtractor::getTrackMetaData( - size_t index, uint32_t flags) { - if (index >= mTracks.size()) { - return NULL; - } - - if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails - && !isLiveStreaming()) { - findThumbnails(); - mExtractedThumbnails = true; - } - - return mTracks.itemAt(index).mMeta; -} - -bool MatroskaExtractor::isLiveStreaming() const { - return mIsLiveStreaming; -} - -static void addESDSFromCodecPrivate( - const sp<MetaData> &meta, - bool isAudio, const void *priv, size_t privSize) { - static const uint8_t kStaticESDS[] = { - 0x03, 22, - 0x00, 0x00, // ES_ID - 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag - - 0x04, 17, - 0x40, // ObjectTypeIndication - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - 0x05, - // CodecSpecificInfo (with size prefix) follows - }; - - // Make sure all sizes can be coded in a single byte. - CHECK(privSize + 22 - 2 < 128); - size_t esdsSize = sizeof(kStaticESDS) + privSize + 1; - uint8_t *esds = new uint8_t[esdsSize]; - memcpy(esds, kStaticESDS, sizeof(kStaticESDS)); - uint8_t *ptr = esds + sizeof(kStaticESDS); - *ptr++ = privSize; - memcpy(ptr, priv, privSize); - - // Increment by codecPrivateSize less 2 bytes that are accounted for - // already in lengths of 22/17 - esds[1] += privSize - 2; - esds[6] += privSize - 2; - - // Set ObjectTypeIndication. - esds[7] = isAudio ? 0x40 // Audio ISO/IEC 14496-3 - : 0x20; // Visual ISO/IEC 14496-2 - - meta->setData(kKeyESDS, 0, esds, esdsSize); - - delete[] esds; - esds = NULL; -} - -void addVorbisCodecInfo( - const sp<MetaData> &meta, - const void *_codecPrivate, size_t codecPrivateSize) { - // printf("vorbis private data follows:\n"); - // hexdump(_codecPrivate, codecPrivateSize); - - CHECK(codecPrivateSize >= 3); - - const uint8_t *codecPrivate = (const uint8_t *)_codecPrivate; - CHECK(codecPrivate[0] == 0x02); - - size_t len1 = codecPrivate[1]; - size_t len2 = codecPrivate[2]; - - CHECK(codecPrivateSize > 3 + len1 + len2); - - CHECK(codecPrivate[3] == 0x01); - meta->setData(kKeyVorbisInfo, 0, &codecPrivate[3], len1); - - CHECK(codecPrivate[len1 + 3] == 0x03); - - CHECK(codecPrivate[len1 + len2 + 3] == 0x05); - meta->setData( - kKeyVorbisBooks, 0, &codecPrivate[len1 + len2 + 3], - codecPrivateSize - len1 - len2 - 3); -} - -void MatroskaExtractor::addTracks() { - const mkvparser::Tracks *tracks = mSegment->GetTracks(); - - for (size_t index = 0; index < tracks->GetTracksCount(); ++index) { - const mkvparser::Track *track = tracks->GetTrackByIndex(index); - - if (track == NULL) { - // Apparently this is currently valid (if unexpected) behaviour - // of the mkv parser lib. - continue; - } - - const char *const codecID = track->GetCodecId(); - ALOGV("codec id = %s", codecID); - ALOGV("codec name = %s", track->GetCodecNameAsUTF8()); - - size_t codecPrivateSize; - const unsigned char *codecPrivate = - track->GetCodecPrivate(codecPrivateSize); - - enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 }; - - sp<MetaData> meta = new MetaData; - - switch (track->GetType()) { - case VIDEO_TRACK: - { - const mkvparser::VideoTrack *vtrack = - static_cast<const mkvparser::VideoTrack *>(track); - - if (!strcmp("V_MPEG4/ISO/AVC", codecID)) { - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); - meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize); - } else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) { - if (codecPrivateSize > 0) { - meta->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); - addESDSFromCodecPrivate( - meta, false, codecPrivate, codecPrivateSize); - } else { - ALOGW("%s is detected, but does not have configuration.", - codecID); - continue; - } - } else if (!strcmp("V_VP8", codecID)) { - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX); - } else { - ALOGW("%s is not supported.", codecID); - continue; - } - - meta->setInt32(kKeyWidth, vtrack->GetWidth()); - meta->setInt32(kKeyHeight, vtrack->GetHeight()); - break; - } - - case AUDIO_TRACK: - { - const mkvparser::AudioTrack *atrack = - static_cast<const mkvparser::AudioTrack *>(track); - - if (!strcmp("A_AAC", codecID)) { - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); - CHECK(codecPrivateSize >= 2); - - addESDSFromCodecPrivate( - meta, true, codecPrivate, codecPrivateSize); - } else if (!strcmp("A_VORBIS", codecID)) { - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); - - addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize); - } else if (!strcmp("A_MPEG/L3", codecID)) { - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); - } else { - ALOGW("%s is not supported.", codecID); - continue; - } - - meta->setInt32(kKeySampleRate, atrack->GetSamplingRate()); - meta->setInt32(kKeyChannelCount, atrack->GetChannels()); - break; - } - - default: - continue; - } - - long long durationNs = mSegment->GetDuration(); - meta->setInt64(kKeyDuration, (durationNs + 500) / 1000); - - mTracks.push(); - TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1); - trackInfo->mTrackNum = track->GetNumber(); - trackInfo->mMeta = meta; - } -} - -void MatroskaExtractor::findThumbnails() { - for (size_t i = 0; i < mTracks.size(); ++i) { - TrackInfo *info = &mTracks.editItemAt(i); - - const char *mime; - CHECK(info->mMeta->findCString(kKeyMIMEType, &mime)); - - if (strncasecmp(mime, "video/", 6)) { - continue; - } - - BlockIterator iter(this, info->mTrackNum); - int32_t i = 0; - int64_t thumbnailTimeUs = 0; - size_t maxBlockSize = 0; - while (!iter.eos() && i < 20) { - if (iter.block()->IsKey()) { - ++i; - - size_t blockSize = 0; - for (int i = 0; i < iter.block()->GetFrameCount(); ++i) { - blockSize += iter.block()->GetFrame(i).len; - } - - if (blockSize > maxBlockSize) { - maxBlockSize = blockSize; - thumbnailTimeUs = iter.blockTimeUs(); - } - } - iter.advance(); - } - info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs); - } -} - -sp<MetaData> MatroskaExtractor::getMetaData() { - sp<MetaData> meta = new MetaData; - - meta->setCString( - kKeyMIMEType, - mIsWebm ? "video/webm" : MEDIA_MIMETYPE_CONTAINER_MATROSKA); - - return meta; -} - -uint32_t MatroskaExtractor::flags() const { - uint32_t x = CAN_PAUSE; - if (!isLiveStreaming()) { - x |= CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK; - } - - return x; -} - -bool SniffMatroska( - const sp<DataSource> &source, String8 *mimeType, float *confidence, - sp<AMessage> *) { - DataSourceReader reader(source); - mkvparser::EBMLHeader ebmlHeader; - long long pos; - if (ebmlHeader.Parse(&reader, pos) < 0) { - return false; - } - - mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA); - *confidence = 0.6; - - return true; -} - -} // namespace android |