From patchwork Tue Aug 31 22:37:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= X-Patchwork-Id: 23009 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by patchwork.libcamera.org (Postfix) with ESMTPS id CAAEEC0DA4 for ; Mon, 24 Mar 2025 17:12:39 +0000 (UTC) Received: from pendragon.ideasonboard.com (cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 522C8455 for ; Mon, 24 Mar 2025 18:10:53 +0100 (CET) Delivered-To: kbingham@ideasonboard.com Received: from perceval.ideasonboard.com by perceval.ideasonboard.com with LMTP id yBcMHjqvLmFtcAAA4E0KoQ (envelope-from ) for ; Wed, 01 Sep 2021 00:37:46 +0200 Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by perceval.ideasonboard.com (Postfix) with ESMTPS id 6D8DC8F; Wed, 1 Sep 2021 00:37:46 +0200 (CEST) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1302F6917E; Wed, 1 Sep 2021 00:37:46 +0200 (CEST) Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BAB6760258 for ; Wed, 1 Sep 2021 00:37:33 +0200 (CEST) Received: from localhost.localdomain (unknown [IPv6:2804:14c:1a9:2434:b693:c9:5cb6:b688]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: nfraprado) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id D32D61F43866; Tue, 31 Aug 2021 23:37:31 +0100 (BST) From: =?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= To: libcamera-devel@lists.libcamera.org Date: Tue, 31 Aug 2021 19:37:02 -0300 Message-Id: <20210831223705.1928000-3-nfraprado@collabora.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210831223705.1928000-1-nfraprado@collabora.com> References: <20210831223705.1928000-1-nfraprado@collabora.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 2/5] libcamera: pipeline: uvcvideo: Add internal request queue 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: , Cc: kernel@collabora.com, =?utf-8?q?Andr=C3=A9_Almeida?= Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" X-TUID: 4UL7mSPzsoKm Resent-From: Kieran Bingham Resent-To: parsemail@patchwork.libcamera.org 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 --- Changes in v2: - Added a counter to keep track of the number of available buffer slots - Moved cancellation of pending requests to after video devices stop - Added error log on failure to process controls src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 98 ++++++++++++++++---- 1 file changed, 81 insertions(+), 17 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 5977312a795d..5e73a8e682dd 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -46,8 +47,22 @@ public: ControlInfoMap::Map *ctrls); void bufferReady(FrameBuffer *buffer); + void queuePendingRequests(); + void cancelPendingRequests(); + + void setAvailableBufferSlotCount(unsigned int count) { availableBufferSlotCount_ = count; } + std::unique_ptr video_; Stream stream_; + + std::queue pendingRequests_; + +private: + int processControls(Request *request); + int processControl(ControlList *controls, unsigned int id, + const ControlValue &value); + + unsigned int availableBufferSlotCount_; }; class UVCCameraConfiguration : public CameraConfiguration @@ -83,10 +98,6 @@ public: private: std::string generateId(const UVCCameraData *data); - int processControl(ControlList *controls, unsigned int id, - const ControlValue &value); - int processControls(UVCCameraData *data, Request *request); - UVCCameraData *cameraData(Camera *camera) { return static_cast(camera->_d()); @@ -240,6 +251,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(); @@ -253,10 +266,11 @@ void PipelineHandlerUVC::stop(Camera *camera) { UVCCameraData *data = cameraData(camera); data->video_->streamOff(); + data->cancelPendingRequests(); data->video_->releaseBuffers(); } -int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, +int UVCCameraData::processControl(ControlList *controls, unsigned int id, const ControlValue &value) { uint32_t cid; @@ -337,9 +351,9 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, return 0; } -int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) +int UVCCameraData::processControls(Request *request) { - ControlList controls(data->video_->controls()); + ControlList controls(video_->controls()); for (auto it : request->controls()) { unsigned int id = it.first; @@ -353,7 +367,7 @@ int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) << "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; @@ -365,21 +379,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; } @@ -670,6 +679,61 @@ void UVCCameraData::bufferReady(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->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->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->cancel(); + pipe()->completeBuffer(request, buffer); + pipe()->completeRequest(request); + + pendingRequests_.pop(); + } } REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC)