From e40cda70eec141fa05cbcca1de420fdb22b98be6 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 17 Jul 2013 13:55:26 -0700 Subject: Support "suspension" of a video encoder in "surface-input" mode. i.e. feed no more input frames to the encoder while suspended. Change-Id: I51391e18c1517548e869f8ddece19f4af37e78f9 --- include/media/IOMX.h | 10 +++++ media/libmedia/IOMX.cpp | 29 ++++++++++++ media/libstagefright/ACodec.cpp | 13 ++++++ media/libstagefright/OMXClient.cpp | 16 +++++++ media/libstagefright/include/OMX.h | 7 +++ media/libstagefright/include/OMXNodeInstance.h | 6 +++ media/libstagefright/omx/GraphicBufferSource.cpp | 48 ++++++++++++++++++-- media/libstagefright/omx/GraphicBufferSource.h | 6 +++ media/libstagefright/omx/OMX.cpp | 9 ++++ media/libstagefright/omx/OMXNodeInstance.cpp | 57 +++++++++++++++++++----- 10 files changed, 187 insertions(+), 14 deletions(-) diff --git a/include/media/IOMX.h b/include/media/IOMX.h index 0b1d1e4..38f9d11 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -130,6 +130,16 @@ public: node_id node, const char *parameter_name, OMX_INDEXTYPE *index) = 0; + + enum InternalOptionType { + INTERNAL_OPTION_SUSPEND, // data is a bool + }; + virtual status_t setInternalOption( + node_id node, + OMX_U32 port_index, + InternalOptionType type, + const void *data, + size_t size) = 0; }; struct omx_message { diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index d6cd43a..5bbb2f0 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -51,6 +51,7 @@ enum { GET_EXTENSION_INDEX, OBSERVER_ON_MSG, GET_GRAPHIC_BUFFER_USAGE, + SET_INTERNAL_OPTION, }; class BpOMX : public BpInterface { @@ -439,6 +440,24 @@ public: return err; } + + virtual status_t setInternalOption( + node_id node, + OMX_U32 port_index, + InternalOptionType type, + const void *optionData, + size_t size) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); + data.writeInt32(port_index); + data.writeInt32(size); + data.write(optionData, size); + data.writeInt32(type); + remote()->transact(SET_INTERNAL_OPTION, data, &reply); + + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX"); @@ -537,6 +556,7 @@ status_t BnOMX::onTransact( case SET_PARAMETER: case GET_CONFIG: case SET_CONFIG: + case SET_INTERNAL_OPTION: { CHECK_OMX_INTERFACE(IOMX, data, reply); @@ -562,6 +582,15 @@ status_t BnOMX::onTransact( case SET_CONFIG: err = setConfig(node, index, params, size); break; + case SET_INTERNAL_OPTION: + { + InternalOptionType type = + (InternalOptionType)data.readInt32(); + + err = setInternalOption(node, index, type, params, size); + break; + } + default: TRESPASS(); } diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 6bc7718..8d1020e 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -4106,6 +4106,19 @@ status_t ACodec::setParameters(const sp ¶ms) { } } + int32_t dropInputFrames; + if (params->findInt32("drop-input-frames", &dropInputFrames)) { + bool suspend = dropInputFrames != 0; + + CHECK_EQ((status_t)OK, + mOMX->setInternalOption( + mNode, + kPortIndexInput, + IOMX::INTERNAL_OPTION_SUSPEND, + &suspend, + sizeof(suspend))); + } + return OK; } diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index 1822f07..810d88f 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -113,6 +113,13 @@ struct MuxOMX : public IOMX { const char *parameter_name, OMX_INDEXTYPE *index); + virtual status_t setInternalOption( + node_id node, + OMX_U32 port_index, + InternalOptionType type, + const void *data, + size_t size); + private: mutable Mutex mLock; @@ -331,6 +338,15 @@ status_t MuxOMX::getExtensionIndex( return getOMX(node)->getExtensionIndex(node, parameter_name, index); } +status_t MuxOMX::setInternalOption( + node_id node, + OMX_U32 port_index, + InternalOptionType type, + const void *data, + size_t size) { + return getOMX(node)->setInternalOption(node, port_index, type, data, size); +} + OMXClient::OMXClient() { } diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index 24b8d98..7fed7d4 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -109,6 +109,13 @@ public: const char *parameter_name, OMX_INDEXTYPE *index); + virtual status_t setInternalOption( + node_id node, + OMX_U32 port_index, + InternalOptionType type, + const void *data, + size_t size); + virtual void binderDied(const wp &the_late_who); OMX_ERRORTYPE OnEvent( diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index 67aba6b..f6ae376 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -96,6 +96,12 @@ struct OMXNodeInstance { status_t getExtensionIndex( const char *parameterName, OMX_INDEXTYPE *index); + status_t setInternalOption( + OMX_U32 portIndex, + IOMX::InternalOptionType type, + const void *data, + size_t size); + void onMessage(const omx_message &msg); void onObserverDied(OMXMaster *master); void onGetHandleFailed(); diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index b3167b5..6f3ed0d 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -36,6 +36,7 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, mInitCheck(UNKNOWN_ERROR), mNodeInstance(nodeInstance), mExecuting(false), + mSuspended(false), mNumFramesAvailable(0), mEndOfStream(false), mEndOfStreamSent(false) { @@ -237,9 +238,43 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { return; } +void GraphicBufferSource::suspend(bool suspend) { + Mutex::Autolock autoLock(mMutex); + + if (suspend) { + mSuspended = true; + + while (mNumFramesAvailable > 0) { + BufferQueue::BufferItem item; + status_t err = mBufferQueue->acquireBuffer(&item, 0); + + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + // shouldn't happen. + ALOGW("suspend: frame was not available"); + break; + } else if (err != OK) { + ALOGW("suspend: acquireBuffer returned err=%d", err); + break; + } + + --mNumFramesAvailable; + + mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); + } + return; + } + + mSuspended = false; +} + bool GraphicBufferSource::fillCodecBuffer_l() { CHECK(mExecuting && mNumFramesAvailable > 0); + if (mSuspended) { + return false; + } + int cbi = findAvailableCodecBuffer_l(); if (cbi < 0) { // No buffers available, bail. @@ -416,10 +451,15 @@ void GraphicBufferSource::onFrameAvailable() { ALOGV("onFrameAvailable exec=%d avail=%d", mExecuting, mNumFramesAvailable); - if (mEndOfStream) { - // This should only be possible if a new buffer was queued after - // EOS was signaled, i.e. the app is misbehaving. - ALOGW("onFrameAvailable: EOS is set, ignoring frame"); + if (mEndOfStream || mSuspended) { + if (mEndOfStream) { + // This should only be possible if a new buffer was queued after + // EOS was signaled, i.e. the app is misbehaving. + + ALOGW("onFrameAvailable: EOS is set, ignoring frame"); + } else { + ALOGV("onFrameAvailable: suspended, ignoring frame"); + } BufferQueue::BufferItem item; status_t err = mBufferQueue->acquireBuffer(&item, 0); diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 8c6b470..ac73770 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -85,6 +85,10 @@ public: // have a codec buffer ready, we just set the mEndOfStream flag. status_t signalEndOfInputStream(); + // If suspend is true, all incoming buffers (including those currently + // in the BufferQueue) will be discarded until the suspension is lifted. + void suspend(bool suspend); + protected: // BufferQueue::ConsumerListener interface, called when a new frame of // data is available. If we're executing and a codec buffer is @@ -155,6 +159,8 @@ private: // Set by omxExecuting() / omxIdling(). bool mExecuting; + bool mSuspended; + // We consume graphic buffers from this. sp mBufferQueue; diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 3987ead..4b1dbe6 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -396,6 +396,15 @@ status_t OMX::getExtensionIndex( parameter_name, index); } +status_t OMX::setInternalOption( + node_id node, + OMX_U32 port_index, + InternalOptionType type, + const void *data, + size_t size) { + return findInstance(node)->setInternalOption(port_index, type, data, size); +} + OMX_ERRORTYPE OMX::OnEvent( node_id node, OMX_IN OMX_EVENTTYPE eEvent, diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index a9eb94f..61a866f 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -238,6 +238,18 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) { status_t OMXNodeInstance::sendCommand( OMX_COMMANDTYPE cmd, OMX_S32 param) { + const sp& bufferSource(getGraphicBufferSource()); + if (bufferSource != NULL + && cmd == OMX_CommandStateSet + && param == OMX_StateLoaded) { + // Initiating transition from Executing -> Loaded + // Buffers are about to be freed. + bufferSource->omxLoaded(); + setGraphicBufferSource(NULL); + + // fall through + } + Mutex::Autolock autoLock(mLock); OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL); @@ -769,6 +781,36 @@ status_t OMXNodeInstance::getExtensionIndex( return StatusFromOMXError(err); } +status_t OMXNodeInstance::setInternalOption( + OMX_U32 portIndex, + IOMX::InternalOptionType type, + const void *data, + size_t size) { + switch (type) { + case IOMX::INTERNAL_OPTION_SUSPEND: + { + const sp &bufferSource = + getGraphicBufferSource(); + + if (bufferSource == NULL || portIndex != kPortIndexInput) { + return ERROR_UNSUPPORTED; + } + + if (size != sizeof(bool)) { + return INVALID_OPERATION; + } + + bool suspend = *(bool *)data; + bufferSource->suspend(suspend); + + return OK; + } + + default: + return ERROR_UNSUPPORTED; + } +} + void OMXNodeInstance::onMessage(const omx_message &msg) { if (msg.type == omx_message::FILL_BUFFER_DONE) { OMX_BUFFERHEADERTYPE *buffer = @@ -818,16 +860,11 @@ void OMXNodeInstance::onEvent( OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) { const sp& bufferSource(getGraphicBufferSource()); - if (bufferSource != NULL && event == OMX_EventCmdComplete && - arg1 == OMX_CommandStateSet) { - if (arg2 == OMX_StateExecuting) { - bufferSource->omxExecuting(); - } else if (arg2 == OMX_StateLoaded) { - // Must be shutting down -- won't have a GraphicBufferSource - // on the way up. - bufferSource->omxLoaded(); - setGraphicBufferSource(NULL); - } + if (bufferSource != NULL + && event == OMX_EventCmdComplete + && arg1 == OMX_CommandStateSet + && arg2 == OMX_StateExecuting) { + bufferSource->omxExecuting(); } } -- cgit v1.1