{"id":23500,"url":"https://patchwork.libcamera.org/api/1.1/patches/23500/?format=json","web_url":"https://patchwork.libcamera.org/patch/23500/","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":"<20250606164156.1442682-19-barnabas.pocze@ideasonboard.com>","date":"2025-06-06T16:41:51","name":"[RFC,v1,18/23] libcamera: pipeline: Fill `MetadataListPlan` of cameras","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"48b3c4f27c8a7ec44e8a55809701a8d25b488d10","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/1.1/people/216/?format=json","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/23500/mbox/","series":[{"id":5210,"url":"https://patchwork.libcamera.org/api/1.1/series/5210/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5210","date":"2025-06-06T16:41:33","name":"libcamera: Add `MetadataList`","version":1,"mbox":"https://patchwork.libcamera.org/series/5210/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/23500/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/23500/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 EC19CC332F\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  6 Jun 2025 16:42:52 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4E3F168DDF;\n\tFri,  6 Jun 2025 18:42:52 +0200 (CEST)","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 0EF4368DBE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  6 Jun 2025 18:42:20 +0200 (CEST)","from pb-laptop.local (185.182.215.79.nat.pool.zt.hu\n\t[185.182.215.79])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 85A1C6DC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  6 Jun 2025 18:42:15 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"XsaOqk/8\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1749228135;\n\tbh=It+Q59xjSMgFvh2ZWYUB5X0W02YEhlkpD+do6j4AZWg=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=XsaOqk/8uqgc9zVp3qGOp81d4mnZ+vl+PDX1VPUXGwrdZvwlST1j6qmTA4lpYGmQv\n\tkG+6R10aKXItGLrInRa/4xOKWQatRQ3PfgZQp2S+24dN3/xfuzlYKUg3VeYIi2Hz49\n\tTdKya/1944rfxeRTnZNlN/UiL0zxz5+CswfNj7QU=","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Subject":"[RFC PATCH v1 18/23] libcamera: pipeline: Fill `MetadataListPlan` of\n\tcameras","Date":"Fri,  6 Jun 2025 18:41:51 +0200","Message-ID":"<20250606164156.1442682-19-barnabas.pocze@ideasonboard.com>","X-Mailer":"git-send-email 2.49.0","In-Reply-To":"<20250606164156.1442682-1-barnabas.pocze@ideasonboard.com>","References":"<20250606164156.1442682-1-barnabas.pocze@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","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":"Fill the newly introduced `MetadataListPlan` member of the camera's private\ndata during initializations, similarly to the camera's `ControlInfoMap`.\n\nSigned-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n---\n .../internal/software_isp/software_isp.h      |  3 +-\n include/libcamera/ipa/ipu3.mojom              |  3 +-\n include/libcamera/ipa/mali-c55.mojom          |  3 +-\n include/libcamera/ipa/raspberrypi.mojom       |  1 +\n include/libcamera/ipa/rkisp1.mojom            |  2 +-\n include/libcamera/ipa/soft.mojom              |  3 +-\n src/ipa/ipu3/algorithms/agc.cpp               |  4 +++\n src/ipa/ipu3/algorithms/awb.cpp               | 12 +++++++\n src/ipa/ipu3/algorithms/awb.h                 |  1 +\n src/ipa/ipu3/ipa_context.cpp                  |  3 ++\n src/ipa/ipu3/ipa_context.h                    |  3 ++\n src/ipa/ipu3/ipu3.cpp                         |  8 +++--\n src/ipa/mali-c55/algorithms/agc.cpp           |  5 +++\n src/ipa/mali-c55/algorithms/awb.cpp           |  7 ++++\n src/ipa/mali-c55/algorithms/awb.h             |  1 +\n src/ipa/mali-c55/algorithms/blc.cpp           |  2 ++\n src/ipa/mali-c55/ipa_context.h                |  3 ++\n src/ipa/mali-c55/mali-c55.cpp                 |  6 ++--\n src/ipa/rkisp1/algorithms/agc.cpp             | 10 ++++++\n src/ipa/rkisp1/algorithms/awb.cpp             |  4 +++\n src/ipa/rkisp1/algorithms/blc.cpp             |  2 ++\n src/ipa/rkisp1/ipa_context.h                  |  1 +\n src/ipa/rkisp1/rkisp1.cpp                     |  8 +++--\n src/ipa/rpi/common/ipa_base.cpp               | 34 +++++++++++++++++++\n src/ipa/rpi/pisp/pisp.cpp                     |  5 +--\n src/ipa/rpi/vc4/vc4.cpp                       |  4 ++-\n src/ipa/simple/algorithms/agc.cpp             |  8 +++++\n src/ipa/simple/algorithms/agc.h               |  1 +\n src/ipa/simple/algorithms/awb.cpp             |  8 +++++\n src/ipa/simple/algorithms/awb.h               |  1 +\n src/ipa/simple/algorithms/blc.cpp             |  3 ++\n src/ipa/simple/algorithms/ccm.cpp             |  3 ++\n src/ipa/simple/algorithms/lut.cpp             |  3 ++\n src/ipa/simple/ipa_context.h                  |  2 ++\n src/ipa/simple/soft_simple.cpp                |  8 +++--\n src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |  2 ++\n src/libcamera/pipeline/ipu3/ipu3.cpp          |  7 +++-\n src/libcamera/pipeline/mali-c55/mali-c55.cpp  |  2 +-\n src/libcamera/pipeline/rkisp1/rkisp1.cpp      |  4 ++-\n .../pipeline/rpi/common/pipeline_base.cpp     |  7 ++++\n src/libcamera/pipeline/simple/simple.cpp      |  2 +-\n src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |  2 ++\n src/libcamera/pipeline/vimc/vimc.cpp          |  2 ++\n .../pipeline/virtual/config_parser.cpp        |  3 ++\n src/libcamera/software_isp/software_isp.cpp   |  6 ++--\n 45 files changed, 190 insertions(+), 22 deletions(-)","diff":"diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h\nindex 786246592..bd85f6b4b 100644\n--- a/include/libcamera/internal/software_isp/software_isp.h\n+++ b/include/libcamera/internal/software_isp/software_isp.h\n@@ -41,6 +41,7 @@ class DebayerCpu;\n class FrameBuffer;\n class PixelFormat;\n class Stream;\n+class MetadataListPlan;\n struct StreamConfiguration;\n \n LOG_DECLARE_CATEGORY(SoftwareIsp)\n@@ -49,7 +50,7 @@ class SoftwareIsp : public Object\n {\n public:\n \tSoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n-\t\t    ControlInfoMap *ipaControls);\n+\t\t    ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan);\n \t~SoftwareIsp();\n \n \tint loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; }\ndiff --git a/include/libcamera/ipa/ipu3.mojom b/include/libcamera/ipa/ipu3.mojom\nindex d9a50b01d..f49b77797 100644\n--- a/include/libcamera/ipa/ipu3.mojom\n+++ b/include/libcamera/ipa/ipu3.mojom\n@@ -20,7 +20,8 @@ interface IPAIPU3Interface {\n \tinit(libcamera.IPASettings settings,\n \t     libcamera.IPACameraSensorInfo sensorInfo,\n \t     libcamera.ControlInfoMap sensorControls)\n-\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls);\n+\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls,\n+\t\t    libcamera.MetadataListPlan metadata);\n \tstart() => (int32 ret);\n \tstop();\n \ndiff --git a/include/libcamera/ipa/mali-c55.mojom b/include/libcamera/ipa/mali-c55.mojom\nindex 5d7eb4eef..7229c53e1 100644\n--- a/include/libcamera/ipa/mali-c55.mojom\n+++ b/include/libcamera/ipa/mali-c55.mojom\n@@ -11,7 +11,8 @@ struct IPAConfigInfo {\n \n interface IPAMaliC55Interface {\n \tinit(libcamera.IPASettings settings, IPAConfigInfo configInfo)\n-\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls);\n+\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls,\n+\t\t    libcamera.MetadataListPlan metadataPlan);\n \tstart() => (int32 ret);\n \tstop();\n \ndiff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom\nindex e30c70bde..69160e133 100644\n--- a/include/libcamera/ipa/raspberrypi.mojom\n+++ b/include/libcamera/ipa/raspberrypi.mojom\n@@ -26,6 +26,7 @@ struct InitParams {\n struct InitResult {\n \tSensorConfig sensorConfig;\n \tlibcamera.ControlInfoMap controlInfo;\n+\tlibcamera.MetadataListPlan metadataPlan;\n };\n \n struct BufferIds {\ndiff --git a/include/libcamera/ipa/rkisp1.mojom b/include/libcamera/ipa/rkisp1.mojom\nindex 043ad27ea..440a59977 100644\n--- a/include/libcamera/ipa/rkisp1.mojom\n+++ b/include/libcamera/ipa/rkisp1.mojom\n@@ -19,7 +19,7 @@ interface IPARkISP1Interface {\n \t     uint32 hwRevision,\n \t     libcamera.IPACameraSensorInfo sensorInfo,\n \t     libcamera.ControlInfoMap sensorControls)\n-\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls);\n+\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls, libcamera.MetadataListPlan metadataPlan);\n \tstart() => (int32 ret);\n \tstop();\n \ndiff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom\nindex 77328c5fd..360ed668b 100644\n--- a/include/libcamera/ipa/soft.mojom\n+++ b/include/libcamera/ipa/soft.mojom\n@@ -18,7 +18,8 @@ interface IPASoftInterface {\n \t     libcamera.SharedFD fdParams,\n \t     libcamera.IPACameraSensorInfo sensorInfo,\n \t     libcamera.ControlInfoMap sensorControls)\n-\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled);\n+\t\t=> (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled,\n+\t\t    libcamera.MetadataListPlan metadataPlan);\n \tstart() => (int32 ret);\n \tstop();\n \tconfigure(IPAConfigInfo configInfo)\ndiff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\nindex 39d0aebb0..e3b2acbc6 100644\n--- a/src/ipa/ipu3/algorithms/agc.cpp\n+++ b/src/ipa/ipu3/algorithms/agc.cpp\n@@ -82,6 +82,10 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)\n \n \tcontext.ctrlMap.merge(controls());\n \n+\tcontext.metadataPlan.add(controls::AnalogueGain);\n+\tcontext.metadataPlan.add(controls::ExposureTime);\n+\tcontext.metadataPlan.add(controls::FrameDuration);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/ipu3/algorithms/awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp\nindex 55de05d9e..28e29e29c 100644\n--- a/src/ipa/ipu3/algorithms/awb.cpp\n+++ b/src/ipa/ipu3/algorithms/awb.cpp\n@@ -197,6 +197,18 @@ Awb::Awb()\n \n Awb::~Awb() = default;\n \n+/**\n+ * \\copydoc libcamera::ipa::Algorithm::init\n+ */\n+int Awb::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)\n+{\n+\tcontext.metadataPlan.add(controls::AwbEnable);\n+\tcontext.metadataPlan.add(controls::ColourGains);\n+\tcontext.metadataPlan.add(controls::ColourTemperature);\n+\n+\treturn 0;\n+}\n+\n /**\n  * \\copydoc libcamera::ipa::Algorithm::configure\n  */\ndiff --git a/src/ipa/ipu3/algorithms/awb.h b/src/ipa/ipu3/algorithms/awb.h\nindex dbf69c907..1d47bffa3 100644\n--- a/src/ipa/ipu3/algorithms/awb.h\n+++ b/src/ipa/ipu3/algorithms/awb.h\n@@ -40,6 +40,7 @@ public:\n \tAwb();\n \t~Awb();\n \n+\tint init(IPAContext &context, const YamlObject &tuningData) override;\n \tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\ndiff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp\nindex 3b22f7917..f0b8b5dbe 100644\n--- a/src/ipa/ipu3/ipa_context.cpp\n+++ b/src/ipa/ipu3/ipa_context.cpp\n@@ -54,6 +54,9 @@ namespace libcamera::ipa::ipu3 {\n  *\n  * \\var IPAContext::ctrlMap\n  * \\brief A ControlInfoMap::Map of controls populated by the algorithms\n+ *\n+ * \\var IPAContext::metadataPlan\n+ * \\brief A MetadataListPlan populated by the algorithms\n  */\n \n /**\ndiff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h\nindex 97fcf06cd..f4f45ef4d 100644\n--- a/src/ipa/ipu3/ipa_context.h\n+++ b/src/ipa/ipu3/ipa_context.h\n@@ -14,6 +14,7 @@\n \n #include <libcamera/controls.h>\n #include <libcamera/geometry.h>\n+#include <libcamera/metadata_list_plan.h>\n \n #include <libipa/fc_queue.h>\n \n@@ -95,6 +96,8 @@ struct IPAContext {\n \tFCQueue<IPAFrameContext> frameContexts;\n \n \tControlInfoMap::Map ctrlMap;\n+\n+\tMetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?\n };\n \n } /* namespace ipa::ipu3 */\ndiff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\nindex 1cae08bf2..8d8811f71 100644\n--- a/src/ipa/ipu3/ipu3.cpp\n+++ b/src/ipa/ipu3/ipu3.cpp\n@@ -143,7 +143,8 @@ public:\n \tint init(const IPASettings &settings,\n \t\t const IPACameraSensorInfo &sensorInfo,\n \t\t const ControlInfoMap &sensorControls,\n-\t\t ControlInfoMap *ipaControls) override;\n+\t\t ControlInfoMap *ipaControls,\n+\t\t MetadataListPlan *metadataPlan) override;\n \n \tint start() override;\n \tvoid stop() override;\n@@ -299,7 +300,8 @@ void IPAIPU3::updateControls(const IPACameraSensorInfo &sensorInfo,\n int IPAIPU3::init(const IPASettings &settings,\n \t\t  const IPACameraSensorInfo &sensorInfo,\n \t\t  const ControlInfoMap &sensorControls,\n-\t\t  ControlInfoMap *ipaControls)\n+\t\t  ControlInfoMap *ipaControls,\n+\t\t  MetadataListPlan *metadataPlan)\n {\n \tcamHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n \tif (camHelper_ == nullptr) {\n@@ -348,6 +350,8 @@ int IPAIPU3::init(const IPASettings &settings,\n \t/* Initialize controls. */\n \tupdateControls(sensorInfo, sensorControls, ipaControls);\n \n+\t*metadataPlan = std::move(context_.metadataPlan);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp\nindex 70667db34..bfca8f5a5 100644\n--- a/src/ipa/mali-c55/algorithms/agc.cpp\n+++ b/src/ipa/mali-c55/algorithms/agc.cpp\n@@ -145,6 +145,11 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)\n \t);\n \tcontext.ctrlMap.merge(controls());\n \n+\tcontext.metadataPlan.add(controls::ExposureTime);\n+\tcontext.metadataPlan.add(controls::AnalogueGain);\n+\tcontext.metadataPlan.add(controls::DigitalGain);\n+\tcontext.metadataPlan.add(controls::ColourTemperature);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp\nindex 050b191b7..b5acd4390 100644\n--- a/src/ipa/mali-c55/algorithms/awb.cpp\n+++ b/src/ipa/mali-c55/algorithms/awb.cpp\n@@ -29,6 +29,13 @@ Awb::Awb()\n {\n }\n \n+int Awb::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)\n+{\n+\tcontext.metadataPlan.add(controls::ColourGains);\n+\n+\treturn 0;\n+}\n+\n int Awb::configure([[maybe_unused]] IPAContext &context,\n \t\t   [[maybe_unused]] const IPACameraSensorInfo &configInfo)\n {\ndiff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h\nindex 800c2e834..db59e8d79 100644\n--- a/src/ipa/mali-c55/algorithms/awb.h\n+++ b/src/ipa/mali-c55/algorithms/awb.h\n@@ -18,6 +18,7 @@ public:\n \tAwb();\n \t~Awb() = default;\n \n+\tint init(IPAContext &context, const YamlObject &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t      const IPACameraSensorInfo &configInfo) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\ndiff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp\nindex 2a54c86a9..0aaaae7dd 100644\n--- a/src/ipa/mali-c55/algorithms/blc.cpp\n+++ b/src/ipa/mali-c55/algorithms/blc.cpp\n@@ -51,6 +51,8 @@ int BlackLevelCorrection::init([[maybe_unused]] IPAContext &context,\n \n \ttuningParameters_ = true;\n \n+\tcontext.metadataPlan.add(controls::SensorBlackLevels);\n+\n \tLOG(MaliC55Blc, Debug)\n \t\t<< \"Black levels: 00 \" << offset00 << \", 01 \" << offset01\n \t\t<< \", 10 \" << offset10 << \", 11 \" << offset11;\ndiff --git a/src/ipa/mali-c55/ipa_context.h b/src/ipa/mali-c55/ipa_context.h\nindex 5e3e2fbde..d76fdcb2b 100644\n--- a/src/ipa/mali-c55/ipa_context.h\n+++ b/src/ipa/mali-c55/ipa_context.h\n@@ -9,6 +9,7 @@\n \n #include <libcamera/base/utils.h>\n #include <libcamera/controls.h>\n+#include <libcamera/metadata_list_plan.h>\n \n #include \"libcamera/internal/bayer_format.h\"\n \n@@ -83,6 +84,8 @@ struct IPAContext {\n \tFCQueue<IPAFrameContext> frameContexts;\n \n \tControlInfoMap::Map ctrlMap;\n+\n+\tMetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?\n };\n \n } /* namespace ipa::mali_c55 */\ndiff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp\nindex c6941a950..7006ae55c 100644\n--- a/src/ipa/mali-c55/mali-c55.cpp\n+++ b/src/ipa/mali-c55/mali-c55.cpp\n@@ -46,7 +46,7 @@ public:\n \tIPAMaliC55();\n \n \tint init(const IPASettings &settings, const IPAConfigInfo &ipaConfig,\n-\t\t ControlInfoMap *ipaControls) override;\n+\t\t ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan) override;\n \tint start() override;\n \tvoid stop() override;\n \tint configure(const IPAConfigInfo &ipaConfig, uint8_t bayerOrder,\n@@ -96,7 +96,7 @@ std::string IPAMaliC55::logPrefix() const\n }\n \n int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig,\n-\t\t     ControlInfoMap *ipaControls)\n+\t\t     ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan)\n {\n \tcamHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n \tif (!camHelper_) {\n@@ -131,6 +131,8 @@ int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig\n \n \tupdateControls(ipaConfig.sensorInfo, ipaConfig.sensorControls, ipaControls);\n \n+\t*metadataPlan = std::move(context_.metadataPlan);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\nindex 137a07500..22db11b24 100644\n--- a/src/ipa/rkisp1/algorithms/agc.cpp\n+++ b/src/ipa/rkisp1/algorithms/agc.cpp\n@@ -159,6 +159,16 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)\n \tcontext.ctrlMap[&controls::AeEnable] = ControlInfo(false, true, true);\n \tcontext.ctrlMap.merge(controls());\n \n+\tcontext.metadataPlan.add(controls::AnalogueGain);\n+\tcontext.metadataPlan.add(controls::ExposureTime);\n+\tcontext.metadataPlan.add(controls::FrameDuration);\n+\tcontext.metadataPlan.add(controls::FrameDuration);\n+\tcontext.metadataPlan.add(controls::ExposureTimeMode);\n+\tcontext.metadataPlan.add(controls::AnalogueGainMode);\n+\tcontext.metadataPlan.add(controls::AeMeteringMode);\n+\tcontext.metadataPlan.add(controls::AeExposureMode);\n+\tcontext.metadataPlan.add(controls::AeConstraintMode);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\nindex 399fb51be..aaaa3cced 100644\n--- a/src/ipa/rkisp1/algorithms/awb.cpp\n+++ b/src/ipa/rkisp1/algorithms/awb.cpp\n@@ -117,6 +117,10 @@ int Awb::init(IPAContext &context, const YamlObject &tuningData)\n \tconst auto &src = awbAlgo_->controls();\n \tcmap.insert(src.begin(), src.end());\n \n+\tcontext.metadataPlan.add(controls::AwbEnable);\n+\tcontext.metadataPlan.add(controls::ColourGains);\n+\tcontext.metadataPlan.add(controls::ColourTemperature);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp\nindex 98cb7145e..3288f24e3 100644\n--- a/src/ipa/rkisp1/algorithms/blc.cpp\n+++ b/src/ipa/rkisp1/algorithms/blc.cpp\n@@ -103,6 +103,8 @@ int BlackLevelCorrection::init(IPAContext &context, const YamlObject &tuningData\n \t\t<< \", green (blue) \" << blackLevelGreenB_\n \t\t<< \", blue \" << blackLevelBlue_;\n \n+\tcontext.metadataPlan.add(controls::SensorBlackLevels);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\nindex f0d504215..cd4b98921 100644\n--- a/src/ipa/rkisp1/ipa_context.h\n+++ b/src/ipa/rkisp1/ipa_context.h\n@@ -200,6 +200,7 @@ struct IPAContext {\n \tFCQueue<IPAFrameContext> frameContexts;\n \n \tControlInfoMap::Map ctrlMap;\n+\tMetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?\n \n \tDebugMetadata debugMetadata;\n \ndiff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\nindex 1ed7d7d92..88c454ea1 100644\n--- a/src/ipa/rkisp1/rkisp1.cpp\n+++ b/src/ipa/rkisp1/rkisp1.cpp\n@@ -54,7 +54,8 @@ public:\n \tint init(const IPASettings &settings, unsigned int hwRevision,\n \t\t const IPACameraSensorInfo &sensorInfo,\n \t\t const ControlInfoMap &sensorControls,\n-\t\t ControlInfoMap *ipaControls) override;\n+\t\t ControlInfoMap *ipaControls,\n+\t\t MetadataListPlan *metadataPlan) override;\n \tint start() override;\n \tvoid stop() override;\n \n@@ -135,7 +136,8 @@ std::string IPARkISP1::logPrefix() const\n int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,\n \t\t    const IPACameraSensorInfo &sensorInfo,\n \t\t    const ControlInfoMap &sensorControls,\n-\t\t    ControlInfoMap *ipaControls)\n+\t\t    ControlInfoMap *ipaControls,\n+\t\t    MetadataListPlan *metadataPlan)\n {\n \t/* \\todo Add support for other revisions */\n \tswitch (hwRevision) {\n@@ -204,6 +206,8 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,\n \t/* Initialize controls. */\n \tupdateControls(sensorInfo, sensorControls, ipaControls);\n \n+\t*metadataPlan = std::move(context_.metadataPlan);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp\nindex e0f8b7e78..032d6c43b 100644\n--- a/src/ipa/rpi/common/ipa_base.cpp\n+++ b/src/ipa/rpi/common/ipa_base.cpp\n@@ -180,6 +180,40 @@ int32_t IpaBase::init(const IPASettings &settings, const InitParams &params, Ini\n \n \tresult->controlInfo = ControlInfoMap(std::move(ctrlMap), controls::controls);\n \n+\t// TODO: only set those that can be reported by configured algorithms?\n+\t// TODO: move this somewhere else?\n+\tresult->metadataPlan.add(controls::AnalogueGainMode);\n+\tresult->metadataPlan.add(controls::ExposureTimeMode);\n+\tresult->metadataPlan.add(controls::ExposureTime);\n+\tresult->metadataPlan.add(controls::AnalogueGain);\n+\tresult->metadataPlan.add(controls::AeMeteringMode);\n+\tresult->metadataPlan.add(controls::AeConstraintMode);\n+\tresult->metadataPlan.add(controls::AeExposureMode);\n+\tresult->metadataPlan.add(controls::ExposureValue);\n+\tresult->metadataPlan.add(controls::AwbEnable);\n+\tresult->metadataPlan.add(controls::AwbMode);\n+\tresult->metadataPlan.add(controls::ColourGains);\n+\tresult->metadataPlan.add(controls::Brightness);\n+\tresult->metadataPlan.add(controls::Contrast);\n+\tresult->metadataPlan.add(controls::Saturation);\n+\tresult->metadataPlan.add(controls::Sharpness);\n+\tresult->metadataPlan.add(controls::draft::NoiseReductionMode);\n+\tresult->metadataPlan.add(controls::FrameDuration);\n+\tresult->metadataPlan.add(controls::SensorTemperature);\n+\tresult->metadataPlan.add(controls::LensPosition);\n+\tresult->metadataPlan.add(controls::DigitalGain);\n+\tresult->metadataPlan.add(controls::AeState);\n+\tresult->metadataPlan.add(controls::Lux);\n+\tresult->metadataPlan.add(controls::ColourTemperature);\n+\tresult->metadataPlan.add(controls::SensorBlackLevels);\n+\tresult->metadataPlan.add(controls::FocusFoM);\n+\tresult->metadataPlan.add(controls::ColourCorrectionMatrix);\n+\tresult->metadataPlan.add(controls::AfState);\n+\tresult->metadataPlan.add(controls::AfPauseState);\n+\tresult->metadataPlan.add(controls::HdrMode);\n+\tresult->metadataPlan.add(controls::HdrChannel);\n+\tresult->metadataPlan.add(controls::FrameDurationLimits);\n+\n \treturn platformInit(params, result);\n }\n \ndiff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp\nindex bb50a9e05..a640bec32 100644\n--- a/src/ipa/rpi/pisp/pisp.cpp\n+++ b/src/ipa/rpi/pisp/pisp.cpp\n@@ -267,8 +267,7 @@ private:\n \tHdrStatus lastStitchHdrStatus_;\n };\n \n-int32_t IpaPiSP::platformInit(const InitParams &params,\n-\t\t\t      [[maybe_unused]] InitResult *result)\n+int32_t IpaPiSP::platformInit(const InitParams &params, InitResult *result)\n {\n \tconst std::string &target = controller_.getTarget();\n \tif (target != \"pisp\") {\n@@ -301,6 +300,8 @@ int32_t IpaPiSP::platformInit(const InitParams &params,\n \n \tsetDefaultConfig();\n \n+\tresult->metadataPlan.add(controls::rpi::PispStatsOutput, sizeof(pisp_statistics));\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp\nindex ba43e4741..d02e06589 100644\n--- a/src/ipa/rpi/vc4/vc4.cpp\n+++ b/src/ipa/rpi/vc4/vc4.cpp\n@@ -83,7 +83,7 @@ private:\n \tvoid *lsTable_;\n };\n \n-int32_t IpaVc4::platformInit([[maybe_unused]] const InitParams &params, [[maybe_unused]] InitResult *result)\n+int32_t IpaVc4::platformInit([[maybe_unused]] const InitParams &params, InitResult *result)\n {\n \tconst std::string &target = controller_.getTarget();\n \n@@ -94,6 +94,8 @@ int32_t IpaVc4::platformInit([[maybe_unused]] const InitParams &params, [[maybe_\n \t\treturn -EINVAL;\n \t}\n \n+\tresult->metadataPlan.add(controls::rpi::Bcm2835StatsOutput, sizeof(bcm2835_isp_stats));\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp\nindex c46bb0ebe..47a499be6 100644\n--- a/src/ipa/simple/algorithms/agc.cpp\n+++ b/src/ipa/simple/algorithms/agc.cpp\n@@ -41,6 +41,14 @@ Agc::Agc()\n {\n }\n \n+int Agc::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)\n+{\n+\tcontext.metadataPlan.add(controls::ExposureTime);\n+\tcontext.metadataPlan.add(controls::AnalogueGain);\n+\n+\treturn 0;\n+}\n+\n void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV)\n {\n \t/*\ndiff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h\nindex 112d9f5a1..00e70ea70 100644\n--- a/src/ipa/simple/algorithms/agc.h\n+++ b/src/ipa/simple/algorithms/agc.h\n@@ -19,6 +19,7 @@ public:\n \tAgc();\n \t~Agc() = default;\n \n+\tint init(IPAContext &context, const YamlObject &tuningData) override;\n \tvoid process(IPAContext &context, const uint32_t frame,\n \t\t     IPAFrameContext &frameContext,\n \t\t     const SwIspStats *stats,\ndiff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp\nindex cf567e894..cce4585f9 100644\n--- a/src/ipa/simple/algorithms/awb.cpp\n+++ b/src/ipa/simple/algorithms/awb.cpp\n@@ -25,6 +25,14 @@ LOG_DEFINE_CATEGORY(IPASoftAwb)\n \n namespace ipa::soft::algorithms {\n \n+int Awb::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)\n+{\n+\tcontext.metadataPlan.add(controls::ColourGains);\n+\tcontext.metadataPlan.add(controls::ColourTemperature);\n+\n+\treturn 0;\n+}\n+\n int Awb::configure(IPAContext &context,\n \t\t   [[maybe_unused]] const IPAConfigInfo &configInfo)\n {\ndiff --git a/src/ipa/simple/algorithms/awb.h b/src/ipa/simple/algorithms/awb.h\nindex ad993f39c..b8ae63dcb 100644\n--- a/src/ipa/simple/algorithms/awb.h\n+++ b/src/ipa/simple/algorithms/awb.h\n@@ -19,6 +19,7 @@ public:\n \tAwb() = default;\n \t~Awb() = default;\n \n+\tint init(IPAContext &context, const YamlObject &tuningData) override;\n \tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n \tvoid prepare(IPAContext &context,\n \t\t     const uint32_t frame,\ndiff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp\nindex 8c1e9ed08..4b9284e54 100644\n--- a/src/ipa/simple/algorithms/blc.cpp\n+++ b/src/ipa/simple/algorithms/blc.cpp\n@@ -34,6 +34,9 @@ int BlackLevel::init([[maybe_unused]] IPAContext &context,\n \t\t */\n \t\tdefinedLevel_ = blackLevel.value() >> 8;\n \t}\n+\n+\tcontext.metadataPlan.add(controls::SensorBlackLevels);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp\nindex 0a98406c1..3cab8eaa4 100644\n--- a/src/ipa/simple/algorithms/ccm.cpp\n+++ b/src/ipa/simple/algorithms/ccm.cpp\n@@ -39,6 +39,9 @@ int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData\n \tcontext.ccmEnabled = true;\n \tcontext.ctrlMap[&controls::Saturation] = ControlInfo(0.0f, 2.0f, 1.0f);\n \n+\tcontext.metadataPlan.add(controls::ColourCorrectionMatrix);\n+\tcontext.metadataPlan.add(controls::Saturation);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\nindex d1d5f7271..0f99be544 100644\n--- a/src/ipa/simple/algorithms/lut.cpp\n+++ b/src/ipa/simple/algorithms/lut.cpp\n@@ -28,6 +28,9 @@ int Lut::init(IPAContext &context,\n \t      [[maybe_unused]] const YamlObject &tuningData)\n {\n \tcontext.ctrlMap[&controls::Contrast] = ControlInfo(0.0f, 2.0f, 1.0f);\n+\n+\tcontext.metadataPlan.add(controls::Contrast);\n+\n \treturn 0;\n }\n \ndiff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h\nindex a471b80ae..f4ecf43db 100644\n--- a/src/ipa/simple/ipa_context.h\n+++ b/src/ipa/simple/ipa_context.h\n@@ -12,6 +12,7 @@\n #include <stdint.h>\n \n #include <libcamera/controls.h>\n+#include <libcamera/metadata_list_plan.h>\n \n #include \"libcamera/internal/matrix.h\"\n #include \"libcamera/internal/vector.h\"\n@@ -97,6 +98,7 @@ struct IPAContext {\n \tIPAActiveState activeState;\n \tFCQueue<IPAFrameContext> frameContexts;\n \tControlInfoMap::Map ctrlMap;\n+\tMetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?\n \tbool ccmEnabled = false;\n };\n \ndiff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\nindex c94c4cd55..db721199d 100644\n--- a/src/ipa/simple/soft_simple.cpp\n+++ b/src/ipa/simple/soft_simple.cpp\n@@ -56,7 +56,8 @@ public:\n \t\t const IPACameraSensorInfo &sensorInfo,\n \t\t const ControlInfoMap &sensorControls,\n \t\t ControlInfoMap *ipaControls,\n-\t\t bool *ccmEnabled) override;\n+\t\t bool *ccmEnabled,\n+\t\t MetadataListPlan *metadataPlan) override;\n \tint configure(const IPAConfigInfo &configInfo) override;\n \n \tint start() override;\n@@ -96,7 +97,8 @@ int IPASoftSimple::init(const IPASettings &settings,\n \t\t\tconst IPACameraSensorInfo &sensorInfo,\n \t\t\tconst ControlInfoMap &sensorControls,\n \t\t\tControlInfoMap *ipaControls,\n-\t\t\tbool *ccmEnabled)\n+\t\t\tbool *ccmEnabled,\n+\t\t\tMetadataListPlan *metadataPlan)\n {\n \tcamHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n \tif (!camHelper_) {\n@@ -190,6 +192,8 @@ int IPASoftSimple::init(const IPASettings &settings,\n \t\treturn -EINVAL;\n \t}\n \n+\t*metadataPlan = std::move(context_.metadataPlan);\n+\n \treturn 0;\n }\n \ndiff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\nindex ecda426a6..1c6da2006 100644\n--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n@@ -166,6 +166,8 @@ int ISICameraData::init()\n \n \tproperties_ = sensor_->properties();\n \n+\tmetadataPlan_.add(controls::SensorTimestamp);\n+\n \treturn 0;\n }\n \ndiff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex e31e3879d..b4a4283f4 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -1078,6 +1078,11 @@ int PipelineHandlerIPU3::registerCameras()\n \t\tif (ret)\n \t\t\tcontinue;\n \n+\t\tdata->metadataPlan_.add(controls::draft::PipelineDepth);\n+\t\tdata->metadataPlan_.add(controls::draft::TestPatternMode);\n+\t\tdata->metadataPlan_.add(controls::ScalerCrop);\n+\t\tdata->metadataPlan_.add(controls::SensorTimestamp);\n+\n \t\tconst CameraSensorProperties::SensorDelays &delays = cio2->sensor()->sensorDelays();\n \t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n \t\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n@@ -1187,7 +1192,7 @@ int IPU3CameraData::loadIPA()\n \t\tipa_->configurationFile(sensor->model() + \".yaml\", \"uncalibrated.yaml\");\n \n \tret = ipa_->init(IPASettings{ ipaTuningFile, sensor->model() },\n-\t\t\t sensorInfo, sensor->controls(), &ipaControls_);\n+\t\t\t sensorInfo, sensor->controls(), &ipaControls_, &metadataPlan_);\n \tif (ret) {\n \t\tLOG(IPU3, Error) << \"Failed to initialise the IPU3 IPA\";\n \t\treturn ret;\ndiff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\nindex 4acc091bd..19980f6d2 100644\n--- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n+++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n@@ -402,7 +402,7 @@ int MaliC55CameraData::loadIPA()\n \n \tControlInfoMap ipaControls;\n \tret = ipa_->init({ ipaTuningFile, sensor_->model() }, ipaConfig,\n-\t\t\t &ipaControls);\n+\t\t\t &ipaControls, &metadataPlan_);\n \tif (ret) {\n \t\tLOG(MaliC55, Error) << \"Failed to initialise the Mali-C55 IPA\";\n \t\treturn ret;\ndiff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\nindex 675f0a749..34be87087 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n@@ -394,7 +394,7 @@ int RkISP1CameraData::loadIPA(unsigned int hwRevision)\n \t}\n \n \tret = ipa_->init({ ipaTuningFile, sensor_->model() }, hwRevision,\n-\t\t\t sensorInfo, sensor_->controls(), &ipaControls_);\n+\t\t\t sensorInfo, sensor_->controls(), &ipaControls_, &metadataPlan_);\n \tif (ret < 0) {\n \t\tLOG(RkISP1, Error) << \"IPA initialization failure\";\n \t\treturn ret;\n@@ -1333,6 +1333,8 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)\n \n \tupdateControls(data.get());\n \n+\tdata->metadataPlan_.add(controls::SensorTimestamp);\n+\n \tstd::set<Stream *> streams{\n \t\t&data->mainPathStream_,\n \t\t&data->selfPathStream_,\ndiff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\nindex 1f13e5230..98507a152 100644\n--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n@@ -589,6 +589,9 @@ int PipelineHandlerBase::configure(Camera *camera, CameraConfiguration *config)\n \n \tdata->controlInfo_ = ControlInfoMap(std::move(ctrlMap), result.controlInfo.idmap());\n \n+\t/* Update `rpi::ScalerCrops` size for the corrent configuration. */\n+\tdata->metadataPlan_.add(controls::rpi::ScalerCrops, config->size());\n+\n \t/* Setup the Video Mux/Bridge entities. */\n \tfor (auto &[device, link] : data->bridgeDevices_) {\n \t\t/*\n@@ -832,6 +835,10 @@ int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &camera\n \t/* Initialize the camera properties. */\n \tdata->properties_ = data->sensor_->properties();\n \n+\tdata->metadataPlan_ = std::move(result.metadataPlan);\n+\tdata->metadataPlan_.add(controls::SensorTimestamp);\n+\tdata->metadataPlan_.add(controls::ScalerCrop);\n+\n \t/*\n \t * The V4L2_CID_NOTIFY_GAINS control, if present, is used to inform the\n \t * sensor of the colour gains. It is defined to be a linear gain where\ndiff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\nindex efb07051b..05387ca7c 100644\n--- a/src/libcamera/pipeline/simple/simple.cpp\n+++ b/src/libcamera/pipeline/simple/simple.cpp\n@@ -592,7 +592,7 @@ int SimpleCameraData::init()\n \t * Instantiate Soft ISP if this is enabled for the given driver and no converter is used.\n \t */\n \tif (!converter_ && pipe->swIspEnabled()) {\n-\t\tswIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get(), &controlInfo_);\n+\t\tswIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get(), &controlInfo_, &metadataPlan_);\n \t\tif (!swIsp_->isValid()) {\n \t\t\tLOG(SimplePipeline, Warning)\n \t\t\t\t<< \"Failed to create software ISP, disabling software debayering\";\ndiff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\nindex 58aa0eb4c..e0036e3b5 100644\n--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n@@ -603,6 +603,8 @@ int UVCCameraData::init(MediaDevice *media)\n \n \tcontrolInfo_ = ControlInfoMap(std::move(ctrls), controls::controls);\n \n+\tmetadataPlan_.add(controls::SensorTimestamp);\n+\n \t/*\n \t * Close to allow camera to go into runtime-suspend, video_ will be\n \t * re-opened from acquireDevice() and validate().\ndiff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\nindex 07273bd2b..f8a29da41 100644\n--- a/src/libcamera/pipeline/vimc/vimc.cpp\n+++ b/src/libcamera/pipeline/vimc/vimc.cpp\n@@ -590,6 +590,8 @@ int VimcCameraData::init()\n \n \tcontrolInfo_ = ControlInfoMap(std::move(ctrls), controls::controls);\n \n+\tmetadataPlan_.add(controls::SensorTimestamp);\n+\n \t/* Initialize the camera properties. */\n \tproperties_ = sensor_->properties();\n \ndiff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp\nindex 1d3d9ba87..f10aea7bf 100644\n--- a/src/libcamera/pipeline/virtual/config_parser.cpp\n+++ b/src/libcamera/pipeline/virtual/config_parser.cpp\n@@ -65,6 +65,9 @@ ConfigParser::parseConfigFile(File &file, PipelineHandler *pipe)\n \t\tcontrols[&controls::draft::FaceDetectMode] = ControlInfo(supportedFaceDetectModes);\n \n \t\tdata->controlInfo_ = ControlInfoMap(std::move(controls), controls::controls);\n+\n+\t\tdata->metadataPlan_.add(controls::SensorTimestamp);\n+\n \t\tconfigurations.push_back(std::move(data));\n \t}\n \ndiff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp\nindex 28e2a360e..6da69daf9 100644\n--- a/src/libcamera/software_isp/software_isp.cpp\n+++ b/src/libcamera/software_isp/software_isp.cpp\n@@ -71,10 +71,11 @@ LOG_DEFINE_CATEGORY(SoftwareIsp)\n  * \\param[in] pipe The pipeline handler in use\n  * \\param[in] sensor Pointer to the CameraSensor instance owned by the pipeline\n  * \\param[out] ipaControls The IPA controls to update\n+ * \\param[out] metadataPlan The metadata plan to update\n  * handler\n  */\n SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n-\t\t\t ControlInfoMap *ipaControls)\n+\t\t\t ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan)\n \t: dmaHeap_(DmaBufAllocator::DmaBufAllocatorFlag::CmaHeap |\n \t\t   DmaBufAllocator::DmaBufAllocatorFlag::SystemHeap |\n \t\t   DmaBufAllocator::DmaBufAllocatorFlag::UDmaBuf)\n@@ -146,7 +147,8 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n \t\t\t sensorInfo,\n \t\t\t sensor->controls(),\n \t\t\t ipaControls,\n-\t\t\t &ccmEnabled_);\n+\t\t\t &ccmEnabled_,\n+\t\t\t metadataPlan);\n \tif (ret) {\n \t\tLOG(SoftwareIsp, Error) << \"IPA init failed\";\n \t\tdebayer_.reset();\n","prefixes":["RFC","v1","18/23"]}