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

Jacopo Mondi jacopo at jmondi.org
Wed Oct 13 13:41:41 CEST 2021


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 at 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
>


More information about the libcamera-devel mailing list