[libcamera-devel] [PATCH v4 8/8] android: Implement flush() camera operation

Niklas Söderlund niklas.soderlund at ragnatech.se
Fri May 28 09:33:13 CEST 2021


Hi Jacopo,

Thanks for your work.

On 2021-05-28 00:03:59 +0200, Jacopo Mondi wrote:
> Implement the flush() camera operation in the CameraDevice class
> and make it available to the camera framework by implementing the
> operation wrapper in camera_ops.cpp.
> 
> Introduce a new camera state State::Flushing to handle concurrent
> flush() and process_capture_request() calls.
> 
> As flush() can race with processCaptureRequest() protect it
> by introducing a new State::Flushing state that
> processCaptureRequest() inspects before queuing the Request to the
> Camera. If flush() is in progress while processCaptureRequest() is
> called, return the current Request immediately in error state. If
> flush() has completed and a new call to processCaptureRequest() is
> made just after, start the camera again before queuing the request.
> 
> Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>

Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>

> ---
>  src/android/camera_device.cpp | 74 ++++++++++++++++++++++++++++++++++-
>  src/android/camera_device.h   |  3 ++
>  src/android/camera_ops.cpp    |  8 +++-
>  3 files changed, 83 insertions(+), 2 deletions(-)
> 
> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
> index a20c3eaa0ff6..6a8d4d4d5f76 100644
> --- a/src/android/camera_device.cpp
> +++ b/src/android/camera_device.cpp
> @@ -797,6 +797,23 @@ void CameraDevice::close()
>  	camera_->release();
>  }
>  
> +void CameraDevice::flush()
> +{
> +	{
> +		MutexLocker stateLock(stateMutex_);
> +		if (state_ != State::Running)
> +			return;
> +
> +		state_ = State::Flushing;
> +	}
> +
> +	worker_.stop();
> +	camera_->stop();
> +
> +	MutexLocker stateLock(stateMutex_);
> +	state_ = State::Stopped;
> +}
> +
>  void CameraDevice::stop()
>  {
>  	MutexLocker stateLock(stateMutex_);
> @@ -1894,15 +1911,46 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
>  	return 0;
>  }
>  
> +void CameraDevice::abortRequest(camera3_capture_request_t *request)
> +{
> +	notifyError(request->frame_number, nullptr, CAMERA3_MSG_ERROR_REQUEST);
> +
> +	camera3_capture_result_t result = {};
> +	result.num_output_buffers = request->num_output_buffers;
> +	result.frame_number = request->frame_number;
> +	result.partial_result = 0;
> +
> +	std::vector<camera3_stream_buffer_t> resultBuffers(result.num_output_buffers);
> +	for (auto [i, buffer] : utils::enumerate(resultBuffers)) {
> +		buffer = request->output_buffers[i];
> +		buffer.release_fence = request->output_buffers[i].acquire_fence;
> +		buffer.acquire_fence = -1;
> +		buffer.status = CAMERA3_BUFFER_STATUS_ERROR;
> +	}
> +	result.output_buffers = resultBuffers.data();
> +
> +	callbacks_->process_capture_result(callbacks_, &result);
> +}
> +
>  int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request)
>  {
>  	if (!isValidRequest(camera3Request))
>  		return -EINVAL;
>  
>  	{
> +		/*
> +		 * Start the camera if that's the first request we handle after
> +		 * a configuration or after a flush.
> +		 *
> +		 * If flush is in progress, return the pending request
> +		 * immediately in error state.
> +		 */
>  		MutexLocker stateLock(stateMutex_);
> +		if (state_ == State::Flushing) {
> +			abortRequest(camera3Request);
> +			return 0;
> +		}
>  
> -		/* Start the camera if that's the first request we handle. */
>  		if (state_ == State::Stopped) {
>  			worker_.start();
>  
> @@ -2004,6 +2052,30 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques
>  	if (ret)
>  		return ret;
>  
> +	/*
> +	 * Just before queuing the request, make sure flush() has not
> +	 * been called while this function was running. If flush is in progress
> +	 * abort the request. If flush has completed and has stopped the camera
> +	 * we have to re-start it to be able to process the request.
> +	 */
> +	MutexLocker stateLock(stateMutex_);
> +	if (state_ == State::Flushing) {
> +		abortRequest(camera3Request);
> +		return 0;
> +	}
> +
> +	if (state_ == State::Stopped) {
> +		worker_.start();
> +
> +		ret = camera_->start();
> +		if (ret) {
> +			LOG(HAL, Error) << "Failed to start camera";
> +			return ret;
> +		}
> +
> +		state_ = State::Running;
> +	}
> +
>  	worker_.queueRequest(descriptor.request_.get());
>  
>  	{
> diff --git a/src/android/camera_device.h b/src/android/camera_device.h
> index c949fa509ca4..4aadb27c562c 100644
> --- a/src/android/camera_device.h
> +++ b/src/android/camera_device.h
> @@ -43,6 +43,7 @@ public:
>  
>  	int open(const hw_module_t *hardwareModule);
>  	void close();
> +	void flush();
>  
>  	unsigned int id() const { return id_; }
>  	camera3_device_t *camera3Device() { return &camera3Device_; }
> @@ -92,6 +93,7 @@ private:
>  
>  	enum class State {
>  		Stopped,
> +		Flushing,
>  		Running,
>  	};
>  
> @@ -106,6 +108,7 @@ private:
>  	getRawResolutions(const libcamera::PixelFormat &pixelFormat);
>  
>  	libcamera::FrameBuffer *createFrameBuffer(const buffer_handle_t camera3buffer);
> +	void abortRequest(camera3_capture_request_t *request);
>  	void notifyShutter(uint32_t frameNumber, uint64_t timestamp);
>  	void notifyError(uint32_t frameNumber, camera3_stream_t *stream,
>  			 camera3_error_msg_code code);
> diff --git a/src/android/camera_ops.cpp b/src/android/camera_ops.cpp
> index 696e80436821..8a3cfa175ff5 100644
> --- a/src/android/camera_ops.cpp
> +++ b/src/android/camera_ops.cpp
> @@ -66,8 +66,14 @@ static void hal_dev_dump([[maybe_unused]] const struct camera3_device *dev,
>  {
>  }
>  
> -static int hal_dev_flush([[maybe_unused]] const struct camera3_device *dev)
> +static int hal_dev_flush(const struct camera3_device *dev)
>  {
> +	if (!dev)
> +		return -EINVAL;
> +
> +	CameraDevice *camera = reinterpret_cast<CameraDevice *>(dev->priv);
> +	camera->flush();
> +
>  	return 0;
>  }
>  
> -- 
> 2.31.1
> 

-- 
Regards,
Niklas Söderlund


More information about the libcamera-devel mailing list