[{"id":34575,"web_url":"https://patchwork.libcamera.org/comment/34575/","msgid":"<lthakqp6mgn7c45fxbp7o4y5t3n6hgvatmxfh7cubhy52wgezn@gyjhg5zk5aer>","date":"2025-06-19T13:47:36","subject":"Re: [RFC PATCH v1 18/23] libcamera: pipeline: Fill\n\t`MetadataListPlan` of cameras","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Barnabás\n\nOn Fri, Jun 06, 2025 at 06:41:51PM +0200, Barnabás Pőcze wrote:\n> Fill the newly introduced `MetadataListPlan` member of the camera's private\n> data during initializations, similarly to the camera's `ControlInfoMap`.\n>\n> Signed-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(-)\n>\n> diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h\n> index 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; }\n> diff --git a/include/libcamera/ipa/ipu3.mojom b/include/libcamera/ipa/ipu3.mojom\n> index 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>\n> diff --git a/include/libcamera/ipa/mali-c55.mojom b/include/libcamera/ipa/mali-c55.mojom\n> index 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>\n> diff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom\n> index 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 {\n> diff --git a/include/libcamera/ipa/rkisp1.mojom b/include/libcamera/ipa/rkisp1.mojom\n> index 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\nI would break the line like you've done for other mojom files\n\n>  \tstart() => (int32 ret);\n>  \tstop();\n>\n> diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom\n> index 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)\n> diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\n> index 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>\n> diff --git a/src/ipa/ipu3/algorithms/awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp\n> index 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>   */\n> diff --git a/src/ipa/ipu3/algorithms/awb.h b/src/ipa/ipu3/algorithms/awb.h\n> index 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,\n> diff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp\n> index 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>  /**\n> diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h\n> index 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\nDo you think we could remove it by passing metadataPlan to the init()\nfunction of each algorithm ?\n\n>  };\n>\n>  } /* namespace ipa::ipu3 */\n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> index 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>\n> diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp\n> index 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>\n> diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp\n> index 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>  {\n> diff --git a/src/ipa/mali-c55/algorithms/awb.h b/src/ipa/mali-c55/algorithms/awb.h\n> index 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,\n> diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp\n> index 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;\n> diff --git a/src/ipa/mali-c55/ipa_context.h b/src/ipa/mali-c55/ipa_context.h\n> index 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 */\n> diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp\n> index 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>\n> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> index 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\nDouble entry\n\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>\n> diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\n> index 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>\n> diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp\n> index 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\nI also see the following metadata populated by algorithms in the\nRkISP1 IPA\n\nsrc/ipa/rkisp1/algorithms/ccm.cpp:      metadata.set(controls::ColourCorrectionMatrix, frameContext.ccm.ccm.data());\nsrc/ipa/rkisp1/algorithms/goc.cpp:      metadata.set(controls::Gamma, frameContext.goc.gamma);\nsrc/ipa/rkisp1/algorithms/lux.cpp:      metadata.set(controls::Lux, lux);\n\n>\n> diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\n> index 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>\n> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> index 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>\n> diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp\n> index 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\n\nmmm, we don't have the equivalent of Algorithm::init() for rpi, right ?\n\n> +\t// TODO: move this somewhere else?\n\nWhere would you propse ?\n\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>\n> diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp\n> index 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>\n> diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp\n> index 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>\n> diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp\n> index 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/*\n> diff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h\n> index 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,\n> diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp\n> index 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>  {\n> diff --git a/src/ipa/simple/algorithms/awb.h b/src/ipa/simple/algorithms/awb.h\n> index 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,\n> diff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp\n> index 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>\n> diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp\n> index 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>\n> diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\n> index 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>\n> diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h\n> index 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>\n> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n> index 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>\n> diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> index 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>\n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> index 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;\n> diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> index 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;\n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index 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_,\n> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> index 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\n> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> index 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\";\n> diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> index 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().\n> diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp\n> index 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>\n> diff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp\n> index 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>\n> diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp\n> index 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\nWith the above fixed\nReviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n\nThanks\n  j\n\n> --\n> 2.49.0\n>","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 E5053C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 19 Jun 2025 13:47:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8824468DE3;\n\tThu, 19 Jun 2025 15:47:41 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B4DF768DDB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 19 Jun 2025 15:47:40 +0200 (CEST)","from ideasonboard.com (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A98AC2EC;\n\tThu, 19 Jun 2025 15:47:26 +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=\"HkmYUQSw\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750340846;\n\tbh=hhEnyfW/BBHOBeoBJtfZQ1S+hg2KrTEw+/Pj9tbbRaM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=HkmYUQSwJjW8fSitpGVZHRF3nkYJcLI0sybumAGw9y6zBo76kmjHc7uf0OUv3MwRF\n\tTs8V+HWeOqCyg/p2IVyfRA3qYSG3EqWIW+1Ni5CQL5gSVj/tTnQx9nWWW8UVtGmZqa\n\tGAyLdnLMMhiikNk04+Cr6DyB0YP5EP4IqLKoxkSM=","Date":"Thu, 19 Jun 2025 15:47:36 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [RFC PATCH v1 18/23] libcamera: pipeline: Fill\n\t`MetadataListPlan` of cameras","Message-ID":"<lthakqp6mgn7c45fxbp7o4y5t3n6hgvatmxfh7cubhy52wgezn@gyjhg5zk5aer>","References":"<20250606164156.1442682-1-barnabas.pocze@ideasonboard.com>\n\t<20250606164156.1442682-19-barnabas.pocze@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20250606164156.1442682-19-barnabas.pocze@ideasonboard.com>","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>"}},{"id":34583,"web_url":"https://patchwork.libcamera.org/comment/34583/","msgid":"<f7a68d9f-240f-4d85-9bd7-e27622fd5635@ideasonboard.com>","date":"2025-06-19T14:35:26","subject":"Re: [RFC PATCH v1 18/23] libcamera: pipeline: Fill\n\t`MetadataListPlan` of cameras","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2025. 06. 19. 15:47 keltezéssel, Jacopo Mondi írta:\n> Hi Barnabás\n> \n> On Fri, Jun 06, 2025 at 06:41:51PM +0200, Barnabás Pőcze wrote:\n>> Fill the newly introduced `MetadataListPlan` member of the camera's private\n>> data during initializations, similarly to the camera's `ControlInfoMap`.\n>>\n>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n>> ---\n> [...]\n>> diff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom\n>> index 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 {\n>> diff --git a/include/libcamera/ipa/rkisp1.mojom b/include/libcamera/ipa/rkisp1.mojom\n>> index 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> \n> I would break the line like you've done for other mojom files\n\nDone.\n\n\n> \n>>   \tstart() => (int32 ret);\n>>   \tstop();\n>>\n> [...]\n>> diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h\n>> index 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> Do you think we could remove it by passing metadataPlan to the init()\n> function of each algorithm ?\n\nThe arguments are controlled by the generic `Algorithm` template,\nand I did not want to make modifications there.\n\n\n> \n>>   };\n>>\n>>   } /* namespace ipa::ipu3 */\n> [...]\n>> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n>> index 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> \n> Double entry\n\nDone.\n\n\n> \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>>\n>> diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\n>> index 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>>\n>> diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp\n>> index 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> \n> I also see the following metadata populated by algorithms in the\n> RkISP1 IPA\n> \n> src/ipa/rkisp1/algorithms/ccm.cpp:      metadata.set(controls::ColourCorrectionMatrix, frameContext.ccm.ccm.data());\n> src/ipa/rkisp1/algorithms/goc.cpp:      metadata.set(controls::Gamma, frameContext.goc.gamma);\n> src/ipa/rkisp1/algorithms/lux.cpp:      metadata.set(controls::Lux, lux);\n\nOops... you're right.\n\n\n> \n>>\n>> diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\n>> index 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>>\n>> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n>> index 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>>\n>> diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp\n>> index 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> \n> \n> mmm, we don't have the equivalent of Algorithm::init() for rpi, right ?\n> \n>> +\t// TODO: move this somewhere else?\n> \n> Where would you propse ?\n\nNot sure. The rpi `Algorithm` class is a bit different, it does have `initialize()`\nbut it takes no arguments. So that could be modified, but metadata handling is also\ndone through the custom `Metadata` type, and the conversion is also carried out\noutside the algorithms. Now everything libcamera metadata related is in `ipa_base.cpp`.\nAnother thing that could be done is calling `controller_.getAlgorithm(...)` to check\nif the algorithm is active, and enabling the metadata in that case.\n\n\nRegards,\nBarnabás Pőcze\n\n\n> [...]","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 00EF1C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 19 Jun 2025 14:35:32 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DABF468DE3;\n\tThu, 19 Jun 2025 16:35:31 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 878D268DDB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 19 Jun 2025 16:35:30 +0200 (CEST)","from [192.168.33.22] (185.221.143.107.nat.pool.zt.hu\n\t[185.221.143.107])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 41682107;\n\tThu, 19 Jun 2025 16:35: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=\"MO38e30c\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750343716;\n\tbh=bZ+X3dgyshNnko5Ks/Hyl6bL42bJkEfyoTkAeieuTpM=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=MO38e30cjjMKAX0EUOVYNyKTqG7P4xxH//wI7QW6be2raSfw4PYxxLBl8Nth6JaBm\n\tGmGEFI+9LXVnbZ+2ru7+P5+daPzBY7RaXsxhcFECcPtP3VYnh7CgGN5L2tBPN/Z3Ib\n\t6Rii106HDtNw9Ey486NnpqVIPf5GRQ6/SJZ7ahVc=","Message-ID":"<f7a68d9f-240f-4d85-9bd7-e27622fd5635@ideasonboard.com>","Date":"Thu, 19 Jun 2025 16:35:26 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [RFC PATCH v1 18/23] libcamera: pipeline: Fill\n\t`MetadataListPlan` of cameras","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20250606164156.1442682-1-barnabas.pocze@ideasonboard.com>\n\t<20250606164156.1442682-19-barnabas.pocze@ideasonboard.com>\n\t<lthakqp6mgn7c45fxbp7o4y5t3n6hgvatmxfh7cubhy52wgezn@gyjhg5zk5aer>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<lthakqp6mgn7c45fxbp7o4y5t3n6hgvatmxfh7cubhy52wgezn@gyjhg5zk5aer>","Content-Type":"text/plain; charset=UTF-8; format=flowed","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>"}}]