[RFC PATCH v1 18/23] libcamera: pipeline: Fill `MetadataListPlan` of cameras

Barnabás Pőcze barnabas.pocze at ideasonboard.com
Fri Jun 6 18:41:51 CEST 2025


Fill the newly introduced `MetadataListPlan` member of the camera's private
data during initializations, similarly to the camera's `ControlInfoMap`.

Signed-off-by: Barnabás Pőcze <barnabas.pocze at ideasonboard.com>
---
 .../internal/software_isp/software_isp.h      |  3 +-
 include/libcamera/ipa/ipu3.mojom              |  3 +-
 include/libcamera/ipa/mali-c55.mojom          |  3 +-
 include/libcamera/ipa/raspberrypi.mojom       |  1 +
 include/libcamera/ipa/rkisp1.mojom            |  2 +-
 include/libcamera/ipa/soft.mojom              |  3 +-
 src/ipa/ipu3/algorithms/agc.cpp               |  4 +++
 src/ipa/ipu3/algorithms/awb.cpp               | 12 +++++++
 src/ipa/ipu3/algorithms/awb.h                 |  1 +
 src/ipa/ipu3/ipa_context.cpp                  |  3 ++
 src/ipa/ipu3/ipa_context.h                    |  3 ++
 src/ipa/ipu3/ipu3.cpp                         |  8 +++--
 src/ipa/mali-c55/algorithms/agc.cpp           |  5 +++
 src/ipa/mali-c55/algorithms/awb.cpp           |  7 ++++
 src/ipa/mali-c55/algorithms/awb.h             |  1 +
 src/ipa/mali-c55/algorithms/blc.cpp           |  2 ++
 src/ipa/mali-c55/ipa_context.h                |  3 ++
 src/ipa/mali-c55/mali-c55.cpp                 |  6 ++--
 src/ipa/rkisp1/algorithms/agc.cpp             | 10 ++++++
 src/ipa/rkisp1/algorithms/awb.cpp             |  4 +++
 src/ipa/rkisp1/algorithms/blc.cpp             |  2 ++
 src/ipa/rkisp1/ipa_context.h                  |  1 +
 src/ipa/rkisp1/rkisp1.cpp                     |  8 +++--
 src/ipa/rpi/common/ipa_base.cpp               | 34 +++++++++++++++++++
 src/ipa/rpi/pisp/pisp.cpp                     |  5 +--
 src/ipa/rpi/vc4/vc4.cpp                       |  4 ++-
 src/ipa/simple/algorithms/agc.cpp             |  8 +++++
 src/ipa/simple/algorithms/agc.h               |  1 +
 src/ipa/simple/algorithms/awb.cpp             |  8 +++++
 src/ipa/simple/algorithms/awb.h               |  1 +
 src/ipa/simple/algorithms/blc.cpp             |  3 ++
 src/ipa/simple/algorithms/ccm.cpp             |  3 ++
 src/ipa/simple/algorithms/lut.cpp             |  3 ++
 src/ipa/simple/ipa_context.h                  |  2 ++
 src/ipa/simple/soft_simple.cpp                |  8 +++--
 src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |  2 ++
 src/libcamera/pipeline/ipu3/ipu3.cpp          |  7 +++-
 src/libcamera/pipeline/mali-c55/mali-c55.cpp  |  2 +-
 src/libcamera/pipeline/rkisp1/rkisp1.cpp      |  4 ++-
 .../pipeline/rpi/common/pipeline_base.cpp     |  7 ++++
 src/libcamera/pipeline/simple/simple.cpp      |  2 +-
 src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |  2 ++
 src/libcamera/pipeline/vimc/vimc.cpp          |  2 ++
 .../pipeline/virtual/config_parser.cpp        |  3 ++
 src/libcamera/software_isp/software_isp.cpp   |  6 ++--
 45 files changed, 190 insertions(+), 22 deletions(-)

diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h
index 786246592..bd85f6b4b 100644
--- a/include/libcamera/internal/software_isp/software_isp.h
+++ b/include/libcamera/internal/software_isp/software_isp.h
@@ -41,6 +41,7 @@ class DebayerCpu;
 class FrameBuffer;
 class PixelFormat;
 class Stream;
+class MetadataListPlan;
 struct StreamConfiguration;
 
 LOG_DECLARE_CATEGORY(SoftwareIsp)
@@ -49,7 +50,7 @@ class SoftwareIsp : public Object
 {
 public:
 	SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,
-		    ControlInfoMap *ipaControls);
+		    ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan);
 	~SoftwareIsp();
 
 	int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; }
diff --git a/include/libcamera/ipa/ipu3.mojom b/include/libcamera/ipa/ipu3.mojom
index d9a50b01d..f49b77797 100644
--- a/include/libcamera/ipa/ipu3.mojom
+++ b/include/libcamera/ipa/ipu3.mojom
@@ -20,7 +20,8 @@ interface IPAIPU3Interface {
 	init(libcamera.IPASettings settings,
 	     libcamera.IPACameraSensorInfo sensorInfo,
 	     libcamera.ControlInfoMap sensorControls)
-		=> (int32 ret, libcamera.ControlInfoMap ipaControls);
+		=> (int32 ret, libcamera.ControlInfoMap ipaControls,
+		    libcamera.MetadataListPlan metadata);
 	start() => (int32 ret);
 	stop();
 
diff --git a/include/libcamera/ipa/mali-c55.mojom b/include/libcamera/ipa/mali-c55.mojom
index 5d7eb4eef..7229c53e1 100644
--- a/include/libcamera/ipa/mali-c55.mojom
+++ b/include/libcamera/ipa/mali-c55.mojom
@@ -11,7 +11,8 @@ struct IPAConfigInfo {
 
 interface IPAMaliC55Interface {
 	init(libcamera.IPASettings settings, IPAConfigInfo configInfo)
-		=> (int32 ret, libcamera.ControlInfoMap ipaControls);
+		=> (int32 ret, libcamera.ControlInfoMap ipaControls,
+		    libcamera.MetadataListPlan metadataPlan);
 	start() => (int32 ret);
 	stop();
 
diff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom
index e30c70bde..69160e133 100644
--- a/include/libcamera/ipa/raspberrypi.mojom
+++ b/include/libcamera/ipa/raspberrypi.mojom
@@ -26,6 +26,7 @@ struct InitParams {
 struct InitResult {
 	SensorConfig sensorConfig;
 	libcamera.ControlInfoMap controlInfo;
+	libcamera.MetadataListPlan metadataPlan;
 };
 
 struct BufferIds {
diff --git a/include/libcamera/ipa/rkisp1.mojom b/include/libcamera/ipa/rkisp1.mojom
index 043ad27ea..440a59977 100644
--- a/include/libcamera/ipa/rkisp1.mojom
+++ b/include/libcamera/ipa/rkisp1.mojom
@@ -19,7 +19,7 @@ interface IPARkISP1Interface {
 	     uint32 hwRevision,
 	     libcamera.IPACameraSensorInfo sensorInfo,
 	     libcamera.ControlInfoMap sensorControls)
-		=> (int32 ret, libcamera.ControlInfoMap ipaControls);
+		=> (int32 ret, libcamera.ControlInfoMap ipaControls, libcamera.MetadataListPlan metadataPlan);
 	start() => (int32 ret);
 	stop();
 
diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom
index 77328c5fd..360ed668b 100644
--- a/include/libcamera/ipa/soft.mojom
+++ b/include/libcamera/ipa/soft.mojom
@@ -18,7 +18,8 @@ interface IPASoftInterface {
 	     libcamera.SharedFD fdParams,
 	     libcamera.IPACameraSensorInfo sensorInfo,
 	     libcamera.ControlInfoMap sensorControls)
-		=> (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled);
+		=> (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled,
+		    libcamera.MetadataListPlan metadataPlan);
 	start() => (int32 ret);
 	stop();
 	configure(IPAConfigInfo configInfo)
diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp
index 39d0aebb0..e3b2acbc6 100644
--- a/src/ipa/ipu3/algorithms/agc.cpp
+++ b/src/ipa/ipu3/algorithms/agc.cpp
@@ -82,6 +82,10 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)
 
 	context.ctrlMap.merge(controls());
 
+	context.metadataPlan.add(controls::AnalogueGain);
+	context.metadataPlan.add(controls::ExposureTime);
+	context.metadataPlan.add(controls::FrameDuration);
+
 	return 0;
 }
 
diff --git a/src/ipa/ipu3/algorithms/awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp
index 55de05d9e..28e29e29c 100644
--- a/src/ipa/ipu3/algorithms/awb.cpp
+++ b/src/ipa/ipu3/algorithms/awb.cpp
@@ -197,6 +197,18 @@ Awb::Awb()
 
 Awb::~Awb() = default;
 
+/**
+ * \copydoc libcamera::ipa::Algorithm::init
+ */
+int Awb::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)
+{
+	context.metadataPlan.add(controls::AwbEnable);
+	context.metadataPlan.add(controls::ColourGains);
+	context.metadataPlan.add(controls::ColourTemperature);
+
+	return 0;
+}
+
 /**
  * \copydoc libcamera::ipa::Algorithm::configure
  */
diff --git a/src/ipa/ipu3/algorithms/awb.h b/src/ipa/ipu3/algorithms/awb.h
index dbf69c907..1d47bffa3 100644
--- a/src/ipa/ipu3/algorithms/awb.h
+++ b/src/ipa/ipu3/algorithms/awb.h
@@ -40,6 +40,7 @@ public:
 	Awb();
 	~Awb();
 
+	int init(IPAContext &context, const YamlObject &tuningData) override;
 	int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
 	void prepare(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
diff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp
index 3b22f7917..f0b8b5dbe 100644
--- a/src/ipa/ipu3/ipa_context.cpp
+++ b/src/ipa/ipu3/ipa_context.cpp
@@ -54,6 +54,9 @@ namespace libcamera::ipa::ipu3 {
  *
  * \var IPAContext::ctrlMap
  * \brief A ControlInfoMap::Map of controls populated by the algorithms
+ *
+ * \var IPAContext::metadataPlan
+ * \brief A MetadataListPlan populated by the algorithms
  */
 
 /**
diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h
index 97fcf06cd..f4f45ef4d 100644
--- a/src/ipa/ipu3/ipa_context.h
+++ b/src/ipa/ipu3/ipa_context.h
@@ -14,6 +14,7 @@
 
 #include <libcamera/controls.h>
 #include <libcamera/geometry.h>
+#include <libcamera/metadata_list_plan.h>
 
 #include <libipa/fc_queue.h>
 
@@ -95,6 +96,8 @@ struct IPAContext {
 	FCQueue<IPAFrameContext> frameContexts;
 
 	ControlInfoMap::Map ctrlMap;
+
+	MetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?
 };
 
 } /* namespace ipa::ipu3 */
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index 1cae08bf2..8d8811f71 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -143,7 +143,8 @@ public:
 	int init(const IPASettings &settings,
 		 const IPACameraSensorInfo &sensorInfo,
 		 const ControlInfoMap &sensorControls,
-		 ControlInfoMap *ipaControls) override;
+		 ControlInfoMap *ipaControls,
+		 MetadataListPlan *metadataPlan) override;
 
 	int start() override;
 	void stop() override;
@@ -299,7 +300,8 @@ void IPAIPU3::updateControls(const IPACameraSensorInfo &sensorInfo,
 int IPAIPU3::init(const IPASettings &settings,
 		  const IPACameraSensorInfo &sensorInfo,
 		  const ControlInfoMap &sensorControls,
-		  ControlInfoMap *ipaControls)
+		  ControlInfoMap *ipaControls,
+		  MetadataListPlan *metadataPlan)
 {
 	camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
 	if (camHelper_ == nullptr) {
@@ -348,6 +350,8 @@ int IPAIPU3::init(const IPASettings &settings,
 	/* Initialize controls. */
 	updateControls(sensorInfo, sensorControls, ipaControls);
 
+	*metadataPlan = std::move(context_.metadataPlan);
+
 	return 0;
 }
 
diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp
index 70667db34..bfca8f5a5 100644
--- a/src/ipa/mali-c55/algorithms/agc.cpp
+++ b/src/ipa/mali-c55/algorithms/agc.cpp
@@ -145,6 +145,11 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)
 	);
 	context.ctrlMap.merge(controls());
 
+	context.metadataPlan.add(controls::ExposureTime);
+	context.metadataPlan.add(controls::AnalogueGain);
+	context.metadataPlan.add(controls::DigitalGain);
+	context.metadataPlan.add(controls::ColourTemperature);
+
 	return 0;
 }
 
diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp
index 050b191b7..b5acd4390 100644
--- a/src/ipa/mali-c55/algorithms/awb.cpp
+++ b/src/ipa/mali-c55/algorithms/awb.cpp
@@ -29,6 +29,13 @@ Awb::Awb()
 {
 }
 
+int Awb::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)
+{
+	context.metadataPlan.add(controls::ColourGains);
+
+	return 0;
+}
+
 int Awb::configure([[maybe_unused]] IPAContext &context,
 		   [[maybe_unused]] const IPACameraSensorInfo &configInfo)
 {
diff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h
index 800c2e834..db59e8d79 100644
--- a/src/ipa/mali-c55/algorithms/awb.h
+++ b/src/ipa/mali-c55/algorithms/awb.h
@@ -18,6 +18,7 @@ public:
 	Awb();
 	~Awb() = default;
 
+	int init(IPAContext &context, const YamlObject &tuningData) override;
 	int configure(IPAContext &context,
 		      const IPACameraSensorInfo &configInfo) override;
 	void prepare(IPAContext &context, const uint32_t frame,
diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp
index 2a54c86a9..0aaaae7dd 100644
--- a/src/ipa/mali-c55/algorithms/blc.cpp
+++ b/src/ipa/mali-c55/algorithms/blc.cpp
@@ -51,6 +51,8 @@ int BlackLevelCorrection::init([[maybe_unused]] IPAContext &context,
 
 	tuningParameters_ = true;
 
+	context.metadataPlan.add(controls::SensorBlackLevels);
+
 	LOG(MaliC55Blc, Debug)
 		<< "Black levels: 00 " << offset00 << ", 01 " << offset01
 		<< ", 10 " << offset10 << ", 11 " << offset11;
diff --git a/src/ipa/mali-c55/ipa_context.h b/src/ipa/mali-c55/ipa_context.h
index 5e3e2fbde..d76fdcb2b 100644
--- a/src/ipa/mali-c55/ipa_context.h
+++ b/src/ipa/mali-c55/ipa_context.h
@@ -9,6 +9,7 @@
 
 #include <libcamera/base/utils.h>
 #include <libcamera/controls.h>
+#include <libcamera/metadata_list_plan.h>
 
 #include "libcamera/internal/bayer_format.h"
 
@@ -83,6 +84,8 @@ struct IPAContext {
 	FCQueue<IPAFrameContext> frameContexts;
 
 	ControlInfoMap::Map ctrlMap;
+
+	MetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?
 };
 
 } /* namespace ipa::mali_c55 */
diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp
index c6941a950..7006ae55c 100644
--- a/src/ipa/mali-c55/mali-c55.cpp
+++ b/src/ipa/mali-c55/mali-c55.cpp
@@ -46,7 +46,7 @@ public:
 	IPAMaliC55();
 
 	int init(const IPASettings &settings, const IPAConfigInfo &ipaConfig,
-		 ControlInfoMap *ipaControls) override;
+		 ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan) override;
 	int start() override;
 	void stop() override;
 	int configure(const IPAConfigInfo &ipaConfig, uint8_t bayerOrder,
@@ -96,7 +96,7 @@ std::string IPAMaliC55::logPrefix() const
 }
 
 int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig,
-		     ControlInfoMap *ipaControls)
+		     ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan)
 {
 	camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
 	if (!camHelper_) {
@@ -131,6 +131,8 @@ int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig
 
 	updateControls(ipaConfig.sensorInfo, ipaConfig.sensorControls, ipaControls);
 
+	*metadataPlan = std::move(context_.metadataPlan);
+
 	return 0;
 }
 
diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp
index 137a07500..22db11b24 100644
--- a/src/ipa/rkisp1/algorithms/agc.cpp
+++ b/src/ipa/rkisp1/algorithms/agc.cpp
@@ -159,6 +159,16 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)
 	context.ctrlMap[&controls::AeEnable] = ControlInfo(false, true, true);
 	context.ctrlMap.merge(controls());
 
+	context.metadataPlan.add(controls::AnalogueGain);
+	context.metadataPlan.add(controls::ExposureTime);
+	context.metadataPlan.add(controls::FrameDuration);
+	context.metadataPlan.add(controls::FrameDuration);
+	context.metadataPlan.add(controls::ExposureTimeMode);
+	context.metadataPlan.add(controls::AnalogueGainMode);
+	context.metadataPlan.add(controls::AeMeteringMode);
+	context.metadataPlan.add(controls::AeExposureMode);
+	context.metadataPlan.add(controls::AeConstraintMode);
+
 	return 0;
 }
 
diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp
index 399fb51be..aaaa3cced 100644
--- a/src/ipa/rkisp1/algorithms/awb.cpp
+++ b/src/ipa/rkisp1/algorithms/awb.cpp
@@ -117,6 +117,10 @@ int Awb::init(IPAContext &context, const YamlObject &tuningData)
 	const auto &src = awbAlgo_->controls();
 	cmap.insert(src.begin(), src.end());
 
+	context.metadataPlan.add(controls::AwbEnable);
+	context.metadataPlan.add(controls::ColourGains);
+	context.metadataPlan.add(controls::ColourTemperature);
+
 	return 0;
 }
 
diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp
index 98cb7145e..3288f24e3 100644
--- a/src/ipa/rkisp1/algorithms/blc.cpp
+++ b/src/ipa/rkisp1/algorithms/blc.cpp
@@ -103,6 +103,8 @@ int BlackLevelCorrection::init(IPAContext &context, const YamlObject &tuningData
 		<< ", green (blue) " << blackLevelGreenB_
 		<< ", blue " << blackLevelBlue_;
 
+	context.metadataPlan.add(controls::SensorBlackLevels);
+
 	return 0;
 }
 
diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h
index f0d504215..cd4b98921 100644
--- a/src/ipa/rkisp1/ipa_context.h
+++ b/src/ipa/rkisp1/ipa_context.h
@@ -200,6 +200,7 @@ struct IPAContext {
 	FCQueue<IPAFrameContext> frameContexts;
 
 	ControlInfoMap::Map ctrlMap;
+	MetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?
 
 	DebugMetadata debugMetadata;
 
diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
index 1ed7d7d92..88c454ea1 100644
--- a/src/ipa/rkisp1/rkisp1.cpp
+++ b/src/ipa/rkisp1/rkisp1.cpp
@@ -54,7 +54,8 @@ public:
 	int init(const IPASettings &settings, unsigned int hwRevision,
 		 const IPACameraSensorInfo &sensorInfo,
 		 const ControlInfoMap &sensorControls,
-		 ControlInfoMap *ipaControls) override;
+		 ControlInfoMap *ipaControls,
+		 MetadataListPlan *metadataPlan) override;
 	int start() override;
 	void stop() override;
 
@@ -135,7 +136,8 @@ std::string IPARkISP1::logPrefix() const
 int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,
 		    const IPACameraSensorInfo &sensorInfo,
 		    const ControlInfoMap &sensorControls,
-		    ControlInfoMap *ipaControls)
+		    ControlInfoMap *ipaControls,
+		    MetadataListPlan *metadataPlan)
 {
 	/* \todo Add support for other revisions */
 	switch (hwRevision) {
@@ -204,6 +206,8 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,
 	/* Initialize controls. */
 	updateControls(sensorInfo, sensorControls, ipaControls);
 
+	*metadataPlan = std::move(context_.metadataPlan);
+
 	return 0;
 }
 
diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
index e0f8b7e78..032d6c43b 100644
--- a/src/ipa/rpi/common/ipa_base.cpp
+++ b/src/ipa/rpi/common/ipa_base.cpp
@@ -180,6 +180,40 @@ int32_t IpaBase::init(const IPASettings &settings, const InitParams &params, Ini
 
 	result->controlInfo = ControlInfoMap(std::move(ctrlMap), controls::controls);
 
+	// TODO: only set those that can be reported by configured algorithms?
+	// TODO: move this somewhere else?
+	result->metadataPlan.add(controls::AnalogueGainMode);
+	result->metadataPlan.add(controls::ExposureTimeMode);
+	result->metadataPlan.add(controls::ExposureTime);
+	result->metadataPlan.add(controls::AnalogueGain);
+	result->metadataPlan.add(controls::AeMeteringMode);
+	result->metadataPlan.add(controls::AeConstraintMode);
+	result->metadataPlan.add(controls::AeExposureMode);
+	result->metadataPlan.add(controls::ExposureValue);
+	result->metadataPlan.add(controls::AwbEnable);
+	result->metadataPlan.add(controls::AwbMode);
+	result->metadataPlan.add(controls::ColourGains);
+	result->metadataPlan.add(controls::Brightness);
+	result->metadataPlan.add(controls::Contrast);
+	result->metadataPlan.add(controls::Saturation);
+	result->metadataPlan.add(controls::Sharpness);
+	result->metadataPlan.add(controls::draft::NoiseReductionMode);
+	result->metadataPlan.add(controls::FrameDuration);
+	result->metadataPlan.add(controls::SensorTemperature);
+	result->metadataPlan.add(controls::LensPosition);
+	result->metadataPlan.add(controls::DigitalGain);
+	result->metadataPlan.add(controls::AeState);
+	result->metadataPlan.add(controls::Lux);
+	result->metadataPlan.add(controls::ColourTemperature);
+	result->metadataPlan.add(controls::SensorBlackLevels);
+	result->metadataPlan.add(controls::FocusFoM);
+	result->metadataPlan.add(controls::ColourCorrectionMatrix);
+	result->metadataPlan.add(controls::AfState);
+	result->metadataPlan.add(controls::AfPauseState);
+	result->metadataPlan.add(controls::HdrMode);
+	result->metadataPlan.add(controls::HdrChannel);
+	result->metadataPlan.add(controls::FrameDurationLimits);
+
 	return platformInit(params, result);
 }
 
diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp
index bb50a9e05..a640bec32 100644
--- a/src/ipa/rpi/pisp/pisp.cpp
+++ b/src/ipa/rpi/pisp/pisp.cpp
@@ -267,8 +267,7 @@ private:
 	HdrStatus lastStitchHdrStatus_;
 };
 
-int32_t IpaPiSP::platformInit(const InitParams &params,
-			      [[maybe_unused]] InitResult *result)
+int32_t IpaPiSP::platformInit(const InitParams &params, InitResult *result)
 {
 	const std::string &target = controller_.getTarget();
 	if (target != "pisp") {
@@ -301,6 +300,8 @@ int32_t IpaPiSP::platformInit(const InitParams &params,
 
 	setDefaultConfig();
 
+	result->metadataPlan.add(controls::rpi::PispStatsOutput, sizeof(pisp_statistics));
+
 	return 0;
 }
 
diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
index ba43e4741..d02e06589 100644
--- a/src/ipa/rpi/vc4/vc4.cpp
+++ b/src/ipa/rpi/vc4/vc4.cpp
@@ -83,7 +83,7 @@ private:
 	void *lsTable_;
 };
 
-int32_t IpaVc4::platformInit([[maybe_unused]] const InitParams &params, [[maybe_unused]] InitResult *result)
+int32_t IpaVc4::platformInit([[maybe_unused]] const InitParams &params, InitResult *result)
 {
 	const std::string &target = controller_.getTarget();
 
@@ -94,6 +94,8 @@ int32_t IpaVc4::platformInit([[maybe_unused]] const InitParams &params, [[maybe_
 		return -EINVAL;
 	}
 
+	result->metadataPlan.add(controls::rpi::Bcm2835StatsOutput, sizeof(bcm2835_isp_stats));
+
 	return 0;
 }
 
diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp
index c46bb0ebe..47a499be6 100644
--- a/src/ipa/simple/algorithms/agc.cpp
+++ b/src/ipa/simple/algorithms/agc.cpp
@@ -41,6 +41,14 @@ Agc::Agc()
 {
 }
 
+int Agc::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)
+{
+	context.metadataPlan.add(controls::ExposureTime);
+	context.metadataPlan.add(controls::AnalogueGain);
+
+	return 0;
+}
+
 void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV)
 {
 	/*
diff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h
index 112d9f5a1..00e70ea70 100644
--- a/src/ipa/simple/algorithms/agc.h
+++ b/src/ipa/simple/algorithms/agc.h
@@ -19,6 +19,7 @@ public:
 	Agc();
 	~Agc() = default;
 
+	int init(IPAContext &context, const YamlObject &tuningData) override;
 	void process(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
 		     const SwIspStats *stats,
diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp
index cf567e894..cce4585f9 100644
--- a/src/ipa/simple/algorithms/awb.cpp
+++ b/src/ipa/simple/algorithms/awb.cpp
@@ -25,6 +25,14 @@ LOG_DEFINE_CATEGORY(IPASoftAwb)
 
 namespace ipa::soft::algorithms {
 
+int Awb::init(IPAContext &context, [[maybe_unused]] const YamlObject &tuningData)
+{
+	context.metadataPlan.add(controls::ColourGains);
+	context.metadataPlan.add(controls::ColourTemperature);
+
+	return 0;
+}
+
 int Awb::configure(IPAContext &context,
 		   [[maybe_unused]] const IPAConfigInfo &configInfo)
 {
diff --git a/src/ipa/simple/algorithms/awb.h b/src/ipa/simple/algorithms/awb.h
index ad993f39c..b8ae63dcb 100644
--- a/src/ipa/simple/algorithms/awb.h
+++ b/src/ipa/simple/algorithms/awb.h
@@ -19,6 +19,7 @@ public:
 	Awb() = default;
 	~Awb() = default;
 
+	int init(IPAContext &context, const YamlObject &tuningData) override;
 	int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
 	void prepare(IPAContext &context,
 		     const uint32_t frame,
diff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp
index 8c1e9ed08..4b9284e54 100644
--- a/src/ipa/simple/algorithms/blc.cpp
+++ b/src/ipa/simple/algorithms/blc.cpp
@@ -34,6 +34,9 @@ int BlackLevel::init([[maybe_unused]] IPAContext &context,
 		 */
 		definedLevel_ = blackLevel.value() >> 8;
 	}
+
+	context.metadataPlan.add(controls::SensorBlackLevels);
+
 	return 0;
 }
 
diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp
index 0a98406c1..3cab8eaa4 100644
--- a/src/ipa/simple/algorithms/ccm.cpp
+++ b/src/ipa/simple/algorithms/ccm.cpp
@@ -39,6 +39,9 @@ int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData
 	context.ccmEnabled = true;
 	context.ctrlMap[&controls::Saturation] = ControlInfo(0.0f, 2.0f, 1.0f);
 
+	context.metadataPlan.add(controls::ColourCorrectionMatrix);
+	context.metadataPlan.add(controls::Saturation);
+
 	return 0;
 }
 
diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp
index d1d5f7271..0f99be544 100644
--- a/src/ipa/simple/algorithms/lut.cpp
+++ b/src/ipa/simple/algorithms/lut.cpp
@@ -28,6 +28,9 @@ int Lut::init(IPAContext &context,
 	      [[maybe_unused]] const YamlObject &tuningData)
 {
 	context.ctrlMap[&controls::Contrast] = ControlInfo(0.0f, 2.0f, 1.0f);
+
+	context.metadataPlan.add(controls::Contrast);
+
 	return 0;
 }
 
diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h
index a471b80ae..f4ecf43db 100644
--- a/src/ipa/simple/ipa_context.h
+++ b/src/ipa/simple/ipa_context.h
@@ -12,6 +12,7 @@
 #include <stdint.h>
 
 #include <libcamera/controls.h>
+#include <libcamera/metadata_list_plan.h>
 
 #include "libcamera/internal/matrix.h"
 #include "libcamera/internal/vector.h"
@@ -97,6 +98,7 @@ struct IPAContext {
 	IPAActiveState activeState;
 	FCQueue<IPAFrameContext> frameContexts;
 	ControlInfoMap::Map ctrlMap;
+	MetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?
 	bool ccmEnabled = false;
 };
 
diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp
index c94c4cd55..db721199d 100644
--- a/src/ipa/simple/soft_simple.cpp
+++ b/src/ipa/simple/soft_simple.cpp
@@ -56,7 +56,8 @@ public:
 		 const IPACameraSensorInfo &sensorInfo,
 		 const ControlInfoMap &sensorControls,
 		 ControlInfoMap *ipaControls,
-		 bool *ccmEnabled) override;
+		 bool *ccmEnabled,
+		 MetadataListPlan *metadataPlan) override;
 	int configure(const IPAConfigInfo &configInfo) override;
 
 	int start() override;
@@ -96,7 +97,8 @@ int IPASoftSimple::init(const IPASettings &settings,
 			const IPACameraSensorInfo &sensorInfo,
 			const ControlInfoMap &sensorControls,
 			ControlInfoMap *ipaControls,
-			bool *ccmEnabled)
+			bool *ccmEnabled,
+			MetadataListPlan *metadataPlan)
 {
 	camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
 	if (!camHelper_) {
@@ -190,6 +192,8 @@ int IPASoftSimple::init(const IPASettings &settings,
 		return -EINVAL;
 	}
 
+	*metadataPlan = std::move(context_.metadataPlan);
+
 	return 0;
 }
 
diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
index ecda426a6..1c6da2006 100644
--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
@@ -166,6 +166,8 @@ int ISICameraData::init()
 
 	properties_ = sensor_->properties();
 
+	metadataPlan_.add(controls::SensorTimestamp);
+
 	return 0;
 }
 
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index e31e3879d..b4a4283f4 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -1078,6 +1078,11 @@ int PipelineHandlerIPU3::registerCameras()
 		if (ret)
 			continue;
 
+		data->metadataPlan_.add(controls::draft::PipelineDepth);
+		data->metadataPlan_.add(controls::draft::TestPatternMode);
+		data->metadataPlan_.add(controls::ScalerCrop);
+		data->metadataPlan_.add(controls::SensorTimestamp);
+
 		const CameraSensorProperties::SensorDelays &delays = cio2->sensor()->sensorDelays();
 		std::unordered_map<uint32_t, DelayedControls::ControlParams> params = {
 			{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },
@@ -1187,7 +1192,7 @@ int IPU3CameraData::loadIPA()
 		ipa_->configurationFile(sensor->model() + ".yaml", "uncalibrated.yaml");
 
 	ret = ipa_->init(IPASettings{ ipaTuningFile, sensor->model() },
-			 sensorInfo, sensor->controls(), &ipaControls_);
+			 sensorInfo, sensor->controls(), &ipaControls_, &metadataPlan_);
 	if (ret) {
 		LOG(IPU3, Error) << "Failed to initialise the IPU3 IPA";
 		return ret;
diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
index 4acc091bd..19980f6d2 100644
--- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp
+++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp
@@ -402,7 +402,7 @@ int MaliC55CameraData::loadIPA()
 
 	ControlInfoMap ipaControls;
 	ret = ipa_->init({ ipaTuningFile, sensor_->model() }, ipaConfig,
-			 &ipaControls);
+			 &ipaControls, &metadataPlan_);
 	if (ret) {
 		LOG(MaliC55, Error) << "Failed to initialise the Mali-C55 IPA";
 		return ret;
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 675f0a749..34be87087 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -394,7 +394,7 @@ int RkISP1CameraData::loadIPA(unsigned int hwRevision)
 	}
 
 	ret = ipa_->init({ ipaTuningFile, sensor_->model() }, hwRevision,
-			 sensorInfo, sensor_->controls(), &ipaControls_);
+			 sensorInfo, sensor_->controls(), &ipaControls_, &metadataPlan_);
 	if (ret < 0) {
 		LOG(RkISP1, Error) << "IPA initialization failure";
 		return ret;
@@ -1333,6 +1333,8 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)
 
 	updateControls(data.get());
 
+	data->metadataPlan_.add(controls::SensorTimestamp);
+
 	std::set<Stream *> streams{
 		&data->mainPathStream_,
 		&data->selfPathStream_,
diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
index 1f13e5230..98507a152 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
@@ -589,6 +589,9 @@ int PipelineHandlerBase::configure(Camera *camera, CameraConfiguration *config)
 
 	data->controlInfo_ = ControlInfoMap(std::move(ctrlMap), result.controlInfo.idmap());
 
+	/* Update `rpi::ScalerCrops` size for the corrent configuration. */
+	data->metadataPlan_.add(controls::rpi::ScalerCrops, config->size());
+
 	/* Setup the Video Mux/Bridge entities. */
 	for (auto &[device, link] : data->bridgeDevices_) {
 		/*
@@ -832,6 +835,10 @@ int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &camera
 	/* Initialize the camera properties. */
 	data->properties_ = data->sensor_->properties();
 
+	data->metadataPlan_ = std::move(result.metadataPlan);
+	data->metadataPlan_.add(controls::SensorTimestamp);
+	data->metadataPlan_.add(controls::ScalerCrop);
+
 	/*
 	 * The V4L2_CID_NOTIFY_GAINS control, if present, is used to inform the
 	 * sensor of the colour gains. It is defined to be a linear gain where
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index efb07051b..05387ca7c 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -592,7 +592,7 @@ int SimpleCameraData::init()
 	 * Instantiate Soft ISP if this is enabled for the given driver and no converter is used.
 	 */
 	if (!converter_ && pipe->swIspEnabled()) {
-		swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get(), &controlInfo_);
+		swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get(), &controlInfo_, &metadataPlan_);
 		if (!swIsp_->isValid()) {
 			LOG(SimplePipeline, Warning)
 				<< "Failed to create software ISP, disabling software debayering";
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 58aa0eb4c..e0036e3b5 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -603,6 +603,8 @@ int UVCCameraData::init(MediaDevice *media)
 
 	controlInfo_ = ControlInfoMap(std::move(ctrls), controls::controls);
 
+	metadataPlan_.add(controls::SensorTimestamp);
+
 	/*
 	 * Close to allow camera to go into runtime-suspend, video_ will be
 	 * re-opened from acquireDevice() and validate().
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index 07273bd2b..f8a29da41 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -590,6 +590,8 @@ int VimcCameraData::init()
 
 	controlInfo_ = ControlInfoMap(std::move(ctrls), controls::controls);
 
+	metadataPlan_.add(controls::SensorTimestamp);
+
 	/* Initialize the camera properties. */
 	properties_ = sensor_->properties();
 
diff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp
index 1d3d9ba87..f10aea7bf 100644
--- a/src/libcamera/pipeline/virtual/config_parser.cpp
+++ b/src/libcamera/pipeline/virtual/config_parser.cpp
@@ -65,6 +65,9 @@ ConfigParser::parseConfigFile(File &file, PipelineHandler *pipe)
 		controls[&controls::draft::FaceDetectMode] = ControlInfo(supportedFaceDetectModes);
 
 		data->controlInfo_ = ControlInfoMap(std::move(controls), controls::controls);
+
+		data->metadataPlan_.add(controls::SensorTimestamp);
+
 		configurations.push_back(std::move(data));
 	}
 
diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
index 28e2a360e..6da69daf9 100644
--- a/src/libcamera/software_isp/software_isp.cpp
+++ b/src/libcamera/software_isp/software_isp.cpp
@@ -71,10 +71,11 @@ LOG_DEFINE_CATEGORY(SoftwareIsp)
  * \param[in] pipe The pipeline handler in use
  * \param[in] sensor Pointer to the CameraSensor instance owned by the pipeline
  * \param[out] ipaControls The IPA controls to update
+ * \param[out] metadataPlan The metadata plan to update
  * handler
  */
 SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,
-			 ControlInfoMap *ipaControls)
+			 ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan)
 	: dmaHeap_(DmaBufAllocator::DmaBufAllocatorFlag::CmaHeap |
 		   DmaBufAllocator::DmaBufAllocatorFlag::SystemHeap |
 		   DmaBufAllocator::DmaBufAllocatorFlag::UDmaBuf)
@@ -146,7 +147,8 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,
 			 sensorInfo,
 			 sensor->controls(),
 			 ipaControls,
-			 &ccmEnabled_);
+			 &ccmEnabled_,
+			 metadataPlan);
 	if (ret) {
 		LOG(SoftwareIsp, Error) << "IPA init failed";
 		debayer_.reset();
-- 
2.49.0



More information about the libcamera-devel mailing list