{"id":26365,"url":"https://patchwork.libcamera.org/api/1.1/patches/26365/?format=json","web_url":"https://patchwork.libcamera.org/patch/26365/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260325151416.2114564-24-stefan.klug@ideasonboard.com>","date":"2026-03-25T15:13:55","name":"[v2,23/32] libcamera: internal: Add SequenceSyncHelper class","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"ff2b42196818fa60e67d91863a4c7e7d3d3a75ff","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/1.1/people/184/?format=json","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/26365/mbox/","series":[{"id":5849,"url":"https://patchwork.libcamera.org/api/1.1/series/5849/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5849","date":"2026-03-25T15:13:32","name":"rkisp1: pipeline rework for PFC","version":2,"mbox":"https://patchwork.libcamera.org/series/5849/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/26365/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/26365/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id DD8B1BE086\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Mar 2026 15:15:47 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7977862CC9;\n\tWed, 25 Mar 2026 16:15:47 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4773462C44\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Mar 2026 16:15:46 +0100 (CET)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:b16a:5ed9:4ada:a95a])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 4E3C41B98; \n\tWed, 25 Mar 2026 16:14:28 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"TX4+K4z4\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1774451668;\n\tbh=3OpmvkR+XHCPZ8nSjonhVBpIOe4SDmuym/y2EZWkYfU=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=TX4+K4z4CoxWSUeO1VCvhq2cIpBnOP/d+RBJiCDITDckef1ilNkCOoAcnQ18vgJtS\n\tDj33LQvp8id40op2cYBtUoVl1U6JNtmnbggalY+7dbFg7/0+BDe4PDyUPfQTC0T60q\n\tNycLa5/szAk7QCC3cOq+HIUhQz4iAcnt+knErECM=","From":"Stefan Klug <stefan.klug@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Stefan Klug <stefan.klug@ideasonboard.com>","Subject":"[PATCH v2 23/32] libcamera: internal: Add SequenceSyncHelper class","Date":"Wed, 25 Mar 2026 16:13:55 +0100","Message-ID":"<20260325151416.2114564-24-stefan.klug@ideasonboard.com>","X-Mailer":"git-send-email 2.51.0","In-Reply-To":"<20260325151416.2114564-1-stefan.klug@ideasonboard.com>","References":"<20260325151416.2114564-1-stefan.klug@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"On a V4L2 buffer the assigned sequence is not known until the buffer is\ndequeued. But for per frame controls we have to prepare other data like\nsensor controls and ISP params in advance. So we try to anticipate the\nsequence number a given buffer will be. In a perfect world this works\nwell as long as the initial sequence is assigned correctly. But it\nbreaks as soon as things like running out of buffers or incomplete\nimages happen. To make things even more complicated, in most cases\nmore than one buffer is queued to the kernel at a time.\n\nSo as soon as a sequence number doesn't match the expected one after\ndequeuing, most likely all the already queued buffers will be dequeued\nwith the same error.  It is not sufficient to simply add the correction\nafter dequeuing because the error on all queued frames would accumulate\nand the whole system starts to oscillate. To work around that add a\nSequenceSyncHelper class that tracks the expected error and allows to\neasily query the necessary correction when queuing new buffers.\n\nSigned-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n\n---\n\nTodo:\n- Add class documentation\n\nChanges in v2:\n- Moved files to man src dir, to be able to reuse it in other pipelines\n- Added cancel() function.\n---\n include/libcamera/internal/meson.build        |  1 +\n .../libcamera/internal/sequence_sync_helper.h | 76 +++++++++++++++++++\n src/libcamera/meson.build                     |  1 +\n src/libcamera/sequence_sync_helper.cpp        | 21 +++++\n 4 files changed, 99 insertions(+)\n create mode 100644 include/libcamera/internal/sequence_sync_helper.h\n create mode 100644 src/libcamera/sequence_sync_helper.cpp","diff":"diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\nindex 4d2a09bd7041..80c425e13ccd 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -40,6 +40,7 @@ libcamera_internal_headers = files([\n     'process.h',\n     'pub_key.h',\n     'request.h',\n+    'sequence_sync_helper.h',\n     'shared_mem_object.h',\n     'source_paths.h',\n     'sysfs.h',\ndiff --git a/include/libcamera/internal/sequence_sync_helper.h b/include/libcamera/internal/sequence_sync_helper.h\nnew file mode 100644\nindex 000000000000..407c6383dca6\n--- /dev/null\n+++ b/include/libcamera/internal/sequence_sync_helper.h\n@@ -0,0 +1,76 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2025, Ideas on Board\n+ *\n+ * Sequence sync helper\n+ */\n+\n+#pragma once\n+\n+#include <queue>\n+\n+#include <libcamera/base/log.h>\n+\n+namespace libcamera {\n+\n+LOG_DECLARE_CATEGORY(SequenceSyncHelper)\n+\n+class SequenceSyncHelper\n+{\n+public:\n+\tint gotFrame(size_t expectedSequence, size_t actualSequence)\n+\t{\n+\t\tASSERT(!corrections_.empty());\n+\t\tint diff = actualSequence - expectedSequence;\n+\t\tint corr = corrections_.front();\n+\t\tcorrections_.pop();\n+\t\texpectedOffset_ -= corr;\n+\t\tint necessaryCorrection = diff - expectedOffset_;\n+\t\tcorrectionToApply_ += necessaryCorrection;\n+\n+\t\tLOG(SequenceSyncHelper, Debug) << \"Sync frame \"\n+\t\t\t\t\t       << \"expected: \" << expectedSequence\n+\t\t\t\t\t       << \" actual: \" << actualSequence\n+\t\t\t\t\t       << \" correction: \" << corr\n+\t\t\t\t\t       << \" expectedOffset: \" << expectedOffset_\n+\t\t\t\t\t       << \" correctionToApply \" << correctionToApply_;\n+\n+\t\texpectedOffset_ += necessaryCorrection;\n+\t\treturn necessaryCorrection;\n+\t}\n+\n+\tvoid cancelFrame()\n+\t{\n+\t\tint corr = corrections_.front();\n+\t\tcorrections_.pop();\n+\t\texpectedOffset_ -= corr;\n+\t}\n+\n+\t/* Value to be added to the source sequence */\n+\tint correction()\n+\t{\n+\t\treturn correctionToApply_;\n+\t}\n+\n+\tvoid pushCorrection(int correction)\n+\t{\n+\t\tcorrections_.push(correction);\n+\t\tcorrectionToApply_ -= correction;\n+\t\tLOG(SequenceSyncHelper, Debug)\n+\t\t\t<< \"Push correction \" << correction\n+\t\t\t<< \" correctionToApply \" << correctionToApply_;\n+\t}\n+\n+\tvoid reset()\n+\t{\n+\t\tcorrections_ = {};\n+\t\tcorrectionToApply_ = 0;\n+\t\texpectedOffset_ = 0;\n+\t}\n+\n+\tstd::queue<int> corrections_;\n+\tint correctionToApply_ = 0;\n+\tint expectedOffset_ = 0;\n+};\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex d15943586300..8b82555a5e81 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -49,6 +49,7 @@ libcamera_internal_sources = files([\n     'pipeline_handler.cpp',\n     'process.cpp',\n     'pub_key.cpp',\n+    'sequence_sync_helper.cpp',\n     'shared_mem_object.cpp',\n     'source_paths.cpp',\n     'sysfs.cpp',\ndiff --git a/src/libcamera/sequence_sync_helper.cpp b/src/libcamera/sequence_sync_helper.cpp\nnew file mode 100644\nindex 000000000000..7f0b9c9111a7\n--- /dev/null\n+++ b/src/libcamera/sequence_sync_helper.cpp\n@@ -0,0 +1,21 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2026, Ideas on Board.\n+ *\n+ * Helper to easily record debug metadata inside libcamera.\n+ */\n+\n+#include \"libcamera/internal/sequence_sync_helper.h\"\n+\n+#include <libcamera/base/log.h>\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(SequenceSyncHelper)\n+\n+/**\n+ * \\file debug_controls.h\n+ * \\brief Helper to synchronize buffer sequences\n+ */\n+\n+} /* namespace libcamera */\n","prefixes":["v2","23/32"]}