From patchwork Mon Apr 28 09:02:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Sven_P=C3=BCschel?= X-Patchwork-Id: 23288 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 731EEC331E for ; Mon, 28 Apr 2025 09:05:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9752768B31; Mon, 28 Apr 2025 11:05:38 +0200 (CEST) Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [IPv6:2a0a:edc0:2:b01:1d::104]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E6F2568ACF for ; Mon, 28 Apr 2025 11:05:08 +0200 (CEST) Received: from ptz.office.stw.pengutronix.de ([2a0a:edc0:0:900:1d::77] helo=peter.guest.stw.pengutronix.de) by metis.whiteo.stw.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1u9KQG-0001au-Fs; Mon, 28 Apr 2025 11:05:08 +0200 From: =?utf-8?q?Sven_P=C3=BCschel?= To: libcamera-devel@lists.libcamera.org Cc: =?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= , =?utf-8?q?Sven_P=C3=BCschel?= Subject: [PATCH v11 16/19] libcamera: pipeline: uvcvideo: Add internal request queue Date: Mon, 28 Apr 2025 11:02:41 +0200 Message-ID: <20250428090413.38234-17-s.pueschel@pengutronix.de> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250428090413.38234-1-s.pueschel@pengutronix.de> References: <20250428090413.38234-1-s.pueschel@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:900:1d::77 X-SA-Exim-Mail-From: s.pueschel@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: libcamera-devel@lists.libcamera.org 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" From: Nícolas F. R. A. Prado Add an internal queue that stores requests until there are V4L2 buffer slots available. This avoids the need to cancel requests when there is a shortage of said buffers. Signed-off-by: Nícolas F. R. A. Prado Signed-off-by: Sven Püschel --- Changes in v11: - Added from https://lists.libcamera.org/pipermail/libcamera-devel/2021-September/024121.html --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 103 +++++++++++++++---- 1 file changed, 82 insertions(+), 21 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index c3b718f9..52659fa2 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include "libcamera/internal/camera.h" #include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/framebuffer.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/sysfs.h" @@ -53,18 +55,28 @@ public: const std::string &id() const { return id_; } + void queuePendingRequests(); + void cancelPendingRequests(); + + void setAvailableBufferSlotCount(unsigned int count) { availableBufferSlotCount_ = count; } + Mutex openLock_; std::unique_ptr video_; Stream stream_; std::map> formats_; + std::queue pendingRequests_; std::optional autoExposureMode_; std::optional manualExposureMode_; private: bool generateId(); + int processControl(ControlList *controls, unsigned int id, + const ControlValue &value); + int processControls(Request *request); std::string id_; + unsigned int availableBufferSlotCount_; }; class UVCCameraConfiguration : public CameraConfiguration @@ -98,10 +110,6 @@ public: bool match(DeviceEnumerator *enumerator) override; private: - int processControl(const UVCCameraData *data, ControlList *controls, - unsigned int id, const ControlValue &value); - int processControls(UVCCameraData *data, Request *request); - bool acquireDevice(Camera *camera) override; void releaseDevice(Camera *camera) override; @@ -295,6 +303,8 @@ int PipelineHandlerUVC::start(Camera *camera, [[maybe_unused]] const ControlList if (ret < 0) return ret; + data->setAvailableBufferSlotCount(kUVCBufferSlotCount); + ret = data->video_->streamOn(); if (ret < 0) { data->video_->releaseBuffers(); @@ -308,11 +318,12 @@ void PipelineHandlerUVC::stopDevice(Camera *camera) { UVCCameraData *data = cameraData(camera); data->video_->streamOff(); + data->cancelPendingRequests(); data->video_->releaseBuffers(); } -int PipelineHandlerUVC::processControl(const UVCCameraData *data, ControlList *controls, - unsigned int id, const ControlValue &value) +int UVCCameraData::processControl(ControlList *controls, unsigned int id, + const ControlValue &value) { uint32_t cid; @@ -362,10 +373,10 @@ int PipelineHandlerUVC::processControl(const UVCCameraData *data, ControlList *c switch (value.get()) { case controls::ExposureTimeModeAuto: - mode = data->autoExposureMode_; + mode = autoExposureMode_; break; case controls::ExposureTimeModeManual: - mode = data->manualExposureMode_; + mode = manualExposureMode_; break; } @@ -409,19 +420,19 @@ int PipelineHandlerUVC::processControl(const UVCCameraData *data, ControlList *c return 0; } -int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) +int UVCCameraData::processControls(Request *request) { - ControlList controls(data->video_->controls()); + ControlList controls(video_->controls()); for (const auto &[id, value] : request->controls()) - processControl(data, &controls, id, value); + processControl(&controls, id, value); for (const auto &ctrl : controls) LOG(UVC, Debug) << "Setting control " << utils::hex(ctrl.first) << " to " << ctrl.second.toString(); - int ret = data->video_->setControls(&controls); + int ret = video_->setControls(&controls); if (ret) { LOG(UVC, Error) << "Failed to set controls: " << ret; return ret < 0 ? ret : -EINVAL; @@ -433,21 +444,16 @@ int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request) { UVCCameraData *data = cameraData(camera); - FrameBuffer *buffer = request->findBuffer(&data->stream_); - if (!buffer) { + + if (!request->findBuffer(&data->stream_)) { LOG(UVC, Error) << "Attempt to queue request with invalid stream"; return -ENOENT; } - int ret = processControls(data, request); - if (ret < 0) - return ret; - - ret = data->video_->queueBuffer(buffer); - if (ret < 0) - return ret; + data->pendingRequests_.push(request); + data->queuePendingRequests(); return 0; } @@ -882,6 +888,61 @@ void UVCCameraData::imageBufferReady(FrameBuffer *buffer) pipe()->completeBuffer(request, buffer); pipe()->completeRequest(request); + + availableBufferSlotCount_++; + + queuePendingRequests(); +} + +void UVCCameraData::queuePendingRequests() +{ + while (!pendingRequests_.empty() && availableBufferSlotCount_) { + Request *request = pendingRequests_.front(); + FrameBuffer *buffer = request->findBuffer(&stream_); + + int ret = processControls(request); + if (ret < 0) { + LOG(UVC, Error) << "Failed to process controls with" + << " error " << ret << ". Cancelling" + << " buffer."; + buffer->_d()->cancel(); + pipe()->completeBuffer(request, buffer); + pipe()->completeRequest(request); + pendingRequests_.pop(); + + continue; + } + + ret = video_->queueBuffer(buffer); + if (ret < 0) { + LOG(UVC, Error) << "Failed to queue buffer with error " + << ret << ". Cancelling buffer."; + buffer->_d()->cancel(); + pipe()->completeBuffer(request, buffer); + pipe()->completeRequest(request); + pendingRequests_.pop(); + + continue; + } + + availableBufferSlotCount_--; + + pendingRequests_.pop(); + } +} + +void UVCCameraData::cancelPendingRequests() +{ + while (!pendingRequests_.empty()) { + Request *request = pendingRequests_.front(); + FrameBuffer *buffer = request->findBuffer(&stream_); + + buffer->_d()->cancel(); + pipe()->completeBuffer(request, buffer); + pipe()->completeRequest(request); + + pendingRequests_.pop(); + } } REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC, "uvcvideo")