From 32f3cefa373cd55e63deda36ca9d07c7fe22eaaf Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 2 Mar 2011 15:34:46 -0800 Subject: Allow optional specification of a PTS timestamp when signalling a discontinuity. If present, rendering will be suppressed until reaching the timestamp. Change-Id: Ic64bdf4225063c5a4d042ea9809960b843a46d19 related-to-bug: 3489454 --- include/media/IStreamSource.h | 6 +++ media/libmedia/IStreamSource.cpp | 3 ++ .../nuplayer/HTTPLiveSource.cpp | 4 +- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 48 ++++++++++++++++++++ media/libmediaplayerservice/nuplayer/NuPlayer.h | 3 ++ .../nuplayer/NuPlayerStreamListener.cpp | 7 ++- .../nuplayer/NuPlayerStreamListener.h | 2 +- .../nuplayer/StreamingSource.cpp | 9 ++-- media/libstagefright/mpeg2ts/ATSParser.cpp | 52 ++++++++++++++++------ media/libstagefright/mpeg2ts/ATSParser.h | 5 ++- .../libstagefright/mpeg2ts/AnotherPacketSource.cpp | 4 +- media/libstagefright/mpeg2ts/AnotherPacketSource.h | 5 ++- 12 files changed, 126 insertions(+), 22 deletions(-) diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h index 4b698e6920..d310cee309 100644 --- a/include/media/IStreamSource.h +++ b/include/media/IStreamSource.h @@ -45,6 +45,12 @@ struct IStreamListener : public IInterface { virtual void queueBuffer(size_t index, size_t size) = 0; + // When signalling a discontinuity you can optionally + // specify an int64_t PTS timestamp in "msg". + // If present, rendering of data following the discontinuity + // will be suppressed until media time reaches this timestamp. + static const char *const kKeyResumeAtPTS; + virtual void issueCommand( Command cmd, bool synchronous, const sp &msg = NULL) = 0; }; diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp index 5069002029..c14ee828c5 100644 --- a/media/libmedia/IStreamSource.cpp +++ b/media/libmedia/IStreamSource.cpp @@ -26,6 +26,9 @@ namespace android { +// static +const char *const IStreamListener::kKeyResumeAtPTS = "resume-at-PTS"; + enum { // IStreamSource SET_LISTENER = IBinder::FIRST_CALL_TRANSACTION, diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index b3314bed76..d07ea1b966 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -96,10 +96,12 @@ bool NuPlayer::HTTPLiveSource::feedMoreTSData() { } else { if (buffer[0] == 0x00) { // XXX legacy + sp extra; mTSParser->signalDiscontinuity( buffer[1] == 0x00 ? ATSParser::DISCONTINUITY_SEEK - : ATSParser::DISCONTINUITY_FORMATCHANGE); + : ATSParser::DISCONTINUITY_FORMATCHANGE, + extra); } else { mTSParser->feedTSPacket(buffer, sizeof(buffer)); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 474c056243..d439f6ec75 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -191,6 +191,8 @@ void NuPlayer::onMessageReceived(const sp &msg) { mAudioEOS = false; mVideoEOS = false; + mSkipRenderingAudioUntilMediaTimeUs = -1; + mSkipRenderingVideoUntilMediaTimeUs = -1; mSource->start(); @@ -592,6 +594,31 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { LOGV("%s discontinuity (formatChange=%d)", audio ? "audio" : "video", formatChange); + if (audio) { + mSkipRenderingAudioUntilMediaTimeUs = -1; + } else { + mSkipRenderingVideoUntilMediaTimeUs = -1; + } + + sp extra; + if (accessUnit->meta()->findMessage("extra", &extra) + && extra != NULL) { + int64_t resumeAtMediaTimeUs; + if (extra->findInt64( + "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { + LOGI("suppressing rendering of %s until %lld us", + audio ? "audio" : "video", resumeAtMediaTimeUs); + + if (audio) { + mSkipRenderingAudioUntilMediaTimeUs = + resumeAtMediaTimeUs; + } else { + mSkipRenderingVideoUntilMediaTimeUs = + resumeAtMediaTimeUs; + } + } + } + flushDecoder(audio, formatChange); } @@ -627,6 +654,27 @@ void NuPlayer::renderBuffer(bool audio, const sp &msg) { sp buffer = static_cast(obj.get()); + int64_t &skipUntilMediaTimeUs = + audio + ? mSkipRenderingAudioUntilMediaTimeUs + : mSkipRenderingVideoUntilMediaTimeUs; + + if (skipUntilMediaTimeUs >= 0) { + int64_t mediaTimeUs; + CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); + + if (mediaTimeUs < skipUntilMediaTimeUs) { + LOGV("dropping %s buffer at time %lld as requested.", + audio ? "audio" : "video", + mediaTimeUs); + + reply->post(); + return; + } + + skipUntilMediaTimeUs = -1; + } + mRenderer->queueBuffer(audio, buffer, reply); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index e7c6a42629..fb5b001fb7 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -112,6 +112,9 @@ private: bool mResetInProgress; bool mResetPostponed; + int64_t mSkipRenderingAudioUntilMediaTimeUs; + int64_t mSkipRenderingVideoUntilMediaTimeUs; + status_t instantiateDecoder(bool audio, sp *decoder); status_t feedDecoderInputData(bool audio, const sp &msg); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp index a23beb7d51..885ebe4f47 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp @@ -92,9 +92,12 @@ void NuPlayer::NuPlayerStreamListener::issueCommand( } } -ssize_t NuPlayer::NuPlayerStreamListener::read(void *data, size_t size) { +ssize_t NuPlayer::NuPlayerStreamListener::read( + void *data, size_t size, sp *extra) { CHECK_GT(size, 0u); + extra->clear(); + Mutex::Autolock autoLock(mLock); if (mEOS) { @@ -122,6 +125,8 @@ ssize_t NuPlayer::NuPlayerStreamListener::read(void *data, size_t size) { case DISCONTINUITY: { + *extra = entry->mExtra; + mQueue.erase(mQueue.begin()); entry = NULL; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h index f88e945da5..df0935d806 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h @@ -37,7 +37,7 @@ struct NuPlayer::NuPlayerStreamListener : public BnStreamListener { Command cmd, bool synchronous, const sp &extra); void start(); - ssize_t read(void *data, size_t size); + ssize_t read(void *data, size_t size, sp *extra); private: enum { diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp index b85ac9fdff..201628270f 100644 --- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp +++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp @@ -54,7 +54,8 @@ bool NuPlayer::StreamingSource::feedMoreTSData() { for (int32_t i = 0; i < 10; ++i) { char buffer[188]; - ssize_t n = mStreamListener->read(buffer, sizeof(buffer)); + sp extra; + ssize_t n = mStreamListener->read(buffer, sizeof(buffer), &extra); if (n == 0) { LOGI("input data EOS reached."); @@ -62,7 +63,8 @@ bool NuPlayer::StreamingSource::feedMoreTSData() { mEOS = true; break; } else if (n == INFO_DISCONTINUITY) { - mTSParser->signalDiscontinuity(ATSParser::DISCONTINUITY_SEEK); + mTSParser->signalDiscontinuity( + ATSParser::DISCONTINUITY_SEEK, extra); } else if (n < 0) { CHECK_EQ(n, -EWOULDBLOCK); break; @@ -72,7 +74,8 @@ bool NuPlayer::StreamingSource::feedMoreTSData() { mTSParser->signalDiscontinuity( buffer[1] == 0x00 ? ATSParser::DISCONTINUITY_SEEK - : ATSParser::DISCONTINUITY_FORMATCHANGE); + : ATSParser::DISCONTINUITY_FORMATCHANGE, + extra); } else { mTSParser->feedTSPacket(buffer, sizeof(buffer)); } diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 60567395f0..5ba4a4fe1e 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include namespace android { @@ -49,7 +50,9 @@ struct ATSParser::Program : public RefBase { unsigned pid, unsigned payload_unit_start_indicator, ABitReader *br); - void signalDiscontinuity(DiscontinuityType type); + void signalDiscontinuity( + DiscontinuityType type, const sp &extra); + void signalEOS(status_t finalResult); sp getSource(SourceType type); @@ -83,7 +86,9 @@ struct ATSParser::Stream : public RefBase { unsigned payload_unit_start_indicator, ABitReader *br); - void signalDiscontinuity(DiscontinuityType type); + void signalDiscontinuity( + DiscontinuityType type, const sp &extra); + void signalEOS(status_t finalResult); sp getSource(SourceType type); @@ -100,6 +105,7 @@ private: sp mSource; bool mPayloadStarted; DiscontinuityType mPendingDiscontinuity; + sp mPendingDiscontinuityExtra; ElementaryStreamQueue mQueue; @@ -112,7 +118,8 @@ private: void extractAACFrames(const sp &buffer); - void deferDiscontinuity(DiscontinuityType type); + void deferDiscontinuity( + DiscontinuityType type, const sp &extra); DISALLOW_EVIL_CONSTRUCTORS(Stream); }; @@ -150,9 +157,10 @@ bool ATSParser::Program::parsePID( return true; } -void ATSParser::Program::signalDiscontinuity(DiscontinuityType type) { +void ATSParser::Program::signalDiscontinuity( + DiscontinuityType type, const sp &extra) { for (size_t i = 0; i < mStreams.size(); ++i) { - mStreams.editValueAt(i)->signalDiscontinuity(type); + mStreams.editValueAt(i)->signalDiscontinuity(type, extra); } } @@ -283,7 +291,8 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) { mStreams.add(info.mPID, stream); if (PIDsChanged) { - stream->signalDiscontinuity(DISCONTINUITY_FORMATCHANGE); + sp extra; + stream->signalDiscontinuity(DISCONTINUITY_FORMATCHANGE, extra); } } } @@ -366,7 +375,8 @@ void ATSParser::Stream::parse( mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8); } -void ATSParser::Stream::signalDiscontinuity(DiscontinuityType type) { +void ATSParser::Stream::signalDiscontinuity( + DiscontinuityType type, const sp &extra) { mPayloadStarted = false; mBuffer->setRange(0, 0); @@ -378,10 +388,21 @@ void ATSParser::Stream::signalDiscontinuity(DiscontinuityType type) { mQueue.clear(!isASeek); + uint64_t resumeAtPTS; + if (extra != NULL + && extra->findInt64( + IStreamListener::kKeyResumeAtPTS, + (int64_t *)&resumeAtPTS)) { + int64_t resumeAtMediaTimeUs = + mProgram->convertPTSToTimestamp(resumeAtPTS); + + extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs); + } + if (mSource != NULL) { - mSource->queueDiscontinuity(type); + mSource->queueDiscontinuity(type, extra); } else { - deferDiscontinuity(type); + deferDiscontinuity(type, extra); } break; } @@ -392,10 +413,12 @@ void ATSParser::Stream::signalDiscontinuity(DiscontinuityType type) { } } -void ATSParser::Stream::deferDiscontinuity(DiscontinuityType type) { +void ATSParser::Stream::deferDiscontinuity( + DiscontinuityType type, const sp &extra) { if (type > mPendingDiscontinuity) { // Only upgrade discontinuities. mPendingDiscontinuity = type; + mPendingDiscontinuityExtra = extra; } } @@ -596,8 +619,10 @@ void ATSParser::Stream::onPayloadData( mSource = new AnotherPacketSource(meta); if (mPendingDiscontinuity != DISCONTINUITY_NONE) { - mSource->queueDiscontinuity(mPendingDiscontinuity); + mSource->queueDiscontinuity( + mPendingDiscontinuity, mPendingDiscontinuityExtra); mPendingDiscontinuity = DISCONTINUITY_NONE; + mPendingDiscontinuityExtra.clear(); } mSource->queueAccessUnit(accessUnit); @@ -639,9 +664,10 @@ void ATSParser::feedTSPacket(const void *data, size_t size) { parseTS(&br); } -void ATSParser::signalDiscontinuity(DiscontinuityType type) { +void ATSParser::signalDiscontinuity( + DiscontinuityType type, const sp &extra) { for (size_t i = 0; i < mPrograms.size(); ++i) { - mPrograms.editItemAt(i)->signalDiscontinuity(type); + mPrograms.editItemAt(i)->signalDiscontinuity(type, extra); } } diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index 455f9d5c7d..3936f059de 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -41,7 +41,10 @@ struct ATSParser : public RefBase { ATSParser(); void feedTSPacket(const void *data, size_t size); - void signalDiscontinuity(DiscontinuityType type); + + void signalDiscontinuity( + DiscontinuityType type, const sp &extra); + void signalEOS(status_t finalResult); enum SourceType { diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 0ad883b02c..59de17eb7b 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -136,9 +136,11 @@ void AnotherPacketSource::queueAccessUnit(const sp &buffer) { } void AnotherPacketSource::queueDiscontinuity( - ATSParser::DiscontinuityType type) { + ATSParser::DiscontinuityType type, + const sp &extra) { sp buffer = new ABuffer(0); buffer->meta()->setInt32("discontinuity", static_cast(type)); + buffer->meta()->setMessage("extra", extra); Mutex::Autolock autoLock(mLock); diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h index 6fe93f8a5c..439c78531f 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h @@ -46,7 +46,10 @@ struct AnotherPacketSource : public MediaSource { status_t nextBufferTime(int64_t *timeUs); void queueAccessUnit(const sp &buffer); - void queueDiscontinuity(ATSParser::DiscontinuityType type); + + void queueDiscontinuity( + ATSParser::DiscontinuityType type, const sp &extra); + void signalEOS(status_t result); status_t dequeueAccessUnit(sp *buffer); -- cgit v1.2.3