From patchwork Mon Jun 29 16:30:10 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: 27125 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 912B7C3261 for ; Mon, 29 Jun 2026 16:31:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2E1CD65FA7; Mon, 29 Jun 2026 18:31:38 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="uBb3rZh0"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CD75965F6C for ; Mon, 29 Jun 2026 18:30:31 +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 A2CA1E91 for ; Mon, 29 Jun 2026 18:29:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1782750588; bh=A7RzXyNilVle6ZNxDCeLorY7SJjPqpPuLemMS8BMaTg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=uBb3rZh0Ods9LLp4Cr6rkSpvY8pSJtldH54MDmAnzElP616LK8xGNYgyrBkVTYp3w 2OrloXBMZohQhvByUAuMF03pRXfHT30Shwg+aSquYf6SZflzZzv8gpMTpLIDugPG1j 9rziOI5cJpmOy879lIEklrHuRYr7vRHoIleslvUs= From: =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= To: libcamera-devel@lists.libcamera.org Subject: [RFC PATCH v1 47/54] gstreamer: Use camera buffer pool Date: Mon, 29 Jun 2026 18:30:10 +0200 Message-ID: <20260629163017.863145-48-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" Port to using the camera's buffer pool. TODO: this is a horrible mess, probably incorrect in many places, but this is the best for now. Signed-off-by: Barnabás Pőcze --- src/gstreamer/gstlibcamerasrc.cpp | 136 ++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 34 deletions(-) diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 9061f9163c..b65422b2a3 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -48,7 +48,6 @@ struct RequestWrap { RequestWrap(std::unique_ptr request); ~RequestWrap(); - void attachBuffer(GstPad *srcpad, GstBuffer *buffer); GstBuffer *detachBuffer(GstPad *srcpad); std::unique_ptr request_; @@ -68,6 +67,9 @@ RequestWrap::~RequestWrap() return; for (const auto &[stream, fb] : request_->buffers()) { + if (!fb) + continue; + auto *buffer = reinterpret_cast(fb->cookie()); if (buffer) gst_buffer_unref(buffer); @@ -76,15 +78,6 @@ RequestWrap::~RequestWrap() } } -void RequestWrap::attachBuffer(GstPad *srcpad, GstBuffer *buffer) -{ - FrameBuffer *fb = gst_libcamera_buffer_get_frame_buffer(buffer); - Stream *stream = gst_libcamera_pad_get_stream(srcpad); - - request_->addBuffer(stream, fb); - fb->setCookie(reinterpret_cast(buffer)); -} - GstBuffer *RequestWrap::detachBuffer(GstPad *srcpad) { const Stream *stream = gst_libcamera_pad_get_stream(srcpad); @@ -128,11 +121,80 @@ struct GstLibcameraSrcState { ControlList initControls_; guint group_id_; GstCameraControls controls_; + size_t maxRequests_ = 0; int queueRequest(); void requestCompleted(Request *request); int processRequest(); void clearRequests(); + + void addBuffers(GstLibcameraPool *pool) + { + const Stream *stream = gst_libcamera_pool_get_stream(pool); + + for (;;) { + GstBuffer *buffer = nullptr; + GstFlowReturn ret = gst_buffer_pool_acquire_buffer(GST_BUFFER_POOL(pool), &buffer, nullptr); + if (ret != GST_FLOW_OK) + break; + + FrameBuffer *fb = gst_libcamera_buffer_get_frame_buffer(buffer); + fb->setCookie(reinterpret_cast(buffer)); + + GST_TRACE_OBJECT(src_, "Adding buffer for stream:%p fb:%p buffer:%p", + stream, fb, buffer); + + if (cam_->addBuffer(stream, fb)) { + fb->setCookie(0); + gst_buffer_pool_release_buffer(GST_BUFFER_POOL(pool), buffer); + break; + } + } + } + + void addAllBuffers() + { + for (auto *srcpad : srcpads_) + addBuffers(gst_libcamera_pad_get_pool(srcpad)); + } + + int start() + { + int ret = cam_->start(&initControls_); + if (ret) + return ret; + + addAllBuffers(); + + return 0; + } + + void stop() + { + cam_->bufferCompleted.connect(this, [&](Request *request, const Stream *stream, FrameBuffer *fb) { + if (request) + return; + + // \todo no... just no... + for (auto *pad : srcpads_) { + if (gst_libcamera_pad_get_stream(pad) != stream) + continue; + + auto *pool = gst_libcamera_pad_get_pool(pad); + auto *buffer = reinterpret_cast(fb->cookie()); + fb->setCookie(0); + + gst_buffer_pool_release_buffer(GST_BUFFER_POOL(pool), buffer); + + break; + } + }); + + cam_->stop(); + + cam_->bufferCompleted.disconnect(this); + clearRequests(); + } }; struct _GstLibcameraSrc { @@ -182,6 +244,13 @@ GstStaticPadTemplate request_src_template = { /* Must be called with stream_lock held. */ int GstLibcameraSrcState::queueRequest() { + { + GLibLocker locker(&lock_); + + if (queuedRequests_.size() + completedRequests_.size() >= maxRequests_) + return -EAGAIN; + } + std::unique_ptr request = cam_->createRequest(); if (!request) return -ENOMEM; @@ -189,27 +258,12 @@ int GstLibcameraSrcState::queueRequest() /* Apply controls */ controls_.applyControls(request); + for (auto *srcpad : srcpads_) + request->enableStream(gst_libcamera_pad_get_stream(srcpad), true); + std::unique_ptr wrap = std::make_unique(std::move(request)); - for (GstPad *srcpad : srcpads_) { - GstLibcameraPool *pool = gst_libcamera_pad_get_pool(srcpad); - GstBuffer *buffer; - GstFlowReturn ret; - - ret = gst_buffer_pool_acquire_buffer(GST_BUFFER_POOL(pool), - &buffer, nullptr); - if (ret != GST_FLOW_OK) { - /* - * RequestWrap has ownership of the request, and we - * won't be queueing this one due to lack of buffers. - */ - return -ENOBUFS; - } - - wrap->attachBuffer(srcpad, buffer); - } - GST_TRACE_OBJECT(src_, "Requesting buffers"); { @@ -363,6 +417,8 @@ int GstLibcameraSrcState::processRequest() const StreamConfiguration &stream_cfg = stream->configuration(); GstBufferPool *video_pool = gst_libcamera_pad_get_video_pool(srcpad); + GST_TRACE_OBJECT(src_, "Received fb:%p buffer:%p on stream:%p", fb, buffer, stream); + if (video_pool) { /* Only set video pool when a copy is needed. */ GstBuffer *copy = nullptr; @@ -702,6 +758,18 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self) gst_pad_check_reconfigure(srcpad); } + state->maxRequests_ = 0; + + for (auto *srcpad : state->srcpads_) { + Stream *stream = gst_libcamera_pad_get_stream(srcpad); + size_t poolSize = gst_libcamera_allocator_get_pool_size(self->allocator, stream); + + state->maxRequests_ = std::max(state->maxRequests_, poolSize); + } + + if (state->maxRequests_ <= 0) + return false; + return true; } @@ -748,17 +816,18 @@ gst_libcamera_src_task_run(gpointer user_data) } if (reconfigure) { - state->cam_->stop(); - state->clearRequests(); + state->stop(); if (!gst_libcamera_src_negotiate(self)) { GST_ELEMENT_FLOW_ERROR(self, GST_FLOW_NOT_NEGOTIATED); gst_task_stop(self->task); } - state->cam_->start(&state->initControls_); + state->start(); } + state->addAllBuffers(); + /* * Create and queue one request. If no buffers are available the * function returns -ENOBUFS, which we ignore here as that's not a @@ -915,7 +984,7 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread, gst_pad_push_event(srcpad, gst_event_new_segment(&segment)); } - ret = state->cam_->start(&state->initControls_); + ret = state->start(); if (ret) { GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS, ("Failed to start the camera: %s", g_strerror(-ret)), @@ -935,8 +1004,7 @@ gst_libcamera_src_task_leave([[maybe_unused]] GstTask *task, GST_DEBUG_OBJECT(self, "Streaming thread is about to stop"); - state->cam_->stop(); - state->clearRequests(); + state->stop(); { GLibRecLocker locker(&self->stream_lock);