From 87603c0dd1f4e62e52feffa8d6e960ad21f68893 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 20 Aug 2014 19:25:30 -0700 Subject: [PATCH] NuPlayer: remember and resubmit CSDs after flush Bug: 17118001 Change-Id: I09bbefd4c05de0db1c593e8d6d38859358a20ebb --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 65 +++++++++++++++++----- media/libmediaplayerservice/nuplayer/NuPlayer.h | 9 ++- .../nuplayer/NuPlayerDecoder.cpp | 57 +++++++++++++++++-- .../nuplayer/NuPlayerDecoder.h | 7 ++- 4 files changed, 117 insertions(+), 21 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index b79a5dd27d..f4cd02cbaf 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -756,7 +756,7 @@ void NuPlayer::onMessageReceived(const sp &msg) { ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video"); - (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); + getDecoder(audio)->initiateShutdown(); if (audio) { mFlushingAudio = SHUTTING_DOWN_DECODER; @@ -1292,7 +1292,24 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { mTimeDiscontinuityPending = mTimeDiscontinuityPending || timeChange; - if (mFlushingAudio == NONE && mFlushingVideo == NONE) { + bool seamlessFormatChange = false; + sp newFormat = mSource->getFormat(audio); + if (formatChange) { + seamlessFormatChange = + getDecoder(audio)->supportsSeamlessFormatChange(newFormat); + // treat seamless format change separately + formatChange = !seamlessFormatChange; + } + bool shutdownOrFlush = formatChange || timeChange; + + // We want to queue up scan-sources only once per discontinuity. + // We control this by doing it only if neither audio nor video are + // flushing or shutting down. (After handling 1st discontinuity, one + // of the flushing states will not be NONE.) + // No need to scan sources if this discontinuity does not result + // in a flush or shutdown, as the flushing state will stay NONE. + if (mFlushingAudio == NONE && mFlushingVideo == NONE && + shutdownOrFlush) { // And we'll resume scanning sources once we're done // flushing. mDeferredActions.push_front( @@ -1300,16 +1317,17 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { &NuPlayer::performScanSources)); } - if (formatChange || timeChange) { - - sp newFormat = mSource->getFormat(audio); - sp &decoder = audio ? mAudioDecoder : mVideoDecoder; - if (formatChange && !decoder->supportsSeamlessFormatChange(newFormat)) { - flushDecoder(audio, /* needShutdown = */ true); - } else { - flushDecoder(audio, /* needShutdown = */ false); - err = OK; - } + if (formatChange /* not seamless */) { + // must change decoder + flushDecoder(audio, /* needShutdown = */ true); + } else if (timeChange) { + // need to flush + flushDecoder(audio, /* needShutdown = */ false, newFormat); + err = OK; + } else if (seamlessFormatChange) { + // reuse existing decoder and don't flush + updateDecoderFormatWithoutFlush(audio, newFormat); + err = OK; } else { // This stream is unaffected by the discontinuity return -EWOULDBLOCK; @@ -1488,20 +1506,23 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) { driver->notifyListener(msg, ext1, ext2, in); } -void NuPlayer::flushDecoder(bool audio, bool needShutdown) { +void NuPlayer::flushDecoder( + bool audio, bool needShutdown, const sp &newFormat) { ALOGV("[%s] flushDecoder needShutdown=%d", audio ? "audio" : "video", needShutdown); - if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) { + const sp &decoder = getDecoder(audio); + if (decoder == NULL) { ALOGI("flushDecoder %s without decoder present", audio ? "audio" : "video"); + return; } // Make sure we don't continue to scan sources until we finish flushing. ++mScanSourcesGeneration; mScanSourcesPending = false; - (audio ? mAudioDecoder : mVideoDecoder)->signalFlush(); + decoder->signalFlush(newFormat); mRenderer->flush(audio); FlushStatus newStatus = @@ -1518,6 +1539,20 @@ void NuPlayer::flushDecoder(bool audio, bool needShutdown) { } } +void NuPlayer::updateDecoderFormatWithoutFlush( + bool audio, const sp &format) { + ALOGV("[%s] updateDecoderFormatWithoutFlush", audio ? "audio" : "video"); + + const sp &decoder = getDecoder(audio); + if (decoder == NULL) { + ALOGI("updateDecoderFormatWithoutFlush %s without decoder present", + audio ? "audio" : "video"); + return; + } + + decoder->signalUpdateFormat(format); +} + void NuPlayer::queueDecoderShutdown( bool audio, bool video, const sp &reply) { ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 96306db43d..511d7522bc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -25,6 +25,7 @@ namespace android { struct ABuffer; +struct AMessage; struct MetaData; struct NuPlayerDriver; @@ -169,6 +170,10 @@ private: bool mStarted; + inline const sp &getDecoder(bool audio) { + return audio ? mAudioDecoder : mVideoDecoder; + } + void openAudioSink(const sp &format, bool offloadOnly); void closeAudioSink(); @@ -185,7 +190,9 @@ private: void finishFlushIfPossible(); - void flushDecoder(bool audio, bool needShutdown); + void flushDecoder( + bool audio, bool needShutdown, const sp &newFormat = NULL); + void updateDecoderFormatWithoutFlush(bool audio, const sp &format); static bool IsFlushingState(FlushStatus state, bool *needShutdown = NULL); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 47c46d6e15..d1aac501f4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -71,6 +71,19 @@ status_t PostAndAwaitResponse( return err; } +void NuPlayer::Decoder::rememberCodecSpecificData(const sp &format) { + mCSDsForCurrentFormat.clear(); + for (int32_t i = 0; ; ++i) { + AString tag = "csd-"; + tag.append(i); + sp buffer; + if (!format->findBuffer(tag.c_str(), &buffer)) { + break; + } + mCSDsForCurrentFormat.push(buffer); + } +} + void NuPlayer::Decoder::onConfigure(const sp &format) { CHECK(mCodec == NULL); @@ -123,6 +136,8 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { handleError(err); return; } + rememberCodecSpecificData(format); + // the following should work in configured state CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat)); CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat)); @@ -189,6 +204,12 @@ void NuPlayer::Decoder::configure(const sp &format) { msg->post(); } +void NuPlayer::Decoder::signalUpdateFormat(const sp &format) { + sp msg = new AMessage(kWhatUpdateFormat, id()); + msg->setMessage("format", format); + msg->post(); +} + status_t NuPlayer::Decoder::getInputBuffers(Vector > *buffers) const { sp msg = new AMessage(kWhatGetInputBuffers, id()); msg->setPointer("buffers", buffers); @@ -229,6 +250,15 @@ bool NuPlayer::Decoder::handleAnInputBuffer() { reply->setSize("buffer-ix", bufferIx); reply->setInt32("generation", mBufferGeneration); + if (!mCSDsToSubmit.isEmpty()) { + sp buffer = mCSDsToSubmit.itemAt(0); + ALOGI("[%s] resubmitting CSD", mComponentName.c_str()); + reply->setBuffer("buffer", buffer); + mCSDsToSubmit.removeAt(0); + reply->post(); + return true; + } + sp notify = mNotify->dup(); notify->setInt32("what", kWhatFillThisBuffer); notify->setBuffer("buffer", mInputBuffers[bufferIx]); @@ -312,10 +342,12 @@ void android::NuPlayer::Decoder::onInputBufferFilled(const sp &msg) { uint32_t flags = 0; CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - int32_t eos; - // we do not expect CODECCONFIG or SYNCFRAME for decoder + int32_t eos, csd; + // we do not expect SYNCFRAME for decoder if (buffer->meta()->findInt32("eos", &eos) && eos) { flags |= MediaCodec::BUFFER_FLAG_EOS; + } else if (buffer->meta()->findInt32("csd", &csd) && csd) { + flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG; } // copy into codec buffer @@ -448,6 +480,7 @@ void NuPlayer::Decoder::onFlush() { status_t err = OK; if (mCodec != NULL) { err = mCodec->flush(); + mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator ++mBufferGeneration; } @@ -515,6 +548,14 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { break; } + case kWhatUpdateFormat: + { + sp format; + CHECK(msg->findMessage("format", &format)); + rememberCodecSpecificData(format); + break; + } + case kWhatGetInputBuffers: { uint32_t replyID; @@ -566,6 +607,10 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { case kWhatFlush: { + sp format; + if (msg->findMessage("new-format", &format)) { + rememberCodecSpecificData(format); + } onFlush(); break; } @@ -588,8 +633,12 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { } } -void NuPlayer::Decoder::signalFlush() { - (new AMessage(kWhatFlush, id()))->post(); +void NuPlayer::Decoder::signalFlush(const sp &format) { + sp msg = new AMessage(kWhatFlush, id()); + if (format != NULL) { + msg->setMessage("new-format", format); + } + msg->post(); } void NuPlayer::Decoder::signalResume() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index c6fc237389..67bddb8836 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -36,7 +36,8 @@ struct NuPlayer::Decoder : public AHandler { virtual void init(); status_t getInputBuffers(Vector > *dstBuffers) const; - virtual void signalFlush(); + virtual void signalFlush(const sp &format = NULL); + virtual void signalUpdateFormat(const sp &format); virtual void signalResume(); virtual void initiateShutdown(); @@ -67,6 +68,7 @@ private: kWhatRenderBuffer = 'rndr', kWhatFlush = 'flus', kWhatShutdown = 'shuD', + kWhatUpdateFormat = 'uFmt', }; sp mNotify; @@ -80,6 +82,8 @@ private: Vector > mInputBuffers; Vector > mOutputBuffers; + Vector > mCSDsForCurrentFormat; + Vector > mCSDsToSubmit; Vector mInputBufferIsDequeued; Vector mMediaBuffers; @@ -103,6 +107,7 @@ private: AString mComponentName; bool supportsSeamlessAudioFormatChange(const sp &targetFormat) const; + void rememberCodecSpecificData(const sp &format); DISALLOW_EVIL_CONSTRUCTORS(Decoder); }; -- 2.11.0