From patchwork Mon Oct 26 13:08:20 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tatsuki Sugiura X-Patchwork-Id: 28616 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 C5393C3261 for ; Mon, 26 Oct 2026 13:14:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BC0C568FD7; Mon, 26 Oct 2026 14:14:56 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=nemui.org header.i=@nemui.org header.b="GjcKMacd"; dkim-atps=neutral Received: from desire.arege.jp (desire.arege.jp [106.185.149.26]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C5EF368E22 for ; Mon, 26 Oct 2026 14:10:03 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=nemui.org; s=dkim-default; t=1793020168; bh=pbhPPGiOwqzYVLlxdXnI2hiSgT2ongKLECTkYhY5Kr8=; h=From:To:Cc:Subject:Date:From; b=GjcKMacdgox8Jrbl0r+zzcvgYOmqj+V7o60zDHItPVJXohwd02JB8uMmMld/feepn tYEMQIK6LtDhV3N2ZHvLpbqf3BBNMkZUf5k5IpxBlRtKR0Uy2LfLqxjNSHAAOXT1Tj 1JNXR9ZrQNFyoirVHwGHu9L+0RNP27QilMbMIZd42egkDYNdPALVlkBsmhDtK//fA3 Bc0PIdab7dNSqIHpbSmWD72f2CtJDGRIaGa49kUSq+4hrPICuSPJoejpK2HUnza6hD ilf19r4vsa9qBu4Ou8bactVLSN4TD1OzaOop+TF/qWb2kKbdHs0UkbxHO0mfTdxXaO bAK8RgxlvbqZw== Received: from haze.nemui.org (tempest.nemui.org [106.185.149.25]) by desire.arege.jp (Postfix) with ESMTPSA id A21C0C0560C; Mon, 26 Oct 2026 22:09:28 +0900 (JST) Received: by haze.nemui.org (Postfix, from userid 1000) id 716731BA02F8; Mon, 26 Oct 2026 22:09:25 +0900 (JST) From: Tatsuki Sugiura To: libcamera-devel@lists.libcamera.org Cc: Tatsuki Sugiura Subject: [PATCH] gstreamer: Apply controls after acquiring buffers Date: Mon, 26 Oct 2026 22:08:20 +0900 Message-ID: <20261026130820.27075-1-sugi@nemui.org> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 X-Mailman-Approved-At: Mon, 26 Oct 2026 14:14:55 +0100 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" GstLibcameraSrcState::queueRequest() calls GstCameraControls::applyControls() before acquiring the buffers for the request. applyControls() merges the pending controls into the request and then clears them, so they are consumed even when the request is dropped immediately afterwards because the buffer pool is empty, gst_buffer_pool_acquire_buffer() fails and queueRequest() returns -ENOBUFS. The source task retries on -ENOBUFS far faster than requests complete, so most controls an application sets on a playing pipeline are consumed by a request that is never queued. Measured on an OV5675 behind the software ISP, 640x480 into fakesink: of 150 changes to the "saturation" property over 1.5 s, none reached the IPA. Re-sending each value until the request metadata confirmed it landed 2 of 20, after 919 attempts in all, so retrying from the application is not a workaround. Controls set before PLAYING are unaffected, as setCamera() rebuilds the pending controls from the accumulator. Apply the controls after the buffer acquisition loop instead, so that they are only consumed once the request is known to be queueable. The same test then reports 49 of 150, which is all of them: only about 45 requests are queued in 1.5 s. This change was made with the assistance of Claude Code; the behaviour described above was measured on the affected machine. Signed-off-by: Tatsuki Sugiura --- src/gstreamer/gstlibcamerasrc.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 9541aa3..e408d72 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -186,9 +186,6 @@ int GstLibcameraSrcState::queueRequest() if (!request) return -ENOMEM; - /* Apply controls */ - controls_.applyControls(request); - std::unique_ptr wrap = std::make_unique(std::move(request)); @@ -210,6 +207,13 @@ int GstLibcameraSrcState::queueRequest() wrap->attachBuffer(srcpad, buffer); } + /* + * Apply the controls now that the request is known to be queueable. + * applyControls() consumes the pending controls, so calling it before + * the buffers are acquired would drop them along with the request. + */ + controls_.applyControls(wrap->request_); + GST_TRACE_OBJECT(src_, "Requesting buffers"); {