summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/matroska/MatroskaExtractor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/matroska/MatroskaExtractor.cpp')
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp898
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