[{"id":36618,"web_url":"https://patchwork.libcamera.org/comment/36618/","msgid":"<176209864677.2973778.17565323710269908500@ping.linuxembedded.co.uk>","date":"2025-11-02T15:50:46","subject":"Re: [RFC PATCH v3 20/22] libcamera: pipeline: Fill\n\t`MetadataListPlan` of cameras","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Barnabás Pőcze (2025-10-30 16:58:14)\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> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\nNot much to say for this one except it would need to be double checked\nbefore merging.\n\nThough I guess we'll get errors if we try to add metadata when it's not\nin the plan ?\n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> ---\n> changes in v2:\n>   * add missing controls for `rkisp1`\n>   * sort alphabetically\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            |  3 +-\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/algorithms/ccm.cpp             |  2 ++\n>  src/ipa/rkisp1/algorithms/goc.cpp             |  2 ++\n>  src/ipa/rkisp1/algorithms/lux.cpp             |  8 ++++-\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     |  8 +++++\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>  48 files changed, 203 insertions(+), 23 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 7862465924..bd85f6b4bd 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>         SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n> -                   ControlInfoMap *ipaControls);\n> +                   ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan);\n>         ~SoftwareIsp();\n>  \n>         int 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 d9a50b01db..f49b777973 100644\n> --- a/include/libcamera/ipa/ipu3.mojom\n> +++ b/include/libcamera/ipa/ipu3.mojom\n> @@ -20,7 +20,8 @@ interface IPAIPU3Interface {\n>         init(libcamera.IPASettings settings,\n>              libcamera.IPACameraSensorInfo sensorInfo,\n>              libcamera.ControlInfoMap sensorControls)\n> -               => (int32 ret, libcamera.ControlInfoMap ipaControls);\n> +               => (int32 ret, libcamera.ControlInfoMap ipaControls,\n> +                   libcamera.MetadataListPlan metadata);\n>         start() => (int32 ret);\n>         stop();\n>  \n> diff --git a/include/libcamera/ipa/mali-c55.mojom b/include/libcamera/ipa/mali-c55.mojom\n> index 39b7f1f109..af1d083728 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>         init(libcamera.IPASettings settings, IPAConfigInfo configInfo)\n> -               => (int32 ret, libcamera.ControlInfoMap ipaControls);\n> +               => (int32 ret, libcamera.ControlInfoMap ipaControls,\n> +                   libcamera.MetadataListPlan metadataPlan);\n>         start() => (int32 ret);\n>         stop();\n>  \n> diff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom\n> index 12b083e9d0..c32391911e 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>         SensorConfig sensorConfig;\n>         libcamera.ControlInfoMap controlInfo;\n> +       libcamera.MetadataListPlan metadataPlan;\n>  };\n>  \n>  struct BufferIds {\n> diff --git a/include/libcamera/ipa/rkisp1.mojom b/include/libcamera/ipa/rkisp1.mojom\n> index 068e898848..015ba46036 100644\n> --- a/include/libcamera/ipa/rkisp1.mojom\n> +++ b/include/libcamera/ipa/rkisp1.mojom\n> @@ -19,7 +19,8 @@ interface IPARkISP1Interface {\n>              uint32 hwRevision, uint32 supportedBlocks,\n>              libcamera.IPACameraSensorInfo sensorInfo,\n>              libcamera.ControlInfoMap sensorControls)\n> -               => (int32 ret, libcamera.ControlInfoMap ipaControls);\n> +               => (int32 ret, libcamera.ControlInfoMap ipaControls,\n> +                   libcamera.MetadataListPlan metadataPlan);\n>         start() => (int32 ret);\n>         stop();\n>  \n> diff --git a/include/libcamera/ipa/soft.mojom b/include/libcamera/ipa/soft.mojom\n> index 77328c5fd5..360ed668b7 100644\n> --- a/include/libcamera/ipa/soft.mojom\n> +++ b/include/libcamera/ipa/soft.mojom\n> @@ -18,7 +18,8 @@ interface IPASoftInterface {\n>              libcamera.SharedFD fdParams,\n>              libcamera.IPACameraSensorInfo sensorInfo,\n>              libcamera.ControlInfoMap sensorControls)\n> -               => (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled);\n> +               => (int32 ret, libcamera.ControlInfoMap ipaControls, bool ccmEnabled,\n> +                   libcamera.MetadataListPlan metadataPlan);\n>         start() => (int32 ret);\n>         stop();\n>         configure(IPAConfigInfo configInfo)\n> diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\n> index b0d89541da..2d7b0482fe 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>         context.ctrlMap.merge(controls());\n>  \n> +       context.metadataPlan.set(controls::AnalogueGain);\n> +       context.metadataPlan.set(controls::ExposureTime);\n> +       context.metadataPlan.set(controls::FrameDuration);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/ipu3/algorithms/awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp\n> index 55de05d9e3..499c7790f9 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> +       context.metadataPlan.set(controls::AwbEnable);\n> +       context.metadataPlan.set(controls::ColourGains);\n> +       context.metadataPlan.set(controls::ColourTemperature);\n> +\n> +       return 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 dbf69c9073..1d47bffa34 100644\n> --- a/src/ipa/ipu3/algorithms/awb.h\n> +++ b/src/ipa/ipu3/algorithms/awb.h\n> @@ -40,6 +40,7 @@ public:\n>         Awb();\n>         ~Awb();\n>  \n> +       int init(IPAContext &context, const YamlObject &tuningData) override;\n>         int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n>         void prepare(IPAContext &context, const uint32_t frame,\n>                      IPAFrameContext &frameContext,\n> diff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp\n> index 3b22f79176..f0b8b5dbea 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 97fcf06cd4..f4f45ef4d4 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>         FCQueue<IPAFrameContext> frameContexts;\n>  \n>         ControlInfoMap::Map ctrlMap;\n> +\n> +       MetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?\n>  };\n>  \n>  } /* namespace ipa::ipu3 */\n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> index 1cae08bf25..8d8811f717 100644\n> --- a/src/ipa/ipu3/ipu3.cpp\n> +++ b/src/ipa/ipu3/ipu3.cpp\n> @@ -143,7 +143,8 @@ public:\n>         int init(const IPASettings &settings,\n>                  const IPACameraSensorInfo &sensorInfo,\n>                  const ControlInfoMap &sensorControls,\n> -                ControlInfoMap *ipaControls) override;\n> +                ControlInfoMap *ipaControls,\n> +                MetadataListPlan *metadataPlan) override;\n>  \n>         int start() override;\n>         void stop() override;\n> @@ -299,7 +300,8 @@ void IPAIPU3::updateControls(const IPACameraSensorInfo &sensorInfo,\n>  int IPAIPU3::init(const IPASettings &settings,\n>                   const IPACameraSensorInfo &sensorInfo,\n>                   const ControlInfoMap &sensorControls,\n> -                 ControlInfoMap *ipaControls)\n> +                 ControlInfoMap *ipaControls,\n> +                 MetadataListPlan *metadataPlan)\n>  {\n>         camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n>         if (camHelper_ == nullptr) {\n> @@ -348,6 +350,8 @@ int IPAIPU3::init(const IPASettings &settings,\n>         /* Initialize controls. */\n>         updateControls(sensorInfo, sensorControls, ipaControls);\n>  \n> +       *metadataPlan = std::move(context_.metadataPlan);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp\n> index f60fddac3f..97316ca35c 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>         );\n>         context.ctrlMap.merge(controls());\n>  \n> +       context.metadataPlan.set(controls::AnalogueGain);\n> +       context.metadataPlan.set(controls::ColourTemperature);\n> +       context.metadataPlan.set(controls::DigitalGain);\n> +       context.metadataPlan.set(controls::ExposureTime);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/mali-c55/algorithms/awb.cpp b/src/ipa/mali-c55/algorithms/awb.cpp\n> index 3d546e5a85..1fd67a4f9f 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> +       context.metadataPlan.set(controls::ColourGains);\n> +\n> +       return 0;\n> +}\n> +\n>  int Awb::configure([[maybe_unused]] IPAContext &context,\n>                    [[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 2351d40555..6bdc88a193 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>         Awb();\n>         ~Awb() = default;\n>  \n> +       int init(IPAContext &context, const YamlObject &tuningData) override;\n>         int configure(IPAContext &context,\n>                       const IPACameraSensorInfo &configInfo) override;\n>         void 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 2a54c86a91..d36c7ac66e 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>         tuningParameters_ = true;\n>  \n> +       context.metadataPlan.set(controls::SensorBlackLevels);\n> +\n>         LOG(MaliC55Blc, Debug)\n>                 << \"Black levels: 00 \" << offset00 << \", 01 \" << offset01\n>                 << \", 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 13885eb83b..55aef1d100 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>         FCQueue<IPAFrameContext> frameContexts;\n>  \n>         ControlInfoMap::Map ctrlMap;\n> +\n> +       MetadataListPlan 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 7d45e7310a..10b61b4fb3 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>         IPAMaliC55();\n>  \n>         int init(const IPASettings &settings, const IPAConfigInfo &ipaConfig,\n> -                ControlInfoMap *ipaControls) override;\n> +                ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan) override;\n>         int start() override;\n>         void stop() override;\n>         int 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> -                    ControlInfoMap *ipaControls)\n> +                    ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan)\n>  {\n>         camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n>         if (!camHelper_) {\n> @@ -131,6 +131,8 @@ int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig\n>  \n>         updateControls(ipaConfig.sensorInfo, ipaConfig.sensorControls, ipaControls);\n>  \n> +       *metadataPlan = std::move(context_.metadataPlan);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> index f5a3c917cb..cbc7311cd5 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/agc.cpp\n> @@ -160,6 +160,16 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)\n>         context.ctrlMap[&controls::ExposureValue] = ControlInfo(-8.0f, 8.0f, 0.0f);\n>         context.ctrlMap.merge(controls());\n>  \n> +       context.metadataPlan.set(controls::AeConstraintMode);\n> +       context.metadataPlan.set(controls::AeExposureMode);\n> +       context.metadataPlan.set(controls::AeMeteringMode);\n> +       context.metadataPlan.set(controls::AnalogueGain);\n> +       context.metadataPlan.set(controls::AnalogueGainMode);\n> +       context.metadataPlan.set(controls::ExposureTime);\n> +       context.metadataPlan.set(controls::ExposureTimeMode);\n> +       context.metadataPlan.set(controls::ExposureValue);\n> +       context.metadataPlan.set(controls::FrameDuration);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\n> index 399fb51be4..8de7ea3951 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>         const auto &src = awbAlgo_->controls();\n>         cmap.insert(src.begin(), src.end());\n>  \n> +       context.metadataPlan.set(controls::AwbEnable);\n> +       context.metadataPlan.set(controls::ColourGains);\n> +       context.metadataPlan.set(controls::ColourTemperature);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp\n> index 32fc44ffff..03071360b3 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>                 << \", green (blue) \" << blackLevelGreenB_\n>                 << \", blue \" << blackLevelBlue_;\n>  \n> +       context.metadataPlan.set(controls::SensorBlackLevels);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/rkisp1/algorithms/ccm.cpp b/src/ipa/rkisp1/algorithms/ccm.cpp\n> index de2b6fe775..3115d3effa 100644\n> --- a/src/ipa/rkisp1/algorithms/ccm.cpp\n> +++ b/src/ipa/rkisp1/algorithms/ccm.cpp\n> @@ -66,6 +66,8 @@ int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData\n>                 offsets_.setData({ { 0, Matrix<int16_t, 3, 1>({ 0, 0, 0 }) } });\n>         }\n>  \n> +       context.metadataPlan.set(controls::ColourCorrectionMatrix);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/rkisp1/algorithms/goc.cpp b/src/ipa/rkisp1/algorithms/goc.cpp\n> index a0e7030fe5..46a4c2c364 100644\n> --- a/src/ipa/rkisp1/algorithms/goc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/goc.cpp\n> @@ -60,6 +60,8 @@ int GammaOutCorrection::init(IPAContext &context, const YamlObject &tuningData)\n>         defaultGamma_ = tuningData[\"gamma\"].get<double>(kDefaultGamma);\n>         context.ctrlMap[&controls::Gamma] = ControlInfo(0.1f, 10.0f, defaultGamma_);\n>  \n> +       context.metadataPlan.set(controls::Gamma);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/rkisp1/algorithms/lux.cpp b/src/ipa/rkisp1/algorithms/lux.cpp\n> index e8da698100..966c711375 100644\n> --- a/src/ipa/rkisp1/algorithms/lux.cpp\n> +++ b/src/ipa/rkisp1/algorithms/lux.cpp\n> @@ -43,7 +43,13 @@ Lux::Lux()\n>   */\n>  int Lux::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)\n>  {\n> -       return lux_.parseTuningData(tuningData);\n> +       int ret = lux_.parseTuningData(tuningData);\n> +       if (ret)\n> +               return ret;\n> +\n> +       context.metadataPlan.set(controls::Lux);\n> +\n> +       return 0;\n>  }\n>  \n>  /**\n> diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\n> index f85a130d9c..caf7d9d448 100644\n> --- a/src/ipa/rkisp1/ipa_context.h\n> +++ b/src/ipa/rkisp1/ipa_context.h\n> @@ -230,6 +230,7 @@ struct IPAContext {\n>         FCQueue<IPAFrameContext> frameContexts;\n>  \n>         ControlInfoMap::Map ctrlMap;\n> +       MetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?\n>  \n>         DebugMetadata debugMetadata;\n>  \n> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> index fa22bfc349..9815b83a03 100644\n> --- a/src/ipa/rkisp1/rkisp1.cpp\n> +++ b/src/ipa/rkisp1/rkisp1.cpp\n> @@ -55,7 +55,8 @@ public:\n>                  uint32_t supportedBlocks,\n>                  const IPACameraSensorInfo &sensorInfo,\n>                  const ControlInfoMap &sensorControls,\n> -                ControlInfoMap *ipaControls) override;\n> +                ControlInfoMap *ipaControls,\n> +                MetadataListPlan *metadataPlan) override;\n>         int start() override;\n>         void stop() override;\n>  \n> @@ -139,7 +140,8 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,\n>                     uint32_t supportedBlocks,\n>                     const IPACameraSensorInfo &sensorInfo,\n>                     const ControlInfoMap &sensorControls,\n> -                   ControlInfoMap *ipaControls)\n> +                   ControlInfoMap *ipaControls,\n> +                   MetadataListPlan *metadataPlan)\n>  {\n>         /* \\todo Add support for other revisions */\n>         switch (hwRevision) {\n> @@ -209,6 +211,8 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,\n>         /* Initialize controls. */\n>         updateControls(sensorInfo, sensorControls, ipaControls);\n>  \n> +       *metadataPlan = std::move(context_.metadataPlan);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp\n> index 8dfe35cc32..15e65f9315 100644\n> --- a/src/ipa/rpi/common/ipa_base.cpp\n> +++ b/src/ipa/rpi/common/ipa_base.cpp\n> @@ -182,6 +182,40 @@ int32_t IpaBase::init(const IPASettings &settings, const InitParams &params, Ini\n>  \n>         result->controlInfo = ControlInfoMap(std::move(ctrlMap), controls::controls);\n>  \n> +       // TODO: only set those that can be reported by configured algorithms?\n> +       // TODO: move this somewhere else?\n> +       result->metadataPlan.set(controls::AeConstraintMode);\n> +       result->metadataPlan.set(controls::AeExposureMode);\n> +       result->metadataPlan.set(controls::AeMeteringMode);\n> +       result->metadataPlan.set(controls::AeState);\n> +       result->metadataPlan.set(controls::AfPauseState);\n> +       result->metadataPlan.set(controls::AfState);\n> +       result->metadataPlan.set(controls::AnalogueGain);\n> +       result->metadataPlan.set(controls::AnalogueGainMode);\n> +       result->metadataPlan.set(controls::AwbEnable);\n> +       result->metadataPlan.set(controls::AwbMode);\n> +       result->metadataPlan.set(controls::Brightness);\n> +       result->metadataPlan.set(controls::ColourCorrectionMatrix);\n> +       result->metadataPlan.set(controls::ColourGains);\n> +       result->metadataPlan.set(controls::ColourTemperature);\n> +       result->metadataPlan.set(controls::Contrast);\n> +       result->metadataPlan.set(controls::DigitalGain);\n> +       result->metadataPlan.set(controls::ExposureTime);\n> +       result->metadataPlan.set(controls::ExposureTimeMode);\n> +       result->metadataPlan.set(controls::ExposureValue);\n> +       result->metadataPlan.set(controls::FocusFoM);\n> +       result->metadataPlan.set(controls::FrameDuration);\n> +       result->metadataPlan.set(controls::FrameDurationLimits);\n> +       result->metadataPlan.set(controls::HdrChannel);\n> +       result->metadataPlan.set(controls::HdrMode);\n> +       result->metadataPlan.set(controls::LensPosition);\n> +       result->metadataPlan.set(controls::Lux);\n> +       result->metadataPlan.set(controls::Saturation);\n> +       result->metadataPlan.set(controls::SensorBlackLevels);\n> +       result->metadataPlan.set(controls::SensorTemperature);\n> +       result->metadataPlan.set(controls::Sharpness);\n> +       result->metadataPlan.set(controls::draft::NoiseReductionMode);\n> +\n>         return platformInit(params, result);\n>  }\n>  \n> diff --git a/src/ipa/rpi/pisp/pisp.cpp b/src/ipa/rpi/pisp/pisp.cpp\n> index ec7593ffc9..04e7731d22 100644\n> --- a/src/ipa/rpi/pisp/pisp.cpp\n> +++ b/src/ipa/rpi/pisp/pisp.cpp\n> @@ -291,8 +291,7 @@ private:\n>         HdrStatus lastStitchHdrStatus_;\n>  };\n>  \n> -int32_t IpaPiSP::platformInit(const InitParams &params,\n> -                             [[maybe_unused]] InitResult *result)\n> +int32_t IpaPiSP::platformInit(const InitParams &params, InitResult *result)\n>  {\n>         const std::string &target = controller_.getTarget();\n>         if (target != \"pisp\") {\n> @@ -325,6 +324,8 @@ int32_t IpaPiSP::platformInit(const InitParams &params,\n>  \n>         setDefaultConfig();\n>  \n> +       result->metadataPlan.set(controls::rpi::PispStatsOutput, sizeof(pisp_statistics));\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp\n> index 2b205b2861..3014925eaf 100644\n> --- a/src/ipa/rpi/vc4/vc4.cpp\n> +++ b/src/ipa/rpi/vc4/vc4.cpp\n> @@ -91,7 +91,7 @@ private:\n>         AwbStatus lastAwbStatus_;\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>         const std::string &target = controller_.getTarget();\n>  \n> @@ -102,6 +102,8 @@ int32_t IpaVc4::platformInit([[maybe_unused]] const InitParams &params, [[maybe_\n>                 return -EINVAL;\n>         }\n>  \n> +       result->metadataPlan.set(controls::rpi::Bcm2835StatsOutput, sizeof(bcm2835_isp_stats));\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp\n> index 189de770c6..c4e52328f0 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> +       context.metadataPlan.set(controls::AnalogueGain);\n> +       context.metadataPlan.set(controls::ExposureTime);\n> +\n> +       return 0;\n> +}\n> +\n>  void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV)\n>  {\n>         /*\n> diff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h\n> index 112d9f5a19..00e70ea705 100644\n> --- a/src/ipa/simple/algorithms/agc.h\n> +++ b/src/ipa/simple/algorithms/agc.h\n> @@ -19,6 +19,7 @@ public:\n>         Agc();\n>         ~Agc() = default;\n>  \n> +       int init(IPAContext &context, const YamlObject &tuningData) override;\n>         void process(IPAContext &context, const uint32_t frame,\n>                      IPAFrameContext &frameContext,\n>                      const SwIspStats *stats,\n> diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp\n> index cf78e98009..fe605117ab 100644\n> --- a/src/ipa/simple/algorithms/awb.cpp\n> +++ b/src/ipa/simple/algorithms/awb.cpp\n> @@ -26,6 +26,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> +       context.metadataPlan.set(controls::ColourGains);\n> +       context.metadataPlan.set(controls::ColourTemperature);\n> +\n> +       return 0;\n> +}\n> +\n>  int Awb::configure(IPAContext &context,\n>                    [[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 ad993f39c1..b8ae63dcb1 100644\n> --- a/src/ipa/simple/algorithms/awb.h\n> +++ b/src/ipa/simple/algorithms/awb.h\n> @@ -19,6 +19,7 @@ public:\n>         Awb() = default;\n>         ~Awb() = default;\n>  \n> +       int init(IPAContext &context, const YamlObject &tuningData) override;\n>         int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n>         void prepare(IPAContext &context,\n>                      const uint32_t frame,\n> diff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp\n> index 370385afc6..bcb67b832a 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>                  */\n>                 definedLevel_ = blackLevel.value() >> 8;\n>         }\n> +\n> +       context.metadataPlan.set(controls::SensorBlackLevels);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp\n> index 0a98406c1a..b1758ff39b 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>         context.ccmEnabled = true;\n>         context.ctrlMap[&controls::Saturation] = ControlInfo(0.0f, 2.0f, 1.0f);\n>  \n> +       context.metadataPlan.set(controls::ColourCorrectionMatrix);\n> +       context.metadataPlan.set(controls::Saturation);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\n> index d1d5f72712..5a7ffbd8fa 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>               [[maybe_unused]] const YamlObject &tuningData)\n>  {\n>         context.ctrlMap[&controls::Contrast] = ControlInfo(0.0f, 2.0f, 1.0f);\n> +\n> +       context.metadataPlan.set(controls::Contrast);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h\n> index c3081e3069..d76c0f79ee 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> @@ -102,6 +103,7 @@ struct IPAContext {\n>         IPAActiveState activeState;\n>         FCQueue<IPAFrameContext> frameContexts;\n>         ControlInfoMap::Map ctrlMap;\n> +       MetadataListPlan metadataPlan; // TODO: only needed during init(), how could be removed?\n>         bool ccmEnabled = false;\n>  };\n>  \n> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n> index b147aca2e3..9d698a27b3 100644\n> --- a/src/ipa/simple/soft_simple.cpp\n> +++ b/src/ipa/simple/soft_simple.cpp\n> @@ -56,7 +56,8 @@ public:\n>                  const IPACameraSensorInfo &sensorInfo,\n>                  const ControlInfoMap &sensorControls,\n>                  ControlInfoMap *ipaControls,\n> -                bool *ccmEnabled) override;\n> +                bool *ccmEnabled,\n> +                MetadataListPlan *metadataPlan) override;\n>         int configure(const IPAConfigInfo &configInfo) override;\n>  \n>         int start() override;\n> @@ -96,7 +97,8 @@ int IPASoftSimple::init(const IPASettings &settings,\n>                         const IPACameraSensorInfo &sensorInfo,\n>                         const ControlInfoMap &sensorControls,\n>                         ControlInfoMap *ipaControls,\n> -                       bool *ccmEnabled)\n> +                       bool *ccmEnabled,\n> +                       MetadataListPlan *metadataPlan)\n>  {\n>         camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);\n>         if (!camHelper_) {\n> @@ -190,6 +192,8 @@ int IPASoftSimple::init(const IPASettings &settings,\n>                 return -EINVAL;\n>         }\n>  \n> +       *metadataPlan = std::move(context_.metadataPlan);\n> +\n>         return 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 de09431cb9..fbad880b23 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>         properties_ = sensor_->properties();\n>  \n> +       metadataPlan_.set(controls::SensorTimestamp);\n> +\n>         return 0;\n>  }\n>  \n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> index d6b7edcb5a..13dbdb6268 100644\n> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> @@ -1082,6 +1082,11 @@ int PipelineHandlerIPU3::registerCameras()\n>                 if (ret)\n>                         continue;\n>  \n> +               data->metadataPlan_.set(controls::draft::PipelineDepth);\n> +               data->metadataPlan_.set(controls::draft::TestPatternMode);\n> +               data->metadataPlan_.set(controls::ScalerCrop);\n> +               data->metadataPlan_.set(controls::SensorTimestamp);\n> +\n>                 const CameraSensorProperties::SensorDelays &delays = cio2->sensor()->sensorDelays();\n>                 std::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n>                         { V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> @@ -1191,7 +1196,7 @@ int IPU3CameraData::loadIPA()\n>                 ipa_->configurationFile(sensor->model() + \".yaml\", \"uncalibrated.yaml\");\n>  \n>         ret = ipa_->init(IPASettings{ ipaTuningFile, sensor->model() },\n> -                        sensorInfo, sensor->controls(), &ipaControls_);\n> +                        sensorInfo, sensor->controls(), &ipaControls_, &metadataPlan_);\n>         if (ret) {\n>                 LOG(IPU3, Error) << \"Failed to initialise the IPU3 IPA\";\n>                 return ret;\n> diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> index 38bdc6138e..938c5b2890 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>         ControlInfoMap ipaControls;\n>         ret = ipa_->init({ ipaTuningFile, sensor_->model() }, ipaConfig,\n> -                        &ipaControls);\n> +                        &ipaControls, &metadataPlan_);\n>         if (ret) {\n>                 LOG(MaliC55, Error) << \"Failed to initialise the Mali-C55 IPA\";\n>                 return ret;\n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index ecd1383153..002a44f304 100644\n> --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> @@ -406,7 +406,7 @@ int RkISP1CameraData::loadIPA(unsigned int hwRevision, uint32_t supportedBlocks)\n>  \n>         ret = ipa_->init({ ipaTuningFile, sensor_->model() }, hwRevision,\n>                          supportedBlocks, sensorInfo, sensor_->controls(),\n> -                        &ipaControls_);\n> +                        &ipaControls_, &metadataPlan_);\n>         if (ret < 0) {\n>                 LOG(RkISP1, Error) << \"IPA initialization failure\";\n>                 return ret;\n> @@ -1377,6 +1377,8 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)\n>  \n>         updateControls(data.get());\n>  \n> +       data->metadataPlan_.set(controls::SensorTimestamp);\n> +\n>         std::set<Stream *> streams{\n>                 &data->mainPathStream_,\n>                 &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 c209aa5963..87ce290225 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>         data->controlInfo_ = ControlInfoMap(std::move(ctrlMap), result.controlInfo.idmap());\n>  \n> +       /* Update `rpi::ScalerCrops` size for the corrent configuration. */\n> +       data->metadataPlan_.set(controls::rpi::ScalerCrops, config->size());\n> +\n>         /* Setup the Video Mux/Bridge entities. */\n>         for (auto &[device, link] : data->bridgeDevices_) {\n>                 /*\n> @@ -835,6 +838,11 @@ int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &camera\n>         /* Initialize the camera properties. */\n>         data->properties_ = data->sensor_->properties();\n>  \n> +       data->metadataPlan_ = std::move(result.metadataPlan);\n> +       data->metadataPlan_.set(controls::SensorTimestamp);\n> +       data->metadataPlan_.set(controls::FrameWallClock);\n> +       data->metadataPlan_.set(controls::ScalerCrop);\n> +\n>         /*\n>          * The V4L2_CID_NOTIFY_GAINS control, if present, is used to inform the\n>          * 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 91715b7f8a..312f35ad15 100644\n> --- a/src/libcamera/pipeline/simple/simple.cpp\n> +++ b/src/libcamera/pipeline/simple/simple.cpp\n> @@ -602,7 +602,7 @@ int SimpleCameraData::init()\n>          * Instantiate Soft ISP if this is enabled for the given driver and no converter is used.\n>          */\n>         if (!converter_ && pipe->swIspEnabled()) {\n> -               swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get(), &controlInfo_);\n> +               swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get(), &controlInfo_, &metadataPlan_);\n>                 if (!swIsp_->isValid()) {\n>                         LOG(SimplePipeline, Warning)\n>                                 << \"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 4b5816dfdd..59fb4bd5c9 100644\n> --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n> @@ -614,6 +614,8 @@ int UVCCameraData::init(MediaDevice *media)\n>  \n>         controlInfo_ = ControlInfoMap(std::move(ctrls), controls::controls);\n>  \n> +       metadataPlan_.set(controls::SensorTimestamp);\n> +\n>         /*\n>          * Close to allow camera to go into runtime-suspend, video_ will be\n>          * 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 5022101505..1b6880a5dc 100644\n> --- a/src/libcamera/pipeline/vimc/vimc.cpp\n> +++ b/src/libcamera/pipeline/vimc/vimc.cpp\n> @@ -593,6 +593,8 @@ int VimcCameraData::init()\n>  \n>         controlInfo_ = ControlInfoMap(std::move(ctrls), controls::controls);\n>  \n> +       metadataPlan_.set(controls::SensorTimestamp);\n> +\n>         /* Initialize the camera properties. */\n>         properties_ = sensor_->properties();\n>  \n> diff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp\n> index 1d3d9ba87e..608bbd469f 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>                 controls[&controls::draft::FaceDetectMode] = ControlInfo(supportedFaceDetectModes);\n>  \n>                 data->controlInfo_ = ControlInfoMap(std::move(controls), controls::controls);\n> +\n> +               data->metadataPlan_.set(controls::SensorTimestamp);\n> +\n>                 configurations.push_back(std::move(data));\n>         }\n>  \n> diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp\n> index fdadf79e19..30a4b89666 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> -                        ControlInfoMap *ipaControls)\n> +                        ControlInfoMap *ipaControls, MetadataListPlan *metadataPlan)\n>         : dmaHeap_(DmaBufAllocator::DmaBufAllocatorFlag::CmaHeap |\n>                    DmaBufAllocator::DmaBufAllocatorFlag::SystemHeap |\n>                    DmaBufAllocator::DmaBufAllocatorFlag::UDmaBuf)\n> @@ -147,7 +148,8 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor,\n>                          sensorInfo,\n>                          sensor->controls(),\n>                          ipaControls,\n> -                        &ccmEnabled_);\n> +                        &ccmEnabled_,\n> +                        metadataPlan);\n>         if (ret) {\n>                 LOG(SoftwareIsp, Error) << \"IPA init failed\";\n>                 debayer_.reset();\n> -- \n> 2.51.1\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 AA5E9BDE4C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun,  2 Nov 2025 15:50:52 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5536060A80;\n\tSun,  2 Nov 2025 16:50:52 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 40BE8606E6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun,  2 Nov 2025 16:50:50 +0100 (CET)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 0754110D4;\n\tSun,  2 Nov 2025 16:48:58 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"ry1+I8fB\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1762098538;\n\tbh=uKI6uAv12zs+xkaSmRoGi6pFxlQN9d+WipD6/8F3HoA=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=ry1+I8fBdh6PuOZeQo9R5cYc7Hf3aG/H5LlCCXWUD6jT6VdgB8MhP5ovdm/ihisop\n\tLwZ996FjlHg8NXb9d8NDHOQEkRTQBb+TQv3ydLAkcz7xIv2gUGR9iefbXTgH3phMb/\n\tjHoz69y4v0ngdeVDq0huX1WddqYMm7iMC0H2+gW0=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20251030165816.1095180-21-barnabas.pocze@ideasonboard.com>","References":"<20251030165816.1095180-1-barnabas.pocze@ideasonboard.com>\n\t<20251030165816.1095180-21-barnabas.pocze@ideasonboard.com>","Subject":"Re: [RFC PATCH v3 20/22] libcamera: pipeline: Fill\n\t`MetadataListPlan` of cameras","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Paul Elder <paul.elder@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Sun, 02 Nov 2025 15:50:46 +0000","Message-ID":"<176209864677.2973778.17565323710269908500@ping.linuxembedded.co.uk>","User-Agent":"alot/0.9.1","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>"}}]