[PATCH v3 3/7] android: Correctly support multiple Mapped streams

Harvey Yang chenghaoyang at chromium.org
Wed Dec 4 17:36:28 CET 2024


The Android camera HAL supports creating streams for the Android
framework by post-processing streams produced by libcamera.

However at the moment a single Mapped stream can be associated with a
Direct stream because, after the first post-processing, the data from
the internal stream are returned preventing further post-processing
passes.

Fix this by storing the list of Direct stream buffers used as the
post-processing source in an Camera3RequestDescriptor::internalBuffers_
map to replace the single internalBuffer_ pointer and return the
internal buffers when the capture request is deleted.

Signed-off-by: Han-Lin Chen <hanlinchen at chromium.org>
Co-developed-by: Harvey Yang <chenghaoyang at chromium.org>
Signed-off-by: Harvey Yang <chenghaoyang at chromium.org>
---
 src/android/camera_device.cpp  | 66 +++++++++++++++++++---------------
 src/android/camera_request.cpp | 11 +++---
 src/android/camera_request.h   |  3 +-
 3 files changed, 47 insertions(+), 33 deletions(-)

diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index f6dadaf22..f2dd8d4fd 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -966,9 +966,10 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 	 * to a libcamera stream. Streams of type Mapped will be handled later.
 	 *
 	 * Collect the CameraStream associated to each requested capture stream.
-	 * Since requestedStreams is an std:map<>, no duplications can happen.
+	 * Since directBuffers is an std:map<>, no duplications can
+	 * happen.
 	 */
-	std::map<CameraStream *, libcamera::FrameBuffer *> requestedBuffers;
+	std::map<CameraStream *, libcamera::FrameBuffer *> directBuffers;
 	for (const auto &[i, buffer] : utils::enumerate(descriptor->buffers_)) {
 		CameraStream *cameraStream = buffer.stream;
 		camera3_stream_t *camera3Stream = cameraStream->camera3Stream();
@@ -1007,6 +1008,8 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 						  cameraStream->configuration().size);
 			frameBuffer = buffer.frameBuffer.get();
 			acquireFence = std::move(buffer.fence);
+
+			directBuffers[cameraStream] = frameBuffer;
 			LOG(HAL, Debug) << ss.str() << " (direct)";
 			break;
 
@@ -1015,13 +1018,17 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 			 * Get the frame buffer from the CameraStream internal
 			 * buffer pool.
 			 *
-			 * The buffer has to be returned to the CameraStream
-			 * once it has been processed.
+			 * The buffer will be returned to the CameraStream when
+			 * the request is destroyed.
 			 */
 			frameBuffer = cameraStream->getBuffer();
-			buffer.internalBuffer = frameBuffer;
 			buffer.srcBuffer = frameBuffer;
 
+			/*
+			 * Track the allocated internal buffers, which will be
+			 * recycled when the descriptor destroyed.
+			 */
+			descriptor->internalBuffers_[cameraStream] = frameBuffer;
 			LOG(HAL, Debug) << ss.str() << " (internal)";
 
 			descriptor->pendingStreamsToProcess_.insert(
@@ -1037,8 +1044,6 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 		auto fence = std::make_unique<Fence>(std::move(acquireFence));
 		descriptor->request_->addBuffer(cameraStream->stream(),
 						frameBuffer, std::move(fence));
-
-		requestedBuffers[cameraStream] = frameBuffer;
 	}
 
 	/*
@@ -1076,24 +1081,43 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 		 * post-processing. No need to recycle the buffer since it's
 		 * owned by Android.
 		 */
-		auto iterDirectBuffer = requestedBuffers.find(sourceStream);
-		if (iterDirectBuffer != requestedBuffers.end()) {
+		auto iterDirectBuffer = directBuffers.find(sourceStream);
+		if (iterDirectBuffer != directBuffers.end()) {
 			buffer.srcBuffer = iterDirectBuffer->second;
 			continue;
 		}
 
 		/*
-		 * If that's not the case, we need to add a buffer to the request
-		 * for this stream.
+		 * If that's not the case, we use an internal buffer allocated
+		 * from the source stream.
+		 */
+
+		/*
+		 * If an internal buffer has been requested for the source
+		 * stream before, we should reuse it.
 		 */
-		FrameBuffer *frameBuffer = cameraStream->getBuffer();
-		buffer.internalBuffer = frameBuffer;
+		auto iterInternalBuffer = descriptor->internalBuffers_.find(sourceStream);
+		if (iterInternalBuffer != descriptor->internalBuffers_.end()) {
+			buffer.srcBuffer = iterInternalBuffer->second;
+			continue;
+		}
+
+		/*
+		 * Otherwise, we need to create an internal buffer to the
+		 * request for the source stream. Get the frame buffer from the
+		 * source stream's internal buffer pool.
+		 *
+		 * The buffer will be returned to the CameraStream when the
+		 * request is destructed.
+		 */
+		FrameBuffer *frameBuffer = sourceStream->getBuffer();
 		buffer.srcBuffer = frameBuffer;
 
 		descriptor->request_->addBuffer(sourceStream->stream(),
 						frameBuffer, nullptr);
 
-		requestedBuffers[sourceStream] = frameBuffer;
+		/* Track the allocated internal buffer. */
+		descriptor->internalBuffers_[sourceStream] = frameBuffer;
 	}
 
 	/*
@@ -1253,13 +1277,6 @@ void CameraDevice::requestComplete(Request *request)
 		if (ret) {
 			setBufferStatus(*buffer, StreamBuffer::Status::Error);
 			descriptor->pendingStreamsToProcess_.erase(stream);
-
-			/*
-			 * If the framebuffer is internal to CameraStream return
-			 * it back now that we're done processing it.
-			 */
-			if (buffer->internalBuffer)
-				stream->putBuffer(buffer->internalBuffer);
 		}
 	}
 
@@ -1378,13 +1395,6 @@ void CameraDevice::streamProcessingComplete(StreamBuffer *streamBuffer,
 {
 	setBufferStatus(*streamBuffer, status);
 
-	/*
-	 * If the framebuffer is internal to CameraStream return it back now
-	 * that we're done processing it.
-	 */
-	if (streamBuffer->internalBuffer)
-		streamBuffer->stream->putBuffer(streamBuffer->internalBuffer);
-
 	Camera3RequestDescriptor *request = streamBuffer->request;
 
 	{
diff --git a/src/android/camera_request.cpp b/src/android/camera_request.cpp
index 52a3ac1f7..92e74ab6a 100644
--- a/src/android/camera_request.cpp
+++ b/src/android/camera_request.cpp
@@ -10,6 +10,7 @@
 #include <libcamera/base/span.h>
 
 #include "camera_buffer.h"
+#include "camera_stream.h"
 
 using namespace libcamera;
 
@@ -138,7 +139,12 @@ Camera3RequestDescriptor::Camera3RequestDescriptor(
 	request_ = camera->createRequest(reinterpret_cast<uint64_t>(this));
 }
 
-Camera3RequestDescriptor::~Camera3RequestDescriptor() = default;
+Camera3RequestDescriptor::~Camera3RequestDescriptor()
+{
+	/* Recycle the allocated internal buffer back to its source stream. */
+	for (auto &[sourceStream, frameBuffer] : internalBuffers_)
+		sourceStream->putBuffer(frameBuffer);
+}
 
 /**
  * \class StreamBuffer
@@ -166,9 +172,6 @@ Camera3RequestDescriptor::~Camera3RequestDescriptor() = default;
  * \var StreamBuffer::status
  * \brief Track the status of the buffer
  *
- * \var StreamBuffer::internalBuffer
- * \brief Pointer to a buffer internally handled by CameraStream (if any)
- *
  * \var StreamBuffer::srcBuffer
  * \brief Pointer to the source frame buffer used for post-processing
  *
diff --git a/src/android/camera_request.h b/src/android/camera_request.h
index 335f1985d..6b2a00795 100644
--- a/src/android/camera_request.h
+++ b/src/android/camera_request.h
@@ -49,7 +49,6 @@ public:
 	std::unique_ptr<HALFrameBuffer> frameBuffer;
 	libcamera::UniqueFD fence;
 	Status status = Status::Success;
-	libcamera::FrameBuffer *internalBuffer = nullptr;
 	const libcamera::FrameBuffer *srcBuffer = nullptr;
 	std::unique_ptr<CameraBuffer> dstBuffer;
 	Camera3RequestDescriptor *request;
@@ -85,6 +84,8 @@ public:
 	std::unique_ptr<libcamera::Request> request_;
 	std::unique_ptr<CameraMetadata> resultMetadata_;
 
+	std::map<CameraStream *, libcamera::FrameBuffer *> internalBuffers_;
+
 	bool complete_ = false;
 	Status status_ = Status::Success;
 
-- 
2.47.0.338.g60cca15819-goog



More information about the libcamera-devel mailing list