[{"id":25467,"web_url":"https://patchwork.libcamera.org/comment/25467/","msgid":"<166617936110.2560709.5189091996563787597@Monstersaurus>","date":"2022-10-19T11:36:01","subject":"Re: [libcamera-devel] [PATCH v1 2/4] ipa: Pass metadata to\n\tAlgorithm::process() function","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart via libcamera-devel (2022-10-19 12:04:32)\n> Extend the Algorithm::process() function with a metadata control list,\n> to be filled by individual algorithms with frame metadata. Update the\n> rkisp1 and ipu3 IPA modules accordingly, and drop the dead code in the\n> IPARkISP1::prepareMetadata() function while at it.\n> \n> This only creates the infrastructure, filling metadata in individual\n> algorithms will be handled separately.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  src/ipa/ipu3/algorithms/af.cpp           |  2 ++\n>  src/ipa/ipu3/algorithms/af.h             |  2 +-\n>  src/ipa/ipu3/algorithms/agc.cpp          |  2 ++\n>  src/ipa/ipu3/algorithms/agc.h            |  2 +-\n>  src/ipa/ipu3/algorithms/awb.cpp          |  1 +\n>  src/ipa/ipu3/algorithms/awb.h            |  2 +-\n>  src/ipa/ipu3/algorithms/tone_mapping.cpp |  2 ++\n>  src/ipa/ipu3/algorithms/tone_mapping.h   |  2 +-\n>  src/ipa/ipu3/ipu3.cpp                    |  3 ++-\n>  src/ipa/libipa/algorithm.cpp             |  5 +++--\n>  src/ipa/libipa/algorithm.h               |  1 +\n>  src/ipa/rkisp1/algorithms/agc.cpp        |  4 +++-\n>  src/ipa/rkisp1/algorithms/agc.h          |  2 +-\n>  src/ipa/rkisp1/algorithms/awb.cpp        |  1 +\n>  src/ipa/rkisp1/algorithms/awb.h          |  2 +-\n>  src/ipa/rkisp1/rkisp1.cpp                | 17 +++--------------\n>  16 files changed, 26 insertions(+), 24 deletions(-)\n> \n> diff --git a/src/ipa/ipu3/algorithms/af.cpp b/src/ipa/ipu3/algorithms/af.cpp\n> index 75632aa39d21..2d728871a63b 100644\n> --- a/src/ipa/ipu3/algorithms/af.cpp\n> +++ b/src/ipa/ipu3/algorithms/af.cpp\n> @@ -408,6 +408,7 @@ bool Af::afIsOutOfFocus(IPAContext &context)\n>   * \\param[in] context The IPA context\n>   * \\param[in] frame The frame context sequence number\n>   * \\param[in] frameContext The current frame context\n> + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n>   * \\param[in] stats The statistics buffer of IPU3\n>   *\n>   * Ideally, a clear image also has a relatively higher contrast. So, every\n> @@ -423,6 +424,7 @@ bool Af::afIsOutOfFocus(IPAContext &context)\n>   */\n>  void Af::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>                  [[maybe_unused]] IPAFrameContext &frameContext,\n> +                [[maybe_unused]] ControlList &metadata,\n>                  const ipu3_uapi_stats_3a *stats)\n>  {\n>         /* Evaluate the AF buffer length */\n> diff --git a/src/ipa/ipu3/algorithms/af.h b/src/ipa/ipu3/algorithms/af.h\n> index 89d37ac18615..ea7ca647df12 100644\n> --- a/src/ipa/ipu3/algorithms/af.h\n> +++ b/src/ipa/ipu3/algorithms/af.h\n> @@ -35,7 +35,7 @@ public:\n>                      IPAFrameContext &frameContext,\n>                      ipu3_uapi_params *params) override;\n>         void process(IPAContext &context, const uint32_t frame,\n> -                    IPAFrameContext &frameContext,\n> +                    IPAFrameContext &frameContext, ControlList &metadata,\n>                      const ipu3_uapi_stats_3a *stats) override;\n>  \n>  private:\n> diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\n> index a1a3c38ffe84..44dd5c809e26 100644\n> --- a/src/ipa/ipu3/algorithms/agc.cpp\n> +++ b/src/ipa/ipu3/algorithms/agc.cpp\n> @@ -319,6 +319,7 @@ double Agc::estimateLuminance(IPAActiveState &activeState,\n>   * \\param[in] context The shared IPA context\n>   * \\param[in] frame The current frame sequence number\n>   * \\param[in] frameContext The current frame context\n> + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n>   * \\param[in] stats The IPU3 statistics and ISP results\n>   *\n>   * Identify the current image brightness, and use that to estimate the optimal\n> @@ -326,6 +327,7 @@ double Agc::estimateLuminance(IPAActiveState &activeState,\n>   */\n>  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>                   IPAFrameContext &frameContext,\n> +                 [[maybe_unused]] ControlList &metadata,\n>                   const ipu3_uapi_stats_3a *stats)\n>  {\n>         /*\n> diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h\n> index 59b4b9843c2f..9106cbefe87a 100644\n> --- a/src/ipa/ipu3/algorithms/agc.h\n> +++ b/src/ipa/ipu3/algorithms/agc.h\n> @@ -29,7 +29,7 @@ public:\n>  \n>         int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n>         void process(IPAContext &context, const uint32_t frame,\n> -                    IPAFrameContext &frameContext,\n> +                    IPAFrameContext &frameContext, ControlList &metadata,\n>                      const ipu3_uapi_stats_3a *stats) override;\n>  \n>  private:\n> diff --git a/src/ipa/ipu3/algorithms/awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp\n> index 0dbd7d4c374f..836eb0687181 100644\n> --- a/src/ipa/ipu3/algorithms/awb.cpp\n> +++ b/src/ipa/ipu3/algorithms/awb.cpp\n> @@ -389,6 +389,7 @@ void Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)\n>   */\n>  void Awb::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>                   [[maybe_unused]] IPAFrameContext &frameContext,\n> +                 [[maybe_unused]] ControlList &metadata,\n>                   const ipu3_uapi_stats_3a *stats)\n>  {\n>         calculateWBGains(stats);\n> diff --git a/src/ipa/ipu3/algorithms/awb.h b/src/ipa/ipu3/algorithms/awb.h\n> index 28e2d38a711c..c38c425c3654 100644\n> --- a/src/ipa/ipu3/algorithms/awb.h\n> +++ b/src/ipa/ipu3/algorithms/awb.h\n> @@ -43,7 +43,7 @@ public:\n>                      IPAFrameContext &frameContext,\n>                      ipu3_uapi_params *params) override;\n>         void process(IPAContext &context, const uint32_t frame,\n> -                    IPAFrameContext &frameContext,\n> +                    IPAFrameContext &frameContext, ControlList &metadata,\n>                      const ipu3_uapi_stats_3a *stats) override;\n>  \n>  private:\n> diff --git a/src/ipa/ipu3/algorithms/tone_mapping.cpp b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> index eac3d4064443..6fcc03f3fcf7 100644\n> --- a/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> +++ b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> @@ -78,6 +78,7 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n>   * \\param[in] context The shared IPA context\n>   * \\param[in] frame The current frame sequence number\n>   * \\param[in] frameContext The current frame context\n> + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n>   * \\param[in] stats The IPU3 statistics and ISP results\n>   *\n>   * The tone mapping look up table is generated as an inverse power curve from\n> @@ -85,6 +86,7 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n>   */\n>  void ToneMapping::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>                           [[maybe_unused]] IPAFrameContext &frameContext,\n> +                         [[maybe_unused]] ControlList &metadata,\n>                           [[maybe_unused]] const ipu3_uapi_stats_3a *stats)\n>  {\n>         /*\n> diff --git a/src/ipa/ipu3/algorithms/tone_mapping.h b/src/ipa/ipu3/algorithms/tone_mapping.h\n> index 822e5168df82..ab2a1c000f2f 100644\n> --- a/src/ipa/ipu3/algorithms/tone_mapping.h\n> +++ b/src/ipa/ipu3/algorithms/tone_mapping.h\n> @@ -22,7 +22,7 @@ public:\n>         void prepare(IPAContext &context, const uint32_t frame,\n>                      IPAFrameContext &frameContext, ipu3_uapi_params *params) override;\n>         void process(IPAContext &context, const uint32_t frame,\n> -                    IPAFrameContext &frameContext,\n> +                    IPAFrameContext &frameContext, ControlList &metadata,\n>                      const ipu3_uapi_stats_3a *stats) override;\n>  \n>  private:\n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> index 891643e057b8..0ccc6bf5c8af 100644\n> --- a/src/ipa/ipu3/ipu3.cpp\n> +++ b/src/ipa/ipu3/ipu3.cpp\n> @@ -631,9 +631,10 @@ void IPAIPU3::processStatsBuffer(const uint32_t frame,\n>         double lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();\n>         int32_t vBlank = context_.configuration.sensor.defVBlank;\n>         ControlList ctrls(controls::controls);\n\nIt looks like ctrls() is what is currently used as metadata here.\n\nIt gets emitted at the end of this function.\nCan we either use ctrls passed in to algo->process() or (preferred)\nrename ctrls to metadata here to ensure that /when/ we set metadata in\nthe algorithms it will reach the pipeline handler?\n\nProbably keep the existing metadata additions in this function still -\nconverting them can be later, but otherwise this is a partial\nimplementation for IPU3.\n\n*with that* \n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> +       ControlList metadata(controls::controls);\n>  \n>         for (auto const &algo : algorithms())\n> -               algo->process(context_, frame, frameContext, stats);\n> +               algo->process(context_, frame, frameContext, metadata, stats);\n\nI would have had metadata as the last parameter as an 'output'\n(inputs, outputs) ... but I bet you've gone alphabetical.\n\nNo point changing it though - that's too much work, and this is fine.\n\n  \n>         setControls(frame);\n>  \n> diff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp\n> index 55abddab2b0a..a34c583d947e 100644\n> --- a/src/ipa/libipa/algorithm.cpp\n> +++ b/src/ipa/libipa/algorithm.cpp\n> @@ -106,12 +106,13 @@ namespace ipa {\n>   * \\param[in] context The shared IPA context\n>   * \\param[in] frame The frame context sequence number\n>   * \\param[in] frameContext The current frame's context\n> + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n>   * \\param[in] stats The IPA statistics and ISP results\n>   *\n>   * This function is called while camera is running for every frame processed by\n>   * the ISP, to process statistics generated from that frame by the ISP.\n> - * Algorithms shall use this data to run calculations and update their state\n> - * accordingly.\n> + * Algorithms shall use this data to run calculations, update their state\n> + * accordingly, and fill the frame metadata.\n>   *\n>   * Processing shall not take an undue amount of time, and any extended or\n>   * computationally expensive calculations or operations must be handled\n> diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h\n> index d8601f9ccaff..793247be8129 100644\n> --- a/src/ipa/libipa/algorithm.h\n> +++ b/src/ipa/libipa/algorithm.h\n> @@ -55,6 +55,7 @@ public:\n>         virtual void process([[maybe_unused]] typename Module::Context &context,\n>                              [[maybe_unused]] const uint32_t frame,\n>                              [[maybe_unused]] typename Module::FrameContext &frameContext,\n> +                            [[maybe_unused]] ControlList &metadata,\n>                              [[maybe_unused]] const typename Module::Stats *stats)\n>         {\n>         }\n> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> index 04062a364e7f..9de11a2a3bca 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/agc.cpp\n> @@ -288,7 +288,9 @@ double Agc::measureBrightness(const rkisp1_cif_isp_hist_stat *hist) const\n>   * new exposure and gain for the scene.\n>   */\n>  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> -                 IPAFrameContext &frameContext, const rkisp1_stat_buffer *stats)\n> +                 IPAFrameContext &frameContext,\n> +                 [[maybe_unused]] ControlList &metadata,\n> +                 const rkisp1_stat_buffer *stats)\n>  {\n>         /*\n>          * \\todo Verify that the exposure and gain applied by the sensor for\n> diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\n> index 9ad5c32fd6f6..99af09167331 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.h\n> +++ b/src/ipa/rkisp1/algorithms/agc.h\n> @@ -30,7 +30,7 @@ public:\n>                      IPAFrameContext &frameContext,\n>                      rkisp1_params_cfg *params) override;\n>         void process(IPAContext &context, const uint32_t frame,\n> -                    IPAFrameContext &frameContext,\n> +                    IPAFrameContext &frameContext, ControlList &metadata,\n>                      const rkisp1_stat_buffer *stats) override;\n>  \n>  private:\n> diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\n> index 3349948a3acf..9b97db7d5c5a 100644\n> --- a/src/ipa/rkisp1/algorithms/awb.cpp\n> +++ b/src/ipa/rkisp1/algorithms/awb.cpp\n> @@ -208,6 +208,7 @@ void Awb::queueRequest(IPAContext &context,\n>  void Awb::process(IPAContext &context,\n>                   [[maybe_unused]] const uint32_t frame,\n>                   IPAFrameContext &frameContext,\n> +                 [[maybe_unused]] ControlList &metadata,\n>                   const rkisp1_stat_buffer *stats)\n>  {\n>         const rkisp1_cif_isp_stat *params = &stats->params;\n> diff --git a/src/ipa/rkisp1/algorithms/awb.h b/src/ipa/rkisp1/algorithms/awb.h\n> index d76b538288ec..3659b2d5405f 100644\n> --- a/src/ipa/rkisp1/algorithms/awb.h\n> +++ b/src/ipa/rkisp1/algorithms/awb.h\n> @@ -27,7 +27,7 @@ public:\n>                           IPAFrameContext &frameContext,\n>                           const ControlList &controls) override;\n>         void process(IPAContext &context, const uint32_t frame,\n> -                    IPAFrameContext &frameCtx,\n> +                    IPAFrameContext &frameContext, ControlList &metadata,\n>                      const rkisp1_stat_buffer *stats) override;\n>  \n>  private:\n> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> index 3f5c1a58695c..bef5211d5c34 100644\n> --- a/src/ipa/rkisp1/rkisp1.cpp\n> +++ b/src/ipa/rkisp1/rkisp1.cpp\n> @@ -69,7 +69,6 @@ protected:\n>  \n>  private:\n>         void setControls(unsigned int frame);\n> -       void prepareMetadata(unsigned int frame, unsigned int aeState);\n>  \n>         std::map<unsigned int, FrameBuffer> buffers_;\n>         std::map<unsigned int, MappedFrameBuffer> mappedBuffers_;\n> @@ -338,14 +337,14 @@ void IPARkISP1::processStatsBuffer(const uint32_t frame, const uint32_t bufferId\n>         frameContext.sensor.gain =\n>                 camHelper_->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());\n>  \n> -       unsigned int aeState = 0;\n> +       ControlList metadata(controls::controls);\n>  \n>         for (auto const &algo : algorithms())\n> -               algo->process(context_, frame, frameContext, stats);\n> +               algo->process(context_, frame, frameContext, metadata, stats);\n>  \n>         setControls(frame);\n>  \n> -       prepareMetadata(frame, aeState);\n> +       metadataReady.emit(frame, metadata);\n\nThat ties in much better.\n\n>  }\n>  \n>  void IPARkISP1::setControls(unsigned int frame)\n> @@ -366,16 +365,6 @@ void IPARkISP1::setControls(unsigned int frame)\n>         setSensorControls.emit(frame, ctrls);\n>  }\n>  \n> -void IPARkISP1::prepareMetadata(unsigned int frame, unsigned int aeState)\n> -{\n> -       ControlList ctrls(controls::controls);\n> -\n> -       if (aeState)\n> -               ctrls.set(controls::AeLocked, aeState == 2);\n\nPhew, that's good to see it all go.\n\n> -\n> -       metadataReady.emit(frame, ctrls);\n> -}\n> -\n>  } /* namespace ipa::rkisp1 */\n>  \n>  /*\n> -- \n> Regards,\n> \n> Laurent Pinchart\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 A7C92BD16B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Oct 2022 11:36:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DF13762E52;\n\tWed, 19 Oct 2022 13:36:05 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 75E7E62DFA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Oct 2022 13:36:04 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E2EAF5A4;\n\tWed, 19 Oct 2022 13:36:03 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1666179365;\n\tbh=tN6tXMS674zewwEBtOfBY/vOdUomH3peA+M5/xDYFYI=;\n\th=In-Reply-To:References:To:Date:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=A+7HzrdnDxAHr9/DAoH3SidY+DKt2BiD814HeysmxrNy4KWipqQ66ZZ4z5U3IuiGP\n\tWs3GbqtP6bfGq+pXylaFoK6HTGOZ64Knp2gVdnvrX/T7UVR9IXaueo77woTn1t6Awd\n\thRHf69HtJ+2Y9z4brImRZo1H64xxm50tuJoguYI72A4oPNq9jTTVsgM1QPHxCAV9L8\n\tC8nlpmMjPFv6CaGxVO2wNSjYVuaOBNYTKISJDAEQG2uVmGdp5t8f/906P7Q5XKTQmL\n\tTAe15MUG9Rw/0LSEovmSWmfNzSVI9YWXJlQ23YQWJ/XIgpfOFOFoJ28USscoIMtZ/H\n\tLMGyDsrTeRtnQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1666179364;\n\tbh=tN6tXMS674zewwEBtOfBY/vOdUomH3peA+M5/xDYFYI=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=mLdCNdmjI/hepFXOrqQ8hib7tkOtJkvWRUWz7XoalGxWmaoIZWAbpFgXm1joa0xI/\n\tfwigQwlPQ9TFqBNkzgJxOTUOyHrJE13dhwv32ksIunQg/O5H8EGqIUbRDnwf9a/129\n\t4/JrtNO2NnhWGfWWzRfTOFcP2iaVP5qQu4+2Q7n0="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"mLdCNdmj\"; dkim-atps=neutral","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20221019110434.17767-3-laurent.pinchart@ideasonboard.com>","References":"<20221019110434.17767-1-laurent.pinchart@ideasonboard.com>\n\t<20221019110434.17767-3-laurent.pinchart@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Wed, 19 Oct 2022 12:36:01 +0100","Message-ID":"<166617936110.2560709.5189091996563787597@Monstersaurus>","User-Agent":"alot/0.10","Subject":"Re: [libcamera-devel] [PATCH v1 2/4] ipa: Pass metadata to\n\tAlgorithm::process() function","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>","From":"Kieran Bingham via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":25471,"web_url":"https://patchwork.libcamera.org/comment/25471/","msgid":"<20221019114912.klejuewk3l4djimk@uno.localdomain>","date":"2022-10-19T11:49:12","subject":"Re: [libcamera-devel] [PATCH v1 2/4] ipa: Pass metadata to\n\tAlgorithm::process() function","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent\n\nOn Wed, Oct 19, 2022 at 02:04:32PM +0300, Laurent Pinchart via libcamera-devel wrote:\n> Extend the Algorithm::process() function with a metadata control list,\n> to be filled by individual algorithms with frame metadata. Update the\n> rkisp1 and ipu3 IPA modules accordingly, and drop the dead code in the\n> IPARkISP1::prepareMetadata() function while at it.\n>\n> This only creates the infrastructure, filling metadata in individual\n> algorithms will be handled separately.\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nDo we want metadata to be passed in as argument, or do we want\nmetadata to be part of the frame context ?\n\nAlso, a reference is nice, but we usually use pointers for modifiable\narguments. Just pointing out for sake of consistency (I'm not even\nsure we actually enforce that anymore), I'm fine with a reference\ntoo..\n\n> ---\n>  src/ipa/ipu3/algorithms/af.cpp           |  2 ++\n>  src/ipa/ipu3/algorithms/af.h             |  2 +-\n>  src/ipa/ipu3/algorithms/agc.cpp          |  2 ++\n>  src/ipa/ipu3/algorithms/agc.h            |  2 +-\n>  src/ipa/ipu3/algorithms/awb.cpp          |  1 +\n>  src/ipa/ipu3/algorithms/awb.h            |  2 +-\n>  src/ipa/ipu3/algorithms/tone_mapping.cpp |  2 ++\n>  src/ipa/ipu3/algorithms/tone_mapping.h   |  2 +-\n>  src/ipa/ipu3/ipu3.cpp                    |  3 ++-\n>  src/ipa/libipa/algorithm.cpp             |  5 +++--\n>  src/ipa/libipa/algorithm.h               |  1 +\n>  src/ipa/rkisp1/algorithms/agc.cpp        |  4 +++-\n>  src/ipa/rkisp1/algorithms/agc.h          |  2 +-\n>  src/ipa/rkisp1/algorithms/awb.cpp        |  1 +\n>  src/ipa/rkisp1/algorithms/awb.h          |  2 +-\n>  src/ipa/rkisp1/rkisp1.cpp                | 17 +++--------------\n>  16 files changed, 26 insertions(+), 24 deletions(-)\n>\n> diff --git a/src/ipa/ipu3/algorithms/af.cpp b/src/ipa/ipu3/algorithms/af.cpp\n> index 75632aa39d21..2d728871a63b 100644\n> --- a/src/ipa/ipu3/algorithms/af.cpp\n> +++ b/src/ipa/ipu3/algorithms/af.cpp\n> @@ -408,6 +408,7 @@ bool Af::afIsOutOfFocus(IPAContext &context)\n>   * \\param[in] context The IPA context\n>   * \\param[in] frame The frame context sequence number\n>   * \\param[in] frameContext The current frame context\n> + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n>   * \\param[in] stats The statistics buffer of IPU3\n>   *\n>   * Ideally, a clear image also has a relatively higher contrast. So, every\n> @@ -423,6 +424,7 @@ bool Af::afIsOutOfFocus(IPAContext &context)\n>   */\n>  void Af::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>  \t\t [[maybe_unused]] IPAFrameContext &frameContext,\n> +\t\t [[maybe_unused]] ControlList &metadata,\n>  \t\t const ipu3_uapi_stats_3a *stats)\n>  {\n>  \t/* Evaluate the AF buffer length */\n> diff --git a/src/ipa/ipu3/algorithms/af.h b/src/ipa/ipu3/algorithms/af.h\n> index 89d37ac18615..ea7ca647df12 100644\n> --- a/src/ipa/ipu3/algorithms/af.h\n> +++ b/src/ipa/ipu3/algorithms/af.h\n> @@ -35,7 +35,7 @@ public:\n>  \t\t     IPAFrameContext &frameContext,\n>  \t\t     ipu3_uapi_params *params) override;\n>  \tvoid process(IPAContext &context, const uint32_t frame,\n> -\t\t     IPAFrameContext &frameContext,\n> +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n>  \t\t     const ipu3_uapi_stats_3a *stats) override;\n>\n>  private:\n> diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\n> index a1a3c38ffe84..44dd5c809e26 100644\n> --- a/src/ipa/ipu3/algorithms/agc.cpp\n> +++ b/src/ipa/ipu3/algorithms/agc.cpp\n> @@ -319,6 +319,7 @@ double Agc::estimateLuminance(IPAActiveState &activeState,\n>   * \\param[in] context The shared IPA context\n>   * \\param[in] frame The current frame sequence number\n>   * \\param[in] frameContext The current frame context\n> + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n>   * \\param[in] stats The IPU3 statistics and ISP results\n>   *\n>   * Identify the current image brightness, and use that to estimate the optimal\n> @@ -326,6 +327,7 @@ double Agc::estimateLuminance(IPAActiveState &activeState,\n>   */\n>  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>  \t\t  IPAFrameContext &frameContext,\n> +\t\t  [[maybe_unused]] ControlList &metadata,\n>  \t\t  const ipu3_uapi_stats_3a *stats)\n>  {\n>  \t/*\n> diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h\n> index 59b4b9843c2f..9106cbefe87a 100644\n> --- a/src/ipa/ipu3/algorithms/agc.h\n> +++ b/src/ipa/ipu3/algorithms/agc.h\n> @@ -29,7 +29,7 @@ public:\n>\n>  \tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n>  \tvoid process(IPAContext &context, const uint32_t frame,\n> -\t\t     IPAFrameContext &frameContext,\n> +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n>  \t\t     const ipu3_uapi_stats_3a *stats) override;\n>\n>  private:\n> diff --git a/src/ipa/ipu3/algorithms/awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp\n> index 0dbd7d4c374f..836eb0687181 100644\n> --- a/src/ipa/ipu3/algorithms/awb.cpp\n> +++ b/src/ipa/ipu3/algorithms/awb.cpp\n> @@ -389,6 +389,7 @@ void Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)\n>   */\n>  void Awb::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>  \t\t  [[maybe_unused]] IPAFrameContext &frameContext,\n> +\t\t  [[maybe_unused]] ControlList &metadata,\n>  \t\t  const ipu3_uapi_stats_3a *stats)\n>  {\n>  \tcalculateWBGains(stats);\n> diff --git a/src/ipa/ipu3/algorithms/awb.h b/src/ipa/ipu3/algorithms/awb.h\n> index 28e2d38a711c..c38c425c3654 100644\n> --- a/src/ipa/ipu3/algorithms/awb.h\n> +++ b/src/ipa/ipu3/algorithms/awb.h\n> @@ -43,7 +43,7 @@ public:\n>  \t\t     IPAFrameContext &frameContext,\n>  \t\t     ipu3_uapi_params *params) override;\n>  \tvoid process(IPAContext &context, const uint32_t frame,\n> -\t\t     IPAFrameContext &frameContext,\n> +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n>  \t\t     const ipu3_uapi_stats_3a *stats) override;\n>\n>  private:\n> diff --git a/src/ipa/ipu3/algorithms/tone_mapping.cpp b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> index eac3d4064443..6fcc03f3fcf7 100644\n> --- a/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> +++ b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> @@ -78,6 +78,7 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n>   * \\param[in] context The shared IPA context\n>   * \\param[in] frame The current frame sequence number\n>   * \\param[in] frameContext The current frame context\n> + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n>   * \\param[in] stats The IPU3 statistics and ISP results\n>   *\n>   * The tone mapping look up table is generated as an inverse power curve from\n> @@ -85,6 +86,7 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n>   */\n>  void ToneMapping::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n>  \t\t\t  [[maybe_unused]] IPAFrameContext &frameContext,\n> +\t\t\t  [[maybe_unused]] ControlList &metadata,\n>  \t\t\t  [[maybe_unused]] const ipu3_uapi_stats_3a *stats)\n>  {\n>  \t/*\n> diff --git a/src/ipa/ipu3/algorithms/tone_mapping.h b/src/ipa/ipu3/algorithms/tone_mapping.h\n> index 822e5168df82..ab2a1c000f2f 100644\n> --- a/src/ipa/ipu3/algorithms/tone_mapping.h\n> +++ b/src/ipa/ipu3/algorithms/tone_mapping.h\n> @@ -22,7 +22,7 @@ public:\n>  \tvoid prepare(IPAContext &context, const uint32_t frame,\n>  \t\t     IPAFrameContext &frameContext, ipu3_uapi_params *params) override;\n>  \tvoid process(IPAContext &context, const uint32_t frame,\n> -\t\t     IPAFrameContext &frameContext,\n> +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n>  \t\t     const ipu3_uapi_stats_3a *stats) override;\n>\n>  private:\n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> index 891643e057b8..0ccc6bf5c8af 100644\n> --- a/src/ipa/ipu3/ipu3.cpp\n> +++ b/src/ipa/ipu3/ipu3.cpp\n> @@ -631,9 +631,10 @@ void IPAIPU3::processStatsBuffer(const uint32_t frame,\n>  \tdouble lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();\n>  \tint32_t vBlank = context_.configuration.sensor.defVBlank;\n>  \tControlList ctrls(controls::controls);\n> +\tControlList metadata(controls::controls);\n>\n>  \tfor (auto const &algo : algorithms())\n> -\t\talgo->process(context_, frame, frameContext, stats);\n> +\t\talgo->process(context_, frame, frameContext, metadata, stats);\n>\n>  \tsetControls(frame);\n>\n> diff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp\n> index 55abddab2b0a..a34c583d947e 100644\n> --- a/src/ipa/libipa/algorithm.cpp\n> +++ b/src/ipa/libipa/algorithm.cpp\n> @@ -106,12 +106,13 @@ namespace ipa {\n>   * \\param[in] context The shared IPA context\n>   * \\param[in] frame The frame context sequence number\n>   * \\param[in] frameContext The current frame's context\n> + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n>   * \\param[in] stats The IPA statistics and ISP results\n>   *\n>   * This function is called while camera is running for every frame processed by\n>   * the ISP, to process statistics generated from that frame by the ISP.\n> - * Algorithms shall use this data to run calculations and update their state\n> - * accordingly.\n> + * Algorithms shall use this data to run calculations, update their state\n> + * accordingly, and fill the frame metadata.\n>   *\n>   * Processing shall not take an undue amount of time, and any extended or\n>   * computationally expensive calculations or operations must be handled\n> diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h\n> index d8601f9ccaff..793247be8129 100644\n> --- a/src/ipa/libipa/algorithm.h\n> +++ b/src/ipa/libipa/algorithm.h\n> @@ -55,6 +55,7 @@ public:\n>  \tvirtual void process([[maybe_unused]] typename Module::Context &context,\n>  \t\t\t     [[maybe_unused]] const uint32_t frame,\n>  \t\t\t     [[maybe_unused]] typename Module::FrameContext &frameContext,\n> +\t\t\t     [[maybe_unused]] ControlList &metadata,\n>  \t\t\t     [[maybe_unused]] const typename Module::Stats *stats)\n>  \t{\n>  \t}\n> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> index 04062a364e7f..9de11a2a3bca 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/agc.cpp\n> @@ -288,7 +288,9 @@ double Agc::measureBrightness(const rkisp1_cif_isp_hist_stat *hist) const\n>   * new exposure and gain for the scene.\n>   */\n>  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> -\t\t  IPAFrameContext &frameContext, const rkisp1_stat_buffer *stats)\n> +\t\t  IPAFrameContext &frameContext,\n> +\t\t  [[maybe_unused]] ControlList &metadata,\n> +\t\t  const rkisp1_stat_buffer *stats)\n>  {\n>  \t/*\n>  \t * \\todo Verify that the exposure and gain applied by the sensor for\n> diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\n> index 9ad5c32fd6f6..99af09167331 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.h\n> +++ b/src/ipa/rkisp1/algorithms/agc.h\n> @@ -30,7 +30,7 @@ public:\n>  \t\t     IPAFrameContext &frameContext,\n>  \t\t     rkisp1_params_cfg *params) override;\n>  \tvoid process(IPAContext &context, const uint32_t frame,\n> -\t\t     IPAFrameContext &frameContext,\n> +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n>  \t\t     const rkisp1_stat_buffer *stats) override;\n>\n>  private:\n> diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\n> index 3349948a3acf..9b97db7d5c5a 100644\n> --- a/src/ipa/rkisp1/algorithms/awb.cpp\n> +++ b/src/ipa/rkisp1/algorithms/awb.cpp\n> @@ -208,6 +208,7 @@ void Awb::queueRequest(IPAContext &context,\n>  void Awb::process(IPAContext &context,\n>  \t\t  [[maybe_unused]] const uint32_t frame,\n>  \t\t  IPAFrameContext &frameContext,\n> +\t\t  [[maybe_unused]] ControlList &metadata,\n>  \t\t  const rkisp1_stat_buffer *stats)\n>  {\n>  \tconst rkisp1_cif_isp_stat *params = &stats->params;\n> diff --git a/src/ipa/rkisp1/algorithms/awb.h b/src/ipa/rkisp1/algorithms/awb.h\n> index d76b538288ec..3659b2d5405f 100644\n> --- a/src/ipa/rkisp1/algorithms/awb.h\n> +++ b/src/ipa/rkisp1/algorithms/awb.h\n> @@ -27,7 +27,7 @@ public:\n>  \t\t\t  IPAFrameContext &frameContext,\n>  \t\t\t  const ControlList &controls) override;\n>  \tvoid process(IPAContext &context, const uint32_t frame,\n> -\t\t     IPAFrameContext &frameCtx,\n> +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n>  \t\t     const rkisp1_stat_buffer *stats) override;\n>\n>  private:\n> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> index 3f5c1a58695c..bef5211d5c34 100644\n> --- a/src/ipa/rkisp1/rkisp1.cpp\n> +++ b/src/ipa/rkisp1/rkisp1.cpp\n> @@ -69,7 +69,6 @@ protected:\n>\n>  private:\n>  \tvoid setControls(unsigned int frame);\n> -\tvoid prepareMetadata(unsigned int frame, unsigned int aeState);\n>\n>  \tstd::map<unsigned int, FrameBuffer> buffers_;\n>  \tstd::map<unsigned int, MappedFrameBuffer> mappedBuffers_;\n> @@ -338,14 +337,14 @@ void IPARkISP1::processStatsBuffer(const uint32_t frame, const uint32_t bufferId\n>  \tframeContext.sensor.gain =\n>  \t\tcamHelper_->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());\n>\n> -\tunsigned int aeState = 0;\n> +\tControlList metadata(controls::controls);\n>\n>  \tfor (auto const &algo : algorithms())\n> -\t\talgo->process(context_, frame, frameContext, stats);\n> +\t\talgo->process(context_, frame, frameContext, metadata, stats);\n>\n>  \tsetControls(frame);\n>\n> -\tprepareMetadata(frame, aeState);\n> +\tmetadataReady.emit(frame, metadata);\n>  }\n>\n>  void IPARkISP1::setControls(unsigned int frame)\n> @@ -366,16 +365,6 @@ void IPARkISP1::setControls(unsigned int frame)\n>  \tsetSensorControls.emit(frame, ctrls);\n>  }\n>\n> -void IPARkISP1::prepareMetadata(unsigned int frame, unsigned int aeState)\n> -{\n> -\tControlList ctrls(controls::controls);\n> -\n> -\tif (aeState)\n> -\t\tctrls.set(controls::AeLocked, aeState == 2);\n> -\n> -\tmetadataReady.emit(frame, ctrls);\n> -}\n> -\n>  } /* namespace ipa::rkisp1 */\n>\n>  /*\n> --\n> Regards,\n>\n> Laurent Pinchart\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 74FBCC0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Oct 2022 11:49:17 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D4C1662E59;\n\tWed, 19 Oct 2022 13:49:16 +0200 (CEST)","from relay11.mail.gandi.net (relay11.mail.gandi.net\n\t[217.70.178.231])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 00D8D62DFA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Oct 2022 13:49:14 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id 3CC00100011;\n\tWed, 19 Oct 2022 11:49:13 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1666180156;\n\tbh=YeeAfS0Zm9BSy2do2kdCkPAFPdnxLzPLYIWaZL5Jkfc=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=r70s/JekgWbikLPMrlp5oa0cHIFCV3g8Eu7atJok/eTkm3EgnqIv6l6ZnbIcXXNKZ\n\tDhBYmkwUSjN0w//rQAvXBs8O5q+sppzU5D6PYd6TG0gT9zCiEajI4mFYVQQPlYXCYz\n\t+lEPWgSE1B+L5Cx5dAggpUCCtHRwsPx4/f1KqcdqVkp1aqXmhatnZIUShv2RGerWqP\n\tU+deW9aI9ogEY4Slzquf4zvtO4nwDTI+n3+aVh+FayoIOoxZyBUCFsvnyIR5mBGdsm\n\tUPR53YLT06Tu0a8hGmOi56gshdrL1urjUmNql9VSUdaB8mtWh09loFOXKP0Tj+Om9c\n\tDmvOKEk9saQhw==","Date":"Wed, 19 Oct 2022 13:49:12 +0200","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20221019114912.klejuewk3l4djimk@uno.localdomain>","References":"<20221019110434.17767-1-laurent.pinchart@ideasonboard.com>\n\t<20221019110434.17767-3-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20221019110434.17767-3-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v1 2/4] ipa: Pass metadata to\n\tAlgorithm::process() function","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>","From":"Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":25479,"web_url":"https://patchwork.libcamera.org/comment/25479/","msgid":"<Y1BEHODMgD/Atcib@pendragon.ideasonboard.com>","date":"2022-10-19T18:38:20","subject":"Re: [libcamera-devel] [PATCH v1 2/4] ipa: Pass metadata to\n\tAlgorithm::process() function","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Wed, Oct 19, 2022 at 12:36:01PM +0100, Kieran Bingham wrote:\n> Quoting Laurent Pinchart via libcamera-devel (2022-10-19 12:04:32)\n> > Extend the Algorithm::process() function with a metadata control list,\n> > to be filled by individual algorithms with frame metadata. Update the\n> > rkisp1 and ipu3 IPA modules accordingly, and drop the dead code in the\n> > IPARkISP1::prepareMetadata() function while at it.\n> > \n> > This only creates the infrastructure, filling metadata in individual\n> > algorithms will be handled separately.\n> > \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  src/ipa/ipu3/algorithms/af.cpp           |  2 ++\n> >  src/ipa/ipu3/algorithms/af.h             |  2 +-\n> >  src/ipa/ipu3/algorithms/agc.cpp          |  2 ++\n> >  src/ipa/ipu3/algorithms/agc.h            |  2 +-\n> >  src/ipa/ipu3/algorithms/awb.cpp          |  1 +\n> >  src/ipa/ipu3/algorithms/awb.h            |  2 +-\n> >  src/ipa/ipu3/algorithms/tone_mapping.cpp |  2 ++\n> >  src/ipa/ipu3/algorithms/tone_mapping.h   |  2 +-\n> >  src/ipa/ipu3/ipu3.cpp                    |  3 ++-\n> >  src/ipa/libipa/algorithm.cpp             |  5 +++--\n> >  src/ipa/libipa/algorithm.h               |  1 +\n> >  src/ipa/rkisp1/algorithms/agc.cpp        |  4 +++-\n> >  src/ipa/rkisp1/algorithms/agc.h          |  2 +-\n> >  src/ipa/rkisp1/algorithms/awb.cpp        |  1 +\n> >  src/ipa/rkisp1/algorithms/awb.h          |  2 +-\n> >  src/ipa/rkisp1/rkisp1.cpp                | 17 +++--------------\n> >  16 files changed, 26 insertions(+), 24 deletions(-)\n> > \n> > diff --git a/src/ipa/ipu3/algorithms/af.cpp b/src/ipa/ipu3/algorithms/af.cpp\n> > index 75632aa39d21..2d728871a63b 100644\n> > --- a/src/ipa/ipu3/algorithms/af.cpp\n> > +++ b/src/ipa/ipu3/algorithms/af.cpp\n> > @@ -408,6 +408,7 @@ bool Af::afIsOutOfFocus(IPAContext &context)\n> >   * \\param[in] context The IPA context\n> >   * \\param[in] frame The frame context sequence number\n> >   * \\param[in] frameContext The current frame context\n> > + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n> >   * \\param[in] stats The statistics buffer of IPU3\n> >   *\n> >   * Ideally, a clear image also has a relatively higher contrast. So, every\n> > @@ -423,6 +424,7 @@ bool Af::afIsOutOfFocus(IPAContext &context)\n> >   */\n> >  void Af::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> >                  [[maybe_unused]] IPAFrameContext &frameContext,\n> > +                [[maybe_unused]] ControlList &metadata,\n> >                  const ipu3_uapi_stats_3a *stats)\n> >  {\n> >         /* Evaluate the AF buffer length */\n> > diff --git a/src/ipa/ipu3/algorithms/af.h b/src/ipa/ipu3/algorithms/af.h\n> > index 89d37ac18615..ea7ca647df12 100644\n> > --- a/src/ipa/ipu3/algorithms/af.h\n> > +++ b/src/ipa/ipu3/algorithms/af.h\n> > @@ -35,7 +35,7 @@ public:\n> >                      IPAFrameContext &frameContext,\n> >                      ipu3_uapi_params *params) override;\n> >         void process(IPAContext &context, const uint32_t frame,\n> > -                    IPAFrameContext &frameContext,\n> > +                    IPAFrameContext &frameContext, ControlList &metadata,\n> >                      const ipu3_uapi_stats_3a *stats) override;\n> >  \n> >  private:\n> > diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\n> > index a1a3c38ffe84..44dd5c809e26 100644\n> > --- a/src/ipa/ipu3/algorithms/agc.cpp\n> > +++ b/src/ipa/ipu3/algorithms/agc.cpp\n> > @@ -319,6 +319,7 @@ double Agc::estimateLuminance(IPAActiveState &activeState,\n> >   * \\param[in] context The shared IPA context\n> >   * \\param[in] frame The current frame sequence number\n> >   * \\param[in] frameContext The current frame context\n> > + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n> >   * \\param[in] stats The IPU3 statistics and ISP results\n> >   *\n> >   * Identify the current image brightness, and use that to estimate the optimal\n> > @@ -326,6 +327,7 @@ double Agc::estimateLuminance(IPAActiveState &activeState,\n> >   */\n> >  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> >                   IPAFrameContext &frameContext,\n> > +                 [[maybe_unused]] ControlList &metadata,\n> >                   const ipu3_uapi_stats_3a *stats)\n> >  {\n> >         /*\n> > diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h\n> > index 59b4b9843c2f..9106cbefe87a 100644\n> > --- a/src/ipa/ipu3/algorithms/agc.h\n> > +++ b/src/ipa/ipu3/algorithms/agc.h\n> > @@ -29,7 +29,7 @@ public:\n> >  \n> >         int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n> >         void process(IPAContext &context, const uint32_t frame,\n> > -                    IPAFrameContext &frameContext,\n> > +                    IPAFrameContext &frameContext, ControlList &metadata,\n> >                      const ipu3_uapi_stats_3a *stats) override;\n> >  \n> >  private:\n> > diff --git a/src/ipa/ipu3/algorithms/awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp\n> > index 0dbd7d4c374f..836eb0687181 100644\n> > --- a/src/ipa/ipu3/algorithms/awb.cpp\n> > +++ b/src/ipa/ipu3/algorithms/awb.cpp\n> > @@ -389,6 +389,7 @@ void Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)\n> >   */\n> >  void Awb::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> >                   [[maybe_unused]] IPAFrameContext &frameContext,\n> > +                 [[maybe_unused]] ControlList &metadata,\n> >                   const ipu3_uapi_stats_3a *stats)\n> >  {\n> >         calculateWBGains(stats);\n> > diff --git a/src/ipa/ipu3/algorithms/awb.h b/src/ipa/ipu3/algorithms/awb.h\n> > index 28e2d38a711c..c38c425c3654 100644\n> > --- a/src/ipa/ipu3/algorithms/awb.h\n> > +++ b/src/ipa/ipu3/algorithms/awb.h\n> > @@ -43,7 +43,7 @@ public:\n> >                      IPAFrameContext &frameContext,\n> >                      ipu3_uapi_params *params) override;\n> >         void process(IPAContext &context, const uint32_t frame,\n> > -                    IPAFrameContext &frameContext,\n> > +                    IPAFrameContext &frameContext, ControlList &metadata,\n> >                      const ipu3_uapi_stats_3a *stats) override;\n> >  \n> >  private:\n> > diff --git a/src/ipa/ipu3/algorithms/tone_mapping.cpp b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> > index eac3d4064443..6fcc03f3fcf7 100644\n> > --- a/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> > +++ b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> > @@ -78,6 +78,7 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n> >   * \\param[in] context The shared IPA context\n> >   * \\param[in] frame The current frame sequence number\n> >   * \\param[in] frameContext The current frame context\n> > + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n> >   * \\param[in] stats The IPU3 statistics and ISP results\n> >   *\n> >   * The tone mapping look up table is generated as an inverse power curve from\n> > @@ -85,6 +86,7 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n> >   */\n> >  void ToneMapping::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> >                           [[maybe_unused]] IPAFrameContext &frameContext,\n> > +                         [[maybe_unused]] ControlList &metadata,\n> >                           [[maybe_unused]] const ipu3_uapi_stats_3a *stats)\n> >  {\n> >         /*\n> > diff --git a/src/ipa/ipu3/algorithms/tone_mapping.h b/src/ipa/ipu3/algorithms/tone_mapping.h\n> > index 822e5168df82..ab2a1c000f2f 100644\n> > --- a/src/ipa/ipu3/algorithms/tone_mapping.h\n> > +++ b/src/ipa/ipu3/algorithms/tone_mapping.h\n> > @@ -22,7 +22,7 @@ public:\n> >         void prepare(IPAContext &context, const uint32_t frame,\n> >                      IPAFrameContext &frameContext, ipu3_uapi_params *params) override;\n> >         void process(IPAContext &context, const uint32_t frame,\n> > -                    IPAFrameContext &frameContext,\n> > +                    IPAFrameContext &frameContext, ControlList &metadata,\n> >                      const ipu3_uapi_stats_3a *stats) override;\n> >  \n> >  private:\n> > diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> > index 891643e057b8..0ccc6bf5c8af 100644\n> > --- a/src/ipa/ipu3/ipu3.cpp\n> > +++ b/src/ipa/ipu3/ipu3.cpp\n> > @@ -631,9 +631,10 @@ void IPAIPU3::processStatsBuffer(const uint32_t frame,\n> >         double lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();\n> >         int32_t vBlank = context_.configuration.sensor.defVBlank;\n> >         ControlList ctrls(controls::controls);\n> \n> It looks like ctrls() is what is currently used as metadata here.\n> \n> It gets emitted at the end of this function.\n> Can we either use ctrls passed in to algo->process() or (preferred)\n> rename ctrls to metadata here to ensure that /when/ we set metadata in\n> the algorithms it will reach the pipeline handler?\n\nGood catch. I'll do this in v2.\n\n> Probably keep the existing metadata additions in this function still -\n> converting them can be later, but otherwise this is a partial\n> implementation for IPU3.\n\nI'll add patches on top of the series to do so.\n\n> *with that* \n> \n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> > +       ControlList metadata(controls::controls);\n> >  \n> >         for (auto const &algo : algorithms())\n> > -               algo->process(context_, frame, frameContext, stats);\n> > +               algo->process(context_, frame, frameContext, metadata, stats);\n> \n> I would have had metadata as the last parameter as an 'output'\n> (inputs, outputs) ... but I bet you've gone alphabetical.\n> \n> No point changing it though - that's too much work, and this is fine.\n\nToo late, I've moved it already :-)\n\nI'm also toying with the idea of adding the metadata to the frame\ncontext, but that won't be done yet.\n\n> >         setControls(frame);\n> >  \n> > diff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp\n> > index 55abddab2b0a..a34c583d947e 100644\n> > --- a/src/ipa/libipa/algorithm.cpp\n> > +++ b/src/ipa/libipa/algorithm.cpp\n> > @@ -106,12 +106,13 @@ namespace ipa {\n> >   * \\param[in] context The shared IPA context\n> >   * \\param[in] frame The frame context sequence number\n> >   * \\param[in] frameContext The current frame's context\n> > + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n> >   * \\param[in] stats The IPA statistics and ISP results\n> >   *\n> >   * This function is called while camera is running for every frame processed by\n> >   * the ISP, to process statistics generated from that frame by the ISP.\n> > - * Algorithms shall use this data to run calculations and update their state\n> > - * accordingly.\n> > + * Algorithms shall use this data to run calculations, update their state\n> > + * accordingly, and fill the frame metadata.\n> >   *\n> >   * Processing shall not take an undue amount of time, and any extended or\n> >   * computationally expensive calculations or operations must be handled\n> > diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h\n> > index d8601f9ccaff..793247be8129 100644\n> > --- a/src/ipa/libipa/algorithm.h\n> > +++ b/src/ipa/libipa/algorithm.h\n> > @@ -55,6 +55,7 @@ public:\n> >         virtual void process([[maybe_unused]] typename Module::Context &context,\n> >                              [[maybe_unused]] const uint32_t frame,\n> >                              [[maybe_unused]] typename Module::FrameContext &frameContext,\n> > +                            [[maybe_unused]] ControlList &metadata,\n> >                              [[maybe_unused]] const typename Module::Stats *stats)\n> >         {\n> >         }\n> > diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> > index 04062a364e7f..9de11a2a3bca 100644\n> > --- a/src/ipa/rkisp1/algorithms/agc.cpp\n> > +++ b/src/ipa/rkisp1/algorithms/agc.cpp\n> > @@ -288,7 +288,9 @@ double Agc::measureBrightness(const rkisp1_cif_isp_hist_stat *hist) const\n> >   * new exposure and gain for the scene.\n> >   */\n> >  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> > -                 IPAFrameContext &frameContext, const rkisp1_stat_buffer *stats)\n> > +                 IPAFrameContext &frameContext,\n> > +                 [[maybe_unused]] ControlList &metadata,\n> > +                 const rkisp1_stat_buffer *stats)\n> >  {\n> >         /*\n> >          * \\todo Verify that the exposure and gain applied by the sensor for\n> > diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\n> > index 9ad5c32fd6f6..99af09167331 100644\n> > --- a/src/ipa/rkisp1/algorithms/agc.h\n> > +++ b/src/ipa/rkisp1/algorithms/agc.h\n> > @@ -30,7 +30,7 @@ public:\n> >                      IPAFrameContext &frameContext,\n> >                      rkisp1_params_cfg *params) override;\n> >         void process(IPAContext &context, const uint32_t frame,\n> > -                    IPAFrameContext &frameContext,\n> > +                    IPAFrameContext &frameContext, ControlList &metadata,\n> >                      const rkisp1_stat_buffer *stats) override;\n> >  \n> >  private:\n> > diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\n> > index 3349948a3acf..9b97db7d5c5a 100644\n> > --- a/src/ipa/rkisp1/algorithms/awb.cpp\n> > +++ b/src/ipa/rkisp1/algorithms/awb.cpp\n> > @@ -208,6 +208,7 @@ void Awb::queueRequest(IPAContext &context,\n> >  void Awb::process(IPAContext &context,\n> >                   [[maybe_unused]] const uint32_t frame,\n> >                   IPAFrameContext &frameContext,\n> > +                 [[maybe_unused]] ControlList &metadata,\n> >                   const rkisp1_stat_buffer *stats)\n> >  {\n> >         const rkisp1_cif_isp_stat *params = &stats->params;\n> > diff --git a/src/ipa/rkisp1/algorithms/awb.h b/src/ipa/rkisp1/algorithms/awb.h\n> > index d76b538288ec..3659b2d5405f 100644\n> > --- a/src/ipa/rkisp1/algorithms/awb.h\n> > +++ b/src/ipa/rkisp1/algorithms/awb.h\n> > @@ -27,7 +27,7 @@ public:\n> >                           IPAFrameContext &frameContext,\n> >                           const ControlList &controls) override;\n> >         void process(IPAContext &context, const uint32_t frame,\n> > -                    IPAFrameContext &frameCtx,\n> > +                    IPAFrameContext &frameContext, ControlList &metadata,\n> >                      const rkisp1_stat_buffer *stats) override;\n> >  \n> >  private:\n> > diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> > index 3f5c1a58695c..bef5211d5c34 100644\n> > --- a/src/ipa/rkisp1/rkisp1.cpp\n> > +++ b/src/ipa/rkisp1/rkisp1.cpp\n> > @@ -69,7 +69,6 @@ protected:\n> >  \n> >  private:\n> >         void setControls(unsigned int frame);\n> > -       void prepareMetadata(unsigned int frame, unsigned int aeState);\n> >  \n> >         std::map<unsigned int, FrameBuffer> buffers_;\n> >         std::map<unsigned int, MappedFrameBuffer> mappedBuffers_;\n> > @@ -338,14 +337,14 @@ void IPARkISP1::processStatsBuffer(const uint32_t frame, const uint32_t bufferId\n> >         frameContext.sensor.gain =\n> >                 camHelper_->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());\n> >  \n> > -       unsigned int aeState = 0;\n> > +       ControlList metadata(controls::controls);\n> >  \n> >         for (auto const &algo : algorithms())\n> > -               algo->process(context_, frame, frameContext, stats);\n> > +               algo->process(context_, frame, frameContext, metadata, stats);\n> >  \n> >         setControls(frame);\n> >  \n> > -       prepareMetadata(frame, aeState);\n> > +       metadataReady.emit(frame, metadata);\n> \n> That ties in much better.\n> \n> >  }\n> >  \n> >  void IPARkISP1::setControls(unsigned int frame)\n> > @@ -366,16 +365,6 @@ void IPARkISP1::setControls(unsigned int frame)\n> >         setSensorControls.emit(frame, ctrls);\n> >  }\n> >  \n> > -void IPARkISP1::prepareMetadata(unsigned int frame, unsigned int aeState)\n> > -{\n> > -       ControlList ctrls(controls::controls);\n> > -\n> > -       if (aeState)\n> > -               ctrls.set(controls::AeLocked, aeState == 2);\n> \n> Phew, that's good to see it all go.\n> \n> > -\n> > -       metadataReady.emit(frame, ctrls);\n> > -}\n> > -\n> >  } /* namespace ipa::rkisp1 */\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 DDF7FC0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Oct 2022 18:38:47 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4D78862E63;\n\tWed, 19 Oct 2022 20:38:47 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 957E162DFA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Oct 2022 20:38:45 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EAD595A4;\n\tWed, 19 Oct 2022 20:38:44 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1666204727;\n\tbh=Dw2lfldU3sDvhi4jylcp3KSRm5zWtsb6XZo4tlHCTsQ=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=bdBcgOexM0pqkCj5EMN2Sjql3hGuJjTXfid8aMAxCFT7ZQeNk4IwxxDDb/2nFRjmn\n\tT2BSmQSfZ7O05U0p97jzv61PXAdqgj/FsGx9V0SBw1G94Skm8hvX+uTCwQ0c87/9r1\n\t8yiGy30fzigZkmrABWTEFndVMNBMuLOCFLi8NCcabRmPu+FcycDhCIxiMGIfjtDKMb\n\tltHhZR3vyVm3rOeVfGJs3oX95EIg1hT2FZ6Ki/W7QDrv0ktGNwCwMfyPGiawq1qU63\n\tT6KLUkDAdxHeVGlBgwANwj/w/m2oB3CsWRIWKqZV0KTNzftcSvFjYQ6F7pYDITCtC9\n\th24TVjxwm26Gg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1666204725;\n\tbh=Dw2lfldU3sDvhi4jylcp3KSRm5zWtsb6XZo4tlHCTsQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=uUqx4kcK7WC7eGvmycX2icMwGfIcez/WibwjTqLcTsevDkYRR6PpfSHhUIw94WpAv\n\tQ5945TTASNRD+V2uyHNOzSsQ05b8auJBgQqlhSLkKn+ZIGPqRfniiNahH9GesFD7ic\n\tCt18jO+lOm66tXZXlUBYH5PYI45sphbQOTCULdoQ="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"uUqx4kcK\"; dkim-atps=neutral","Date":"Wed, 19 Oct 2022 21:38:20 +0300","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<Y1BEHODMgD/Atcib@pendragon.ideasonboard.com>","References":"<20221019110434.17767-1-laurent.pinchart@ideasonboard.com>\n\t<20221019110434.17767-3-laurent.pinchart@ideasonboard.com>\n\t<166617936110.2560709.5189091996563787597@Monstersaurus>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<166617936110.2560709.5189091996563787597@Monstersaurus>","Subject":"Re: [libcamera-devel] [PATCH v1 2/4] ipa: Pass metadata to\n\tAlgorithm::process() function","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":25480,"web_url":"https://patchwork.libcamera.org/comment/25480/","msgid":"<Y1BFoO7LnsudMqPu@pendragon.ideasonboard.com>","date":"2022-10-19T18:44:48","subject":"Re: [libcamera-devel] [PATCH v1 2/4] ipa: Pass metadata to\n\tAlgorithm::process() function","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Wed, Oct 19, 2022 at 01:49:12PM +0200, Jacopo Mondi wrote:\n> On Wed, Oct 19, 2022 at 02:04:32PM +0300, Laurent Pinchart via libcamera-devel wrote:\n> > Extend the Algorithm::process() function with a metadata control list,\n> > to be filled by individual algorithms with frame metadata. Update the\n> > rkisp1 and ipu3 IPA modules accordingly, and drop the dead code in the\n> > IPARkISP1::prepareMetadata() function while at it.\n> >\n> > This only creates the infrastructure, filling metadata in individual\n> > algorithms will be handled separately.\n> >\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> \n> Do we want metadata to be passed in as argument, or do we want\n> metadata to be part of the frame context ?\n\nI've considered both, and haven't been able to decide which is best.\nMoving the metadata to the frame context is more complicated, as the\nFrameContext won't be default-constructible anymore. I started going in\nthat direction, but it will require quite a lot of extra work.\n\n> Also, a reference is nice, but we usually use pointers for modifiable\n> arguments. Just pointing out for sake of consistency (I'm not even\n> sure we actually enforce that anymore), I'm fine with a reference\n> too..\n\nThe context and frame context are already passed by reference, so I've\ndone the same. We could address all of those globally.\n\n> > ---\n> >  src/ipa/ipu3/algorithms/af.cpp           |  2 ++\n> >  src/ipa/ipu3/algorithms/af.h             |  2 +-\n> >  src/ipa/ipu3/algorithms/agc.cpp          |  2 ++\n> >  src/ipa/ipu3/algorithms/agc.h            |  2 +-\n> >  src/ipa/ipu3/algorithms/awb.cpp          |  1 +\n> >  src/ipa/ipu3/algorithms/awb.h            |  2 +-\n> >  src/ipa/ipu3/algorithms/tone_mapping.cpp |  2 ++\n> >  src/ipa/ipu3/algorithms/tone_mapping.h   |  2 +-\n> >  src/ipa/ipu3/ipu3.cpp                    |  3 ++-\n> >  src/ipa/libipa/algorithm.cpp             |  5 +++--\n> >  src/ipa/libipa/algorithm.h               |  1 +\n> >  src/ipa/rkisp1/algorithms/agc.cpp        |  4 +++-\n> >  src/ipa/rkisp1/algorithms/agc.h          |  2 +-\n> >  src/ipa/rkisp1/algorithms/awb.cpp        |  1 +\n> >  src/ipa/rkisp1/algorithms/awb.h          |  2 +-\n> >  src/ipa/rkisp1/rkisp1.cpp                | 17 +++--------------\n> >  16 files changed, 26 insertions(+), 24 deletions(-)\n> >\n> > diff --git a/src/ipa/ipu3/algorithms/af.cpp b/src/ipa/ipu3/algorithms/af.cpp\n> > index 75632aa39d21..2d728871a63b 100644\n> > --- a/src/ipa/ipu3/algorithms/af.cpp\n> > +++ b/src/ipa/ipu3/algorithms/af.cpp\n> > @@ -408,6 +408,7 @@ bool Af::afIsOutOfFocus(IPAContext &context)\n> >   * \\param[in] context The IPA context\n> >   * \\param[in] frame The frame context sequence number\n> >   * \\param[in] frameContext The current frame context\n> > + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n> >   * \\param[in] stats The statistics buffer of IPU3\n> >   *\n> >   * Ideally, a clear image also has a relatively higher contrast. So, every\n> > @@ -423,6 +424,7 @@ bool Af::afIsOutOfFocus(IPAContext &context)\n> >   */\n> >  void Af::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> >  \t\t [[maybe_unused]] IPAFrameContext &frameContext,\n> > +\t\t [[maybe_unused]] ControlList &metadata,\n> >  \t\t const ipu3_uapi_stats_3a *stats)\n> >  {\n> >  \t/* Evaluate the AF buffer length */\n> > diff --git a/src/ipa/ipu3/algorithms/af.h b/src/ipa/ipu3/algorithms/af.h\n> > index 89d37ac18615..ea7ca647df12 100644\n> > --- a/src/ipa/ipu3/algorithms/af.h\n> > +++ b/src/ipa/ipu3/algorithms/af.h\n> > @@ -35,7 +35,7 @@ public:\n> >  \t\t     IPAFrameContext &frameContext,\n> >  \t\t     ipu3_uapi_params *params) override;\n> >  \tvoid process(IPAContext &context, const uint32_t frame,\n> > -\t\t     IPAFrameContext &frameContext,\n> > +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n> >  \t\t     const ipu3_uapi_stats_3a *stats) override;\n> >\n> >  private:\n> > diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\n> > index a1a3c38ffe84..44dd5c809e26 100644\n> > --- a/src/ipa/ipu3/algorithms/agc.cpp\n> > +++ b/src/ipa/ipu3/algorithms/agc.cpp\n> > @@ -319,6 +319,7 @@ double Agc::estimateLuminance(IPAActiveState &activeState,\n> >   * \\param[in] context The shared IPA context\n> >   * \\param[in] frame The current frame sequence number\n> >   * \\param[in] frameContext The current frame context\n> > + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n> >   * \\param[in] stats The IPU3 statistics and ISP results\n> >   *\n> >   * Identify the current image brightness, and use that to estimate the optimal\n> > @@ -326,6 +327,7 @@ double Agc::estimateLuminance(IPAActiveState &activeState,\n> >   */\n> >  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> >  \t\t  IPAFrameContext &frameContext,\n> > +\t\t  [[maybe_unused]] ControlList &metadata,\n> >  \t\t  const ipu3_uapi_stats_3a *stats)\n> >  {\n> >  \t/*\n> > diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h\n> > index 59b4b9843c2f..9106cbefe87a 100644\n> > --- a/src/ipa/ipu3/algorithms/agc.h\n> > +++ b/src/ipa/ipu3/algorithms/agc.h\n> > @@ -29,7 +29,7 @@ public:\n> >\n> >  \tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n> >  \tvoid process(IPAContext &context, const uint32_t frame,\n> > -\t\t     IPAFrameContext &frameContext,\n> > +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n> >  \t\t     const ipu3_uapi_stats_3a *stats) override;\n> >\n> >  private:\n> > diff --git a/src/ipa/ipu3/algorithms/awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp\n> > index 0dbd7d4c374f..836eb0687181 100644\n> > --- a/src/ipa/ipu3/algorithms/awb.cpp\n> > +++ b/src/ipa/ipu3/algorithms/awb.cpp\n> > @@ -389,6 +389,7 @@ void Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)\n> >   */\n> >  void Awb::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> >  \t\t  [[maybe_unused]] IPAFrameContext &frameContext,\n> > +\t\t  [[maybe_unused]] ControlList &metadata,\n> >  \t\t  const ipu3_uapi_stats_3a *stats)\n> >  {\n> >  \tcalculateWBGains(stats);\n> > diff --git a/src/ipa/ipu3/algorithms/awb.h b/src/ipa/ipu3/algorithms/awb.h\n> > index 28e2d38a711c..c38c425c3654 100644\n> > --- a/src/ipa/ipu3/algorithms/awb.h\n> > +++ b/src/ipa/ipu3/algorithms/awb.h\n> > @@ -43,7 +43,7 @@ public:\n> >  \t\t     IPAFrameContext &frameContext,\n> >  \t\t     ipu3_uapi_params *params) override;\n> >  \tvoid process(IPAContext &context, const uint32_t frame,\n> > -\t\t     IPAFrameContext &frameContext,\n> > +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n> >  \t\t     const ipu3_uapi_stats_3a *stats) override;\n> >\n> >  private:\n> > diff --git a/src/ipa/ipu3/algorithms/tone_mapping.cpp b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> > index eac3d4064443..6fcc03f3fcf7 100644\n> > --- a/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> > +++ b/src/ipa/ipu3/algorithms/tone_mapping.cpp\n> > @@ -78,6 +78,7 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n> >   * \\param[in] context The shared IPA context\n> >   * \\param[in] frame The current frame sequence number\n> >   * \\param[in] frameContext The current frame context\n> > + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n> >   * \\param[in] stats The IPU3 statistics and ISP results\n> >   *\n> >   * The tone mapping look up table is generated as an inverse power curve from\n> > @@ -85,6 +86,7 @@ void ToneMapping::prepare([[maybe_unused]] IPAContext &context,\n> >   */\n> >  void ToneMapping::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> >  \t\t\t  [[maybe_unused]] IPAFrameContext &frameContext,\n> > +\t\t\t  [[maybe_unused]] ControlList &metadata,\n> >  \t\t\t  [[maybe_unused]] const ipu3_uapi_stats_3a *stats)\n> >  {\n> >  \t/*\n> > diff --git a/src/ipa/ipu3/algorithms/tone_mapping.h b/src/ipa/ipu3/algorithms/tone_mapping.h\n> > index 822e5168df82..ab2a1c000f2f 100644\n> > --- a/src/ipa/ipu3/algorithms/tone_mapping.h\n> > +++ b/src/ipa/ipu3/algorithms/tone_mapping.h\n> > @@ -22,7 +22,7 @@ public:\n> >  \tvoid prepare(IPAContext &context, const uint32_t frame,\n> >  \t\t     IPAFrameContext &frameContext, ipu3_uapi_params *params) override;\n> >  \tvoid process(IPAContext &context, const uint32_t frame,\n> > -\t\t     IPAFrameContext &frameContext,\n> > +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n> >  \t\t     const ipu3_uapi_stats_3a *stats) override;\n> >\n> >  private:\n> > diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> > index 891643e057b8..0ccc6bf5c8af 100644\n> > --- a/src/ipa/ipu3/ipu3.cpp\n> > +++ b/src/ipa/ipu3/ipu3.cpp\n> > @@ -631,9 +631,10 @@ void IPAIPU3::processStatsBuffer(const uint32_t frame,\n> >  \tdouble lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();\n> >  \tint32_t vBlank = context_.configuration.sensor.defVBlank;\n> >  \tControlList ctrls(controls::controls);\n> > +\tControlList metadata(controls::controls);\n> >\n> >  \tfor (auto const &algo : algorithms())\n> > -\t\talgo->process(context_, frame, frameContext, stats);\n> > +\t\talgo->process(context_, frame, frameContext, metadata, stats);\n> >\n> >  \tsetControls(frame);\n> >\n> > diff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp\n> > index 55abddab2b0a..a34c583d947e 100644\n> > --- a/src/ipa/libipa/algorithm.cpp\n> > +++ b/src/ipa/libipa/algorithm.cpp\n> > @@ -106,12 +106,13 @@ namespace ipa {\n> >   * \\param[in] context The shared IPA context\n> >   * \\param[in] frame The frame context sequence number\n> >   * \\param[in] frameContext The current frame's context\n> > + * \\param[out] metadata Metadata for the frame, to be filled by the algorithm\n> >   * \\param[in] stats The IPA statistics and ISP results\n> >   *\n> >   * This function is called while camera is running for every frame processed by\n> >   * the ISP, to process statistics generated from that frame by the ISP.\n> > - * Algorithms shall use this data to run calculations and update their state\n> > - * accordingly.\n> > + * Algorithms shall use this data to run calculations, update their state\n> > + * accordingly, and fill the frame metadata.\n> >   *\n> >   * Processing shall not take an undue amount of time, and any extended or\n> >   * computationally expensive calculations or operations must be handled\n> > diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h\n> > index d8601f9ccaff..793247be8129 100644\n> > --- a/src/ipa/libipa/algorithm.h\n> > +++ b/src/ipa/libipa/algorithm.h\n> > @@ -55,6 +55,7 @@ public:\n> >  \tvirtual void process([[maybe_unused]] typename Module::Context &context,\n> >  \t\t\t     [[maybe_unused]] const uint32_t frame,\n> >  \t\t\t     [[maybe_unused]] typename Module::FrameContext &frameContext,\n> > +\t\t\t     [[maybe_unused]] ControlList &metadata,\n> >  \t\t\t     [[maybe_unused]] const typename Module::Stats *stats)\n> >  \t{\n> >  \t}\n> > diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> > index 04062a364e7f..9de11a2a3bca 100644\n> > --- a/src/ipa/rkisp1/algorithms/agc.cpp\n> > +++ b/src/ipa/rkisp1/algorithms/agc.cpp\n> > @@ -288,7 +288,9 @@ double Agc::measureBrightness(const rkisp1_cif_isp_hist_stat *hist) const\n> >   * new exposure and gain for the scene.\n> >   */\n> >  void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n> > -\t\t  IPAFrameContext &frameContext, const rkisp1_stat_buffer *stats)\n> > +\t\t  IPAFrameContext &frameContext,\n> > +\t\t  [[maybe_unused]] ControlList &metadata,\n> > +\t\t  const rkisp1_stat_buffer *stats)\n> >  {\n> >  \t/*\n> >  \t * \\todo Verify that the exposure and gain applied by the sensor for\n> > diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\n> > index 9ad5c32fd6f6..99af09167331 100644\n> > --- a/src/ipa/rkisp1/algorithms/agc.h\n> > +++ b/src/ipa/rkisp1/algorithms/agc.h\n> > @@ -30,7 +30,7 @@ public:\n> >  \t\t     IPAFrameContext &frameContext,\n> >  \t\t     rkisp1_params_cfg *params) override;\n> >  \tvoid process(IPAContext &context, const uint32_t frame,\n> > -\t\t     IPAFrameContext &frameContext,\n> > +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n> >  \t\t     const rkisp1_stat_buffer *stats) override;\n> >\n> >  private:\n> > diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\n> > index 3349948a3acf..9b97db7d5c5a 100644\n> > --- a/src/ipa/rkisp1/algorithms/awb.cpp\n> > +++ b/src/ipa/rkisp1/algorithms/awb.cpp\n> > @@ -208,6 +208,7 @@ void Awb::queueRequest(IPAContext &context,\n> >  void Awb::process(IPAContext &context,\n> >  \t\t  [[maybe_unused]] const uint32_t frame,\n> >  \t\t  IPAFrameContext &frameContext,\n> > +\t\t  [[maybe_unused]] ControlList &metadata,\n> >  \t\t  const rkisp1_stat_buffer *stats)\n> >  {\n> >  \tconst rkisp1_cif_isp_stat *params = &stats->params;\n> > diff --git a/src/ipa/rkisp1/algorithms/awb.h b/src/ipa/rkisp1/algorithms/awb.h\n> > index d76b538288ec..3659b2d5405f 100644\n> > --- a/src/ipa/rkisp1/algorithms/awb.h\n> > +++ b/src/ipa/rkisp1/algorithms/awb.h\n> > @@ -27,7 +27,7 @@ public:\n> >  \t\t\t  IPAFrameContext &frameContext,\n> >  \t\t\t  const ControlList &controls) override;\n> >  \tvoid process(IPAContext &context, const uint32_t frame,\n> > -\t\t     IPAFrameContext &frameCtx,\n> > +\t\t     IPAFrameContext &frameContext, ControlList &metadata,\n> >  \t\t     const rkisp1_stat_buffer *stats) override;\n> >\n> >  private:\n> > diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> > index 3f5c1a58695c..bef5211d5c34 100644\n> > --- a/src/ipa/rkisp1/rkisp1.cpp\n> > +++ b/src/ipa/rkisp1/rkisp1.cpp\n> > @@ -69,7 +69,6 @@ protected:\n> >\n> >  private:\n> >  \tvoid setControls(unsigned int frame);\n> > -\tvoid prepareMetadata(unsigned int frame, unsigned int aeState);\n> >\n> >  \tstd::map<unsigned int, FrameBuffer> buffers_;\n> >  \tstd::map<unsigned int, MappedFrameBuffer> mappedBuffers_;\n> > @@ -338,14 +337,14 @@ void IPARkISP1::processStatsBuffer(const uint32_t frame, const uint32_t bufferId\n> >  \tframeContext.sensor.gain =\n> >  \t\tcamHelper_->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());\n> >\n> > -\tunsigned int aeState = 0;\n> > +\tControlList metadata(controls::controls);\n> >\n> >  \tfor (auto const &algo : algorithms())\n> > -\t\talgo->process(context_, frame, frameContext, stats);\n> > +\t\talgo->process(context_, frame, frameContext, metadata, stats);\n> >\n> >  \tsetControls(frame);\n> >\n> > -\tprepareMetadata(frame, aeState);\n> > +\tmetadataReady.emit(frame, metadata);\n> >  }\n> >\n> >  void IPARkISP1::setControls(unsigned int frame)\n> > @@ -366,16 +365,6 @@ void IPARkISP1::setControls(unsigned int frame)\n> >  \tsetSensorControls.emit(frame, ctrls);\n> >  }\n> >\n> > -void IPARkISP1::prepareMetadata(unsigned int frame, unsigned int aeState)\n> > -{\n> > -\tControlList ctrls(controls::controls);\n> > -\n> > -\tif (aeState)\n> > -\t\tctrls.set(controls::AeLocked, aeState == 2);\n> > -\n> > -\tmetadataReady.emit(frame, ctrls);\n> > -}\n> > -\n> >  } /* namespace ipa::rkisp1 */\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 C2528BD16B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 Oct 2022 18:45:14 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3D65362E64;\n\tWed, 19 Oct 2022 20:45:14 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9029E62DFA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Oct 2022 20:45:13 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id B3AB15A4;\n\tWed, 19 Oct 2022 20:45:12 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1666205114;\n\tbh=6M+OQyAgElfXDXzJQDI8mJc8EMs5t4nGzDMyws7RXas=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=dE+5jiBi7uXvqMYmw/P9q7IlPy7fCPPGaHToaHRUVLCPdb0TlxLPxmd4APZTLGrby\n\t7A+tq7wNRk01H+U1lYB0T7SE5Ic3oRNffLLRujpr4T6W8s8vgdMJrEJjBKmZY4rjWp\n\ttXxwgQ/iseU48Ktb2+e12fGeTZNj3eB1oVmC/fhlpGoUJr//uYpQtrDtJ5UrfF57tm\n\tX+b5J7+LY9y/hbvaekO2nCihVSq4stZn/jTkjFLoAcm7EyOBfzgx8v8+3ZHVmtdQeZ\n\tQjXluENDTKkYG/Pp6if1ouy16FN3563TOjQZHOB1UEWs8Olb73cANVw/TN0O2M+MkS\n\tau3BmFN49srQA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1666205113;\n\tbh=6M+OQyAgElfXDXzJQDI8mJc8EMs5t4nGzDMyws7RXas=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=YKTMQ+krUe9pCN64finXyYdcBq6NqNb8olo6FKY/1RtPp3+pmhOhYy0NZfxMTE8GU\n\tr1cb7UOl4Y4pHtSknGWZy9sdFMSJVordgXf0s1BAwB03GDcTz6Vp9/jL4prygTE28A\n\t9JcHKYcXCdIIVNCDy56H6cIaJ5sutJI7J6SJYvzA="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"YKTMQ+kr\"; dkim-atps=neutral","Date":"Wed, 19 Oct 2022 21:44:48 +0300","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<Y1BFoO7LnsudMqPu@pendragon.ideasonboard.com>","References":"<20221019110434.17767-1-laurent.pinchart@ideasonboard.com>\n\t<20221019110434.17767-3-laurent.pinchart@ideasonboard.com>\n\t<20221019114912.klejuewk3l4djimk@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20221019114912.klejuewk3l4djimk@uno.localdomain>","Subject":"Re: [libcamera-devel] [PATCH v1 2/4] ipa: Pass metadata to\n\tAlgorithm::process() function","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]