diff options
author | Andreas Huber <andih@google.com> | 2011-03-18 14:38:56 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2011-03-18 15:11:52 -0700 |
commit | d42573cace9db2b5948e540c32beaef80f04153c (patch) | |
tree | 50702825c0cdf513c41c3ffaaae151fce4eb0aa2 /media/libstagefright/matroska | |
parent | cfee2a39edf05ab0f97595d0ec5bda6a19f03659 (diff) | |
download | frameworks_av-d42573cace9db2b5948e540c32beaef80f04153c.zip frameworks_av-d42573cace9db2b5948e540c32beaef80f04153c.tar.gz frameworks_av-d42573cace9db2b5948e540c32beaef80f04153c.tar.bz2 |
Squashed commit of the following:
commit ed615e2803839ef28e0eab50d17844c207083ad6
Author: Andreas Huber <andih@google.com>
Date: Fri Mar 18 12:38:30 2011 -0700
Support for live streaming of webm content over http.
Change-Id: Ie9ebd23d2c44d192d348b9fa3f3a0f3f28ac9e4c
commit 9c50b1392471a3d652b4a875c823bee854f8855b
Author: Andreas Huber <andih@google.com>
Date: Thu Mar 17 13:33:22 2011 -0700
Upgrade to the latest version of libwebm.
Change-Id: Ic7965dda84131a38f9d3c72b6acd2025ace939ce
Change-Id: I3c993a89f749f05741594ef0ea47864e17ee783b
Diffstat (limited to 'media/libstagefright/matroska')
-rw-r--r-- | media/libstagefright/matroska/MatroskaExtractor.cpp | 331 | ||||
-rw-r--r-- | media/libstagefright/matroska/MatroskaExtractor.h | 9 |
2 files changed, 145 insertions, 195 deletions
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index 733de92..b3e29b9 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -60,7 +60,10 @@ struct DataSourceReader : public mkvparser::IMkvReader { virtual int Length(long long* total, long long* available) { off64_t size; if (mSource->getSize(&size) != OK) { - return -1; + *total = -1; + *available = (long long)((1ull << 63) - 1); + + return 0; } if (total) { @@ -84,7 +87,7 @@ private: //////////////////////////////////////////////////////////////////////////////// struct BlockIterator { - BlockIterator(mkvparser::Segment *segment, unsigned long trackNum); + BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum); bool eos() const; @@ -96,11 +99,14 @@ struct BlockIterator { int64_t blockTimeUs() const; private: - mkvparser::Segment *mSegment; + MatroskaExtractor *mExtractor; unsigned long mTrackNum; - mkvparser::Cluster *mCluster; + const mkvparser::Cluster *mCluster; const mkvparser::BlockEntry *mBlockEntry; + long mBlockEntryIndex; + + void advance_l(); BlockIterator(const BlockIterator &); BlockIterator &operator=(const BlockIterator &); @@ -150,7 +156,7 @@ MatroskaSource::MatroskaSource( : mExtractor(extractor), mTrackIndex(index), mType(OTHER), - mBlockIter(mExtractor->mSegment, + mBlockIter(mExtractor.get(), mExtractor->mTracks.itemAt(index).mTrackNum), mNALSizeLen(0) { sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta; @@ -199,11 +205,12 @@ sp<MetaData> MatroskaSource::getFormat() { //////////////////////////////////////////////////////////////////////////////// BlockIterator::BlockIterator( - mkvparser::Segment *segment, unsigned long trackNum) - : mSegment(segment), + MatroskaExtractor *extractor, unsigned long trackNum) + : mExtractor(extractor), mTrackNum(trackNum), mCluster(NULL), - mBlockEntry(NULL) { + mBlockEntry(NULL), + mBlockEntryIndex(0) { reset(); } @@ -212,45 +219,97 @@ bool BlockIterator::eos() const { } void BlockIterator::advance() { - while (!eos()) { - if (mBlockEntry != NULL) { - mBlockEntry = mCluster->GetNext(mBlockEntry); - } else if (mCluster != NULL) { - mCluster = mSegment->GetNext(mCluster); + Mutex::Autolock autoLock(mExtractor->mLock); + advance_l(); +} + +void BlockIterator::advance_l() { + for (;;) { + long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry); + LOGV("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); + LOGV("Parse returned %ld", res); + + if (res < 0) { + // I/O error + + LOGE("Cluster::Parse returned result %ld", res); - if (eos()) { + mCluster = NULL; break; } - mBlockEntry = mCluster->GetFirst(); + continue; + } else if (res == 0) { + // We're done with this cluster + + const mkvparser::Cluster *nextCluster; + res = mExtractor->mSegment->ParseNext( + mCluster, nextCluster, pos, len); + LOGV("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); + LOGV("Parse (2) returned %ld", res); + CHECK_GE(res, 0); + + mBlockEntryIndex = 0; + continue; } - if (mBlockEntry != NULL - && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) { + CHECK(mBlockEntry != NULL); + CHECK(mBlockEntry->GetBlock() != NULL); + ++mBlockEntryIndex; + + if (mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) { break; } } } void BlockIterator::reset() { - mCluster = mSegment->GetFirst(); - mBlockEntry = mCluster->GetFirst(); + Mutex::Autolock autoLock(mExtractor->mLock); - while (!eos() && block()->GetTrackNumber() != mTrackNum) { - advance(); - } + mCluster = mExtractor->mSegment->GetFirst(); + mBlockEntryIndex = 0; + + do { + advance_l(); + } while (!eos() && block()->GetTrackNumber() != mTrackNum); } void BlockIterator::seek(int64_t seekTimeUs) { - mCluster = mSegment->FindCluster(seekTimeUs * 1000ll); - mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL; + Mutex::Autolock autoLock(mExtractor->mLock); + + mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll); + mBlockEntryIndex = 0; while (!eos() && block()->GetTrackNumber() != mTrackNum) { - advance(); + advance_l(); } while (!eos() && !mBlockEntry->GetBlock()->IsKey()) { - advance(); + advance_l(); } } @@ -291,16 +350,6 @@ void MatroskaSource::clearPendingFrames() { } } -#define BAIL(err) \ - do { \ - if (bigbuf) { \ - bigbuf->release(); \ - bigbuf = NULL; \ - } \ - \ - return err; \ - } while (0) - status_t MatroskaSource::readBlock() { CHECK(mPendingFrames.empty()); @@ -310,181 +359,39 @@ status_t MatroskaSource::readBlock() { const mkvparser::Block *block = mBlockIter.block(); - size_t size = block->GetSize(); int64_t timeUs = mBlockIter.blockTimeUs(); - int32_t isSync = block->IsKey(); - - MediaBuffer *bigbuf = new MediaBuffer(size); - - long res = block->Read( - mExtractor->mReader, (unsigned char *)bigbuf->data()); - - if (res != 0) { - bigbuf->release(); - bigbuf = NULL; - - return ERROR_END_OF_STREAM; - } - - mBlockIter.advance(); - - bigbuf->meta_data()->setInt64(kKeyTime, timeUs); - bigbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync); - - unsigned lacing = (block->Flags() >> 1) & 3; - - if (lacing == 0) { - mPendingFrames.push_back(bigbuf); - return OK; - } - - LOGV("lacing = %u, size = %d", lacing, size); - - const uint8_t *data = (const uint8_t *)bigbuf->data(); - // hexdump(data, size); - - if (size == 0) { - BAIL(ERROR_MALFORMED); - } - - unsigned numFrames = (unsigned)data[0] + 1; - ++data; - --size; - - Vector<uint64_t> frameSizes; - - switch (lacing) { - case 1: // Xiph - { - for (size_t i = 0; i < numFrames - 1; ++i) { - size_t frameSize = 0; - uint8_t byte; - do { - if (size == 0) { - BAIL(ERROR_MALFORMED); - } - byte = data[0]; - ++data; - --size; - - frameSize += byte; - } while (byte == 0xff); - - frameSizes.push(frameSize); - } - - break; - } - - case 2: // fixed-size - { - if ((size % numFrames) != 0) { - BAIL(ERROR_MALFORMED); - } - - size_t frameSize = size / numFrames; - for (size_t i = 0; i < numFrames - 1; ++i) { - frameSizes.push(frameSize); - } - - break; - } - - case 3: // EBML - { - uint64_t lastFrameSize = 0; - for (size_t i = 0; i < numFrames - 1; ++i) { - uint8_t byte; - if (size == 0) { - BAIL(ERROR_MALFORMED); - } - byte = data[0]; - ++data; - --size; - - size_t numLeadingZeroes = clz(byte); - - uint64_t frameSize = byte & ~(0x80 >> numLeadingZeroes); - for (size_t j = 0; j < numLeadingZeroes; ++j) { - if (size == 0) { - BAIL(ERROR_MALFORMED); - } - - frameSize = frameSize << 8; - frameSize |= data[0]; - ++data; - --size; - } - - if (i == 0) { - frameSizes.push(frameSize); - } else { - size_t shift = - 7 - numLeadingZeroes + 8 * numLeadingZeroes; - - int64_t delta = - (int64_t)frameSize - (1ll << (shift - 1)) + 1; - - frameSize = lastFrameSize + delta; - - frameSizes.push(frameSize); - } - - lastFrameSize = frameSize; - } - break; - } + for (int i = 0; i < block->GetFrameCount(); ++i) { + const mkvparser::Block::Frame &frame = block->GetFrame(i); - default: - TRESPASS(); - } - -#if 0 - AString out; - for (size_t i = 0; i < frameSizes.size(); ++i) { - if (i > 0) { - out.append(", "); - } - out.append(StringPrintf("%llu", frameSizes.itemAt(i))); - } - LOGV("sizes = [%s]", out.c_str()); -#endif + MediaBuffer *mbuf = new MediaBuffer(frame.len); + mbuf->meta_data()->setInt64(kKeyTime, timeUs); + mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey()); - for (size_t i = 0; i < frameSizes.size(); ++i) { - uint64_t frameSize = frameSizes.itemAt(i); + long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data()); + if (n != 0) { + mPendingFrames.clear(); - if (size < frameSize) { - BAIL(ERROR_MALFORMED); + mBlockIter.advance(); + return ERROR_IO; } - MediaBuffer *mbuf = new MediaBuffer(frameSize); - mbuf->meta_data()->setInt64(kKeyTime, timeUs); - mbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync); - memcpy(mbuf->data(), data, frameSize); mPendingFrames.push_back(mbuf); - - data += frameSize; - size -= frameSize; } - size_t offset = bigbuf->range_length() - size; - bigbuf->set_range(offset, size); - - mPendingFrames.push_back(bigbuf); + mBlockIter.advance(); return OK; } -#undef BAIL - status_t MatroskaSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; int64_t seekTimeUs; ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { + if (options && options->getSeekTo(&seekTimeUs, &mode) + && !mExtractor->isLiveStreaming()) { clearPendingFrames(); mBlockIter.seek(seekTimeUs); } @@ -584,6 +491,13 @@ MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) mReader(new DataSourceReader(mDataSource)), mSegment(NULL), mExtractedThumbnails(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) { @@ -598,7 +512,16 @@ MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source) return; } - ret = mSegment->Load(); + 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; @@ -635,7 +558,8 @@ sp<MetaData> MatroskaExtractor::getTrackMetaData( return NULL; } - if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) { + if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails + && !isLiveStreaming()) { findThumbnails(); mExtractedThumbnails = true; } @@ -643,6 +567,10 @@ sp<MetaData> MatroskaExtractor::getTrackMetaData( return mTracks.itemAt(index).mMeta; } +bool MatroskaExtractor::isLiveStreaming() const { + return mIsLiveStreaming; +} + static void addESDSFromAudioSpecificInfo( const sp<MetaData> &meta, const void *asi, size_t asiSize) { static const uint8_t kStaticESDS[] = { @@ -794,7 +722,7 @@ void MatroskaExtractor::findThumbnails() { continue; } - BlockIterator iter(mSegment, info->mTrackNum); + BlockIterator iter(this, info->mTrackNum); int32_t i = 0; int64_t thumbnailTimeUs = 0; size_t maxBlockSize = 0; @@ -802,7 +730,11 @@ void MatroskaExtractor::findThumbnails() { if (iter.block()->IsKey()) { ++i; - size_t blockSize = iter.block()->GetSize(); + 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(); @@ -821,6 +753,15 @@ sp<MetaData> MatroskaExtractor::getMetaData() { 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> *) { diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h index fa20b84..38ebd61 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.h +++ b/media/libstagefright/matroska/MatroskaExtractor.h @@ -20,6 +20,7 @@ #include <media/stagefright/MediaExtractor.h> #include <utils/Vector.h> +#include <utils/threads.h> namespace mkvparser { struct Segment; @@ -45,26 +46,34 @@ struct MatroskaExtractor : public MediaExtractor { virtual sp<MetaData> getMetaData(); + virtual uint32_t flags() const; + protected: virtual ~MatroskaExtractor(); private: friend struct MatroskaSource; + friend struct BlockIterator; struct TrackInfo { unsigned long mTrackNum; sp<MetaData> mMeta; }; + + Mutex mLock; Vector<TrackInfo> mTracks; sp<DataSource> mDataSource; DataSourceReader *mReader; mkvparser::Segment *mSegment; bool mExtractedThumbnails; + bool mIsLiveStreaming; void addTracks(); void findThumbnails(); + bool isLiveStreaming() const; + MatroskaExtractor(const MatroskaExtractor &); MatroskaExtractor &operator=(const MatroskaExtractor &); }; |