From a15874665fa785c82afa9f2e8cb3512470c297cb Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 15 Dec 2010 15:17:42 -0800 Subject: Initial support for a true streaming player for mpeg2 transport streams. Change-Id: I153eec439d260a5524b21270e16d36940ec3161a --- media/libstagefright/mpeg2ts/ATSParser.cpp | 95 +++++++++++++++------- media/libstagefright/mpeg2ts/ATSParser.h | 11 ++- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 48 ++++++++++- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 4 + media/libstagefright/mpeg2ts/ESQueue.cpp | 11 ++- media/libstagefright/mpeg2ts/ESQueue.h | 2 +- media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp | 2 +- 7 files changed, 133 insertions(+), 40 deletions(-) (limited to 'media/libstagefright/mpeg2ts') diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index a559b21..de6346b 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -43,19 +43,21 @@ namespace android { static const size_t kTSPacketSize = 188; struct ATSParser::Program : public RefBase { - Program(unsigned programMapPID); + Program(ATSParser *parser, unsigned programMapPID); bool parsePID( unsigned pid, unsigned payload_unit_start_indicator, ABitReader *br); - void signalDiscontinuity(bool isASeek); + void signalDiscontinuity(DiscontinuityType type); + void signalEOS(status_t finalResult); sp getSource(SourceType type); int64_t convertPTSToTimestamp(uint64_t PTS); private: + ATSParser *mParser; unsigned mProgramMapPID; KeyedVector > mStreams; bool mFirstPTSValid; @@ -73,7 +75,8 @@ struct ATSParser::Stream : public RefBase { unsigned payload_unit_start_indicator, ABitReader *br); - void signalDiscontinuity(bool isASeek); + void signalDiscontinuity(DiscontinuityType type); + void signalEOS(status_t finalResult); sp getSource(SourceType type); @@ -105,8 +108,9 @@ private: //////////////////////////////////////////////////////////////////////////////// -ATSParser::Program::Program(unsigned programMapPID) - : mProgramMapPID(programMapPID), +ATSParser::Program::Program(ATSParser *parser, unsigned programMapPID) + : mParser(parser), + mProgramMapPID(programMapPID), mFirstPTSValid(false), mFirstPTS(0) { } @@ -135,9 +139,15 @@ bool ATSParser::Program::parsePID( return true; } -void ATSParser::Program::signalDiscontinuity(bool isASeek) { +void ATSParser::Program::signalDiscontinuity(DiscontinuityType type) { for (size_t i = 0; i < mStreams.size(); ++i) { - mStreams.editValueAt(i)->signalDiscontinuity(isASeek); + mStreams.editValueAt(i)->signalDiscontinuity(type); + } +} + +void ATSParser::Program::signalEOS(status_t finalResult) { + for (size_t i = 0; i < mStreams.size(); ++i) { + mStreams.editValueAt(i)->signalEOS(finalResult); } } @@ -155,7 +165,7 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) { unsigned section_length = br->getBits(12); LOGV(" section_length = %u", section_length); - CHECK((section_length & 0xc00) == 0); + CHECK_EQ(section_length & 0xc00, 0u); CHECK_LE(section_length, 1021u); MY_LOGV(" program_number = %u", br->getBits(16)); @@ -170,7 +180,7 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) { unsigned program_info_length = br->getBits(12); LOGV(" program_info_length = %u", program_info_length); - CHECK((program_info_length & 0xc00) == 0); + CHECK_EQ(program_info_length & 0xc00, 0u); br->skipBits(program_info_length * 8); // skip descriptors @@ -194,7 +204,7 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) { unsigned ES_info_length = br->getBits(12); LOGV(" ES_info_length = %u", ES_info_length); - CHECK((ES_info_length & 0xc00) == 0); + CHECK_EQ(ES_info_length & 0xc00, 0u); CHECK_GE(infoBytesRemaining - 5, ES_info_length); @@ -305,7 +315,7 @@ void ATSParser::Stream::parse( } size_t payloadSizeBits = br->numBitsLeft(); - CHECK((payloadSizeBits % 8) == 0); + CHECK_EQ(payloadSizeBits % 8, 0u); CHECK_LE(mBuffer->size() + payloadSizeBits / 8, mBuffer->capacity()); @@ -313,27 +323,45 @@ void ATSParser::Stream::parse( mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8); } -void ATSParser::Stream::signalDiscontinuity(bool isASeek) { - isASeek = false; // Always signal a "real" discontinuity - +void ATSParser::Stream::signalDiscontinuity(DiscontinuityType type) { mPayloadStarted = false; mBuffer->setRange(0, 0); - mQueue.clear(); + switch (type) { + case DISCONTINUITY_HTTPLIVE: + { + mQueue.clear(true); - if (isASeek) { - // This is only a "minor" discontinuity, we stay within the same - // bitstream. + if (mStreamType == 0x1b && mSource != NULL) { + // Don't signal discontinuities on audio streams. + mSource->queueDiscontinuity(); + } + break; + } + + case DISCONTINUITY_SEEK: + case DISCONTINUITY_FORMATCHANGE: + { + bool isASeek = (type == DISCONTINUITY_SEEK); - if (mSource != NULL) { - mSource->clear(); + mQueue.clear(!isASeek); + + if (mSource != NULL) { + mSource->clear(); + mSource->queueDiscontinuity(); + } + break; } - return; + + default: + TRESPASS(); + break; } +} - if (mStreamType == 0x1b && mSource != NULL) { - // Don't signal discontinuities on audio streams. - mSource->queueDiscontinuity(); +void ATSParser::Stream::signalEOS(status_t finalResult) { + if (mSource != NULL) { + mSource->signalEOS(finalResult); } } @@ -478,7 +506,7 @@ void ATSParser::Stream::parsePES(ABitReader *br) { br->data(), br->numBitsLeft() / 8); size_t payloadSizeBits = br->numBitsLeft(); - CHECK((payloadSizeBits % 8) == 0); + CHECK_EQ(payloadSizeBits % 8, 0u); LOGV("There's %d bytes of payload.", payloadSizeBits / 8); } @@ -526,6 +554,7 @@ void ATSParser::Stream::onPayloadData( if (meta != NULL) { LOGV("created source!"); mSource = new AnotherPacketSource(meta); + mSource->queueAccessUnit(accessUnit); } } else if (mQueue.getFormat() != NULL) { @@ -561,9 +590,17 @@ void ATSParser::feedTSPacket(const void *data, size_t size) { parseTS(&br); } -void ATSParser::signalDiscontinuity(bool isASeek) { +void ATSParser::signalDiscontinuity(DiscontinuityType type) { + for (size_t i = 0; i < mPrograms.size(); ++i) { + mPrograms.editItemAt(i)->signalDiscontinuity(type); + } +} + +void ATSParser::signalEOS(status_t finalResult) { + CHECK_NE(finalResult, (status_t)OK); + for (size_t i = 0; i < mPrograms.size(); ++i) { - mPrograms.editItemAt(i)->signalDiscontinuity(isASeek); + mPrograms.editItemAt(i)->signalEOS(finalResult); } } @@ -581,7 +618,7 @@ void ATSParser::parseProgramAssociationTable(ABitReader *br) { unsigned section_length = br->getBits(12); LOGV(" section_length = %u", section_length); - CHECK((section_length & 0xc00) == 0); + CHECK_EQ(section_length & 0xc00, 0u); MY_LOGV(" transport_stream_id = %u", br->getBits(16)); MY_LOGV(" reserved = %u", br->getBits(2)); @@ -606,7 +643,7 @@ void ATSParser::parseProgramAssociationTable(ABitReader *br) { LOGV(" program_map_PID = 0x%04x", programMapPID); - mPrograms.push(new Program(programMapPID)); + mPrograms.push(new Program(this, programMapPID)); } } diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index 11b1de4..ef78c77 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -21,19 +21,28 @@ #include #include +#include #include #include namespace android { struct ABitReader; +struct ABuffer; struct MediaSource; struct ATSParser : public RefBase { + enum DiscontinuityType { + DISCONTINUITY_HTTPLIVE, + DISCONTINUITY_SEEK, + DISCONTINUITY_FORMATCHANGE + }; + ATSParser(); void feedTSPacket(const void *data, size_t size); - void signalDiscontinuity(bool isASeek = false); + void signalDiscontinuity(DiscontinuityType type); + void signalEOS(status_t finalResult); enum SourceType { AVC_VIDEO, diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index ea747c8..7a1d5b0 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -48,6 +48,32 @@ sp AnotherPacketSource::getFormat() { return mFormat; } +status_t AnotherPacketSource::dequeueAccessUnit(sp *buffer) { + buffer->clear(); + + Mutex::Autolock autoLock(mLock); + while (mEOSResult == OK && mBuffers.empty()) { + mCondition.wait(mLock); + } + + if (!mBuffers.empty()) { + *buffer = *mBuffers.begin(); + mBuffers.erase(mBuffers.begin()); + + int32_t discontinuity; + if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity) + && discontinuity) { + buffer->clear(); + + return INFO_DISCONTINUITY; + } + + return OK; + } + + return mEOSResult; +} + status_t AnotherPacketSource::read( MediaBuffer **out, const ReadOptions *) { *out = NULL; @@ -66,9 +92,8 @@ status_t AnotherPacketSource::read( && discontinuity) { return INFO_DISCONTINUITY; } else { - uint64_t timeUs; - CHECK(buffer->meta()->findInt64( - "time", (int64_t *)&timeUs)); + int64_t timeUs; + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size()); mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); @@ -92,7 +117,7 @@ void AnotherPacketSource::queueAccessUnit(const sp &buffer) { } int64_t timeUs; - CHECK(buffer->meta()->findInt64("time", &timeUs)); + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); LOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", timeUs, timeUs / 1E6); Mutex::Autolock autoLock(mLock); @@ -134,4 +159,19 @@ bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) { return false; } +status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) { + *timeUs = 0; + + Mutex::Autolock autoLock(mLock); + + if (mBuffers.empty()) { + return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK; + } + + sp buffer = *mBuffers.begin(); + CHECK(buffer->meta()->findInt64("timeUs", timeUs)); + + return OK; +} + } // namespace android diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index 6999175..2bc7404 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -39,12 +39,16 @@ struct AnotherPacketSource : public MediaSource { bool hasBufferAvailable(status_t *finalResult); + status_t nextBufferTime(int64_t *timeUs); + void queueAccessUnit(const sp &buffer); void queueDiscontinuity(); void signalEOS(status_t result); void clear(); + status_t dequeueAccessUnit(sp *buffer); + protected: virtual ~AnotherPacketSource(); diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index 4b4490d..4e7759d 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -40,13 +40,16 @@ sp ElementaryStreamQueue::getFormat() { return mFormat; } -void ElementaryStreamQueue::clear() { +void ElementaryStreamQueue::clear(bool clearFormat) { if (mBuffer != NULL) { mBuffer->setRange(0, 0); } mRangeInfos.clear(); - mFormat.clear(); + + if (clearFormat) { + mFormat.clear(); + } } static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) { @@ -289,7 +292,7 @@ sp ElementaryStreamQueue::dequeueAccessUnitAAC() { mBuffer->setRange(0, mBuffer->size() - offset); if (timeUs >= 0) { - accessUnit->meta()->setInt64("time", timeUs); + accessUnit->meta()->setInt64("timeUs", timeUs); } else { LOGW("no time for AAC access unit"); } @@ -470,7 +473,7 @@ sp ElementaryStreamQueue::dequeueAccessUnitH264() { int64_t timeUs = fetchTimestamp(nextScan); CHECK_GE(timeUs, 0ll); - accessUnit->meta()->setInt64("time", timeUs); + accessUnit->meta()->setInt64("timeUs", timeUs); if (mFormat == NULL) { mFormat = MakeAVCCodecSpecificData(accessUnit); diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h index adce153..5b7957e 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.h +++ b/media/libstagefright/mpeg2ts/ESQueue.h @@ -35,7 +35,7 @@ struct ElementaryStreamQueue { ElementaryStreamQueue(Mode mode); status_t appendData(const void *data, size_t size, int64_t timeUs); - void clear(); + void clear(bool clearFormat); sp dequeueAccessUnit(); diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp index 600116e..a1f0796 100644 --- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp @@ -214,7 +214,7 @@ status_t MPEG2TSExtractor::feedMore() { if (isDiscontinuity(packet, n)) { LOGI("XXX discontinuity detected"); - mParser->signalDiscontinuity(); + mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_HTTPLIVE); } else if (n < (ssize_t)kTSPacketSize) { return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; } else { -- cgit v1.1