[libcamera-devel] [PATCH v2 8/9] android: camera_stream: Run post-processor in a separate thread

Laurent Pinchart laurent.pinchart at ideasonboard.com
Mon Sep 13 03:21:20 CEST 2021


Hi Umang,

Thank you for the patch.

On Fri, Sep 10, 2021 at 12:36:37PM +0530, Umang Jain wrote:
> In CameraStream, introduce a new private PostProcessorWorker
> class derived from Object. A instance of PostProcessorWorker
> is moved to a separate thread instance which will be responsible
> to run the post-processor.
> 
> Running PostProcessor asynchronously should entail that all the
> data context needed by the PostProcessor should remain valid for
> the entire duration of its run. Most of the context preserving
> part has been addressed in the previous commits, we just need to
> ensure the source framebuffer data that comes via Camera::Request,
> should remain valid for the entire duration of post-processing
> running asynchronously. In order to so, we maintain a separate
> copy of the framebuffer data and add it to the Camera3RequestDescriptor
> structure in which we preserve rest of the context.
> 
> Signed-off-by: Umang Jain <umang.jain at ideasonboard.com>
> ---
>  src/android/camera_device.cpp | 19 ++++++++++++++++++-
>  src/android/camera_device.h   |  4 ++++
>  src/android/camera_stream.cpp | 16 ++++++++++++++--
>  src/android/camera_stream.h   | 28 ++++++++++++++++++++++++++++
>  4 files changed, 64 insertions(+), 3 deletions(-)
> 
> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
> index 988d4232..73eb5758 100644
> --- a/src/android/camera_device.cpp
> +++ b/src/android/camera_device.cpp
> @@ -1174,13 +1174,29 @@ void CameraDevice::requestComplete(Request *request)
>  			return;
>  		}
>  
> +		FrameBuffer *source = src;
> +		if (cameraStream->type() != CameraStream::Type::Internal) {
> +			/*
> +			 * The source buffer is owned by Request object which
> +			 * can be reused by libcamera. Since post-processor will
> +			 * run asynchrnously, we need to copy the request's
> +			 * frame buffer and use that as the source buffer for
> +			 * post processing.

I don't think this is right. The request can be reused indeed, but with
new FrameBuffer instances every time. The frame buffers are owned by
Camera3RequestDescriptor, they're stored in a vector there.

> +			 */
> +			for (const auto &plane : src->planes())
> +				descriptor.srcPlanes_.push_back(plane);
> +			descriptor.srcFramebuffer_ =
> +				std::make_unique<FrameBuffer>(descriptor.srcPlanes_);
> +			source = descriptor.srcFramebuffer_.get();
> +		}
> +
>  		std::unique_ptr<Camera3RequestDescriptor> reqDescriptor =
>  			std::make_unique<Camera3RequestDescriptor>();
>  		*reqDescriptor = std::move(descriptor);
>  		queuedDescriptor_.push_back(std::move(reqDescriptor));
>  
>  		Camera3RequestDescriptor *currentDescriptor = queuedDescriptor_.back().get();
> -		int ret = cameraStream->process(src,
> +		int ret = cameraStream->process(source,
>  						currentDescriptor->destBuffer_.get(),
>  						currentDescriptor->settings_,
>  						currentDescriptor->resultMetadata_.get(),
> @@ -1255,6 +1271,7 @@ void CameraDevice::streamProcessingComplete(CameraStream *cameraStream,
>  
>  void CameraDevice::sendQueuedCaptureResults()
>  {
> +	MutexLocker lock(queuedDescriptorsMutex_);
>  	while (!queuedDescriptor_.empty()) {
>  		std::unique_ptr<Camera3RequestDescriptor> &d = queuedDescriptor_.front();
>  		if (d->status_ == Camera3RequestDescriptor::Pending)
> diff --git a/src/android/camera_device.h b/src/android/camera_device.h
> index b62d373c..ecdda06e 100644
> --- a/src/android/camera_device.h
> +++ b/src/android/camera_device.h
> @@ -62,6 +62,9 @@ struct Camera3RequestDescriptor {
>  	camera3_capture_result_t captureResult_;
>  	libcamera::FrameBuffer *internalBuffer_;
>  	completionStatus status_;
> +
> +	std::unique_ptr<libcamera::FrameBuffer> srcFramebuffer_;
> +	std::vector<libcamera::FrameBuffer::Plane> srcPlanes_;
>  };
>  
>  class CameraDevice : protected libcamera::Loggable
> @@ -147,6 +150,7 @@ private:
>  	libcamera::Mutex descriptorsMutex_; /* Protects descriptors_. */
>  	std::map<uint64_t, Camera3RequestDescriptor> descriptors_;
>  
> +	libcamera::Mutex queuedDescriptorsMutex_; /* Protects queuedDescriptor_. */

This belongs to the previous patch.

>  	std::deque<std::unique_ptr<Camera3RequestDescriptor>> queuedDescriptor_;
>  
>  	std::string maker_;
> diff --git a/src/android/camera_stream.cpp b/src/android/camera_stream.cpp
> index 5fd04bbf..845e2462 100644
> --- a/src/android/camera_stream.cpp
> +++ b/src/android/camera_stream.cpp
> @@ -55,6 +55,15 @@ CameraStream::CameraStream(CameraDevice *const cameraDevice,
>  		 * is what we instantiate here.
>  		 */
>  		postProcessor_ = std::make_unique<PostProcessorJpeg>(cameraDevice_);
> +		ppWorker_ = std::make_unique<PostProcessorWorker>(postProcessor_.get());
> +
> +		thread_ = std::make_unique<libcamera::Thread>();
> +		ppWorker_->moveToThread(thread_.get());
> +		/*
> +		 * \todo: Class is MoveConstructible, so where to stop thread
> +		 * if we don't user-defined destructor? See RFC patch at the end.
> +		 */
> +		thread_->start();
>  	}
>  
>  	if (type == Type::Internal) {
> @@ -110,8 +119,11 @@ int CameraStream::process(const FrameBuffer *source,
>  	if (!postProcessor_)
>  		return 0;
>  
> -	return postProcessor_->process(source, destBuffer, requestMetadata,
> -				       resultMetadata, context);
> +	ppWorker_->invokeMethod(&PostProcessorWorker::process,
> +				ConnectionTypeQueued, source, destBuffer,
> +				requestMetadata, resultMetadata, context);
> +
> +	return 0;
>  }
>  
>  void CameraStream::postProcessingComplete(PostProcessor::Status status,
> diff --git a/src/android/camera_stream.h b/src/android/camera_stream.h
> index 8097ddbc..dbb7eee3 100644
> --- a/src/android/camera_stream.h
> +++ b/src/android/camera_stream.h
> @@ -13,7 +13,9 @@
>  
>  #include <hardware/camera3.h>
>  
> +#include <libcamera/base/object.h>
>  #include <libcamera/base/signal.h>
> +#include <libcamera/base/thread.h>
>  
>  #include <libcamera/camera.h>
>  #include <libcamera/framebuffer.h>
> @@ -23,6 +25,7 @@
>  
>  #include "post_processor.h"
>  
> +class CameraBuffer;
>  class CameraDevice;
>  class CameraMetadata;
>  
> @@ -137,6 +140,29 @@ public:
>  	};
>  
>  private:
> +	class PostProcessorWorker : public libcamera::Object
> +	{
> +	public:
> +		PostProcessorWorker(PostProcessor *postProcessor)
> +		{
> +			postProcessor_ = postProcessor;
> +		}
> +
> +		void process(const libcamera::FrameBuffer *source,
> +			     CameraBuffer *destination,
> +			     const CameraMetadata &requestMetadata,
> +			     CameraMetadata *resultMetadata,
> +			     const Camera3RequestDescriptor *context)
> +		{
> +			postProcessor_->process(source, destination,
> +						requestMetadata, resultMetadata,
> +						context);
> +		}
> +
> +	private:
> +		PostProcessor *postProcessor_;
> +	};

If it wasn't for the fact that I mentioned in the review of v1 that it
would be best to keep the PostProcessor class not thread-aware, I'd be
tempted to say we could make PostProcessor inherit from Object and drop
this class completely :-) Would you be tempted to do so too ? Compared
to v1 (the RFC) it would resurect patch 1/5, but we wouldn't need the
PostProcessorWorker class at all.

On the other hand, given that I've mentioned in the review of a 7/9 that
mapping the destination buffer could be done in the post-processor
thread, maybe PostProcessorWorker::process() is the right place to do
so. And now that I've written that, I now realize we've split the
construction of CameraBuffer from the actual mapping, which is performed
on the first call to CameraBuffer::plane(), so the mapping is already
done in the post-processor thread. It's thus likely fine to have the
construction of CameraBuffer in CameraStream or CameraDevice.

> +
>  	void postProcessingComplete(PostProcessor::Status status,
>  				    const Camera3RequestDescriptor *context);
>  
> @@ -154,6 +180,8 @@ private:
>  	 */
>  	std::unique_ptr<std::mutex> mutex_;
>  	std::unique_ptr<PostProcessor> postProcessor_;
> +	std::unique_ptr<PostProcessorWorker> ppWorker_;
> +	std::unique_ptr<libcamera::Thread> thread_;
>  };
>  
>  #endif /* __ANDROID_CAMERA_STREAM__ */

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list