[libcamera-devel,RFC,2/2] android: Send alternative stream configuration if no buffer to be sent exists
diff mbox series

Message ID 20210927104821.2526508-3-hiroh@chromium.org
State New
Headers show
Series
  • android: Fix the issue with Type::Mapped only request
Related show

Commit Message

Hirokazu Honda Sept. 27, 2021, 10:48 a.m. UTC
A request given in processCaptureRequest() can contain only streams
that are resolved CameraStream::Type::Mapped. In the case, no buffer
is sent to a native camera. This fixes the issue by looking for the
stream to be requested and alternatively sending a buffer for the
stream to a camera.

However, the substitute stream is Direct and a buffer needs to be
provided by a HAL client. So we have to allocate a buffer in
Android HAL adaptation layer using PlatformFrameBufferAllocator.

Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
---
 src/android/camera_device.cpp | 50 +++++++++++++++++++++++++++++------
 src/android/camera_device.h   |  4 +++
 src/android/camera_stream.cpp | 37 ++++++++++++++++++++++----
 src/android/camera_stream.h   | 10 +++++--
 4 files changed, 86 insertions(+), 15 deletions(-)

Comments

Laurent Pinchart Oct. 13, 2021, 3:40 a.m. UTC | #1
Hi Hiro,

Thank you for the patch.

On Mon, Sep 27, 2021 at 07:48:21PM +0900, Hirokazu Honda wrote:
> A request given in processCaptureRequest() can contain only streams
> that are resolved CameraStream::Type::Mapped. In the case, no buffer
> is sent to a native camera. This fixes the issue by looking for the
> stream to be requested and alternatively sending a buffer for the
> stream to a camera.
> 
> However, the substitute stream is Direct and a buffer needs to be
> provided by a HAL client. So we have to allocate a buffer in
> Android HAL adaptation layer using PlatformFrameBufferAllocator.
> 
> Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> ---
>  src/android/camera_device.cpp | 50 +++++++++++++++++++++++++++++------
>  src/android/camera_device.h   |  4 +++
>  src/android/camera_stream.cpp | 37 ++++++++++++++++++++++----
>  src/android/camera_stream.h   | 10 +++++--
>  4 files changed, 86 insertions(+), 15 deletions(-)
> 
> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
> index a693dcbe..5887e85e 100644
> --- a/src/android/camera_device.cpp
> +++ b/src/android/camera_device.cpp
> @@ -724,10 +724,14 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
>  	for (const auto &streamConfig : streamConfigs) {
>  		config->addConfiguration(streamConfig.config);
>  
> +		CameraStream *mappedStream = nullptr;

mappedStream isn't a very good name I think, as it is non-null when
constructing a Mapped CameraStream and points to a Direct stream. How
about sourceStream instead ?

>  		for (auto &stream : streamConfig.streams) {
>  			streams_.emplace_back(this, config.get(), stream.type,
> -					      stream.stream, config->size() - 1);
> +					      stream.stream, mappedStream,
> +					      config->size() - 1);
>  			stream.stream->priv = static_cast<void *>(&streams_.back());
> +			if (stream.type == CameraStream::Type::Direct)
> +				mappedStream = &streams_.back();

Is there a guarantee that a mapped stream uses the direct stream that
has been created just before it ? This seems fragile.

>  		}
>  	}
>  
> @@ -969,6 +973,8 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
>  
>  	LOG(HAL, Debug) << "Queueing request " << descriptor.request_->cookie()
>  			<< " with " << descriptor.buffers_.size() << " streams";
> +
> +	std::set<Stream *> addedStreams;
>  	for (unsigned int i = 0; i < descriptor.buffers_.size(); ++i) {
>  		const camera3_stream_buffer_t &camera3Buffer = descriptor.buffers_[i];
>  		camera3_stream *camera3Stream = camera3Buffer.stream;
> @@ -1018,6 +1024,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
>  			 * once it has been processed.
>  			 */
>  			buffer = cameraStream->getBuffer();
> +			descriptor.internalBuffers_[cameraStream] = buffer;
>  			LOG(HAL, Debug) << ss.str() << " (internal)";
>  			break;
>  		}
> @@ -1029,6 +1036,37 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
>  
>  		descriptor.request_->addBuffer(cameraStream->stream(), buffer,
>  						camera3Buffer.acquire_fence);
> +		addedStreams.insert(cameraStream->stream());
> +	}
> +
> +	for (unsigned int i = 0; i < descriptor.buffers_.size(); ++i) {
> +		const camera3_stream_buffer_t &camera3Buffer = descriptor.buffers_[i];
> +		camera3_stream *camera3Stream = camera3Buffer.stream;
> +		CameraStream *cameraStream = static_cast<CameraStream *>(camera3Stream->priv);
> +		if (cameraStream->type() != CameraStream::Type::Mapped)
> +			continue;
> +		if (addedStreams.find(cameraStream->stream()) != addedStreams.end())
> +			continue;

All this deserves comments, it's far from trivial. The code is hard to
follow in the context of this patch already, knowing what you're trying
to achieve, it will be much harder in a few months from now when reading
the implementation. The whole idea behind this needs to be captured in
comments.

> +
> +		CameraStream *mappedStream = cameraStream->mappedStream();
> +		if (!mappedStream) {
> +			LOG(HAL, Error)
> +				<< "Could not find mappedStream for ("
> +				<< camera3Stream->width << "x"
> +				<< camera3Stream->height << ")"
> +				<< "[" << utils::hex(camera3Stream->format) << "]";
> +			return -EINVAL;
> +		}
> +
> +		ASSERT(mappedStream->type() == CameraStream::Type::Direct);
> +		FrameBuffer *mappedBuffer = mappedStream->getBuffer();
> +		if (!mappedBuffer) {
> +			LOG(HAL, Error) << "Failed getting a buffer";
> +			return -EINVAL;
> +		}
> +
> +		descriptor.internalBuffers_[mappedStream] = mappedBuffer;
> +		descriptor.request_->addBuffer(mappedStream->stream(), mappedBuffer, -1);
>  	}
>  
>  	/*
> @@ -1180,13 +1218,6 @@ void CameraDevice::requestComplete(Request *request)
>  		int ret = cameraStream->process(*src, *buffer.buffer,
>  						descriptor.settings_,
>  						resultMetadata.get());
> -		/*
> -		 * Return the FrameBuffer to the CameraStream now that we're
> -		 * done processing it.
> -		 */
> -		if (cameraStream->type() == CameraStream::Type::Internal)
> -			cameraStream->putBuffer(src);
> -
>  		if (ret) {
>  			buffer.status = CAMERA3_BUFFER_STATUS_ERROR;
>  			notifyError(descriptor.frameNumber_, buffer.stream,
> @@ -1194,6 +1225,9 @@ void CameraDevice::requestComplete(Request *request)
>  		}
>  	}
>  
> +	for (auto &[stream, buffer] : descriptor.internalBuffers_)
> +		stream->putBuffer(buffer);
> +
>  	captureResult.result = resultMetadata->get();
>  	callbacks_->process_capture_result(callbacks_, &captureResult);
>  }
> diff --git a/src/android/camera_device.h b/src/android/camera_device.h
> index 296c2f18..74d8150b 100644
> --- a/src/android/camera_device.h
> +++ b/src/android/camera_device.h
> @@ -21,6 +21,7 @@
>  
>  #include <libcamera/camera.h>
>  #include <libcamera/framebuffer.h>
> +#include <libcamera/framebuffer_allocator.h>
>  #include <libcamera/geometry.h>
>  #include <libcamera/pixel_format.h>
>  #include <libcamera/request.h>
> @@ -84,6 +85,7 @@ private:
>  		std::vector<std::unique_ptr<libcamera::FrameBuffer>> frameBuffers_;
>  		CameraMetadata settings_;
>  		std::unique_ptr<CaptureRequest> request_;
> +		std::map<CameraStream *, libcamera::FrameBuffer *> internalBuffers_;
>  	};

Camera3RequestDescriptor will need to be documented in the near future,
or it will become unmaintainable :-(

>  
>  	enum class State {
> @@ -118,6 +120,8 @@ private:
>  	std::unique_ptr<libcamera::CameraConfiguration> config_;
>  	CameraCapabilities capabilities_;
>  
> +	std::unique_ptr<libcamera::FrameBufferAllocator> frame_buffer_allocator_;

This isn't used.

> +
>  	std::map<unsigned int, std::unique_ptr<CameraMetadata>> requestTemplates_;
>  	const camera3_callback_ops_t *callbacks_;
>  
> diff --git a/src/android/camera_stream.cpp b/src/android/camera_stream.cpp
> index e30c7ee4..fc2e82cd 100644
> --- a/src/android/camera_stream.cpp
> +++ b/src/android/camera_stream.cpp
> @@ -18,6 +18,7 @@
>  #include "camera_capabilities.h"
>  #include "camera_device.h"
>  #include "camera_metadata.h"
> +#include "frame_buffer.h"
>  
>  using namespace libcamera;
>  
> @@ -46,10 +47,14 @@ 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 mappedStream,
> +			   unsigned int index)
>  	: cameraDevice_(cameraDevice), config_(config), type_(type),
> -	  camera3Stream_(camera3Stream), index_(index)
> +	  camera3Stream_(camera3Stream), mappedStream_(mappedStream),
> +	  index_(index)
>  {
> +	ASSERT(type_ != Type::Mapped || !!mappedStream);
>  }
>  
>  const StreamConfiguration &CameraStream::configuration() const
> @@ -134,8 +139,30 @@ int CameraStream::process(const FrameBuffer &source,
>  
>  FrameBuffer *CameraStream::getBuffer()
>  {
> -	if (!allocator_)
> -		return nullptr;
> +	if (!mutex_) {

Using the mutex for this seems to be a hack, it makes it hard to follow
the code flow and ensure correctness. There's quite a bit of code here
that looks like work in progress, so I assume this will be refactored in
the next version.

> +		ASSERT(type_ == Type::Direct);
> +		ASSERT(!allocator_);
> +		mutex_ = std::make_unique<std::mutex>();
> +		platform_allocator_ = std::make_unique<PlatformFrameBufferAllocator>(cameraDevice_);
> +		const StreamConfiguration &config = configuration();
> +		size_t numBuffers = config.bufferCount;
> +		const int halPixelFormat = camera3Stream_->format;
> +		const uint32_t usage = camera3Stream_->usage;
> +		LOG(HAL, Error) << "getBuffer@@@@@ " << numBuffers;
> +		// numBuffers is 4 (=config.bufferCount) is not enough sadly...
> +		// Should we dynamically allocate?

I think we should, 20 is a lot (beside being random).

What is the impact of allocating buffers at runtime ? It can be a costly
operation, could it cause significant delays to the processing of
capture requests ?

It would be nice if the code could be designed in such a way that the
decision to preallocate at configure time or allocate dynamically at
runtime could be made in a single place, likely in the CameraStream
class, and not visible outside. That way we could also experiment with
pre-allocation if needed, changing CameraStream only without touching
CameraDevice. Maybe it already is architectured that way, I'm not
entirely sure :-)

> +		numBuffers = 20;
> +		const auto &buffers = platform_allocator_->allocate(
> +			halPixelFormat, config.size, usage, numBuffers);
> +		if (buffers.empty() || buffers.size() != numBuffers) {
> +			LOG(HAL, Error) << "Failed allocating FrameBuffers";
> +			return nullptr;
> +		}
> +
> +		buffers_.reserve(numBuffers);
> +		for (const auto &frameBuffer : buffers)
> +			buffers_.push_back(frameBuffer.get());
> +	}
>  
>  	std::lock_guard<std::mutex> locker(*mutex_);
>  
> @@ -143,7 +170,7 @@ FrameBuffer *CameraStream::getBuffer()
>  		LOG(HAL, Error) << "Buffer underrun";
>  		return nullptr;
>  	}
> -
> +	LOG(HAL, Error) << buffers_.size();
>  	FrameBuffer *buffer = buffers_.back();
>  	buffers_.pop_back();
>  
> diff --git a/src/android/camera_stream.h b/src/android/camera_stream.h
> index 2dab6c3a..c8eee908 100644
> --- a/src/android/camera_stream.h
> +++ b/src/android/camera_stream.h
> @@ -15,10 +15,11 @@
>  
>  #include <libcamera/camera.h>
>  #include <libcamera/framebuffer.h>
> -#include <libcamera/framebuffer_allocator.h>
>  #include <libcamera/geometry.h>
>  #include <libcamera/pixel_format.h>
>  
> +#include "frame_buffer.h"
> +
>  class CameraDevice;
>  class CameraMetadata;
>  class PostProcessor;
> @@ -110,12 +111,14 @@ public:
>  	};
>  	CameraStream(CameraDevice *const cameraDevice,
>  		     libcamera::CameraConfiguration *config, Type type,
> -		     camera3_stream_t *camera3Stream, unsigned int index);
> +		     camera3_stream_t *camera3Stream,
> +		     CameraStream *const mappedStream, unsigned int index);
>  
>  	Type type() const { return type_; }
>  	const camera3_stream_t &camera3Stream() const { return *camera3Stream_; }
>  	const libcamera::StreamConfiguration &configuration() const;
>  	libcamera::Stream *stream() const;
> +	CameraStream *mappedStream() const { return mappedStream_; }
>  
>  	int configure();
>  	int process(const libcamera::FrameBuffer &source,
> @@ -130,10 +133,13 @@ private:
>  	const libcamera::CameraConfiguration *config_;
>  	const Type type_;
>  	camera3_stream_t *camera3Stream_;
> +	CameraStream *const mappedStream_;
>  	const unsigned int index_;
>  
>  	std::unique_ptr<libcamera::FrameBufferAllocator> allocator_;

Now that we have a platform-specific allocator, shouldn't we drop this
one (not in this patch of course) ? It will require changes to the
PlatformFrameBufferAllocator API to allocate buffers individually, but I
think that would result in a cleaner API, with the caller being
responsible for handling the allocated buffer life time (through a
unique pointer). That part of the API change is something that could
make sense in this series.

> +	std::unique_ptr<PlatformFrameBufferAllocator> platform_allocator_;

platformAllocator_

Constructing the allocator is cheap, you don't have to use a pointer, up
to you.

Overall, I think the direction is right, but this needs some more work.
Not a surprise, given that the patch is an RFC :-)

>  	std::vector<libcamera::FrameBuffer *> buffers_;
> +	std::vector<std::unique_ptr<libcamera::FrameBuffer>> frameBuffers_;
>  	/*
>  	 * The class has to be MoveConstructible as instances are stored in
>  	 * an std::vector in CameraDevice.
Jacopo Mondi Oct. 13, 2021, 11:41 a.m. UTC | #2
Hi Hiro,

  I'll try not to repeat what Laurent already asked

On Mon, Sep 27, 2021 at 07:48:21PM +0900, Hirokazu Honda wrote:
> A request given in processCaptureRequest() can contain only streams
> that are resolved CameraStream::Type::Mapped. In the case, no buffer
> is sent to a native camera. This fixes the issue by looking for the
> stream to be requested and alternatively sending a buffer for the
> stream to a camera.
>
> However, the substitute stream is Direct and a buffer needs to be
> provided by a HAL client. So we have to allocate a buffer in
> Android HAL adaptation layer using PlatformFrameBufferAllocator.
>
> Signed-off-by: Hirokazu Honda <hiroh@chromium.org>
> ---
>  src/android/camera_device.cpp | 50 +++++++++++++++++++++++++++++------
>  src/android/camera_device.h   |  4 +++
>  src/android/camera_stream.cpp | 37 ++++++++++++++++++++++----
>  src/android/camera_stream.h   | 10 +++++--
>  4 files changed, 86 insertions(+), 15 deletions(-)
>
> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
> index a693dcbe..5887e85e 100644
> --- a/src/android/camera_device.cpp
> +++ b/src/android/camera_device.cpp
> @@ -724,10 +724,14 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
>  	for (const auto &streamConfig : streamConfigs) {
>  		config->addConfiguration(streamConfig.config);
>
> +		CameraStream *mappedStream = nullptr;
>  		for (auto &stream : streamConfig.streams) {
>  			streams_.emplace_back(this, config.get(), stream.type,
> -					      stream.stream, config->size() - 1);
> +					      stream.stream, mappedStream,
> +					      config->size() - 1);
>  			stream.stream->priv = static_cast<void *>(&streams_.back());
> +			if (stream.type == CameraStream::Type::Direct)
> +				mappedStream = &streams_.back();
>  		}
>  	}
>
> @@ -969,6 +973,8 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
>
>  	LOG(HAL, Debug) << "Queueing request " << descriptor.request_->cookie()
>  			<< " with " << descriptor.buffers_.size() << " streams";
> +
> +	std::set<Stream *> addedStreams;
>  	for (unsigned int i = 0; i < descriptor.buffers_.size(); ++i) {
>  		const camera3_stream_buffer_t &camera3Buffer = descriptor.buffers_[i];
>  		camera3_stream *camera3Stream = camera3Buffer.stream;
> @@ -1018,6 +1024,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
>  			 * once it has been processed.
>  			 */
>  			buffer = cameraStream->getBuffer();
> +			descriptor.internalBuffers_[cameraStream] = buffer;
>  			LOG(HAL, Debug) << ss.str() << " (internal)";
>  			break;
>  		}
> @@ -1029,6 +1036,37 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
>
>  		descriptor.request_->addBuffer(cameraStream->stream(), buffer,
>  						camera3Buffer.acquire_fence);
> +		addedStreams.insert(cameraStream->stream());
> +	}
> +
> +	for (unsigned int i = 0; i < descriptor.buffers_.size(); ++i) {
> +		const camera3_stream_buffer_t &camera3Buffer = descriptor.buffers_[i];
> +		camera3_stream *camera3Stream = camera3Buffer.stream;
> +		CameraStream *cameraStream = static_cast<CameraStream *>(camera3Stream->priv);
> +		if (cameraStream->type() != CameraStream::Type::Mapped)
> +			continue;
> +		if (addedStreams.find(cameraStream->stream()) != addedStreams.end())
> +			continue;

Can't you just iterate on addedStreams then ?

> +
> +		CameraStream *mappedStream = cameraStream->mappedStream();
> +		if (!mappedStream) {
> +			LOG(HAL, Error)
> +				<< "Could not find mappedStream for ("
> +				<< camera3Stream->width << "x"
> +				<< camera3Stream->height << ")"
> +				<< "[" << utils::hex(camera3Stream->format) << "]";
> +			return -EINVAL;
> +		}
> +
> +		ASSERT(mappedStream->type() == CameraStream::Type::Direct);
> +		FrameBuffer *mappedBuffer = mappedStream->getBuffer();
> +		if (!mappedBuffer) {
> +			LOG(HAL, Error) << "Failed getting a buffer";
> +			return -EINVAL;
> +		}
> +
> +		descriptor.internalBuffers_[mappedStream] = mappedBuffer;
> +		descriptor.request_->addBuffer(mappedStream->stream(), mappedBuffer, -1);

I don't get this. What if the 'mapped' stream was already part of the
request ? Does it get added twice ?

>  	}
>
>  	/*
> @@ -1180,13 +1218,6 @@ void CameraDevice::requestComplete(Request *request)
>  		int ret = cameraStream->process(*src, *buffer.buffer,
>  						descriptor.settings_,
>  						resultMetadata.get());
> -		/*
> -		 * Return the FrameBuffer to the CameraStream now that we're
> -		 * done processing it.
> -		 */
> -		if (cameraStream->type() == CameraStream::Type::Internal)
> -			cameraStream->putBuffer(src);
> -
>  		if (ret) {
>  			buffer.status = CAMERA3_BUFFER_STATUS_ERROR;
>  			notifyError(descriptor.frameNumber_, buffer.stream,
> @@ -1194,6 +1225,9 @@ void CameraDevice::requestComplete(Request *request)
>  		}
>  	}
>
> +	for (auto &[stream, buffer] : descriptor.internalBuffers_)
> +		stream->putBuffer(buffer);
> +
>  	captureResult.result = resultMetadata->get();
>  	callbacks_->process_capture_result(callbacks_, &captureResult);
>  }
> diff --git a/src/android/camera_device.h b/src/android/camera_device.h
> index 296c2f18..74d8150b 100644
> --- a/src/android/camera_device.h
> +++ b/src/android/camera_device.h
> @@ -21,6 +21,7 @@
>
>  #include <libcamera/camera.h>
>  #include <libcamera/framebuffer.h>
> #include <libcamera/framebuffer_allocator.h>
>  #include <libcamera/geometry.h>
>  #include <libcamera/pixel_format.h>
>  #include <libcamera/request.h>
> @@ -84,6 +85,7 @@ private:
>  		std::vector<std::unique_ptr<libcamera::FrameBuffer>> frameBuffers_;
>  		CameraMetadata settings_;
>  		std::unique_ptr<CaptureRequest> request_;
> +		std::map<CameraStream *, libcamera::FrameBuffer *> internalBuffers_;
>  	};
>
>  	enum class State {
> @@ -118,6 +120,8 @@ private:
>  	std::unique_ptr<libcamera::CameraConfiguration> config_;
>  	CameraCapabilities capabilities_;
>
> +	std::unique_ptr<libcamera::FrameBufferAllocator> frame_buffer_allocator_;
> +
>  	std::map<unsigned int, std::unique_ptr<CameraMetadata>> requestTemplates_;
>  	const camera3_callback_ops_t *callbacks_;
>
> diff --git a/src/android/camera_stream.cpp b/src/android/camera_stream.cpp
> index e30c7ee4..fc2e82cd 100644
> --- a/src/android/camera_stream.cpp
> +++ b/src/android/camera_stream.cpp
> @@ -18,6 +18,7 @@
>  #include "camera_capabilities.h"
>  #include "camera_device.h"
>  #include "camera_metadata.h"
> +#include "frame_buffer.h"
>
>  using namespace libcamera;
>
> @@ -46,10 +47,14 @@ 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 mappedStream,
> +			   unsigned int index)
>  	: cameraDevice_(cameraDevice), config_(config), type_(type),
> -	  camera3Stream_(camera3Stream), index_(index)
> +	  camera3Stream_(camera3Stream), mappedStream_(mappedStream),
> +	  index_(index)
>  {
> +	ASSERT(type_ != Type::Mapped || !!mappedStream);
>  }
>
>  const StreamConfiguration &CameraStream::configuration() const
> @@ -134,8 +139,30 @@ int CameraStream::process(const FrameBuffer &source,
>
>  FrameBuffer *CameraStream::getBuffer()
>  {
> -	if (!allocator_)
> -		return nullptr;

I assume the style is due the series being an RFC...

Anyway ...

> +	if (!mutex_) {

Relying on !mutex to verify that !Internal and "first time this gets
called" is fragile. Why not handle Direct in configure() and prepare a
buffer cache there.

Anyway, I've not really gone into detail in the platform buffer
allocator but why can't this use the Camera's frame buffer allocator ?

> +		ASSERT(type_ == Type::Direct);
> +		ASSERT(!allocator_);
> +		mutex_ = std::make_unique<std::mutex>();
> +		platform_allocator_ = std::make_unique<PlatformFrameBufferAllocator>(cameraDevice_);
> +		const StreamConfiguration &config = configuration();
> +		size_t numBuffers = config.bufferCount;
> +		const int halPixelFormat = camera3Stream_->format;
> +		const uint32_t usage = camera3Stream_->usage;
> +		LOG(HAL, Error) << "getBuffer@@@@@ " << numBuffers;
> +		// numBuffers is 4 (=config.bufferCount) is not enough sadly...
> +		// Should we dynamically allocate?
> +		numBuffers = 20;
> +		const auto &buffers = platform_allocator_->allocate(
> +			halPixelFormat, config.size, usage, numBuffers);
> +		if (buffers.empty() || buffers.size() != numBuffers) {
> +			LOG(HAL, Error) << "Failed allocating FrameBuffers";
> +			return nullptr;
> +		}
> +
> +		buffers_.reserve(numBuffers);
> +		for (const auto &frameBuffer : buffers)
> +			buffers_.push_back(frameBuffer.get());
> +	}
>
>  	std::lock_guard<std::mutex> locker(*mutex_);
>
> @@ -143,7 +170,7 @@ FrameBuffer *CameraStream::getBuffer()
>  		LOG(HAL, Error) << "Buffer underrun";
>  		return nullptr;
>  	}
> -
> +	LOG(HAL, Error) << buffers_.size();
>  	FrameBuffer *buffer = buffers_.back();
>  	buffers_.pop_back();
>
> diff --git a/src/android/camera_stream.h b/src/android/camera_stream.h
> index 2dab6c3a..c8eee908 100644
> --- a/src/android/camera_stream.h
> +++ b/src/android/camera_stream.h
> @@ -15,10 +15,11 @@
>
>  #include <libcamera/camera.h>
>  #include <libcamera/framebuffer.h>
> -#include <libcamera/framebuffer_allocator.h>
>  #include <libcamera/geometry.h>
>  #include <libcamera/pixel_format.h>
>
> +#include "frame_buffer.h"
> +
>  class CameraDevice;
>  class CameraMetadata;
>  class PostProcessor;
> @@ -110,12 +111,14 @@ public:
>  	};
>  	CameraStream(CameraDevice *const cameraDevice,
>  		     libcamera::CameraConfiguration *config, Type type,
> -		     camera3_stream_t *camera3Stream, unsigned int index);
> +		     camera3_stream_t *camera3Stream,
> +		     CameraStream *const mappedStream, unsigned int index);
>
>  	Type type() const { return type_; }
>  	const camera3_stream_t &camera3Stream() const { return *camera3Stream_; }
>  	const libcamera::StreamConfiguration &configuration() const;
>  	libcamera::Stream *stream() const;
> +	CameraStream *mappedStream() const { return mappedStream_; }
>
>  	int configure();
>  	int process(const libcamera::FrameBuffer &source,
> @@ -130,10 +133,13 @@ private:
>  	const libcamera::CameraConfiguration *config_;
>  	const Type type_;
>  	camera3_stream_t *camera3Stream_;
> +	CameraStream *const mappedStream_;
>  	const unsigned int index_;
>
>  	std::unique_ptr<libcamera::FrameBufferAllocator> allocator_;
> +	std::unique_ptr<PlatformFrameBufferAllocator> platform_allocator_;
>  	std::vector<libcamera::FrameBuffer *> buffers_;
> +	std::vector<std::unique_ptr<libcamera::FrameBuffer>> frameBuffers_;
>  	/*
>  	 * The class has to be MoveConstructible as instances are stored in
>  	 * an std::vector in CameraDevice.
> --
> 2.33.0.685.g46640cef36-goog
>

Patch
diff mbox series

diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index a693dcbe..5887e85e 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -724,10 +724,14 @@  int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)
 	for (const auto &streamConfig : streamConfigs) {
 		config->addConfiguration(streamConfig.config);
 
+		CameraStream *mappedStream = nullptr;
 		for (auto &stream : streamConfig.streams) {
 			streams_.emplace_back(this, config.get(), stream.type,
-					      stream.stream, config->size() - 1);
+					      stream.stream, mappedStream,
+					      config->size() - 1);
 			stream.stream->priv = static_cast<void *>(&streams_.back());
+			if (stream.type == CameraStream::Type::Direct)
+				mappedStream = &streams_.back();
 		}
 	}
 
@@ -969,6 +973,8 @@  int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 
 	LOG(HAL, Debug) << "Queueing request " << descriptor.request_->cookie()
 			<< " with " << descriptor.buffers_.size() << " streams";
+
+	std::set<Stream *> addedStreams;
 	for (unsigned int i = 0; i < descriptor.buffers_.size(); ++i) {
 		const camera3_stream_buffer_t &camera3Buffer = descriptor.buffers_[i];
 		camera3_stream *camera3Stream = camera3Buffer.stream;
@@ -1018,6 +1024,7 @@  int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 			 * once it has been processed.
 			 */
 			buffer = cameraStream->getBuffer();
+			descriptor.internalBuffers_[cameraStream] = buffer;
 			LOG(HAL, Debug) << ss.str() << " (internal)";
 			break;
 		}
@@ -1029,6 +1036,37 @@  int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
 
 		descriptor.request_->addBuffer(cameraStream->stream(), buffer,
 						camera3Buffer.acquire_fence);
+		addedStreams.insert(cameraStream->stream());
+	}
+
+	for (unsigned int i = 0; i < descriptor.buffers_.size(); ++i) {
+		const camera3_stream_buffer_t &camera3Buffer = descriptor.buffers_[i];
+		camera3_stream *camera3Stream = camera3Buffer.stream;
+		CameraStream *cameraStream = static_cast<CameraStream *>(camera3Stream->priv);
+		if (cameraStream->type() != CameraStream::Type::Mapped)
+			continue;
+		if (addedStreams.find(cameraStream->stream()) != addedStreams.end())
+			continue;
+
+		CameraStream *mappedStream = cameraStream->mappedStream();
+		if (!mappedStream) {
+			LOG(HAL, Error)
+				<< "Could not find mappedStream for ("
+				<< camera3Stream->width << "x"
+				<< camera3Stream->height << ")"
+				<< "[" << utils::hex(camera3Stream->format) << "]";
+			return -EINVAL;
+		}
+
+		ASSERT(mappedStream->type() == CameraStream::Type::Direct);
+		FrameBuffer *mappedBuffer = mappedStream->getBuffer();
+		if (!mappedBuffer) {
+			LOG(HAL, Error) << "Failed getting a buffer";
+			return -EINVAL;
+		}
+
+		descriptor.internalBuffers_[mappedStream] = mappedBuffer;
+		descriptor.request_->addBuffer(mappedStream->stream(), mappedBuffer, -1);
 	}
 
 	/*
@@ -1180,13 +1218,6 @@  void CameraDevice::requestComplete(Request *request)
 		int ret = cameraStream->process(*src, *buffer.buffer,
 						descriptor.settings_,
 						resultMetadata.get());
-		/*
-		 * Return the FrameBuffer to the CameraStream now that we're
-		 * done processing it.
-		 */
-		if (cameraStream->type() == CameraStream::Type::Internal)
-			cameraStream->putBuffer(src);
-
 		if (ret) {
 			buffer.status = CAMERA3_BUFFER_STATUS_ERROR;
 			notifyError(descriptor.frameNumber_, buffer.stream,
@@ -1194,6 +1225,9 @@  void CameraDevice::requestComplete(Request *request)
 		}
 	}
 
+	for (auto &[stream, buffer] : descriptor.internalBuffers_)
+		stream->putBuffer(buffer);
+
 	captureResult.result = resultMetadata->get();
 	callbacks_->process_capture_result(callbacks_, &captureResult);
 }
diff --git a/src/android/camera_device.h b/src/android/camera_device.h
index 296c2f18..74d8150b 100644
--- a/src/android/camera_device.h
+++ b/src/android/camera_device.h
@@ -21,6 +21,7 @@ 
 
 #include <libcamera/camera.h>
 #include <libcamera/framebuffer.h>
+#include <libcamera/framebuffer_allocator.h>
 #include <libcamera/geometry.h>
 #include <libcamera/pixel_format.h>
 #include <libcamera/request.h>
@@ -84,6 +85,7 @@  private:
 		std::vector<std::unique_ptr<libcamera::FrameBuffer>> frameBuffers_;
 		CameraMetadata settings_;
 		std::unique_ptr<CaptureRequest> request_;
+		std::map<CameraStream *, libcamera::FrameBuffer *> internalBuffers_;
 	};
 
 	enum class State {
@@ -118,6 +120,8 @@  private:
 	std::unique_ptr<libcamera::CameraConfiguration> config_;
 	CameraCapabilities capabilities_;
 
+	std::unique_ptr<libcamera::FrameBufferAllocator> frame_buffer_allocator_;
+
 	std::map<unsigned int, std::unique_ptr<CameraMetadata>> requestTemplates_;
 	const camera3_callback_ops_t *callbacks_;
 
diff --git a/src/android/camera_stream.cpp b/src/android/camera_stream.cpp
index e30c7ee4..fc2e82cd 100644
--- a/src/android/camera_stream.cpp
+++ b/src/android/camera_stream.cpp
@@ -18,6 +18,7 @@ 
 #include "camera_capabilities.h"
 #include "camera_device.h"
 #include "camera_metadata.h"
+#include "frame_buffer.h"
 
 using namespace libcamera;
 
@@ -46,10 +47,14 @@  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 mappedStream,
+			   unsigned int index)
 	: cameraDevice_(cameraDevice), config_(config), type_(type),
-	  camera3Stream_(camera3Stream), index_(index)
+	  camera3Stream_(camera3Stream), mappedStream_(mappedStream),
+	  index_(index)
 {
+	ASSERT(type_ != Type::Mapped || !!mappedStream);
 }
 
 const StreamConfiguration &CameraStream::configuration() const
@@ -134,8 +139,30 @@  int CameraStream::process(const FrameBuffer &source,
 
 FrameBuffer *CameraStream::getBuffer()
 {
-	if (!allocator_)
-		return nullptr;
+	if (!mutex_) {
+		ASSERT(type_ == Type::Direct);
+		ASSERT(!allocator_);
+		mutex_ = std::make_unique<std::mutex>();
+		platform_allocator_ = std::make_unique<PlatformFrameBufferAllocator>(cameraDevice_);
+		const StreamConfiguration &config = configuration();
+		size_t numBuffers = config.bufferCount;
+		const int halPixelFormat = camera3Stream_->format;
+		const uint32_t usage = camera3Stream_->usage;
+		LOG(HAL, Error) << "getBuffer@@@@@ " << numBuffers;
+		// numBuffers is 4 (=config.bufferCount) is not enough sadly...
+		// Should we dynamically allocate?
+		numBuffers = 20;
+		const auto &buffers = platform_allocator_->allocate(
+			halPixelFormat, config.size, usage, numBuffers);
+		if (buffers.empty() || buffers.size() != numBuffers) {
+			LOG(HAL, Error) << "Failed allocating FrameBuffers";
+			return nullptr;
+		}
+
+		buffers_.reserve(numBuffers);
+		for (const auto &frameBuffer : buffers)
+			buffers_.push_back(frameBuffer.get());
+	}
 
 	std::lock_guard<std::mutex> locker(*mutex_);
 
@@ -143,7 +170,7 @@  FrameBuffer *CameraStream::getBuffer()
 		LOG(HAL, Error) << "Buffer underrun";
 		return nullptr;
 	}
-
+	LOG(HAL, Error) << buffers_.size();
 	FrameBuffer *buffer = buffers_.back();
 	buffers_.pop_back();
 
diff --git a/src/android/camera_stream.h b/src/android/camera_stream.h
index 2dab6c3a..c8eee908 100644
--- a/src/android/camera_stream.h
+++ b/src/android/camera_stream.h
@@ -15,10 +15,11 @@ 
 
 #include <libcamera/camera.h>
 #include <libcamera/framebuffer.h>
-#include <libcamera/framebuffer_allocator.h>
 #include <libcamera/geometry.h>
 #include <libcamera/pixel_format.h>
 
+#include "frame_buffer.h"
+
 class CameraDevice;
 class CameraMetadata;
 class PostProcessor;
@@ -110,12 +111,14 @@  public:
 	};
 	CameraStream(CameraDevice *const cameraDevice,
 		     libcamera::CameraConfiguration *config, Type type,
-		     camera3_stream_t *camera3Stream, unsigned int index);
+		     camera3_stream_t *camera3Stream,
+		     CameraStream *const mappedStream, unsigned int index);
 
 	Type type() const { return type_; }
 	const camera3_stream_t &camera3Stream() const { return *camera3Stream_; }
 	const libcamera::StreamConfiguration &configuration() const;
 	libcamera::Stream *stream() const;
+	CameraStream *mappedStream() const { return mappedStream_; }
 
 	int configure();
 	int process(const libcamera::FrameBuffer &source,
@@ -130,10 +133,13 @@  private:
 	const libcamera::CameraConfiguration *config_;
 	const Type type_;
 	camera3_stream_t *camera3Stream_;
+	CameraStream *const mappedStream_;
 	const unsigned int index_;
 
 	std::unique_ptr<libcamera::FrameBufferAllocator> allocator_;
+	std::unique_ptr<PlatformFrameBufferAllocator> platform_allocator_;
 	std::vector<libcamera::FrameBuffer *> buffers_;
+	std::vector<std::unique_ptr<libcamera::FrameBuffer>> frameBuffers_;
 	/*
 	 * The class has to be MoveConstructible as instances are stored in
 	 * an std::vector in CameraDevice.