From d291c222357303b9611cab89d0c3b047584ef377 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 30 Apr 2015 18:15:52 -0700 Subject: MediaCodec: implement persistent input surface APIs Bug: 19127604 Bug: 19489395 Change-Id: Idaf1cc9008016f66903e93907a676f54e342e1a3 --- media/libmedia/IOMX.cpp | 83 ++++++++++++++++++ media/libstagefright/ACodec.cpp | 96 +++++++++++++++++---- media/libstagefright/MediaCodec.cpp | 59 ++++++++++++- media/libstagefright/OMXClient.cpp | 23 +++++ media/libstagefright/filters/MediaFilter.cpp | 5 ++ media/libstagefright/include/OMX.h | 8 ++ media/libstagefright/include/OMXNodeInstance.h | 9 ++ media/libstagefright/omx/GraphicBufferSource.cpp | 105 ++++++++++++++++------- media/libstagefright/omx/GraphicBufferSource.h | 13 ++- media/libstagefright/omx/OMX.cpp | 15 ++++ media/libstagefright/omx/OMXNodeInstance.cpp | 71 +++++++++++++-- 11 files changed, 426 insertions(+), 61 deletions(-) (limited to 'media') diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index e208df9..39b135b 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -41,6 +41,8 @@ enum { USE_BUFFER, USE_GRAPHIC_BUFFER, CREATE_INPUT_SURFACE, + CREATE_PERSISTENT_INPUT_SURFACE, + USE_PERSISTENT_INPUT_SURFACE, SIGNAL_END_OF_INPUT_STREAM, STORE_META_DATA_IN_BUFFERS, PREPARE_FOR_ADAPTIVE_PLAYBACK, @@ -326,6 +328,51 @@ public: return err; } + virtual status_t createPersistentInputSurface( + sp *bufferProducer, + sp *bufferConsumer) { + Parcel data, reply; + status_t err; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + err = remote()->transact(CREATE_PERSISTENT_INPUT_SURFACE, data, &reply); + if (err != OK) { + ALOGW("binder transaction failed: %d", err); + return err; + } + + err = reply.readInt32(); + if (err != OK) { + return err; + } + + *bufferProducer = IGraphicBufferProducer::asInterface( + reply.readStrongBinder()); + *bufferConsumer = IGraphicBufferConsumer::asInterface( + reply.readStrongBinder()); + + return err; + } + + virtual status_t usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp &bufferConsumer) { + Parcel data, reply; + data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + status_t err; + data.writeInt32((int32_t)node); + data.writeInt32(port_index); + data.writeStrongBinder(IInterface::asBinder(bufferConsumer)); + + err = remote()->transact(USE_PERSISTENT_INPUT_SURFACE, data, &reply); + + if (err != OK) { + ALOGW("binder transaction failed: %d", err); + return err; + } + return reply.readInt32(); + } + + virtual status_t signalEndOfInputStream(node_id node) { Parcel data, reply; status_t err; @@ -781,6 +828,42 @@ status_t BnOMX::onTransact( return NO_ERROR; } + case CREATE_PERSISTENT_INPUT_SURFACE: + { + CHECK_OMX_INTERFACE(IOMX, data, reply); + + sp bufferProducer; + sp bufferConsumer; + status_t err = createPersistentInputSurface( + &bufferProducer, &bufferConsumer); + + reply->writeInt32(err); + + if (err == OK) { + reply->writeStrongBinder(IInterface::asBinder(bufferProducer)); + reply->writeStrongBinder(IInterface::asBinder(bufferConsumer)); + } + + return NO_ERROR; + } + + case USE_PERSISTENT_INPUT_SURFACE: + { + CHECK_OMX_INTERFACE(IOMX, data, reply); + + node_id node = (node_id)data.readInt32(); + OMX_U32 port_index = data.readInt32(); + + sp bufferConsumer = + interface_cast(data.readStrongBinder()); + + status_t err = usePersistentInputSurface( + node, port_index, bufferConsumer); + + reply->writeInt32(err); + return NO_ERROR; + } + case SIGNAL_END_OF_INPUT_STREAM: { CHECK_OMX_INTERFACE(IOMX, data, reply); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 7b87676..5001c16 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -41,7 +41,7 @@ #include #include #include - +#include #include #include @@ -260,9 +260,12 @@ private: bool onConfigureComponent(const sp &msg); void onCreateInputSurface(const sp &msg); + void onUsePersistentInputSurface(const sp &msg); void onStart(); void onShutdown(bool keepComponentAllocated); + status_t setupInputSurface(); + DISALLOW_EVIL_CONSTRUCTORS(LoadedState); }; @@ -480,6 +483,13 @@ void ACodec::initiateCreateInputSurface() { (new AMessage(kWhatCreateInputSurface, this))->post(); } +void ACodec::initiateUsePersistentInputSurface( + const sp &surface) { + sp msg = new AMessage(kWhatUsePersistentInputSurface, this); + msg->setObject("input-surface", surface); + msg->post(); +} + void ACodec::signalEndOfInputStream() { (new AMessage(kWhatSignalEndOfInputStream, this))->post(); } @@ -4200,6 +4210,7 @@ bool ACodec::BaseState::onMessageReceived(const sp &msg) { } case ACodec::kWhatCreateInputSurface: + case ACodec::kWhatUsePersistentInputSurface: case ACodec::kWhatSignalEndOfInputStream: { // This may result in an app illegal state exception. @@ -5095,6 +5106,13 @@ bool ACodec::LoadedState::onMessageReceived(const sp &msg) { break; } + case ACodec::kWhatUsePersistentInputSurface: + { + onUsePersistentInputSurface(msg); + handled = true; + break; + } + case ACodec::kWhatStart: { onStart(); @@ -5162,20 +5180,10 @@ bool ACodec::LoadedState::onConfigureComponent( return true; } -void ACodec::LoadedState::onCreateInputSurface( - const sp & /* msg */) { - ALOGV("onCreateInputSurface"); - - sp notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatInputSurfaceCreated); - - sp bufferProducer; - status_t err; - - err = mCodec->mOMX->createInputSurface(mCodec->mNode, kPortIndexInput, - &bufferProducer); +status_t ACodec::LoadedState::setupInputSurface() { + status_t err = OK; - if (err == OK && mCodec->mRepeatFrameDelayUs > 0ll) { + if (mCodec->mRepeatFrameDelayUs > 0ll) { err = mCodec->mOMX->setInternalOption( mCodec->mNode, kPortIndexInput, @@ -5188,10 +5196,11 @@ void ACodec::LoadedState::onCreateInputSurface( "frames (err %d)", mCodec->mComponentName.c_str(), err); + return err; } } - if (err == OK && mCodec->mMaxPtsGapUs > 0ll) { + if (mCodec->mMaxPtsGapUs > 0ll) { err = mCodec->mOMX->setInternalOption( mCodec->mNode, kPortIndexInput, @@ -5203,10 +5212,11 @@ void ACodec::LoadedState::onCreateInputSurface( ALOGE("[%s] Unable to configure max timestamp gap (err %d)", mCodec->mComponentName.c_str(), err); + return err; } } - if (err == OK && mCodec->mMaxFps > 0) { + if (mCodec->mMaxFps > 0) { err = mCodec->mOMX->setInternalOption( mCodec->mNode, kPortIndexInput, @@ -5218,10 +5228,11 @@ void ACodec::LoadedState::onCreateInputSurface( ALOGE("[%s] Unable to configure max fps (err %d)", mCodec->mComponentName.c_str(), err); + return err; } } - if (err == OK && mCodec->mTimePerCaptureUs > 0ll + if (mCodec->mTimePerCaptureUs > 0ll && mCodec->mTimePerFrameUs > 0ll) { int64_t timeLapse[2]; timeLapse[0] = mCodec->mTimePerFrameUs; @@ -5237,10 +5248,11 @@ void ACodec::LoadedState::onCreateInputSurface( ALOGE("[%s] Unable to configure time lapse (err %d)", mCodec->mComponentName.c_str(), err); + return err; } } - if (err == OK && mCodec->mCreateInputBuffersSuspended) { + if (mCodec->mCreateInputBuffersSuspended) { bool suspend = true; err = mCodec->mOMX->setInternalOption( mCodec->mNode, @@ -5253,9 +5265,28 @@ void ACodec::LoadedState::onCreateInputSurface( ALOGE("[%s] Unable to configure option to suspend (err %d)", mCodec->mComponentName.c_str(), err); + return err; } } + return OK; +} + +void ACodec::LoadedState::onCreateInputSurface( + const sp & /* msg */) { + ALOGV("onCreateInputSurface"); + + sp notify = mCodec->mNotify->dup(); + notify->setInt32("what", CodecBase::kWhatInputSurfaceCreated); + + sp bufferProducer; + status_t err = mCodec->mOMX->createInputSurface( + mCodec->mNode, kPortIndexInput, &bufferProducer); + + if (err == OK) { + err = setupInputSurface(); + } + if (err == OK) { notify->setObject("input-surface", new BufferProducerWrapper(bufferProducer)); @@ -5270,6 +5301,35 @@ void ACodec::LoadedState::onCreateInputSurface( notify->post(); } +void ACodec::LoadedState::onUsePersistentInputSurface( + const sp &msg) { + ALOGV("onUsePersistentInputSurface"); + + sp notify = mCodec->mNotify->dup(); + notify->setInt32("what", CodecBase::kWhatInputSurfaceAccepted); + + sp obj; + CHECK(msg->findObject("input-surface", &obj)); + sp surface = static_cast(obj.get()); + + status_t err = mCodec->mOMX->usePersistentInputSurface( + mCodec->mNode, kPortIndexInput, surface->getBufferConsumer()); + + if (err == OK) { + err = setupInputSurface(); + } + + if (err != OK) { + // Can't use mCodec->signalError() here -- MediaCodec won't forward + // the error through because it's in the "configured" state. We + // send a kWhatInputSurfaceAccepted with an error value instead. + ALOGE("[%s] onUsePersistentInputSurface returning error %d", + mCodec->mComponentName.c_str(), err); + notify->setInt32("err", err); + } + notify->post(); +} + void ACodec::LoadedState::onStart() { ALOGV("onStart"); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 9906a10..ace7826 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -309,6 +313,26 @@ sp MediaCodec::CreateByComponentName( return ret == OK ? codec : NULL; // NULL deallocates codec. } +// static +sp MediaCodec::CreatePersistentInputSurface() { + OMXClient client; + CHECK_EQ(client.connect(), (status_t)OK); + sp omx = client.interface(); + + sp bufferProducer; + sp bufferConsumer; + + status_t err = omx->createPersistentInputSurface( + &bufferProducer, &bufferConsumer); + + if (err != OK) { + ALOGE("Failed to create persistent input surface."); + return NULL; + } + + return new PersistentSurface(bufferProducer, bufferConsumer); +} + MediaCodec::MediaCodec(const sp &looper) : mState(UNINITIALIZED), mLooper(looper), @@ -523,6 +547,15 @@ status_t MediaCodec::configure( return err; } +status_t MediaCodec::usePersistentInputSurface( + const sp &surface) { + sp msg = new AMessage(kWhatUsePersistentInputSurface, this); + msg->setObject("input-surface", surface.get()); + + sp response; + return PostAndAwaitResponse(msg, &response); +} + status_t MediaCodec::createInputSurface( sp* bufferProducer) { sp msg = new AMessage(kWhatCreateInputSurface, this); @@ -1230,6 +1263,20 @@ void MediaCodec::onMessageReceived(const sp &msg) { break; } + case CodecBase::kWhatInputSurfaceAccepted: + { + // response to initiateUsePersistentInputSurface() + status_t err = NO_ERROR; + sp response = new AMessage(); + if (!msg->findInt32("err", &err)) { + mHaveInputSurface = true; + } else { + response->setInt32("err", err); + } + response->postReply(mReplyID); + break; + } + case CodecBase::kWhatSignaledInputEOS: { // response to signalEndOfInputStream() @@ -1640,6 +1687,7 @@ void MediaCodec::onMessageReceived(const sp &msg) { } case kWhatCreateInputSurface: + case kWhatUsePersistentInputSurface: { sp replyID; CHECK(msg->senderAwaitsResponse(&replyID)); @@ -1651,10 +1699,17 @@ void MediaCodec::onMessageReceived(const sp &msg) { } mReplyID = replyID; - mCodec->initiateCreateInputSurface(); + if (msg->what() == kWhatCreateInputSurface) { + mCodec->initiateCreateInputSurface(); + } else { + sp obj; + CHECK(msg->findObject("input-surface", &obj)); + + mCodec->initiateUsePersistentInputSurface( + static_cast(obj.get())); + } break; } - case kWhatStart: { sp replyID; diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index 06a598f..44695ce 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -104,6 +104,14 @@ struct MuxOMX : public IOMX { node_id node, OMX_U32 port_index, sp *bufferProducer); + virtual status_t createPersistentInputSurface( + sp *bufferProducer, + sp *bufferConsumer); + + virtual status_t usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp &bufferConsumer); + virtual status_t signalEndOfInputStream(node_id node); virtual status_t allocateBuffer( @@ -340,6 +348,21 @@ status_t MuxOMX::createInputSurface( return err; } +status_t MuxOMX::createPersistentInputSurface( + sp *bufferProducer, + sp *bufferConsumer) { + // TODO: local or remote? Always use remote for now + return mRemoteOMX->createPersistentInputSurface( + bufferProducer, bufferConsumer); +} + +status_t MuxOMX::usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp &bufferConsumer) { + return getOMX(node)->usePersistentInputSurface( + node, port_index, bufferConsumer); +} + status_t MuxOMX::signalEndOfInputStream(node_id node) { return getOMX(node)->signalEndOfInputStream(node); } diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp index ecbda36..fa9d630 100644 --- a/media/libstagefright/filters/MediaFilter.cpp +++ b/media/libstagefright/filters/MediaFilter.cpp @@ -76,6 +76,11 @@ void MediaFilter::initiateCreateInputSurface() { (new AMessage(kWhatCreateInputSurface, this))->post(); } +void MediaFilter::initiateUsePersistentInputSurface( + const sp & /* surface */) { + ALOGW("initiateUsePersistentInputSurface() unsupported"); +} + void MediaFilter::initiateStart() { (new AMessage(kWhatStart, this))->post(); } diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index b5487fa..b1ee628 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -95,6 +95,14 @@ public: node_id node, OMX_U32 port_index, sp *bufferProducer); + virtual status_t createPersistentInputSurface( + sp *bufferProducer, + sp *bufferConsumer); + + virtual status_t usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp &bufferConsumer); + virtual status_t signalEndOfInputStream(node_id node); virtual status_t allocateBuffer( diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index d87b408..f31af7b 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -81,6 +81,13 @@ struct OMXNodeInstance { status_t createInputSurface( OMX_U32 portIndex, sp *bufferProducer); + static status_t createPersistentInputSurface( + sp *bufferProducer, + sp *bufferConsumer); + + status_t usePersistentInputSurface( + OMX_U32 portIndex, const sp &bufferConsumer); + status_t signalEndOfInputStream(); status_t allocateBuffer( @@ -202,6 +209,8 @@ private: OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr); + status_t createGraphicBufferSource( + OMX_U32 portIndex, sp consumer = NULL); sp getGraphicBufferSource(); void setGraphicBufferSource(const sp& bufferSource); diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 477cfc6..01cd8f0 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -38,13 +38,19 @@ namespace android { static const bool EXTRA_CHECK = true; -GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, - uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount, - bool useGraphicBufferInMeta) : +GraphicBufferSource::GraphicBufferSource( + OMXNodeInstance* nodeInstance, + uint32_t bufferWidth, + uint32_t bufferHeight, + uint32_t bufferCount, + bool useGraphicBufferInMeta, + const sp &consumer) : mInitCheck(UNKNOWN_ERROR), mNodeInstance(nodeInstance), mExecuting(false), mSuspended(false), + mIsPersistent(false), + mConsumer(consumer), mNumFramesAvailable(0), mEndOfStream(false), mEndOfStreamSent(false), @@ -74,20 +80,22 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, return; } - String8 name("GraphicBufferSource"); + if (mConsumer == NULL) { + String8 name("GraphicBufferSource"); - BufferQueue::createBufferQueue(&mProducer, &mConsumer); - mConsumer->setConsumerName(name); - mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight); - mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER); - - mInitCheck = mConsumer->setMaxAcquiredBufferCount(bufferCount); - if (mInitCheck != NO_ERROR) { - ALOGE("Unable to set BQ max acquired buffer count to %u: %d", - bufferCount, mInitCheck); - return; + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + mConsumer->setConsumerName(name); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER); + mInitCheck = mConsumer->setMaxAcquiredBufferCount(bufferCount); + if (mInitCheck != NO_ERROR) { + ALOGE("Unable to set BQ max acquired buffer count to %u: %d", + bufferCount, mInitCheck); + return; + } + } else { + mIsPersistent = true; } - + mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight); // Note that we can't create an sp<...>(this) in a ctor that will not keep a // reference once the ctor ends, as that would cause the refcount of 'this' // dropping to 0 at the end of the ctor. Since all we need is a wp<...> @@ -107,7 +115,7 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, GraphicBufferSource::~GraphicBufferSource() { ALOGV("~GraphicBufferSource"); - if (mConsumer != NULL) { + if (mConsumer != NULL && !mIsPersistent) { status_t err = mConsumer->consumerDisconnect(); if (err != NO_ERROR) { ALOGW("consumerDisconnect failed: %d", err); @@ -292,8 +300,16 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { if (id == mLatestBufferId) { CHECK_GT(mLatestBufferUseCount--, 0); } else { - mConsumer->releaseBuffer(id, codecBuffer.mFrameNumber, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + if (mIsPersistent) { + mConsumer->detachBuffer(id); + int outSlot; + mConsumer->attachBuffer(&outSlot, mBufferSlot[id]); + mConsumer->releaseBuffer(outSlot, 0, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + } else { + mConsumer->releaseBuffer(id, codecBuffer.mFrameNumber, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + } } } else { ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d", @@ -375,8 +391,15 @@ void GraphicBufferSource::suspend(bool suspend) { --mNumFramesAvailable; - mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); + if (mIsPersistent) { + mConsumer->detachBuffer(item.mBuf); + mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer); + mConsumer->releaseBuffer(item.mBuf, 0, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + } else { + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); + } } return; } @@ -463,8 +486,15 @@ bool GraphicBufferSource::fillCodecBuffer_l() { if (err != OK) { ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf); - mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + if (mIsPersistent) { + mConsumer->detachBuffer(item.mBuf); + mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer); + mConsumer->releaseBuffer(item.mBuf, 0, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + } else { + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + } } else { ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi); setLatestBuffer_l(item, dropped); @@ -540,12 +570,19 @@ void GraphicBufferSource::setLatestBuffer_l( if (mLatestBufferId >= 0) { if (mLatestBufferUseCount == 0) { - mConsumer->releaseBuffer( - mLatestBufferId, - mLatestBufferFrameNum, - EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR, - Fence::NO_FENCE); + if (mIsPersistent) { + mConsumer->detachBuffer(mLatestBufferId); + + int outSlot; + mConsumer->attachBuffer(&outSlot, mBufferSlot[mLatestBufferId]); + + mConsumer->releaseBuffer(outSlot, 0, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + } else { + mConsumer->releaseBuffer( + mLatestBufferId, mLatestBufferFrameNum, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + } } } @@ -787,8 +824,16 @@ void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) { ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf); mBufferSlot[item.mBuf] = item.mGraphicBuffer; } - mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); + + if (mIsPersistent) { + mConsumer->detachBuffer(item.mBuf); + mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer); + mConsumer->releaseBuffer(item.mBuf, 0, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); + } else { + mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); + } } return; } diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 718d2ee..1047fb3 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -50,9 +50,15 @@ struct FrameDropper; */ class GraphicBufferSource : public BufferQueue::ConsumerListener { public: - GraphicBufferSource(OMXNodeInstance* nodeInstance, - uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount, - bool useGraphicBufferInMeta = false); + GraphicBufferSource( + OMXNodeInstance* nodeInstance, + uint32_t bufferWidth, + uint32_t bufferHeight, + uint32_t bufferCount, + bool useGraphicBufferInMeta = false, + const sp &consumer = NULL + ); + virtual ~GraphicBufferSource(); // We can't throw an exception if the constructor fails, so we just set @@ -219,6 +225,7 @@ private: // Our BufferQueue interfaces. mProducer is passed to the producer through // getIGraphicBufferProducer, and mConsumer is used internally to retrieve // the buffers queued by the producer. + bool mIsPersistent; sp mProducer; sp mConsumer; diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index f8d38ff..b9e2f9c 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -377,6 +377,21 @@ status_t OMX::createInputSurface( port_index, bufferProducer); } +status_t OMX::createPersistentInputSurface( + sp *bufferProducer, + sp *bufferConsumer) { + return OMXNodeInstance::createPersistentInputSurface( + bufferProducer, bufferConsumer); +} + +status_t OMX::usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp &bufferConsumer) { + return findInstance(node)->usePersistentInputSurface( + port_index, bufferConsumer); +} + + status_t OMX::signalEndOfInputStream(node_id node) { return findInstance(node)->signalEndOfInputStream(); } diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 4779d6a..5bc1972 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -787,9 +787,8 @@ status_t OMXNodeInstance::updateGraphicBufferInMeta( return OK; } -status_t OMXNodeInstance::createInputSurface( - OMX_U32 portIndex, sp *bufferProducer) { - Mutex::Autolock autolock(mLock); +status_t OMXNodeInstance::createGraphicBufferSource( + OMX_U32 portIndex, sp bufferConsumer) { status_t err; const sp& surfaceCheck = getGraphicBufferSource(); @@ -827,19 +826,75 @@ status_t OMXNodeInstance::createInputSurface( return INVALID_OPERATION; } - GraphicBufferSource* bufferSource = new GraphicBufferSource( - this, def.format.video.nFrameWidth, def.format.video.nFrameHeight, - def.nBufferCountActual, usingGraphicBuffer); + sp bufferSource = new GraphicBufferSource(this, + def.format.video.nFrameWidth, + def.format.video.nFrameHeight, + def.nBufferCountActual, + usingGraphicBuffer, + bufferConsumer); + if ((err = bufferSource->initCheck()) != OK) { - delete bufferSource; return err; } setGraphicBufferSource(bufferSource); - *bufferProducer = bufferSource->getIGraphicBufferProducer(); return OK; } +status_t OMXNodeInstance::createInputSurface( + OMX_U32 portIndex, sp *bufferProducer) { + Mutex::Autolock autolock(mLock); + status_t err = createGraphicBufferSource(portIndex); + + if (err != OK) { + return err; + } + + *bufferProducer = mGraphicBufferSource->getIGraphicBufferProducer(); + return OK; +} + +//static +status_t OMXNodeInstance::createPersistentInputSurface( + sp *bufferProducer, + sp *bufferConsumer) { + String8 name("GraphicBufferSource"); + + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->setConsumerName(name); + consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER); + + status_t err = consumer->setMaxAcquiredBufferCount( + BufferQueue::MAX_MAX_ACQUIRED_BUFFERS); + if (err != NO_ERROR) { + ALOGE("Unable to set BQ max acquired buffer count to %u: %d", + BufferQueue::MAX_MAX_ACQUIRED_BUFFERS, err); + return err; + } + + sp proxy = + new BufferQueue::ProxyConsumerListener(NULL); + err = consumer->consumerConnect(proxy, false); + if (err != NO_ERROR) { + ALOGE("Error connecting to BufferQueue: %s (%d)", + strerror(-err), err); + return err; + } + + *bufferProducer = producer; + *bufferConsumer = consumer; + + return OK; +} + +status_t OMXNodeInstance::usePersistentInputSurface( + OMX_U32 portIndex, const sp &bufferConsumer) { + Mutex::Autolock autolock(mLock); + return createGraphicBufferSource(portIndex, bufferConsumer); +} + status_t OMXNodeInstance::signalEndOfInputStream() { // For non-Surface input, the MediaCodec should convert the call to a // pair of requests (dequeue input buffer, queue input buffer with EOS -- cgit v1.1