[libcamera-devel] [PATCH 1/1] android: camera_device: Configure one stream for identical stream requests

Hirokazu Honda hiroh at chromium.org
Thu Jan 6 10:43:23 CET 2022


An Android HAL client may request multiple identical streams. It is
redundant that a native camera device produces a separate stream for
each of the identical requests. Configure the camera with a single
stream in that case. The other identical HAL streams will be produced by
the YUV post-processor.

The Android HAL client can provide capture requests that are resolved as
they are produced by YUV post-processor. Then a buffer to be filled a
camera is not given. So the HAL adaptation layer looks up buffer
information to be passed to a camera and allocate the buffer by using
PlatformBufferAllocator.

Signed-off-by: Hirokazu Honda <hiroh at chromium.org>
---
 src/android/camera_device.cpp | 84 ++++++++++++++++++++++++++++++++++-
 src/android/camera_request.h  |  2 +
 src/android/camera_stream.cpp | 12 ++++-
 src/android/camera_stream.h   |  6 ++-
 4 files changed, 100 insertions(+), 4 deletions(-)

diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index 83825736..53533064 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -9,6 +9,7 @@

 #include <algorithm>
 #include <fstream>
+#include <set>
 #include <sys/mman.h>
 #include <unistd.h>
 #include <vector>
@@ -604,6 +605,35 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
 			continue;
 		}

+		/*
+		 * While gralloc usage flags are supposed to report usage
+		 * patterns to select a suitable buffer allocation strategy, in
+		 * practice they're also used to make other decisions, such as
+		 * selecting the actual format for the IMPLEMENTATION_DEFINED
+		 * HAL pixel format. To avoid issues, we thus have to set the
+		 * GRALLOC_USAGE_HW_CAMERA_WRITE flag unconditionally, even for
+		 * streams that will be produced in software.
+		 */
+		stream->usage |= GRALLOC_USAGE_HW_CAMERA_WRITE;
+
+		/*
+		 * If a CameraStream with the same size and format of the
+		 * current stream has already been requested, associate the two.
+		 */
+		auto iter = std::find_if(
+			streamConfigs.begin(), streamConfigs.end(),
+			[size, format](const Camera3StreamConfig &streamConfig) {
+				return streamConfig.config.size == size &&
+				       streamConfig.config.pixelFormat == format;
+			});
+		if (iter != streamConfigs.end()) {
+			/* Add usage to copy the buffer in streams[0] to stream. */
+			iter->streams[0].stream->usage |= GRALLOC_USAGE_SW_READ_OFTEN;
+			stream->usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+			iter->streams.push_back({ stream, CameraStream::Type::Mapped });
+			continue;
+		}
+
 		Camera3StreamConfig streamConfig;
 		streamConfig.streams = { { stream, CameraStream::Type::Direct } };
 		streamConfig.config.size = size;
@@ -681,10 +711,32 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
 	for (const auto &streamConfig : streamConfigs) {
 		config->addConfiguration(streamConfig.config);

+		CameraStream *directStream = nullptr;
 		for (auto &stream : streamConfig.streams) {
+			CameraStream *sourceStream = nullptr;
+
+			/*
+			 * Sets the source stream for Mapped type streams to the
+			 * same Direct type stream. The Direct type stream is
+			 * put earlier than Mapped type streams in the current
+			 * implementation. This might be broken in the future.
+			 *
+			 * \todo Remove this order assumption.
+			 */
+			if (stream.type == CameraStream::Type::Mapped) {
+				ASSERT(directStream);
+				sourceStream = directStream;
+			}
+
 			streams_.emplace_back(this, config.get(), stream.type,
-					      stream.stream, config->size() - 1);
+					      stream.stream,
+					      sourceStream,
+					      config->size() - 1);
 			stream.stream->priv = static_cast<void *>(&streams_.back());
+			if (!directStream &&
+			    stream.type == CameraStream::Type::Direct) {
+				directStream = &streams_.back();
+			}
 		}
 	}

@@ -917,6 +969,8 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 	LOG(HAL, Debug) << "Queueing request " << descriptor->request_->cookie()
 			<< " with " << descriptor->buffers_.size() << " streams";

+	std::set<CameraStream *> requiredStreams;
+	std::set<CameraStream *> providedStreams;
 	for (const auto &[i, buffer] : utils::enumerate(descriptor->buffers_)) {
 		CameraStream *cameraStream = buffer.stream;
 		camera3_stream_t *camera3Stream = cameraStream->camera3Stream();
@@ -947,6 +1001,8 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques

 			descriptor->pendingStreamsToProcess_.insert(
 				{ cameraStream, &buffer });
+			ASSERT(cameraStream->sourceStream());
+			requiredStreams.insert(cameraStream->sourceStream());
 			continue;

 		case CameraStream::Type::Direct:
@@ -990,8 +1046,32 @@ 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));
+		providedStreams.insert(cameraStream);
 	}

+	for (CameraStream *requiredStream : requiredStreams) {
+		if (providedStreams.find(requiredStream) != providedStreams.end())
+			continue;
+
+		/* \todo Can we Map stream to Internal type stream? */
+		ASSERT(requiredStream->type() == CameraStream::Type::Direct);
+
+		FrameBuffer *frameBuffer = requiredStream->getBuffer();
+		if (!frameBuffer) {
+			LOG(HAL, Error) << "Failed to create frame buffer";
+			return -ENOMEM;
+		}
+
+		/*
+		 * addBuffer() lets a buffer for requiredStream be output by
+		 * camera. Records frameBuffer with requiredStream to call
+		 * putBuffer() after post-processing is complete.
+		 */
+		descriptor->request_->addBuffer(requiredStream->stream(),
+						frameBuffer, nullptr);
+		MutexLocker lock(descriptor->streamsProcessMutex_);
+		descriptor->putBuffers_.push_back({ requiredStream, frameBuffer });
+	}
 	/*
 	 * Translate controls from Android to libcamera and queue the request
 	 * to the camera.
@@ -1251,6 +1331,8 @@ void CameraDevice::streamProcessingComplete(Camera3RequestDescriptor::StreamBuff
 		request->pendingStreamsToProcess_.erase(streamBuffer->stream);
 		if (!request->pendingStreamsToProcess_.empty())
 			return;
+		for (auto [cameraStream, buffer] : request->putBuffers_)
+			cameraStream->putBuffer(buffer);
 	}

 	completeDescriptor(streamBuffer->request);
diff --git a/src/android/camera_request.h b/src/android/camera_request.h
index 37b6ae32..7a41c6d9 100644
--- a/src/android/camera_request.h
+++ b/src/android/camera_request.h
@@ -59,6 +59,8 @@ public:
 	/* Keeps track of streams requiring post-processing. */
 	std::map<CameraStream *, StreamBuffer *> pendingStreamsToProcess_
 		LIBCAMERA_TSA_GUARDED_BY(streamsProcessMutex_);
+	std::vector<std::pair<CameraStream *, libcamera::FrameBuffer *>> putBuffers_
+		LIBCAMERA_TSA_GUARDED_BY(streamsProcessMutex_);
 	libcamera::Mutex streamsProcessMutex_;

 	Camera3RequestDescriptor(libcamera::Camera *camera,
diff --git a/src/android/camera_stream.cpp b/src/android/camera_stream.cpp
index c2157450..634cf319 100644
--- a/src/android/camera_stream.cpp
+++ b/src/android/camera_stream.cpp
@@ -52,9 +52,11 @@ LOG_DECLARE_CATEGORY(HAL)

 CameraStream::CameraStream(CameraDevice *const cameraDevice,
 			   CameraConfiguration *config, Type type,
-			   camera3_stream_t *camera3Stream, unsigned int index)
+			   camera3_stream_t *camera3Stream,
+			   CameraStream *const sourceStream, unsigned int index)
 	: cameraDevice_(cameraDevice), config_(config), type_(type),
-	  camera3Stream_(camera3Stream), index_(index)
+	  camera3Stream_(camera3Stream), sourceStream_(sourceStream),
+	  index_(index)
 {
 }

@@ -206,6 +208,12 @@ void CameraStream::flush()

 FrameBuffer *CameraStream::getBuffer()
 {
+	if (type_ == Type::Direct && !allocator_) {
+		allocator_ = std::make_unique<PlatformFrameBufferAllocator>(cameraDevice_);
+		ASSERT(!mutex_);
+		mutex_ = std::make_unique<Mutex>();
+	}
+
 	if (!allocator_)
 		return nullptr;

diff --git a/src/android/camera_stream.h b/src/android/camera_stream.h
index f9504462..4c5078b2 100644
--- a/src/android/camera_stream.h
+++ b/src/android/camera_stream.h
@@ -114,7 +114,9 @@ public:
 	};
 	CameraStream(CameraDevice *const cameraDevice,
 		     libcamera::CameraConfiguration *config, Type type,
-		     camera3_stream_t *camera3Stream, unsigned int index);
+		     camera3_stream_t *camera3Stream,
+		     CameraStream *const sourceStream,
+		     unsigned int index);
 	CameraStream(CameraStream &&other);
 	~CameraStream();

@@ -122,6 +124,7 @@ public:
 	camera3_stream_t *camera3Stream() const { return camera3Stream_; }
 	const libcamera::StreamConfiguration &configuration() const;
 	libcamera::Stream *stream() const;
+	CameraStream *sourceStream() const { return sourceStream_; }

 	int configure();
 	int process(Camera3RequestDescriptor::StreamBuffer *streamBuffer);
@@ -167,6 +170,7 @@ private:
 	const libcamera::CameraConfiguration *config_;
 	const Type type_;
 	camera3_stream_t *camera3Stream_;
+	CameraStream *const sourceStream_;
 	const unsigned int index_;

 	std::unique_ptr<PlatformFrameBufferAllocator> allocator_;
--
2.34.1.448.ga2b2bfdf31-goog


More information about the libcamera-devel mailing list