summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/omx
diff options
context:
space:
mode:
authorChong Zhang <chz@google.com>2015-06-05 18:38:28 -0700
committerChong Zhang <chz@google.com>2015-06-08 13:23:32 -0700
commitffd8cbb288f096b53df0392bf40d99b89e34bea7 (patch)
tree8eba9d637c0e08b976396089b01152166415bdab /media/libstagefright/omx
parent26a48f304a8754d655e554178ffb6d7ba4c5aac3 (diff)
downloadframeworks_av-ffd8cbb288f096b53df0392bf40d99b89e34bea7.zip
frameworks_av-ffd8cbb288f096b53df0392bf40d99b89e34bea7.tar.gz
frameworks_av-ffd8cbb288f096b53df0392bf40d99b89e34bea7.tar.bz2
fix graphic buffer leak with persistent input surface
implement PersistentProxyListener that returns buffers during period when actual listener is not connected. also clear old buffer slot in GraphicBufferSource when re-attaching. bug: 21473584 Change-Id: I3bcf1a208e745397d6cc6ce9aef9e4f5aa604f3c
Diffstat (limited to 'media/libstagefright/omx')
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.cpp79
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.h25
2 files changed, 102 insertions, 2 deletions
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index d30bba5..ac6bf0d 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -38,6 +38,72 @@ namespace android {
static const bool EXTRA_CHECK = true;
+GraphicBufferSource::PersistentProxyListener::PersistentProxyListener(
+ const wp<IGraphicBufferConsumer> &consumer,
+ const wp<ConsumerListener>& consumerListener) :
+ mConsumerListener(consumerListener),
+ mConsumer(consumer) {}
+
+GraphicBufferSource::PersistentProxyListener::~PersistentProxyListener() {}
+
+void GraphicBufferSource::PersistentProxyListener::onFrameAvailable(
+ const BufferItem& item) {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ listener->onFrameAvailable(item);
+ } else {
+ sp<IGraphicBufferConsumer> consumer(mConsumer.promote());
+ if (consumer == NULL) {
+ return;
+ }
+ BufferItem bi;
+ status_t err = consumer->acquireBuffer(&bi, 0);
+ if (err != OK) {
+ ALOGE("PersistentProxyListener: acquireBuffer failed (%d)", err);
+ return;
+ }
+
+ err = consumer->detachBuffer(bi.mBuf);
+ if (err != OK) {
+ ALOGE("PersistentProxyListener: detachBuffer failed (%d)", err);
+ return;
+ }
+
+ err = consumer->attachBuffer(&bi.mBuf, bi.mGraphicBuffer);
+ if (err != OK) {
+ ALOGE("PersistentProxyListener: attachBuffer failed (%d)", err);
+ return;
+ }
+
+ err = consumer->releaseBuffer(bi.mBuf, 0,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, bi.mFence);
+ if (err != OK) {
+ ALOGE("PersistentProxyListener: releaseBuffer failed (%d)", err);
+ }
+ }
+}
+
+void GraphicBufferSource::PersistentProxyListener::onFrameReplaced(
+ const BufferItem& item) {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ listener->onFrameReplaced(item);
+ }
+}
+
+void GraphicBufferSource::PersistentProxyListener::onBuffersReleased() {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+}
+
+void GraphicBufferSource::PersistentProxyListener::onSidebandStreamChanged() {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ listener->onSidebandStreamChanged();
+ }
+}
GraphicBufferSource::GraphicBufferSource(
OMXNodeInstance* nodeInstance,
@@ -101,7 +167,12 @@ GraphicBufferSource::GraphicBufferSource(
// dropping to 0 at the end of the ctor. Since all we need is a wp<...>
// that's what we create.
wp<BufferQueue::ConsumerListener> listener = static_cast<BufferQueue::ConsumerListener*>(this);
- sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
+ sp<IConsumerListener> proxy;
+ if (!mIsPersistent) {
+ proxy = new BufferQueue::ProxyConsumerListener(listener);
+ } else {
+ proxy = new PersistentProxyListener(mConsumer, listener);
+ }
mInitCheck = mConsumer->consumerConnect(proxy, false);
if (mInitCheck != NO_ERROR) {
@@ -312,6 +383,7 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header, int f
mConsumer->attachBuffer(&outSlot, mBufferSlot[id]);
mConsumer->releaseBuffer(outSlot, 0,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);
+ mBufferSlot[id] = NULL;
} else {
mConsumer->releaseBuffer(id, codecBuffer.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);
@@ -400,6 +472,7 @@ void GraphicBufferSource::suspend(bool suspend) {
if (mIsPersistent) {
mConsumer->detachBuffer(item.mBuf);
+ mBufferSlot[item.mBuf] = NULL;
mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer);
mConsumer->releaseBuffer(item.mBuf, 0,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
@@ -488,6 +561,7 @@ bool GraphicBufferSource::fillCodecBuffer_l() {
ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
if (mIsPersistent) {
mConsumer->detachBuffer(item.mBuf);
+ mBufferSlot[item.mBuf] = NULL;
mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer);
mConsumer->releaseBuffer(item.mBuf, 0,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
@@ -578,9 +652,9 @@ void GraphicBufferSource::setLatestBuffer_l(
int outSlot;
mConsumer->attachBuffer(&outSlot, mBufferSlot[mLatestBufferId]);
-
mConsumer->releaseBuffer(outSlot, 0,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, mLatestBufferFence);
+ mBufferSlot[mLatestBufferId] = NULL;
} else {
mConsumer->releaseBuffer(
mLatestBufferId, mLatestBufferFrameNum,
@@ -803,6 +877,7 @@ void GraphicBufferSource::onFrameAvailable(const BufferItem& /*item*/) {
if (mIsPersistent) {
mConsumer->detachBuffer(item.mBuf);
+ mBufferSlot[item.mBuf] = NULL;
mConsumer->attachBuffer(&item.mBuf, item.mGraphicBuffer);
mConsumer->releaseBuffer(item.mBuf, 0,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 555bbec..2a8c218 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -160,6 +160,31 @@ protected:
virtual void onSidebandStreamChanged();
private:
+ // PersistentProxyListener is similar to BufferQueue::ProxyConsumerListener
+ // except that it returns (acquire/detach/re-attache/release) buffers
+ // in onFrameAvailable() if the actual consumer object is no longer valid.
+ //
+ // This class is used in persistent input surface case to prevent buffer
+ // loss when onFrameAvailable() is received while we don't have a valid
+ // consumer around.
+ class PersistentProxyListener : public BnConsumerListener {
+ public:
+ PersistentProxyListener(
+ const wp<IGraphicBufferConsumer> &consumer,
+ const wp<ConsumerListener>& consumerListener);
+ virtual ~PersistentProxyListener();
+ virtual void onFrameAvailable(const BufferItem& item) override;
+ virtual void onFrameReplaced(const BufferItem& item) override;
+ virtual void onBuffersReleased() override;
+ virtual void onSidebandStreamChanged() override;
+ private:
+ // mConsumerListener is a weak reference to the IConsumerListener.
+ wp<ConsumerListener> mConsumerListener;
+ // mConsumer is a weak reference to the IGraphicBufferConsumer, use
+ // a weak ref to avoid circular ref between mConsumer and this class
+ wp<IGraphicBufferConsumer> mConsumer;
+ };
+
// Keep track of codec input buffers. They may either be available
// (mGraphicBuffer == NULL) or in use by the codec.
struct CodecBuffer {