Merge "Camera: StreamSplitter: Return overwritten buffer to input"
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 07f9491..c9f43aa 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -322,6 +322,13 @@
                         "queueing buffer to output failed (%d)", status);
             }
 
+            // If the queued buffer replaces a pending buffer in the async
+            // queue, no onBufferReleased is called by the buffer queue.
+            // Proactively trigger the callback to avoid buffer loss.
+            if (queueOutput.bufferReplaced) {
+                onBufferReleasedByOutputLocked(mOutputs[id]);
+            }
+
             ALOGV("queued buffer %#" PRIx64 " to output %p",
                     bufferItem.mGraphicBuffer->getId(), mOutputs[id].get());
         }
@@ -335,6 +342,12 @@
     ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
 
+    onBufferReleasedByOutputLocked(from);
+}
+
+void Camera3StreamSplitter::onBufferReleasedByOutputLocked(
+        const sp<IGraphicBufferProducer>& from) {
+
     sp<GraphicBuffer> buffer;
     sp<Fence> fence;
     status_t status = from->detachNextBuffer(&buffer, &fence);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 32ae073..92371ff 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -103,6 +103,11 @@
     // onFrameAvailable call to proceed.
     void onBufferReleasedByOutput(const sp<IGraphicBufferProducer>& from);
 
+    // This is the implementation of onBufferReleasedByOutput without the mutex locked.
+    // It could either be called from onBufferReleasedByOutput or from
+    // onFrameAvailable when a buffer in the async buffer queue is overwritten.
+    void onBufferReleasedByOutputLocked(const sp<IGraphicBufferProducer>& from);
+
     // When this is called, the splitter disconnects from (i.e., abandons) its
     // input queue and signals any waiting onFrameAvailable calls to wake up.
     // It still processes callbacks from other outputs, but only detaches their