From patchwork Mon May 10 10:52:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 12248 X-Patchwork-Delegate: jacopo@jmondi.org Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id AF131BF839 for ; Mon, 10 May 2021 10:52:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4AE236892D; Mon, 10 May 2021 12:52:04 +0200 (CEST) Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C27A86891C for ; Mon, 10 May 2021 12:52:02 +0200 (CEST) X-Originating-IP: 82.59.136.116 Received: from uno.homenet.telecomitalia.it (host-82-59-136-116.retail.telecomitalia.it [82.59.136.116]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 131FBE01CF; Mon, 10 May 2021 10:52:01 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Mon, 10 May 2021 12:52:35 +0200 Message-Id: <20210510105235.28319-9-jacopo@jmondi.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210510105235.28319-1-jacopo@jmondi.org> References: <20210510105235.28319-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 8/8] android: Implement flush() camera operation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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. The flush() implementation stops the Camera and the worker thread and waits for all in-flight requests to be returned. Stopping the Camera forces all Requests already queued to be returned immediately in error state. As flush() has to wait until all of them have been returned, make it wait on a newly introduced condition variable which is notified by the request completion handler when the queue of pending requests has been exhausted. As flush() can race with processCaptureRequest() protect the requests queueing by introducing a new CameraState::CameraFlushing state that processCaptureRequest() inspects before queuing the Request to the Camera. If flush() has been called while processCaptureRequest() was executing, return the current Request immediately in error state. Signed-off-by: Jacopo Mondi --- src/android/camera_device.cpp | 63 +++++++++++++++++++++++++++++++++++ src/android/camera_device.h | 6 ++++ src/android/camera_ops.cpp | 8 ++++- 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index fa12ce5b0133..01b3acd93c4b 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -756,6 +756,42 @@ void CameraDevice::close() camera_->release(); } +/* + * Flush is similar to stop() but sets the camera state to 'flushing' and wait + * until all the in-flight requests have been returned. + */ +void CameraDevice::flush() +{ + { + MutexLocker cameraLock(cameraMutex_); + + if (state_ != CameraRunning) + return; + + state_ = CameraFlushing; + + /* + * Stop the camera and set the state to flushing to prevent any + * new request to be queued from this point on. + */ + worker_.stop(); + camera_->stop(); + } + + /* + * Now wait for all the in-flight requests to be completed before + * returning. Stopping the Camera guarantees that all in-flight requests + * are completed in error state. + */ + { + MutexLocker flushLock(flushMutex_); + flushing_.wait(flushLock, [&] { return descriptors_.empty(); }); + } + + MutexLocker cameraLock(cameraMutex_); + state_ = CameraStopped; +} + void CameraDevice::stop() { MutexLocker cameraLock(cameraMutex_); @@ -2019,6 +2055,26 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques if (ret) return ret; + + /* + * Just before queuing the request, make sure flush() has not + * been called after this function has been executed. In that + * case, immediately return the request with errors. + */ + MutexLocker cameraLock(cameraMutex_); + if (state_ == CameraFlushing || state_ == CameraStopped) { + for (camera3_stream_buffer_t &buffer : descriptor.buffers_) { + buffer.status = CAMERA3_BUFFER_STATUS_ERROR; + buffer.release_fence = buffer.acquire_fence; + } + + notifyError(descriptor.frameNumber_, + descriptor.buffers_[0].stream, + CAMERA3_MSG_ERROR_REQUEST); + + return 0; + } + worker_.queueRequest(descriptor.request_.get()); { @@ -2052,6 +2108,13 @@ void CameraDevice::requestComplete(Request *request) } Camera3RequestDescriptor &descriptor = node.mapped(); + /* Release flush if all the pending requests have been completed. */ + { + MutexLocker flushLock(flushMutex_); + if (descriptors_.empty()) + flushing_.notify_one(); + } + /* * Prepare the capture result for the Android camera stack. * diff --git a/src/android/camera_device.h b/src/android/camera_device.h index ed992ae56d5d..4a9ef495b776 100644 --- a/src/android/camera_device.h +++ b/src/android/camera_device.h @@ -7,6 +7,7 @@ #ifndef __ANDROID_CAMERA_DEVICE_H__ #define __ANDROID_CAMERA_DEVICE_H__ +#include #include #include #include @@ -42,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 +94,7 @@ private: enum State { CameraStopped, CameraRunning, + CameraFlushing, }; void stop(); @@ -124,6 +127,9 @@ private: libcamera::Mutex cameraMutex_; /* Protects access to the camera state. */ State state_; + libcamera::Mutex flushMutex_; /* Protects the flushing condition variable. */ + std::condition_variable flushing_; + std::shared_ptr camera_; std::unique_ptr config_; 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(dev->priv); + camera->flush(); + return 0; }