diff options
author | Chong Zhang <chz@google.com> | 2015-04-30 18:15:52 -0700 |
---|---|---|
committer | Chong Zhang <chz@google.com> | 2015-05-01 19:06:38 -0700 |
commit | d291c222357303b9611cab89d0c3b047584ef377 (patch) | |
tree | 953551d93d5a215cefb14470387ff7494c9b60e5 | |
parent | 64da6f045b1a1d1b8f01391b6e37287f77f85d1e (diff) | |
download | frameworks_av-d291c222357303b9611cab89d0c3b047584ef377.zip frameworks_av-d291c222357303b9611cab89d0c3b047584ef377.tar.gz frameworks_av-d291c222357303b9611cab89d0c3b047584ef377.tar.bz2 |
MediaCodec: implement persistent input surface APIs
Bug: 19127604
Bug: 19489395
Change-Id: Idaf1cc9008016f66903e93907a676f54e342e1a3
-rw-r--r-- | include/media/IOMX.h | 9 | ||||
-rw-r--r-- | include/media/stagefright/ACodec.h | 3 | ||||
-rw-r--r-- | include/media/stagefright/CodecBase.h | 4 | ||||
-rw-r--r-- | include/media/stagefright/MediaCodec.h | 6 | ||||
-rw-r--r-- | include/media/stagefright/MediaFilter.h | 3 | ||||
-rw-r--r-- | include/media/stagefright/PersistentSurface.h | 51 | ||||
-rw-r--r-- | media/libmedia/IOMX.cpp | 83 | ||||
-rw-r--r-- | media/libstagefright/ACodec.cpp | 96 | ||||
-rw-r--r-- | media/libstagefright/MediaCodec.cpp | 59 | ||||
-rw-r--r-- | media/libstagefright/OMXClient.cpp | 23 | ||||
-rw-r--r-- | media/libstagefright/filters/MediaFilter.cpp | 5 | ||||
-rw-r--r-- | media/libstagefright/include/OMX.h | 8 | ||||
-rw-r--r-- | media/libstagefright/include/OMXNodeInstance.h | 9 | ||||
-rw-r--r-- | media/libstagefright/omx/GraphicBufferSource.cpp | 105 | ||||
-rw-r--r-- | media/libstagefright/omx/GraphicBufferSource.h | 13 | ||||
-rw-r--r-- | media/libstagefright/omx/OMX.cpp | 15 | ||||
-rw-r--r-- | media/libstagefright/omx/OMXNodeInstance.cpp | 71 |
17 files changed, 502 insertions, 61 deletions
diff --git a/include/media/IOMX.h b/include/media/IOMX.h index 6def65b..df3aeca 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -20,6 +20,7 @@ #include <binder/IInterface.h> #include <gui/IGraphicBufferProducer.h> +#include <gui/IGraphicBufferConsumer.h> #include <ui/GraphicBuffer.h> #include <utils/List.h> #include <utils/String8.h> @@ -113,6 +114,14 @@ public: node_id node, OMX_U32 port_index, sp<IGraphicBufferProducer> *bufferProducer) = 0; + virtual status_t createPersistentInputSurface( + sp<IGraphicBufferProducer> *bufferProducer, + sp<IGraphicBufferConsumer> *bufferConsumer) = 0; + + virtual status_t usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp<IGraphicBufferConsumer> &bufferConsumer) = 0; + virtual status_t signalEndOfInputStream(node_id node) = 0; // This API clearly only makes sense if the caller lives in the diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index c14e6c0..f941512 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -44,6 +44,8 @@ struct ACodec : public AHierarchicalStateMachine, public CodecBase { virtual void initiateAllocateComponent(const sp<AMessage> &msg); virtual void initiateConfigureComponent(const sp<AMessage> &msg); virtual void initiateCreateInputSurface(); + virtual void initiateUsePersistentInputSurface( + const sp<PersistentSurface> &surface); virtual void initiateStart(); virtual void initiateShutdown(bool keepComponentAllocated = false); @@ -114,6 +116,7 @@ private: kWhatAllocateComponent = 'allo', kWhatConfigureComponent = 'conf', kWhatCreateInputSurface = 'cisf', + kWhatUsePersistentInputSurface = 'pisf', kWhatSignalEndOfInputStream = 'eois', kWhatStart = 'star', kWhatRequestIDRFrame = 'ridr', diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h index 1bf27a6..ce53eda 100644 --- a/include/media/stagefright/CodecBase.h +++ b/include/media/stagefright/CodecBase.h @@ -26,6 +26,7 @@ namespace android { struct ABuffer; +struct PersistentSurface; struct CodecBase : public AHandler { enum { @@ -39,6 +40,7 @@ struct CodecBase : public AHandler { kWhatComponentAllocated = 'cAll', kWhatComponentConfigured = 'cCon', kWhatInputSurfaceCreated = 'isfc', + kWhatInputSurfaceAccepted = 'isfa', kWhatSignaledInputEOS = 'seos', kWhatBuffersAllocated = 'allc', }; @@ -48,6 +50,8 @@ struct CodecBase : public AHandler { virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0; virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0; virtual void initiateCreateInputSurface() = 0; + virtual void initiateUsePersistentInputSurface( + const sp<PersistentSurface> &surface) = 0; virtual void initiateStart() = 0; virtual void initiateShutdown(bool keepComponentAllocated = false) = 0; diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h index e232ce6..bab1426 100644 --- a/include/media/stagefright/MediaCodec.h +++ b/include/media/stagefright/MediaCodec.h @@ -37,6 +37,7 @@ class IMemory; struct MemoryDealer; class IResourceManagerClient; class IResourceManagerService; +struct PersistentSurface; struct SoftwareRenderer; struct Surface; @@ -67,6 +68,8 @@ struct MediaCodec : public AHandler { static sp<MediaCodec> CreateByComponentName( const sp<ALooper> &looper, const char *name, status_t *err = NULL); + static sp<PersistentSurface> CreatePersistentInputSurface(); + status_t configure( const sp<AMessage> &format, const sp<Surface> &nativeWindow, @@ -77,6 +80,8 @@ struct MediaCodec : public AHandler { status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer); + status_t usePersistentInputSurface(const sp<PersistentSurface> &surface); + status_t start(); // Returns to a state in which the component remains allocated but @@ -180,6 +185,7 @@ private: kWhatInit = 'init', kWhatConfigure = 'conf', kWhatCreateInputSurface = 'cisf', + kWhatUsePersistentInputSurface = 'pisf', kWhatStart = 'strt', kWhatStop = 'stop', kWhatRelease = 'rele', diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h index 7b3f700..fdd2a34 100644 --- a/include/media/stagefright/MediaFilter.h +++ b/include/media/stagefright/MediaFilter.h @@ -34,6 +34,9 @@ struct MediaFilter : public CodecBase { virtual void initiateAllocateComponent(const sp<AMessage> &msg); virtual void initiateConfigureComponent(const sp<AMessage> &msg); virtual void initiateCreateInputSurface(); + virtual void initiateUsePersistentInputSurface( + const sp<PersistentSurface> &surface); + virtual void initiateStart(); virtual void initiateShutdown(bool keepComponentAllocated = false); diff --git a/include/media/stagefright/PersistentSurface.h b/include/media/stagefright/PersistentSurface.h new file mode 100644 index 0000000..a35b9f1 --- /dev/null +++ b/include/media/stagefright/PersistentSurface.h @@ -0,0 +1,51 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PERSISTENT_SURFACE_H_ + +#define PERSISTENT_SURFACE_H_ + +#include <gui/IGraphicBufferProducer.h> +#include <gui/IGraphicBufferConsumer.h> +#include <media/stagefright/foundation/ABase.h> + +namespace android { + +struct PersistentSurface : public RefBase { + PersistentSurface( + const sp<IGraphicBufferProducer>& bufferProducer, + const sp<IGraphicBufferConsumer>& bufferConsumer) : + mBufferProducer(bufferProducer), + mBufferConsumer(bufferConsumer) { } + + sp<IGraphicBufferProducer> getBufferProducer() const { + return mBufferProducer; + } + + sp<IGraphicBufferConsumer> getBufferConsumer() const { + return mBufferConsumer; + } + +private: + const sp<IGraphicBufferProducer> mBufferProducer; + const sp<IGraphicBufferConsumer> mBufferConsumer; + + DISALLOW_EVIL_CONSTRUCTORS(PersistentSurface); +}; + +} // namespace android + +#endif // PERSISTENT_SURFACE_H_ 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<IGraphicBufferProducer> *bufferProducer, + sp<IGraphicBufferConsumer> *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<IGraphicBufferConsumer> &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<IGraphicBufferProducer> bufferProducer; + sp<IGraphicBufferConsumer> 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<IGraphicBufferConsumer> bufferConsumer = + interface_cast<IGraphicBufferConsumer>(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 <media/stagefright/MediaDefs.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXCodec.h> - +#include <media/stagefright/PersistentSurface.h> #include <media/hardware/HardwareAPI.h> #include <OMX_AudioExt.h> @@ -260,9 +260,12 @@ private: bool onConfigureComponent(const sp<AMessage> &msg); void onCreateInputSurface(const sp<AMessage> &msg); + void onUsePersistentInputSurface(const sp<AMessage> &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<PersistentSurface> &surface) { + sp<AMessage> 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<AMessage> &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<AMessage> &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<AMessage> & /* msg */) { - ALOGV("onCreateInputSurface"); - - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatInputSurfaceCreated); - - sp<IGraphicBufferProducer> 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<AMessage> & /* msg */) { + ALOGV("onCreateInputSurface"); + + sp<AMessage> notify = mCodec->mNotify->dup(); + notify->setInt32("what", CodecBase::kWhatInputSurfaceCreated); + + sp<IGraphicBufferProducer> 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<AMessage> &msg) { + ALOGV("onUsePersistentInputSurface"); + + sp<AMessage> notify = mCodec->mNotify->dup(); + notify->setInt32("what", CodecBase::kWhatInputSurfaceAccepted); + + sp<RefBase> obj; + CHECK(msg->findObject("input-surface", &obj)); + sp<PersistentSurface> surface = static_cast<PersistentSurface *>(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 <binder/MemoryDealer.h> #include <gui/Surface.h> #include <media/ICrypto.h> +#include <media/IOMX.h> #include <media/IResourceManagerService.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> @@ -42,6 +43,9 @@ #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MediaFilter.h> #include <media/stagefright/MetaData.h> +#include <media/stagefright/OMXClient.h> +#include <media/stagefright/OMXCodec.h> +#include <media/stagefright/PersistentSurface.h> #include <private/android_filesystem_config.h> #include <utils/Log.h> #include <utils/Singleton.h> @@ -309,6 +313,26 @@ sp<MediaCodec> MediaCodec::CreateByComponentName( return ret == OK ? codec : NULL; // NULL deallocates codec. } +// static +sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() { + OMXClient client; + CHECK_EQ(client.connect(), (status_t)OK); + sp<IOMX> omx = client.interface(); + + sp<IGraphicBufferProducer> bufferProducer; + sp<IGraphicBufferConsumer> 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<ALooper> &looper) : mState(UNINITIALIZED), mLooper(looper), @@ -523,6 +547,15 @@ status_t MediaCodec::configure( return err; } +status_t MediaCodec::usePersistentInputSurface( + const sp<PersistentSurface> &surface) { + sp<AMessage> msg = new AMessage(kWhatUsePersistentInputSurface, this); + msg->setObject("input-surface", surface.get()); + + sp<AMessage> response; + return PostAndAwaitResponse(msg, &response); +} + status_t MediaCodec::createInputSurface( sp<IGraphicBufferProducer>* bufferProducer) { sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, this); @@ -1230,6 +1263,20 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } + case CodecBase::kWhatInputSurfaceAccepted: + { + // response to initiateUsePersistentInputSurface() + status_t err = NO_ERROR; + sp<AMessage> 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<AMessage> &msg) { } case kWhatCreateInputSurface: + case kWhatUsePersistentInputSurface: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); @@ -1651,10 +1699,17 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } mReplyID = replyID; - mCodec->initiateCreateInputSurface(); + if (msg->what() == kWhatCreateInputSurface) { + mCodec->initiateCreateInputSurface(); + } else { + sp<RefBase> obj; + CHECK(msg->findObject("input-surface", &obj)); + + mCodec->initiateUsePersistentInputSurface( + static_cast<PersistentSurface *>(obj.get())); + } break; } - case kWhatStart: { sp<AReplyToken> 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<IGraphicBufferProducer> *bufferProducer); + virtual status_t createPersistentInputSurface( + sp<IGraphicBufferProducer> *bufferProducer, + sp<IGraphicBufferConsumer> *bufferConsumer); + + virtual status_t usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp<IGraphicBufferConsumer> &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<IGraphicBufferProducer> *bufferProducer, + sp<IGraphicBufferConsumer> *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<IGraphicBufferConsumer> &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<PersistentSurface> & /* 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<IGraphicBufferProducer> *bufferProducer); + virtual status_t createPersistentInputSurface( + sp<IGraphicBufferProducer> *bufferProducer, + sp<IGraphicBufferConsumer> *bufferConsumer); + + virtual status_t usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp<IGraphicBufferConsumer> &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<IGraphicBufferProducer> *bufferProducer); + static status_t createPersistentInputSurface( + sp<IGraphicBufferProducer> *bufferProducer, + sp<IGraphicBufferConsumer> *bufferConsumer); + + status_t usePersistentInputSurface( + OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &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<IGraphicBufferConsumer> consumer = NULL); sp<GraphicBufferSource> getGraphicBufferSource(); void setGraphicBufferSource(const sp<GraphicBufferSource>& 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<IGraphicBufferConsumer> &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<IGraphicBufferConsumer> &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<IGraphicBufferProducer> mProducer; sp<IGraphicBufferConsumer> 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<IGraphicBufferProducer> *bufferProducer, + sp<IGraphicBufferConsumer> *bufferConsumer) { + return OMXNodeInstance::createPersistentInputSurface( + bufferProducer, bufferConsumer); +} + +status_t OMX::usePersistentInputSurface( + node_id node, OMX_U32 port_index, + const sp<IGraphicBufferConsumer> &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<IGraphicBufferProducer> *bufferProducer) { - Mutex::Autolock autolock(mLock); +status_t OMXNodeInstance::createGraphicBufferSource( + OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer) { status_t err; const sp<GraphicBufferSource>& 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<GraphicBufferSource> 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<IGraphicBufferProducer> *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<IGraphicBufferProducer> *bufferProducer, + sp<IGraphicBufferConsumer> *bufferConsumer) { + String8 name("GraphicBufferSource"); + + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> 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<BufferQueue::ProxyConsumerListener> 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<IGraphicBufferConsumer> &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 |