summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Zhang <chz@google.com>2015-04-30 18:15:52 -0700
committerChong Zhang <chz@google.com>2015-05-01 19:06:38 -0700
commitd291c222357303b9611cab89d0c3b047584ef377 (patch)
tree953551d93d5a215cefb14470387ff7494c9b60e5
parent64da6f045b1a1d1b8f01391b6e37287f77f85d1e (diff)
downloadframeworks_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.h9
-rw-r--r--include/media/stagefright/ACodec.h3
-rw-r--r--include/media/stagefright/CodecBase.h4
-rw-r--r--include/media/stagefright/MediaCodec.h6
-rw-r--r--include/media/stagefright/MediaFilter.h3
-rw-r--r--include/media/stagefright/PersistentSurface.h51
-rw-r--r--media/libmedia/IOMX.cpp83
-rw-r--r--media/libstagefright/ACodec.cpp96
-rw-r--r--media/libstagefright/MediaCodec.cpp59
-rw-r--r--media/libstagefright/OMXClient.cpp23
-rw-r--r--media/libstagefright/filters/MediaFilter.cpp5
-rw-r--r--media/libstagefright/include/OMX.h8
-rw-r--r--media/libstagefright/include/OMXNodeInstance.h9
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.cpp105
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.h13
-rw-r--r--media/libstagefright/omx/OMX.cpp15
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp71
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