From e79ee6494c2a1f2d3b1f1b1393ca85beee41a29d Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Fri, 31 Jan 2014 22:08:54 +0800 Subject: stagefright: Squashed commit of pause/resume features Add 2 APIs (suspend/resume) in MediaPlayer - API:suspend() will just pause the player and release all the decoders to replace release() which will release the whole player - API:resume() will just init the decoders again, then start() will be called to restart streaming playback - Add a check in AwesomePlayer::onVideoEvent() to make sure the first seek operation will always seek to the next i-frame Change-Id: Ie4c82906a2a056378119921a656128ebdc1007c4 audio: Add pause support for hardware omx component - ADSP doesn't enter sleep state after wma playback is paused and power suspended. - No support for NT session pause in case of hardware component. NT session need to be paused to put ADSP into power collapse. - Add support of pause in stagefright to ensure device enters suspend mode. Also add intermediate states to avoid concurrency issues between read and pause. Change-Id: I41b946b8c8805e6ee303646b63513b5b16514ef6 libstagefright: Drain input buffer on resume - Buffers returned from codec in paused state are not drained. When codec is resumed these buffers are not drained until the next flush, and may cause timed out issue. - Added change to drain input buffers for sw decoders when resuming. Change-Id: Ida2ab1d5dc3a1910accdd6fb89548262a912d8e7 CRs-Fixed: 569585, 574967 libstagefright: camcorder pause-resume implementation - Add pause resume feature in camcorder app. So that user can pause recording and resume later which results in a single recorded clip. Change-Id: Id19c45ae5bb85265aa4d5304b160ebf119d9575a libstagefright: support pause/resume for timelapse recording Modify the timestamp calculation mechanism in CameraSourceTimeLapse in order to support pause/resume. Change-Id: Icb02ea798b0b807ffb7ada2d1ef5b2414b74edfb --- media/libstagefright/OMXCodec.cpp | 92 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) (limited to 'media/libstagefright/OMXCodec.cpp') diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index b2bfceb..3ec02d4 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1614,6 +1614,8 @@ bool OMXCodec::isIntermediateState(State state) { return state == LOADED_TO_IDLE || state == IDLE_TO_EXECUTING || state == EXECUTING_TO_IDLE + || state == PAUSING + || state == FLUSHING || state == IDLE_TO_LOADED || state == RECONFIGURING; } @@ -2665,6 +2667,14 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) { break; } + case OMX_StatePause: + { + CODEC_LOGV("Now paused."); + CHECK_EQ((int)mState, (int)PAUSING); + setState(PAUSED); + break; + } + case OMX_StateInvalid: { setState(ERROR); @@ -2780,7 +2790,7 @@ void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) { bool OMXCodec::flushPortAsync(OMX_U32 portIndex) { CHECK(mState == EXECUTING || mState == RECONFIGURING - || mState == EXECUTING_TO_IDLE); + || mState == EXECUTING_TO_IDLE || mState == FLUSHING); CODEC_LOGV("flushPortAsync(%u): we own %zu out of %zu buffers already.", portIndex, countBuffersWeOwn(mPortBuffers[portIndex]), @@ -2830,7 +2840,7 @@ status_t OMXCodec::enablePortAsync(OMX_U32 portIndex) { } void OMXCodec::fillOutputBuffers() { - CHECK_EQ((int)mState, (int)EXECUTING); + CHECK(mState == EXECUTING || mState == FLUSHING); // This is a workaround for some decoders not properly reporting // end-of-output-stream. If we own all input buffers and also own @@ -2857,7 +2867,7 @@ void OMXCodec::fillOutputBuffers() { } void OMXCodec::drainInputBuffers() { - CHECK(mState == EXECUTING || mState == RECONFIGURING); + CHECK(mState == EXECUTING || mState == RECONFIGURING || mState == FLUSHING); if (mFlags & kUseSecureInputBuffers) { Vector *buffers = &mPortBuffers[kPortIndexInput]; @@ -3604,6 +3614,11 @@ void OMXCodec::clearCodecSpecificData() { status_t OMXCodec::start(MetaData *meta) { Mutex::Autolock autoLock(mLock); + if (mPaused) { + status_t err = resumeLocked(true); + return err; + } + if (mState != LOADED) { CODEC_LOGE("called start in the unexpected state: %d", mState); return UNKNOWN_ERROR; @@ -3714,6 +3729,7 @@ status_t OMXCodec::stopOmxComponent_l() { isError = true; } + case PAUSED: case EXECUTING: { setState(EXECUTING_TO_IDLE); @@ -3785,6 +3801,14 @@ status_t OMXCodec::read( Mutex::Autolock autoLock(mLock); + if (mPaused) { + err = resumeLocked(false); + if(err != OK) { + CODEC_LOGE("Failed to restart codec err= %d", err); + return err; + } + } + if (mState != EXECUTING && mState != RECONFIGURING) { return UNKNOWN_ERROR; } @@ -3841,6 +3865,8 @@ status_t OMXCodec::read( mFilledBuffers.clear(); CHECK_EQ((int)mState, (int)EXECUTING); + //DSP supports flushing of ports simultaneously. Flushing individual port is not supported. + setState(FLUSHING); bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput); bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput); @@ -3870,6 +3896,11 @@ status_t OMXCodec::read( return UNKNOWN_ERROR; } + if (seeking) { + CHECK_EQ((int)mState, (int)FLUSHING); + setState(EXECUTING); + } + if (mFilledBuffers.empty()) { return mSignalledEOS ? mFinalStatus : ERROR_END_OF_STREAM; } @@ -4303,11 +4334,60 @@ void OMXCodec::initOutputFormat(const sp &inputFormat) { } status_t OMXCodec::pause() { - Mutex::Autolock autoLock(mLock); + CODEC_LOGV("pause mState=%d", mState); + + Mutex::Autolock autoLock(mLock); + + if (mState != EXECUTING) { + return UNKNOWN_ERROR; + } + + while (isIntermediateState(mState)) { + mAsyncCompletion.wait(mLock); + } + if (!strncmp(mComponentName, "OMX.qcom.", 9)) { + status_t err = mOMX->sendCommand(mNode, + OMX_CommandStateSet, OMX_StatePause); + CHECK_EQ(err, (status_t)OK); + setState(PAUSING); + + mPaused = true; + while (mState != PAUSED && mState != ERROR) { + mAsyncCompletion.wait(mLock); + } + return mState == ERROR ? UNKNOWN_ERROR : OK; + } else { + mPaused = true; + return OK; + } - mPaused = true; +} - return OK; +status_t OMXCodec::resumeLocked(bool drainInputBuf) { + CODEC_LOGV("resume mState=%d", mState); + + if (!strncmp(mComponentName, "OMX.qcom.", 9)) { + while (isIntermediateState(mState)) { + mAsyncCompletion.wait(mLock); + } + CHECK_EQ(mState, (status_t)PAUSED); + status_t err = mOMX->sendCommand(mNode, + OMX_CommandStateSet, OMX_StateExecuting); + CHECK_EQ(err, (status_t)OK); + setState(IDLE_TO_EXECUTING); + mPaused = false; + while (mState != EXECUTING && mState != ERROR) { + mAsyncCompletion.wait(mLock); + } + if(drainInputBuf) + drainInputBuffers(); + return mState == ERROR ? UNKNOWN_ERROR : OK; + } else { // SW Codec + mPaused = false; + if(drainInputBuf) + drainInputBuffers(); + return OK; + } } //////////////////////////////////////////////////////////////////////////////// -- cgit v1.1