diff options
author | Andreas Huber <andih@google.com> | 2010-10-12 11:34:37 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2010-10-12 14:32:10 -0700 |
commit | 54d09724e3ea2af4e08dff47d7ade92a95784127 (patch) | |
tree | 6cc008b4a8acb1ee7f47e3748baa2826257e61ce /media/libstagefright/mpeg2ts | |
parent | a7c76d8307a3b49bf5b8fdda3543455b0e5dd64c (diff) | |
download | frameworks_base-54d09724e3ea2af4e08dff47d7ade92a95784127.zip frameworks_base-54d09724e3ea2af4e08dff47d7ade92a95784127.tar.gz frameworks_base-54d09724e3ea2af4e08dff47d7ade92a95784127.tar.bz2 |
HTTP Live content that are tagged as complete are now seekable.
Change-Id: I9d0d2f009f883e5baf3e9de8c5c0aa05760e4bde
related-to-bug: 2368598
Diffstat (limited to 'media/libstagefright/mpeg2ts')
-rw-r--r-- | media/libstagefright/mpeg2ts/ATSParser.cpp | 61 | ||||
-rw-r--r-- | media/libstagefright/mpeg2ts/ATSParser.h | 2 | ||||
-rw-r--r-- | media/libstagefright/mpeg2ts/AnotherPacketSource.cpp | 11 | ||||
-rw-r--r-- | media/libstagefright/mpeg2ts/AnotherPacketSource.h | 2 | ||||
-rw-r--r-- | media/libstagefright/mpeg2ts/ESQueue.cpp | 1 | ||||
-rw-r--r-- | media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp | 87 |
6 files changed, 144 insertions, 20 deletions
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 7c9b83a..c88c6c1 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -49,13 +49,17 @@ struct ATSParser::Program : public RefBase { unsigned pid, unsigned payload_unit_start_indicator, ABitReader *br); - void signalDiscontinuity(); + void signalDiscontinuity(bool isASeek); sp<MediaSource> getSource(SourceType type); + int64_t convertPTSToTimestamp(uint64_t PTS); + private: unsigned mProgramMapPID; KeyedVector<unsigned, sp<Stream> > mStreams; + bool mFirstPTSValid; + uint64_t mFirstPTS; void parseProgramMap(ABitReader *br); @@ -63,13 +67,13 @@ private: }; struct ATSParser::Stream : public RefBase { - Stream(unsigned elementaryPID, unsigned streamType); + Stream(Program *program, unsigned elementaryPID, unsigned streamType); void parse( unsigned payload_unit_start_indicator, ABitReader *br); - void signalDiscontinuity(); + void signalDiscontinuity(bool isASeek); sp<MediaSource> getSource(SourceType type); @@ -77,6 +81,7 @@ protected: virtual ~Stream(); private: + Program *mProgram; unsigned mElementaryPID; unsigned mStreamType; @@ -101,7 +106,9 @@ private: //////////////////////////////////////////////////////////////////////////////// ATSParser::Program::Program(unsigned programMapPID) - : mProgramMapPID(programMapPID) { + : mProgramMapPID(programMapPID), + mFirstPTSValid(false), + mFirstPTS(0) { } bool ATSParser::Program::parsePID( @@ -128,9 +135,9 @@ bool ATSParser::Program::parsePID( return true; } -void ATSParser::Program::signalDiscontinuity() { +void ATSParser::Program::signalDiscontinuity(bool isASeek) { for (size_t i = 0; i < mStreams.size(); ++i) { - mStreams.editValueAt(i)->signalDiscontinuity(); + mStreams.editValueAt(i)->signalDiscontinuity(isASeek); } } @@ -213,10 +220,12 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) { ssize_t index = mStreams.indexOfKey(elementaryPID); #if 0 // XXX revisit CHECK_LT(index, 0); - mStreams.add(elementaryPID, new Stream(elementaryPID, streamType)); + mStreams.add(elementaryPID, + new Stream(this, elementaryPID, streamType)); #else if (index < 0) { - mStreams.add(elementaryPID, new Stream(elementaryPID, streamType)); + mStreams.add(elementaryPID, + new Stream(this, elementaryPID, streamType)); } #endif @@ -239,10 +248,26 @@ sp<MediaSource> ATSParser::Program::getSource(SourceType type) { return NULL; } +int64_t ATSParser::Program::convertPTSToTimestamp(uint64_t PTS) { + if (!mFirstPTSValid) { + mFirstPTSValid = true; + mFirstPTS = PTS; + PTS = 0; + } else if (PTS < mFirstPTS) { + PTS = 0; + } else { + PTS -= mFirstPTS; + } + + return (PTS * 100) / 9; +} + //////////////////////////////////////////////////////////////////////////////// -ATSParser::Stream::Stream(unsigned elementaryPID, unsigned streamType) - : mElementaryPID(elementaryPID), +ATSParser::Stream::Stream( + Program *program, unsigned elementaryPID, unsigned streamType) + : mProgram(program), + mElementaryPID(elementaryPID), mStreamType(streamType), mBuffer(new ABuffer(128 * 1024)), mPayloadStarted(false), @@ -281,13 +306,21 @@ void ATSParser::Stream::parse( mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8); } -void ATSParser::Stream::signalDiscontinuity() { +void ATSParser::Stream::signalDiscontinuity(bool isASeek) { LOGV("Stream discontinuity"); mPayloadStarted = false; mBuffer->setRange(0, 0); mQueue.clear(); + if (isASeek) { + // This is only a "minor" discontinuity, we stay within the same + // bitstream. + + mSource->clear(); + return; + } + if (mStreamType == 0x1b && mSource != NULL) { // Don't signal discontinuities on audio streams. mSource->queueDiscontinuity(); @@ -467,7 +500,7 @@ void ATSParser::Stream::onPayloadData( LOGV("onPayloadData mStreamType=0x%02x", mStreamType); CHECK(PTS_DTS_flags == 2 || PTS_DTS_flags == 3); - int64_t timeUs = (PTS * 100) / 9; + int64_t timeUs = mProgram->convertPTSToTimestamp(PTS); status_t err = mQueue.appendData(data, size, timeUs); CHECK_EQ(err, (status_t)OK); @@ -515,9 +548,9 @@ void ATSParser::feedTSPacket(const void *data, size_t size) { parseTS(&br); } -void ATSParser::signalDiscontinuity() { +void ATSParser::signalDiscontinuity(bool isASeek) { for (size_t i = 0; i < mPrograms.size(); ++i) { - mPrograms.editItemAt(i)->signalDiscontinuity(); + mPrograms.editItemAt(i)->signalDiscontinuity(isASeek); } } diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index 9ec6d7b..11b1de4 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -33,7 +33,7 @@ struct ATSParser : public RefBase { ATSParser(); void feedTSPacket(const void *data, size_t size); - void signalDiscontinuity(); + void signalDiscontinuity(bool isASeek = false); enum SourceType { AVC_VIDEO, diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 3f76820..ea747c8 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -91,6 +91,10 @@ void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { return; } + int64_t timeUs; + CHECK(buffer->meta()->findInt64("time", &timeUs)); + LOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", timeUs, timeUs / 1E6); + Mutex::Autolock autoLock(mLock); mBuffers.push_back(buffer); mCondition.signal(); @@ -101,10 +105,17 @@ void AnotherPacketSource::queueDiscontinuity() { buffer->meta()->setInt32("discontinuity", true); Mutex::Autolock autoLock(mLock); + mBuffers.push_back(buffer); mCondition.signal(); } +void AnotherPacketSource::clear() { + Mutex::Autolock autoLock(mLock); + mBuffers.clear(); + mEOSResult = OK; +} + void AnotherPacketSource::signalEOS(status_t result) { CHECK(result != OK); diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index 6b43c4e..6999175 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -43,6 +43,8 @@ struct AnotherPacketSource : public MediaSource { void queueDiscontinuity(); void signalEOS(status_t result); + void clear(); + protected: virtual ~AnotherPacketSource(); diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index a13287e..b0b9e66 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -42,6 +42,7 @@ sp<MetaData> ElementaryStreamQueue::getFormat() { void ElementaryStreamQueue::clear() { mBuffer->setRange(0, 0); + mTimestamps.clear(); mFormat.clear(); } diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp index 0d96bd1..3176810 100644 --- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp @@ -19,8 +19,11 @@ #include <utils/Log.h> #include "include/MPEG2TSExtractor.h" +#include "include/LiveSource.h" +#include "include/NuCachedSource2.h" #include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MediaSource.h> @@ -37,7 +40,8 @@ static const size_t kTSPacketSize = 188; struct MPEG2TSSource : public MediaSource { MPEG2TSSource( const sp<MPEG2TSExtractor> &extractor, - const sp<AnotherPacketSource> &impl); + const sp<AnotherPacketSource> &impl, + bool seekable); virtual status_t start(MetaData *params = NULL); virtual status_t stop(); @@ -50,14 +54,20 @@ private: sp<MPEG2TSExtractor> mExtractor; sp<AnotherPacketSource> mImpl; + // If there are both audio and video streams, only the video stream + // will be seekable, otherwise the single stream will be seekable. + bool mSeekable; + DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource); }; MPEG2TSSource::MPEG2TSSource( const sp<MPEG2TSExtractor> &extractor, - const sp<AnotherPacketSource> &impl) + const sp<AnotherPacketSource> &impl, + bool seekable) : mExtractor(extractor), - mImpl(impl) { + mImpl(impl), + mSeekable(seekable) { } status_t MPEG2TSSource::start(MetaData *params) { @@ -69,13 +79,27 @@ status_t MPEG2TSSource::stop() { } sp<MetaData> MPEG2TSSource::getFormat() { - return mImpl->getFormat(); + sp<MetaData> meta = mImpl->getFormat(); + + int64_t durationUs; + if (mExtractor->mLiveSource != NULL + && mExtractor->mLiveSource->getDuration(&durationUs)) { + meta->setInt64(kKeyDuration, durationUs); + } + + return meta; } status_t MPEG2TSSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; + int64_t seekTimeUs; + ReadOptions::SeekMode seekMode; + if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) { + mExtractor->seekTo(seekTimeUs); + } + status_t finalResult; while (!mImpl->hasBufferAvailable(&finalResult)) { if (finalResult != OK) { @@ -109,7 +133,20 @@ sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) { return NULL; } - return new MPEG2TSSource(this, mSourceImpls.editItemAt(index)); + bool seekable = true; + if (mSourceImpls.size() > 1) { + CHECK_EQ(mSourceImpls.size(), 2u); + + sp<MetaData> meta = mSourceImpls.editItemAt(index)->getFormat(); + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + if (!strncasecmp("audio/", mime, 6)) { + seekable = false; + } + } + + return new MPEG2TSSource(this, mSourceImpls.editItemAt(index), seekable); } sp<MetaData> MPEG2TSExtractor::getTrackMetaData( @@ -189,6 +226,46 @@ status_t MPEG2TSExtractor::feedMore() { return OK; } +void MPEG2TSExtractor::setLiveSource(const sp<LiveSource> &liveSource) { + Mutex::Autolock autoLock(mLock); + + mLiveSource = liveSource; +} + +void MPEG2TSExtractor::seekTo(int64_t seekTimeUs) { + Mutex::Autolock autoLock(mLock); + + if (mLiveSource == NULL) { + return; + } + + if (mDataSource->flags() & DataSource::kIsCachingDataSource) { + static_cast<NuCachedSource2 *>(mDataSource.get())->suspend(); + } + + if (mLiveSource->seekTo(seekTimeUs)) { + mParser->signalDiscontinuity(true /* isSeek */); + mOffset = 0; + } + + if (mDataSource->flags() & DataSource::kIsCachingDataSource) { + static_cast<NuCachedSource2 *>(mDataSource.get()) + ->clearCacheAndResume(); + } +} + +uint32_t MPEG2TSExtractor::flags() const { + Mutex::Autolock autoLock(mLock); + + uint32_t flags = CAN_PAUSE; + + if (mLiveSource != NULL && mLiveSource->isSeekable()) { + flags |= CAN_SEEK_FORWARD | CAN_SEEK_BACKWARD | CAN_SEEK; + } + + return flags; +} + //////////////////////////////////////////////////////////////////////////////// bool SniffMPEG2TS( |