Release buffer slot basing on reference counter

This patch introduces counter which stores number
of references kept by CodecBuffers for each GraphicBuffer
on given slot.
The counter is decreased after codec buffers emptied
and increased after buffers submitted. When counter
becomes 0 it means that given buffer slot shall be
released.

Bug: 30024369

Cherry-picked with (rebase and fix) from:

https://android-review.googlesource.com/#/c/246510/2

Change-Id: I4ecd7902a6a525f9a598682d9cccc0f771752280
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 26b41d0..93d6584 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -139,7 +139,6 @@
     mRepeatLastFrameTimestamp(-1ll),
     mLatestBufferId(-1),
     mLatestBufferFrameNum(0),
-    mLatestBufferUseCount(0),
     mLatestBufferFence(Fence::NO_FENCE),
     mRepeatBufferDeferred(false),
     mTimePerCaptureUs(-1ll),
@@ -398,12 +397,16 @@
     sp<Fence> fence = new Fence(fenceFd);
     if (mBufferSlot[id] != NULL &&
         mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
-        ALOGV("cbi %d matches bq slot %d, handle=%p",
-                cbi, id, mBufferSlot[id]->handle);
+        mBufferUseCount[id]--;
 
-        if (id == mLatestBufferId) {
-            CHECK_GT(mLatestBufferUseCount--, 0);
-        } else {
+        ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, handle=%p",
+                id, cbi, mBufferUseCount[id], mBufferSlot[id]->handle);
+
+        if (mBufferUseCount[id] < 0) {
+            ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
+            mBufferUseCount[id] = 0;
+        }
+        if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
             releaseBuffer(id, codecBuffer.mFrameNumber, mBufferSlot[id], fence);
         }
     } else {
@@ -614,6 +617,7 @@
     if (item.mGraphicBuffer != NULL) {
         ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
         mBufferSlot[item.mSlot] = item.mGraphicBuffer;
+        mBufferUseCount[item.mSlot] = 0;
     }
 
     if (item.mDataSpace != mLastDataSpace) {
@@ -699,7 +703,7 @@
         return false;
     }
 
-    ++mLatestBufferUseCount;
+    ++mBufferUseCount[item.mSlot];
 
     /* repeat last frame up to kRepeatLastFrameCount times.
      * in case of static scene, a single repeat might not get rid of encoder
@@ -720,10 +724,8 @@
 
 void GraphicBufferSource::setLatestBuffer_l(
         const BufferItem &item, bool dropped) {
-    ALOGV("setLatestBuffer_l");
-
     if (mLatestBufferId >= 0) {
-        if (mLatestBufferUseCount == 0) {
+        if (mBufferUseCount[mLatestBufferId] == 0) {
             releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
                     mBufferSlot[mLatestBufferId], mLatestBufferFence);
             // mLatestBufferFence will be set to new fence just below
@@ -734,7 +736,13 @@
     mLatestBufferFrameNum = item.mFrameNumber;
     mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
 
-    mLatestBufferUseCount = dropped ? 0 : 1;
+    if (!dropped) {
+        ++mBufferUseCount[item.mSlot];
+    }
+
+    ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
+            item.mSlot, mBufferUseCount[item.mSlot]);
+
     mRepeatBufferDeferred = false;
     mRepeatLastFrameCount = kRepeatLastFrameCount;
     mLatestBufferFence = item.mFence;
@@ -842,7 +850,7 @@
 }
 
 status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
-    ALOGV("submitBuffer_l cbi=%d", cbi);
+    ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
 
     int64_t timeUs = getTimestamp(item);
     if (timeUs < 0ll) {
@@ -935,6 +943,7 @@
 void GraphicBufferSource::releaseBuffer(
         int &id, uint64_t frameNum,
         const sp<GraphicBuffer> buffer, const sp<Fence> &fence) {
+    ALOGV("releaseBuffer: slot=%d", id);
     if (mIsPersistent) {
         mConsumer->detachBuffer(id);
         mBufferSlot[id] = NULL;
@@ -978,6 +987,7 @@
             if (item.mGraphicBuffer != NULL) {
                 ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
                 mBufferSlot[item.mSlot] = item.mGraphicBuffer;
+                mBufferUseCount[item.mSlot] = 0;
             }
 
             releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -1011,6 +1021,7 @@
     for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
         if ((slotMask & 0x01) != 0) {
             mBufferSlot[i] = NULL;
+            mBufferUseCount[i] = 0;
         }
         slotMask >>= 1;
     }
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 30bfddb..aa4ceb3 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -295,6 +295,7 @@
     // is done processing a GraphicBuffer, we can use this to map back
     // to a slot number.
     sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+    int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
 
     // Tracks codec buffers.
     Vector<CodecBuffer> mCodecBuffers;
@@ -327,7 +328,6 @@
 
     int mLatestBufferId;
     uint64_t mLatestBufferFrameNum;
-    int32_t mLatestBufferUseCount;
     sp<Fence> mLatestBufferFence;
 
     // The previous buffer should've been repeated but