Patch Detail
Show a patch.
GET /api/1.1/patches/26374/?format=api
{ "id": 26374, "url": "https://patchwork.libcamera.org/api/1.1/patches/26374/?format=api", "web_url": "https://patchwork.libcamera.org/patch/26374/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "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-33-stefan.klug@ideasonboard.com>", "date": "2026-03-25T15:14:04", "name": "[v2,32/32] DNI: Move all queue/algo logic into FcLogic class", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "caf94d3b8b3867099a33d6c3a817b1bd51c3317c", "submitter": { "id": 184, "url": "https://patchwork.libcamera.org/api/1.1/people/184/?format=api", "name": "Stefan Klug", "email": "stefan.klug@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/26374/mbox/", "series": [ { "id": 5849, "url": "https://patchwork.libcamera.org/api/1.1/series/5849/?format=api", "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/26374/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/26374/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 3D12DC3316\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Mar 2026 15:16:13 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id ACA6B62CE8;\n\tWed, 25 Mar 2026 16:16:12 +0100 (CET)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6229B62BB6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Mar 2026 16:16:11 +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 37C8E1B98; \n\tWed, 25 Mar 2026 16:14:53 +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=\"fQuqcEG5\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1774451693;\n\tbh=mo4fhPqKCeRqTMq1VS82qLaUbLgfc6H1VAwfvMjhmow=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=fQuqcEG5z+zzXPO0FMlSZlYqYVKHzCyYieo2EKfoTBMCSWlShHjNtsQqBq9k8pKss\n\tTpgkc0w1ACz19tmgbL+JbjLuWh3cDd15DytdqSAHP9Fukw0EoA4eVxRshTxH6YHV7X\n\tkHUJER/HQ6fFJGQs+7XDGzIEfTeJYJwpB/U0T0f8=", "From": "Stefan Klug <stefan.klug@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Stefan Klug <stefan.klug@ideasonboard.com>", "Subject": "[PATCH v2 32/32] DNI: Move all queue/algo logic into FcLogic class", "Date": "Wed, 25 Mar 2026 16:14:04 +0100", "Message-ID": "<20260325151416.2114564-33-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": "This is a prototype to toy around with the idea of moving all the\ntypical IPA lgoc into an own FcLogic class (better names welcome). This\ncould further reduce the boilerplate necessary to implement a typical\nIPA.\n\nSigned-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n\n---\n\nChanges in v2:\n- Added this patch\n---\n src/ipa/libipa/algorithm.h | 5 +\n src/ipa/libipa/fc_logic.cpp | 20 ++++\n src/ipa/libipa/fc_logic.h | 151 ++++++++++++++++++++++++++\n src/ipa/libipa/fc_queue.h | 8 +-\n src/ipa/libipa/meson.build | 2 +\n src/ipa/rkisp1/algorithms/algorithm.h | 5 +\n src/ipa/rkisp1/ipa_context.h | 5 +-\n src/ipa/rkisp1/rkisp1.cpp | 61 ++++-------\n 8 files changed, 212 insertions(+), 45 deletions(-)\n create mode 100644 src/ipa/libipa/fc_logic.cpp\n create mode 100644 src/ipa/libipa/fc_logic.h", "diff": "diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h\nindex 9a19dbd61b31..2d7372d2ff5e 100644\n--- a/src/ipa/libipa/algorithm.h\n+++ b/src/ipa/libipa/algorithm.h\n@@ -38,6 +38,11 @@ public:\n \t\treturn 0;\n \t}\n \n+\tvirtual bool enabled()\n+\t{\n+\t\treturn true;\n+\t}\n+\n \tvirtual void queueRequest([[maybe_unused]] typename Module::Context &context,\n \t\t\t\t [[maybe_unused]] const uint32_t frame,\n \t\t\t\t [[maybe_unused]] typename Module::FrameContext &frameContext,\ndiff --git a/src/ipa/libipa/fc_logic.cpp b/src/ipa/libipa/fc_logic.cpp\nnew file mode 100644\nindex 000000000000..8b1917dfd40e\n--- /dev/null\n+++ b/src/ipa/libipa/fc_logic.cpp\n@@ -0,0 +1,20 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2022, Google Inc.\n+ *\n+ * IPA Frame context queue\n+ */\n+\n+#include \"fc_logic.h\"\n+\n+#include <libcamera/base/log.h>\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(FCLogic)\n+\n+namespace ipa {\n+\n+} /* namespace ipa */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/libipa/fc_logic.h b/src/ipa/libipa/fc_logic.h\nnew file mode 100644\nindex 000000000000..be51b09643b8\n--- /dev/null\n+++ b/src/ipa/libipa/fc_logic.h\n@@ -0,0 +1,151 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2022, Google Inc.\n+ *\n+ * IPA Frame context queue\n+ */\n+\n+#pragma once\n+\n+#include <list>\n+#include <stdint.h>\n+#include <vector>\n+\n+#include <libcamera/base/log.h>\n+#include <libcamera/controls.h>\n+\n+#include \"algorithm.h\"\n+#include \"fc_queue.h\"\n+\n+namespace libcamera {\n+\n+LOG_DECLARE_CATEGORY(FCLogic)\n+\n+namespace ipa {\n+\n+template<typename FrameContext>\n+class FCLogic;\n+\n+template<typename _Module>\n+class FCLogic\n+{\n+public:\n+\tusing Module = _Module;\n+\tusing Algo = Algorithm<Module>;\n+\n+\tFCLogic(unsigned int size, Module *module, typename Module::Context &context)\n+\t\t: module_(module), contexts_(size), context_(context)\n+\t{\n+\t\tclear();\n+\t}\n+\n+\tvoid clear()\n+\t{\n+\t\tfor (typename Module::FrameContext &ctx : contexts_) {\n+\t\t\tctx.frame_ = 0;\n+\t\t}\n+\t\tinitialized_ = false;\n+\t\tlastPrepared_ = 0;\n+\t}\n+\n+\ttypename Module::FrameContext &initFrameContext(unsigned int frame, const ControlList &controls = {})\n+\t{\n+\t\ttypename Module::FrameContext &fc = contexts_[frame % contexts_.size()];\n+\t\tFrameContext &frameContext = fc;\n+\n+\t\t/*\n+\t\t * If the IPA algorithms try to access a frame context slot which\n+\t\t * has been already overwritten by a newer context, it means the\n+\t\t * frame context queue has overflowed and the desired context\n+\t\t * has been forever lost. The pipeline handler shall avoid\n+\t\t * queueing more requests to the IPA than the frame context\n+\t\t * queue size.\n+\t\t */\n+\t\tif (frame < frameContext.frame_)\n+\t\t\tLOG(FCLogic, Fatal) << \"Frame context for \" << frame\n+\t\t\t\t\t << \" has been overwritten by \"\n+\t\t\t\t\t << frameContext.frame_;\n+\n+\t\tif (initialized_ && frame == frameContext.frame_) {\n+\t\t\tif (!controls.empty()) {\n+\t\t\t\t/* Too late to apply the controls. Store them for later. */\n+\t\t\t\tLOG(FCLogic, Warning)\n+\t\t\t\t\t<< \"Request underrun. Controls for frame \"\n+\t\t\t\t\t<< frame << \" are delayed \";\n+\t\t\t\tcontrolsToApply_.merge(controls,\n+\t\t\t\t\t\t ControlList::MergePolicy::OverwriteExisting);\n+\t\t\t}\n+\n+\t\t\treturn fc;\n+\t\t}\n+\n+\t\tconst ControlList *controls2 = &controls;\n+\t\tif (!controlsToApply_.empty()) {\n+\t\t\tLOG(FCLogic, Debug) << \"Applied late controls on frame\" << frame;\n+\t\t\tcontrolsToApply_.merge(controls, ControlList::MergePolicy::OverwriteExisting);\n+\t\t\tcontrols2 = &controlsToApply_;\n+\t\t}\n+\n+\t\tfc = {};\n+\t\tframeContext.frame_ = frame;\n+\t\tfor (auto const &a : module_->algorithms()) {\n+\t\t\tAlgo *algo = static_cast<Algo *>(a.get());\n+\t\t\tif (!algo->enabled())\n+\t\t\t\tcontinue;\n+\t\t\talgo->queueRequest(context_, fc.frame(), fc, *controls2);\n+\t\t}\n+\n+\t\tinitialized_ = true;\n+\t\tcontrolsToApply_.clear();\n+\n+\t\treturn fc;\n+\t}\n+\n+\tvoid prepareFrame(const uint32_t frame, typename Module::Params *params)\n+\t{\n+\t\twhile (lastPrepared_ + 1 < frame) {\n+\t\t\tuint32_t f = lastPrepared_ + 1;\n+\t\t\tLOG(FCLogic, Warning) << \"Collect skipped params for frame \" << f;\n+\t\t\tprepareFrame(f, params);\n+\t\t}\n+\n+\t\ttypename Module::FrameContext &frameContext = initFrameContext(frame);\n+\t\tfor (auto const &algo : module_->algorithms())\n+\t\t\talgo->prepare(context_, frameContext.frame(), frameContext, params);\n+\n+\t\tlastPrepared_ = std::max(lastPrepared_, frame);\n+\t}\n+\n+\tvoid processStats(const uint32_t frame, const typename Module::Stats *stats, ControlList &metadata)\n+\t{\n+\t\t/*\n+\t\t * If we apply stats on an uninitialized frame the activeState\n+\t\t * might end up very wrong (imagine exposureTime initialized to\n+\t\t * 0 but used together with the agc stats to upadet activeState.\n+\t\t */\n+\t\tif (!isInitialize(frame))\n+\t\t\tLOG(FCLogic, Error) << \"Process stats called on an uninitialized FC \" << frame;\n+\n+\t\ttypename Module::FrameContext &frameContext = initFrameContext(frame);\n+\t\tfor (auto const &algo : module_->algorithms())\n+\t\t\talgo->process(context_, frameContext.frame(), frameContext, stats, metadata);\n+\t}\n+\n+private:\n+\tbool isInitialize(const uint32_t frame)\n+\t{\n+\t\tFrameContext &frameContext = contexts_[frame % contexts_.size()];\n+\t\treturn initialized_ && frame == frameContext.frame_;\n+\t}\n+\n+\tconst Module *module_;\n+\tstd::vector<typename Module::FrameContext> contexts_;\n+\ttypename Module::Context &context_;\n+\tControlList controlsToApply_;\n+\tuint32_t lastPrepared_;\n+\tbool initialized_;\n+};\n+\n+} /* namespace ipa */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/libipa/fc_queue.h b/src/ipa/libipa/fc_queue.h\nindex 633bf646d88d..34811cfb3514 100644\n--- a/src/ipa/libipa/fc_queue.h\n+++ b/src/ipa/libipa/fc_queue.h\n@@ -22,11 +22,17 @@ namespace ipa {\n template<typename FrameContext>\n class FCQueue;\n \n+template<typename FrameContext>\n+class FCLogic;\n+\n struct FrameContext {\n \tuint32_t frame() const { return frame_; }\n \n private:\n-\ttemplate<typename T> friend class FCQueue;\n+\ttemplate<typename T>\n+\tfriend class FCQueue;\n+\ttemplate<typename T>\n+\tfriend class FCLogic;\n \tuint32_t frame_;\n };\n \ndiff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build\nindex 963c5ee73063..918279a89d27 100644\n--- a/src/ipa/libipa/meson.build\n+++ b/src/ipa/libipa/meson.build\n@@ -9,6 +9,7 @@ libipa_headers = files([\n 'camera_sensor_helper.h',\n 'colours.h',\n 'exposure_mode_helper.h',\n+ 'fc_logic.h',\n 'fc_queue.h',\n 'fixedpoint.h',\n 'histogram.h',\n@@ -30,6 +31,7 @@ libipa_sources = files([\n 'camera_sensor_helper.cpp',\n 'colours.cpp',\n 'exposure_mode_helper.cpp',\n+ 'fc_logic.cpp',\n 'fc_queue.cpp',\n 'fixedpoint.cpp',\n 'histogram.cpp',\ndiff --git a/src/ipa/rkisp1/algorithms/algorithm.h b/src/ipa/rkisp1/algorithms/algorithm.h\nindex 715cfcd8298b..8b6644c0ee26 100644\n--- a/src/ipa/rkisp1/algorithms/algorithm.h\n+++ b/src/ipa/rkisp1/algorithms/algorithm.h\n@@ -23,6 +23,11 @@ public:\n \t{\n \t}\n \n+\tvirtual bool enabled() override\n+\t{\n+\t\treturn !disabled_;\n+\t}\n+\n \tbool disabled_;\n \tbool supportsRaw_;\n };\ndiff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\nindex e61391bb1510..43ac9415a0d5 100644\n--- a/src/ipa/rkisp1/ipa_context.h\n+++ b/src/ipa/rkisp1/ipa_context.h\n@@ -236,8 +236,7 @@ struct IPAFrameContext : public FrameContext {\n };\n \n struct IPAContext {\n-\tIPAContext(unsigned int frameContextSize)\n-\t\t: frameContexts(frameContextSize)\n+\tIPAContext()\n \t{\n \t}\n \n@@ -246,8 +245,6 @@ struct IPAContext {\n \tIPASessionConfiguration configuration;\n \tIPAActiveState activeState;\n \n-\tFCQueue<IPAFrameContext> frameContexts;\n-\n \tControlInfoMap::Map ctrlMap;\n \n \tDebugMetadata debugMetadata;\ndiff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\nindex 863cea13dfa3..baebaa8ceb77 100644\n--- a/src/ipa/rkisp1/rkisp1.cpp\n+++ b/src/ipa/rkisp1/rkisp1.cpp\n@@ -32,6 +32,7 @@\n #include \"libcamera/internal/yaml_parser.h\"\n \n #include \"algorithms/algorithm.h\"\n+#include \"libipa/fc_logic.h\"\n \n #include \"ipa_context.h\"\n #include \"params.h\"\n@@ -78,7 +79,7 @@ protected:\n \tstd::string logPrefix() const override;\n \n private:\n-\tuint32_t computeParamsInternal(IPAFrameContext &frameContext, const uint32_t bufferId);\n+\tuint32_t computeParamsInternal(const uint32_t frame, const uint32_t bufferId);\n \n \tvoid updateControls(const IPACameraSensorInfo &sensorInfo,\n \t\t\t const ControlInfoMap &sensorControls,\n@@ -92,6 +93,7 @@ private:\n \n \t/* Local parameter storage */\n \tstruct IPAContext context_;\n+\tFCLogic<Module> fcLogic_;\n };\n \n namespace {\n@@ -132,12 +134,8 @@ const ControlInfoMap::Map rkisp1Controls{\n } /* namespace */\n \n IPARkISP1::IPARkISP1()\n-\t: context_(kMaxFrameContexts)\n+\t: Module(), context_(), fcLogic_(kMaxFrameContexts, this, context_)\n {\n-\tcontext_.frameContexts.setInitCallback(\n-\t\t[this](IPAFrameContext &fc, const ControlList &c) {\n-\t\t\tthis->initializeFrameContext(fc, c);\n-\t\t});\n }\n \n std::string IPARkISP1::logPrefix() const\n@@ -225,15 +223,15 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,\n void IPARkISP1::start(const ControlList &controls, const uint32_t paramBufferId,\n \t\t StartResult *result)\n {\n-\tIPAFrameContext &frameContext = context_.frameContexts.getOrInitContext(0, controls);\n-\tresult->paramBufferBytesUsed = computeParamsInternal(frameContext, paramBufferId);\n+\tIPAFrameContext &frameContext = fcLogic_.initFrameContext(0, controls);\n+\tresult->paramBufferBytesUsed = computeParamsInternal(0, paramBufferId);\n \tresult->controls = getSensorControls(frameContext);\n \tresult->code = 0;\n }\n \n void IPARkISP1::stop()\n {\n-\tcontext_.frameContexts.clear();\n+\tfcLogic_.clear();\n }\n \n int IPARkISP1::configure(const IPAConfigInfo &ipaConfig,\n@@ -257,7 +255,7 @@ int IPARkISP1::configure(const IPAConfigInfo &ipaConfig,\n \t/* Clear the IPA context before the streaming session. */\n \tcontext_.configuration = {};\n \tcontext_.activeState = {};\n-\tcontext_.frameContexts.clear();\n+\tfcLogic_.clear();\n \n \tcontext_.configuration.paramFormat = ipaConfig.paramFormat;\n \n@@ -345,20 +343,10 @@ void IPARkISP1::unmapBuffers(const std::vector<unsigned int> &ids)\n void IPARkISP1::queueRequest(const uint32_t frame, const ControlList &controls)\n {\n \tcontext_.debugMetadata.enableByControl(controls);\n-\tcontext_.frameContexts.getOrInitContext(frame, controls);\n+\tfcLogic_.initFrameContext(frame, controls);\n }\n \n-void IPARkISP1::initializeFrameContext(IPAFrameContext &fc, const ControlList &controls)\n-{\n-\tfor (const auto &a : algorithms()) {\n-\t\tAlgorithm *algo = static_cast<Algorithm *>(a.get());\n-\t\tif (algo->disabled_)\n-\t\t\tcontinue;\n-\t\talgo->queueRequest(context_, fc.frame(), fc, controls);\n-\t}\n-}\n-\n-uint32_t IPARkISP1::computeParamsInternal(IPAFrameContext &frameContext, const uint32_t bufferId)\n+uint32_t IPARkISP1::computeParamsInternal(const uint32_t frame, const uint32_t bufferId)\n {\n \tif (bufferId == 0)\n \t\treturn 0;\n@@ -366,17 +354,16 @@ uint32_t IPARkISP1::computeParamsInternal(IPAFrameContext &frameContext, const u\n \tRkISP1Params params(context_.configuration.paramFormat,\n \t\t\t mappedBuffers_.at(bufferId).planes()[0]);\n \n-\tfor (const auto &algo : algorithms())\n-\t\talgo->prepare(context_, frameContext.frame(), frameContext, ¶ms);\n+\tfcLogic_.prepareFrame(frame, ¶ms);\n \n \treturn params.bytesused();\n }\n \n void IPARkISP1::computeParams(const uint32_t frame, const uint32_t bufferId)\n {\n-\tIPAFrameContext &frameContext = context_.frameContexts.getOrInitContext(frame);\n+\tuint32_t size = computeParamsInternal(frame, bufferId);\n \n-\tuint32_t size = computeParamsInternal(frameContext, bufferId);\n+\tIPAFrameContext &frameContext = fcLogic_.initFrameContext(frame);\n \tControlList ctrls = getSensorControls(frameContext);\n \tsetSensorControls.emit(frame, ctrls);\n \n@@ -387,7 +374,13 @@ void IPARkISP1::computeParams(const uint32_t frame, const uint32_t bufferId)\n void IPARkISP1::processStats(const uint32_t frame, const uint32_t bufferId,\n \t\t\t const ControlList &sensorControls)\n {\n-\tIPAFrameContext &frameContext = context_.frameContexts.getOrInitContext(frame);\n+\tIPAFrameContext &frameContext = fcLogic_.initFrameContext(frame);\n+\tframeContext.sensor.exposure =\n+\t\tsensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n+\tframeContext.sensor.gain =\n+\t\tcontext_.camHelper->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());\n+\n+\tControlList metadata(controls::controls);\n \n \t/*\n \t * In raw capture mode, the ISP is bypassed and no statistics buffer is\n@@ -398,19 +391,7 @@ void IPARkISP1::processStats(const uint32_t frame, const uint32_t bufferId,\n \t\tstats = reinterpret_cast<rkisp1_stat_buffer *>(\n \t\t\tmappedBuffers_.at(bufferId).planes()[0].data());\n \n-\tframeContext.sensor.exposure =\n-\t\tsensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n-\tframeContext.sensor.gain =\n-\t\tcontext_.camHelper->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());\n-\n-\tControlList metadata(controls::controls);\n-\n-\tfor (const auto &a : algorithms()) {\n-\t\tAlgorithm *algo = static_cast<Algorithm *>(a.get());\n-\t\tif (algo->disabled_)\n-\t\t\tcontinue;\n-\t\talgo->process(context_, frame, frameContext, stats, metadata);\n-\t}\n+\tfcLogic_.processStats(frame, stats, metadata);\n \n \tcontext_.debugMetadata.moveEntries(metadata);\n \tmetadataReady.emit(frame, metadata);\n", "prefixes": [ "v2", "32/32" ] }