From f8d717772f6d185cb07720cd5091df9b7d612e0b Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 26 Nov 2014 15:08:34 -0800 Subject: notify seek complete upon first video output frame Bug: 18541814 Change-Id: Ie4e0976885f26eb253460eab371cb181ea85f2db --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 71 ++++++++++++++++------ media/libmediaplayerservice/nuplayer/NuPlayer.h | 8 ++- .../nuplayer/NuPlayerDecoder.cpp | 25 +++++++- .../nuplayer/NuPlayerDecoder.h | 5 +- .../nuplayer/NuPlayerDecoderBase.cpp | 11 +++- .../nuplayer/NuPlayerDecoderBase.h | 5 +- .../nuplayer/NuPlayerDecoderPassThrough.cpp | 8 ++- .../nuplayer/NuPlayerDecoderPassThrough.h | 2 +- 8 files changed, 107 insertions(+), 28 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 405278c..c69f74b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -80,6 +80,21 @@ private: DISALLOW_EVIL_CONSTRUCTORS(SeekAction); }; +struct NuPlayer::ResumeDecoderAction : public Action { + ResumeDecoderAction(bool needNotify) + : mNeedNotify(needNotify) { + } + + virtual void execute(NuPlayer *player) { + player->performResumeDecoders(mNeedNotify); + } + +private: + bool mNeedNotify; + + DISALLOW_EVIL_CONSTRUCTORS(ResumeDecoderAction); +}; + struct NuPlayer::SetSurfaceAction : public Action { SetSurfaceAction(const sp &wrapper) : mWrapper(wrapper) { @@ -163,6 +178,7 @@ NuPlayer::NuPlayer() mTimedTextGeneration(0), mFlushingAudio(NONE), mFlushingVideo(NONE), + mResumePending(false), mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW), mStarted(false) { clearFlushComplete(); @@ -553,11 +569,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { new SimpleAction(&NuPlayer::performScanSources)); } - // After a flush wihtout shutdown, decoder is paused. - // Don't resume it until source is seeked, otherwise it could + // After a flush without shutdown, decoder is paused. + // Don't resume it until source seek is done, otherwise it could // start pulling stale data too soon. mDeferredActions.push_back( - new SimpleAction(&NuPlayer::performResumeDecoders)); + new ResumeDecoderAction(false /* needNotify */)); processDeferredActions(); break; @@ -747,6 +763,8 @@ void NuPlayer::onMessageReceived(const sp &msg) { } finishFlushIfPossible(); + } else if (what == DecoderBase::kWhatResumeCompleted) { + finishResume(); } else if (what == DecoderBase::kWhatError) { status_t err; if (!msg->findInt32("err", &err) || err == OK) { @@ -923,11 +941,11 @@ void NuPlayer::onMessageReceived(const sp &msg) { mDeferredActions.push_back( new SeekAction(seekTimeUs, needNotify)); - // After a flush wihtout shutdown, decoder is paused. - // Don't resume it until source is seeked, otherwise it could + // After a flush without shutdown, decoder is paused. + // Don't resume it until source seek is done, otherwise it could // start pulling stale data too soon. mDeferredActions.push_back( - new SimpleAction(&NuPlayer::performResumeDecoders)); + new ResumeDecoderAction(needNotify)); processDeferredActions(); break; @@ -1499,15 +1517,6 @@ void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) { mSource->seekTo(seekTimeUs); ++mTimedTextGeneration; - if (mDriver != NULL) { - sp driver = mDriver.promote(); - if (driver != NULL) { - if (needNotify) { - driver->notifySeekComplete(); - } - } - } - // everything's flushed, continue playback. } @@ -1593,13 +1602,39 @@ void NuPlayer::performSetSurface(const sp &wrapper) { } } -void NuPlayer::performResumeDecoders() { +void NuPlayer::performResumeDecoders(bool needNotify) { + if (needNotify) { + mResumePending = true; + if (mVideoDecoder == NULL) { + // if audio-only, we can notify seek complete now, + // as the resume operation will be relatively fast. + finishResume(); + } + } + if (mVideoDecoder != NULL) { - mVideoDecoder->signalResume(); + // When there is continuous seek, MediaPlayer will cache the seek + // position, and send down new seek request when previous seek is + // complete. Let's wait for at least one video output frame before + // notifying seek complete, so that the video thumbnail gets updated + // when seekbar is dragged. + mVideoDecoder->signalResume(needNotify); } if (mAudioDecoder != NULL) { - mAudioDecoder->signalResume(); + mAudioDecoder->signalResume(false /* needNotify */); + } +} + +void NuPlayer::finishResume() { + if (mResumePending) { + mResumePending = false; + if (mDriver != NULL) { + sp driver = mDriver.promote(); + if (driver != NULL) { + driver->notifySeekComplete(); + } + } } } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 6856af1..6be38a4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -93,6 +93,7 @@ private: struct Action; struct SeekAction; struct SetSurfaceAction; + struct ResumeDecoderAction; struct FlushDecoderAction; struct PostMessageAction; struct SimpleAction; @@ -169,6 +170,9 @@ private: FlushStatus mFlushingAudio; FlushStatus mFlushingVideo; + // Status of flush responses from the decoder and renderer. + bool mResumePending; + int32_t mVideoScalingMode; bool mStarted; @@ -205,6 +209,8 @@ private: void flushDecoder(bool audio, bool needShutdown); + void finishResume(); + void postScanSources(); void schedulePollDuration(); @@ -217,7 +223,7 @@ private: void performReset(); void performScanSources(); void performSetSurface(const sp &wrapper); - void performResumeDecoders(); + void performResumeDecoders(bool needNotify); void onSourceNotify(const sp &msg); void onClosedCaptionNotify(const sp &msg); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 0439a9a..012d33e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -58,6 +58,7 @@ NuPlayer::Decoder::Decoder( mFormatChangePending(false), mBufferGeneration(0), mPaused(true), + mResumePending(false), mComponentName("decoder") { mCodecLooper = new ALooper; mCodecLooper->setName("NPDecoder-CL"); @@ -208,6 +209,7 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { requestCodecNotification(); } mPaused = false; + mResumePending = false; } void NuPlayer::Decoder::onSetRenderer(const sp &renderer) { @@ -226,8 +228,12 @@ void NuPlayer::Decoder::onGetInputBuffers( } } -void NuPlayer::Decoder::onResume() { +void NuPlayer::Decoder::onResume(bool notifyComplete) { mPaused = false; + + if (notifyComplete) { + mResumePending = true; + } } void NuPlayer::Decoder::onFlush(bool notifyComplete) { @@ -265,6 +271,10 @@ void NuPlayer::Decoder::onFlush(bool notifyComplete) { void NuPlayer::Decoder::onShutdown(bool notifyComplete) { status_t err = OK; + + // if there is a pending resume request, notify complete now + notifyResumeCompleteIfNecessary(); + if (mCodec != NULL) { err = mCodec->release(); mCodec = NULL; @@ -494,6 +504,9 @@ bool NuPlayer::Decoder::handleAnOutputBuffer() { mSkipRenderingUntilMediaTimeUs = -1; } + // wait until 1st frame comes out to signal resume complete + notifyResumeCompleteIfNecessary(); + if (mRenderer != NULL) { // send the buffer to renderer. mRenderer->queueBuffer(mIsAudio, buffer, reply); @@ -884,5 +897,15 @@ void NuPlayer::Decoder::rememberCodecSpecificData(const sp &format) { } } +void NuPlayer::Decoder::notifyResumeCompleteIfNecessary() { + if (mResumePending) { + mResumePending = false; + + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatResumeCompleted); + notify->post(); + } +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 07401b0..2c08f0d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -42,7 +42,7 @@ protected: virtual void onConfigure(const sp &format); virtual void onSetRenderer(const sp &renderer); virtual void onGetInputBuffers(Vector > *dstBuffers); - virtual void onResume(); + virtual void onResume(bool notifyComplete); virtual void onFlush(bool notifyComplete); virtual void onShutdown(bool notifyComplete); virtual void doRequestBuffers(); @@ -85,6 +85,7 @@ private: int32_t mBufferGeneration; bool mPaused; + bool mResumePending; AString mComponentName; void handleError(int32_t err); @@ -103,6 +104,8 @@ private: bool supportsSeamlessAudioFormatChange(const sp &targetFormat) const; void rememberCodecSpecificData(const sp &format); + void notifyResumeCompleteIfNecessary(); + DISALLOW_EVIL_CONSTRUCTORS(Decoder); }; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp index 6941f77..4164350 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp @@ -86,8 +86,10 @@ void NuPlayer::DecoderBase::signalFlush() { (new AMessage(kWhatFlush, id()))->post(); } -void NuPlayer::DecoderBase::signalResume() { - (new AMessage(kWhatResume, id()))->post(); +void NuPlayer::DecoderBase::signalResume(bool notifyComplete) { + sp msg = new AMessage(kWhatResume, id()); + msg->setInt32("notifyComplete", notifyComplete); + msg->post(); } void NuPlayer::DecoderBase::initiateShutdown() { @@ -159,7 +161,10 @@ void NuPlayer::DecoderBase::onMessageReceived(const sp &msg) { case kWhatResume: { - onResume(); + int32_t notifyComplete; + CHECK(msg->findInt32("notifyComplete", ¬ifyComplete)); + + onResume(notifyComplete); break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h index 1b24c4f..5feb6a1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h @@ -38,7 +38,7 @@ struct NuPlayer::DecoderBase : public AHandler { status_t getInputBuffers(Vector > *dstBuffers) const; void signalFlush(); - void signalResume(); + void signalResume(bool notifyComplete); void initiateShutdown(); virtual void getStats( @@ -50,6 +50,7 @@ struct NuPlayer::DecoderBase : public AHandler { kWhatVideoSizeChanged = 'viSC', kWhatFlushCompleted = 'flsC', kWhatShutdownCompleted = 'shDC', + kWhatResumeCompleted = 'resC', kWhatEOS = 'eos ', kWhatError = 'err ', }; @@ -63,7 +64,7 @@ protected: virtual void onConfigure(const sp &format) = 0; virtual void onSetRenderer(const sp &renderer) = 0; virtual void onGetInputBuffers(Vector > *dstBuffers) = 0; - virtual void onResume() = 0; + virtual void onResume(bool notifyComplete) = 0; virtual void onFlush(bool notifyComplete) = 0; virtual void onShutdown(bool notifyComplete) = 0; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp index 3b4c0a7..8112e9f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp @@ -354,8 +354,14 @@ void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) { onRequestInputBuffers(); } -void NuPlayer::DecoderPassThrough::onResume() { +void NuPlayer::DecoderPassThrough::onResume(bool notifyComplete) { onRequestInputBuffers(); + + if (notifyComplete) { + sp notify = mNotify->dup(); + notify->setInt32("what", kWhatResumeCompleted); + notify->post(); + } } void NuPlayer::DecoderPassThrough::onFlush(bool notifyComplete) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h index 3fe32b6..d761b07 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h @@ -42,7 +42,7 @@ protected: virtual void onConfigure(const sp &format); virtual void onSetRenderer(const sp &renderer); virtual void onGetInputBuffers(Vector > *dstBuffers); - virtual void onResume(); + virtual void onResume(bool notifyComplete); virtual void onFlush(bool notifyComplete); virtual void onShutdown(bool notifyComplete); virtual void doRequestBuffers(); -- cgit v1.1