From patchwork Mon Jun 29 16:29:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= X-Patchwork-Id: 27114 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 63327C3261 for ; Mon, 29 Jun 2026 16:31:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EF1D865F9B; Mon, 29 Jun 2026 18:31:25 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="bgoTa776"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BBDEF65F5E for ; Mon, 29 Jun 2026 18:30:28 +0200 (CEST) Received: from pb-laptop.local (185.221.140.128.nat.pool.zt.hu [185.221.140.128]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 98BEAE91 for ; Mon, 29 Jun 2026 18:29:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1782750585; bh=Y8L3gSLz9th3JTgFM5GAGAjtCWKQ7oKsE1dmWHmWxUA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=bgoTa776n2SaY58TbMII4ORAnRHA1HZB9sXs3IK9RD9//qmfwJvbtMzpi/TewZKoS jteAxBYP4itLL1gheJ8DTwLrqXwqn+cAyFfPezmuuUIqOZqYQDeunX5B/oqWD4y4r+ o6zeuhVF2IZ68AS7YpanyThIbsC6IktyuetpmIeY= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v1 35/54] libcamera: pipeline: uvcvideo: Use buffer pool prototype Date: Mon, 29 Jun 2026 18:29:58 +0200 Message-ID: <20260629163017.863145-36-barnabas.pocze@ideasonboard.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260629163017.863145-1-barnabas.pocze@ideasonboard.com> References: <20260629163017.863145-1-barnabas.pocze@ideasonboard.com> MIME-Version: 1.0 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" Convert the uvcvideo pipeline handler to use the buffer pool interface of cameras. Do that by keeping track of the number of queued buffers, and each time * a request is queued, * a buffer is added, or * a buffer is returned from the kernel the pipeline handler tries to consume as many requests as possible. Signed-off-by: Barnabás Pőcze --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 71 +++++++++++++++----- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 928ee79559..e70cbe23c3 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -62,6 +62,8 @@ public: std::optional autoExposureMode_; std::optional manualExposureMode_; + size_t processedRequests_ = 0; + private: bool generateId(); @@ -95,6 +97,8 @@ public: void stopDevice(Camera *camera) override; int queueRequestDevice(Camera *camera, Request *request) override; + void buffersAddedDevice(Camera *camera) override; + void tryRunCamera(UVCCameraData *data); bool match(DeviceEnumerator *enumerator) override; @@ -230,7 +234,7 @@ CameraConfiguration::Status UVCCameraConfiguration::validate() } PipelineHandlerUVC::PipelineHandlerUVC(CameraManager *manager) - : PipelineHandler(manager, {}) + : PipelineHandler(manager, { .usesBufferPool = true }) { } @@ -323,6 +327,9 @@ void PipelineHandlerUVC::stopDevice(Camera *camera) UVCCameraData *data = cameraData(camera); data->video_->streamOff(); data->video_->releaseBuffers(); + + while (!data->queuedRequests_.empty()) + cancelRequest(data->queuedRequests_.front()); } int PipelineHandlerUVC::processControl(const UVCCameraData *data, ControlList *controls, @@ -446,26 +453,49 @@ int PipelineHandlerUVC::processControls(UVCCameraData *data, const ControlList & return ret; } -int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request) +int PipelineHandlerUVC::queueRequestDevice(Camera *camera, [[maybe_unused]] Request *request) { - UVCCameraData *data = cameraData(camera); - FrameBuffer *buffer = request->findBuffer(&data->stream_); - if (!buffer) { - LOG(UVC, Error) - << "Attempt to queue request with invalid stream"; + /* `request` is already in `Camera::Private::queuedRequests_` */ + tryRunCamera(cameraData(camera)); + return 0; +} - return -ENOENT; - } +void PipelineHandlerUVC::buffersAddedDevice(Camera *camera) +{ + tryRunCamera(cameraData(camera)); +} - int ret = processControls(data, request->controls()); - if (ret < 0) - return ret; +void PipelineHandlerUVC::tryRunCamera(UVCCameraData *data) +{ + ASSERT(data->processedRequests_ <= data->queuedRequests_.size()); - ret = data->video_->queueBuffer(buffer); - if (ret < 0) - return ret; + auto it = std::next(data->queuedRequests_.begin(), data->processedRequests_); + for (; it != data->queuedRequests_.end(); ++it, data->processedRequests_++) { + Request *request = *it; + ASSERT(request->status() == Request::RequestPending); - return 0; + int ret = processControls(data, request->controls()); + if (ret < 0) { + cancelRequest(request); + continue; + } + +again:; + auto buffer = data->acquireBuffer(&data->stream_); + if (!buffer) + break; + + ret = data->video_->queueBuffer(buffer.get()); + if (ret < 0) { + // \todo do not do this if the error is "too many buffers" + // but that probably shouldn't ever be the case because + // VIDEO_MAX_FRAME == 32 == maxQueuedRequestsDevice + data->rejectBuffer(std::move(buffer)); + goto again; + } + + buffer.release(); + } } bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) @@ -893,14 +923,19 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, void UVCCameraData::imageBufferReady(FrameBuffer *buffer) { - Request *request = buffer->_d()->request(); + ASSERT(!queuedRequests_.empty()); + ASSERT(processedRequests_ > 0); + + Request *request = queuedRequests_.front(); /* \todo Use the UVC metadata to calculate a more precise timestamp */ request->_d()->metadata().set(controls::SensorTimestamp, buffer->metadata().timestamp); pipe()->completeBuffer(request, buffer); - pipe()->completeRequest(request); + processedRequests_ -= pipe()->completeRequest(request); + + static_cast(pipe())->tryRunCamera(this); } REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC, "uvcvideo")