diff options
author | Jacopo Mondi <jacopo@jmondi.org> | 2021-05-10 10:13:36 +0200 |
---|---|---|
committer | Jacopo Mondi <jacopo@jmondi.org> | 2021-06-14 12:26:28 +0200 |
commit | efd5fb7288a7a9c72f3ae7b1256c2b808aaf525f (patch) | |
tree | 7e034a7a29c2be7b4c6ca423fbd67a3349226bc9 | |
parent | 103dfb85a7e12c00c1a41eef69f45faa8f5c7597 (diff) |
android: Implement flush() camera operation
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@jmondi.org>
Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r-- | src/android/camera_device.cpp | 77 | ||||
-rw-r--r-- | src/android/camera_device.h | 3 | ||||
-rw-r--r-- | src/android/camera_ops.cpp | 8 |
3 files changed, 71 insertions, 17 deletions
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index b29c1edc..52317037 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -798,6 +798,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_); @@ -1896,27 +1913,31 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor) return 0; } -int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request) +void CameraDevice::abortRequest(camera3_capture_request_t *request) { - if (!isValidRequest(camera3Request)) - return -EINVAL; + notifyError(request->frame_number, nullptr, CAMERA3_MSG_ERROR_REQUEST); - { - MutexLocker stateLock(stateMutex_); + camera3_capture_result_t result = {}; + result.num_output_buffers = request->num_output_buffers; + result.frame_number = request->frame_number; + result.partial_result = 0; - /* Start the camera if that's the first request we handle. */ - if (state_ == State::Stopped) { - worker_.start(); + 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(); - int ret = camera_->start(); - if (ret) { - LOG(HAL, Error) << "Failed to start camera"; - return ret; - } + callbacks_->process_capture_result(callbacks_, &result); +} - state_ = State::Running; - } - } +int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request) +{ + if (!isValidRequest(camera3Request)) + return -EINVAL; /* * Save the request descriptors for use at completion time. @@ -2006,6 +2027,30 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques if (ret) return ret; + /* + * If flush is in progress abort the request. If the camera has been + * stopped 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"; + worker_.stop(); + 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 c949fa50..4aadb27c 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 696e8043..8a3cfa17 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; } |