[{"id":22655,"web_url":"https://patchwork.libcamera.org/comment/22655/","msgid":"<164937003770.22830.7663771483643443643@Monstersaurus>","date":"2022-04-07T22:20:37","subject":"Re: [libcamera-devel] [IPAIPU3 PATCH v5 6/6] ipa: ipu3: Inline\n\tparseStatistics() into processStatsBuffer()","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Umang Jain via libcamera-devel (2022-04-06 15:17:09)\n> Since we have moved away from switch/case on the operation ID,\n> there's little reason to split the operation in two functions.\n> \n> Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> ---\n>  ipu3.cpp | 74 ++++++++++++++++++++++++--------------------------------\n>  1 file changed, 31 insertions(+), 43 deletions(-)\n> \n> diff --git a/ipu3.cpp b/ipu3.cpp\n> index 0543a2e..7ecd377 100644\n> --- a/ipu3.cpp\n> +++ b/ipu3.cpp\n> @@ -60,10 +60,6 @@ private:\n>                             const ControlInfoMap &sensorControls,\n>                             ControlInfoMap *ipaControls);\n>         void runAiq(unsigned int frame);\n> -       void parseStatistics(unsigned int frame,\n> -                            int64_t frameTimestamp,\n> -                            const ipu3_uapi_stats_3a *stats,\n> -                            const ControlList& sensorCtrls);\n>  \n>         void setControls(unsigned int frame);\n>  \n> @@ -379,43 +375,6 @@ void IPAIPU3::processStatsBuffer(const uint32_t frame, const int64_t frameTimest\n>         const ipu3_uapi_stats_3a *stats =\n>                 reinterpret_cast<ipu3_uapi_stats_3a *>(mem.data());\n>  \n> -       parseStatistics(frame, frameTimestamp, stats, sensorControls);\n> -}\n> -\n> -void IPAIPU3::runAiq([[maybe_unused]] unsigned int frame)\n> -{\n> -       /* Run algorithms into/using this context structure */\n> -       resultsHistory_.extendOne();\n> -       aiq::AiqResults& latestResults = resultsHistory_.latest();\n> -\n> -       /* Todo: Refactor AiqInputParameters interface to set following parameters. */\n> -       aiqInputParams_.afParams.lens_position = lensPosition_;\n> -       aiqInputParams_.afParams.lens_movement_start_timestamp = lensMovementStartTime_;\n> -\n> -       aiq_.run2a(frame, aiqInputParams_, latestResults);\n> -\n> -       exposure_ = latestResults.ae()->exposures[0].sensor_exposure->coarse_integration_time;\n> -       gain_ = latestResults.ae()->exposures[0].sensor_exposure->analog_gain_code_global;\n> -\n> -       /*\n> -        * Af algorithm compares the timestamp of start of the lens movement and\n> -        * that of the statistics generated to estimate whether next lens\n> -        * position should be produced.\n> -        * \\todo use the lens movement start time reported by the pipeline handler.\n> -        */\n> -       if (lensPosition_ != latestResults.af()->next_lens_position) {\n> -               utils::time_point time = utils::clock::now();\n> -               uint64_t usecs = std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch()).count();\n> -               lensMovementStartTime_ = usecs;\n> -       }\n> -       lensPosition_ = latestResults.af()->next_lens_position;\n> -}\n> -\n> -void IPAIPU3::parseStatistics(unsigned int frame,\n> -                             int64_t frameTimestamp,\n> -                             const ipu3_uapi_stats_3a *stats,\n> -                             const ControlList& sensorCtrls)\n> -{\n>         ControlList ctrls(controls::controls);\n>  \n>         /* \\todo React to statistics and update internal state machine. */\n> @@ -438,11 +397,11 @@ void IPAIPU3::parseStatistics(unsigned int frame,\n>         int32_t effectiveGain = 0;\n>         ControlValue ctrlValue;\n>  \n> -       ctrlValue = sensorCtrls.get(V4L2_CID_EXPOSURE);\n> +       ctrlValue = sensorControls.get(V4L2_CID_EXPOSURE);\n>         if (!ctrlValue.isNone())\n>                 effectiveExpo = ctrlValue.get<int32_t>();\n>  \n> -       ctrlValue = sensorCtrls.get(V4L2_CID_ANALOGUE_GAIN);\n> +       ctrlValue = sensorControls.get(V4L2_CID_ANALOGUE_GAIN);\n>         if (!ctrlValue.isNone())\n>                 effectiveGain = ctrlValue.get<int32_t>();\n>  \n> @@ -472,6 +431,35 @@ void IPAIPU3::parseStatistics(unsigned int frame,\n>         metadataReady.emit(frame, ctrls);\n>  }\n>  \n> +void IPAIPU3::runAiq([[maybe_unused]] unsigned int frame)\n> +{\n> +       /* Run algorithms into/using this context structure */\n> +       resultsHistory_.extendOne();\n> +       aiq::AiqResults& latestResults = resultsHistory_.latest();\n> +\n> +       /* Todo: Refactor AiqInputParameters interface to set following parameters. */\n> +       aiqInputParams_.afParams.lens_position = lensPosition_;\n> +       aiqInputParams_.afParams.lens_movement_start_timestamp = lensMovementStartTime_;\n> +\n> +       aiq_.run2a(frame, aiqInputParams_, latestResults);\n> +\n> +       exposure_ = latestResults.ae()->exposures[0].sensor_exposure->coarse_integration_time;\n> +       gain_ = latestResults.ae()->exposures[0].sensor_exposure->analog_gain_code_global;\n> +\n> +       /*\n> +        * Af algorithm compares the timestamp of start of the lens movement and\n> +        * that of the statistics generated to estimate whether next lens\n> +        * position should be produced.\n> +        * \\todo use the lens movement start time reported by the pipeline handler.\n> +        */\n> +       if (lensPosition_ != latestResults.af()->next_lens_position) {\n> +               utils::time_point time = utils::clock::now();\n> +               uint64_t usecs = std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch()).count();\n> +               lensMovementStartTime_ = usecs;\n> +       }\n> +       lensPosition_ = latestResults.af()->next_lens_position;\n> +}\n> +\n>  void IPAIPU3::setControls(unsigned int frame)\n>  {\n>         ControlList sensorCtrls(ctrls_);\n> -- \n> 2.31.0\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 3AD4BC0F1B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  7 Apr 2022 22:20:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EC13F65643;\n\tFri,  8 Apr 2022 00:20:41 +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 60AE065640\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  8 Apr 2022 00:20:40 +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 210C6499;\n\tFri,  8 Apr 2022 00:20:40 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1649370041;\n\tbh=1OU0A4+ISyakW6PmeFcg3xjyetFxl3+/GddvtiyLtc8=;\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=Ze3/LWrW5kvVnk16XZqZmVoRUtehPzDeUDsdLg7TzcmSKO0+covOpF+zi4Nq9zdI/\n\tOnQnVS4lOi+VvXh7K5N3XngLz1R8pYdw9GQjS49B28zsWKknqc4sEbjiyFc0HEBQWj\n\t/tfO7vCpQ2V5XrRfo0/JnVw/m2/SG5hZtRBmZob37F9j0jAHanYmDloGgxKcJ00BNq\n\tVBIhZv0Pc0EjqaB++9KLDZVUW3d5B+EJ9DPbyYN6R3wtEM8XyFajEoxQNNzsus5r4c\n\t7CIaoXtMeOW3JpsUesLUW4Q6+kZr1qGAU+VZwY2zw4wOkvH/yCOUPYsZJuVm0IM8aF\n\th5852oV6oAcAg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1649370040;\n\tbh=1OU0A4+ISyakW6PmeFcg3xjyetFxl3+/GddvtiyLtc8=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=sUOM4P6NwB7q1vwWmZ/TR0Hwx/rEZu26rJ1dU0VoaWnCyRJrPpSdIAXw8pCJReLf9\n\t2LWfYUdUg9yon97SAJbWSH2oXOK2porL5ViXz2uRQgitPhuUo99+hj6NJxce6SsHa7\n\tYrzMzjIBGwf6LDdBVmagILjgmVtY2Yfp6kM5NOYM="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"sUOM4P6N\"; dkim-atps=neutral","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20220406141709.164794-7-umang.jain@ideasonboard.com>","References":"<20220406141709.164794-1-umang.jain@ideasonboard.com>\n\t<20220406141709.164794-7-umang.jain@ideasonboard.com>","To":"Umang Jain <umang.jain@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Thu, 07 Apr 2022 23:20:37 +0100","Message-ID":"<164937003770.22830.7663771483643443643@Monstersaurus>","User-Agent":"alot/0.10","Subject":"Re: [libcamera-devel] [IPAIPU3 PATCH v5 6/6] ipa: ipu3: Inline\n\tparseStatistics() into processStatsBuffer()","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":22666,"web_url":"https://patchwork.libcamera.org/comment/22666/","msgid":"<20220408071946.GR3237525@pyrite.rasen.tech>","date":"2022-04-08T07:19:46","subject":"Re: [libcamera-devel] [IPAIPU3 PATCH v5 6/6] ipa: ipu3: Inline\n\tparseStatistics() into processStatsBuffer()","submitter":{"id":97,"url":"https://patchwork.libcamera.org/api/people/97/","name":"Nicolas Dufresne via libcamera-devel","email":"libcamera-devel@lists.libcamera.org"},"content":"Hi Umang,\n\nOn Wed, Apr 06, 2022 at 07:47:09PM +0530, Umang Jain via libcamera-devel wrote:\n> Since we have moved away from switch/case on the operation ID,\n> there's little reason to split the operation in two functions.\n> \n> Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n>  ipu3.cpp | 74 ++++++++++++++++++++++++--------------------------------\n>  1 file changed, 31 insertions(+), 43 deletions(-)\n> \n> diff --git a/ipu3.cpp b/ipu3.cpp\n> index 0543a2e..7ecd377 100644\n> --- a/ipu3.cpp\n> +++ b/ipu3.cpp\n> @@ -60,10 +60,6 @@ private:\n>  \t\t\t    const ControlInfoMap &sensorControls,\n>  \t\t\t    ControlInfoMap *ipaControls);\n>  \tvoid runAiq(unsigned int frame);\n> -\tvoid parseStatistics(unsigned int frame,\n> -\t\t\t     int64_t frameTimestamp,\n> -\t\t\t     const ipu3_uapi_stats_3a *stats,\n> -\t\t\t     const ControlList& sensorCtrls);\n>  \n>  \tvoid setControls(unsigned int frame);\n>  \n> @@ -379,43 +375,6 @@ void IPAIPU3::processStatsBuffer(const uint32_t frame, const int64_t frameTimest\n>  \tconst ipu3_uapi_stats_3a *stats =\n>  \t\treinterpret_cast<ipu3_uapi_stats_3a *>(mem.data());\n>  \n> -\tparseStatistics(frame, frameTimestamp, stats, sensorControls);\n> -}\n> -\n> -void IPAIPU3::runAiq([[maybe_unused]] unsigned int frame)\n> -{\n> -\t/* Run algorithms into/using this context structure */\n> -\tresultsHistory_.extendOne();\n> -\taiq::AiqResults& latestResults = resultsHistory_.latest();\n> -\n> -\t/* Todo: Refactor AiqInputParameters interface to set following parameters. */\n> -\taiqInputParams_.afParams.lens_position = lensPosition_;\n> -\taiqInputParams_.afParams.lens_movement_start_timestamp = lensMovementStartTime_;\n> -\n> -\taiq_.run2a(frame, aiqInputParams_, latestResults);\n> -\n> -\texposure_ = latestResults.ae()->exposures[0].sensor_exposure->coarse_integration_time;\n> -\tgain_ = latestResults.ae()->exposures[0].sensor_exposure->analog_gain_code_global;\n> -\n> -\t/*\n> -\t * Af algorithm compares the timestamp of start of the lens movement and\n> -\t * that of the statistics generated to estimate whether next lens\n> -\t * position should be produced.\n> -\t * \\todo use the lens movement start time reported by the pipeline handler.\n> -\t */\n> -\tif (lensPosition_ != latestResults.af()->next_lens_position) {\n> -\t\tutils::time_point time = utils::clock::now();\n> -\t\tuint64_t usecs = std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch()).count();\n> -\t\tlensMovementStartTime_ = usecs;\n> -\t}\n> -\tlensPosition_ = latestResults.af()->next_lens_position;\n> -}\n> -\n> -void IPAIPU3::parseStatistics(unsigned int frame,\n> -\t\t\t      int64_t frameTimestamp,\n> -\t\t\t      const ipu3_uapi_stats_3a *stats,\n> -\t\t\t      const ControlList& sensorCtrls)\n> -{\n>  \tControlList ctrls(controls::controls);\n>  \n>  \t/* \\todo React to statistics and update internal state machine. */\n> @@ -438,11 +397,11 @@ void IPAIPU3::parseStatistics(unsigned int frame,\n>  \tint32_t effectiveGain = 0;\n>  \tControlValue ctrlValue;\n>  \n> -\tctrlValue = sensorCtrls.get(V4L2_CID_EXPOSURE);\n> +\tctrlValue = sensorControls.get(V4L2_CID_EXPOSURE);\n>  \tif (!ctrlValue.isNone())\n>  \t\teffectiveExpo = ctrlValue.get<int32_t>();\n>  \n> -\tctrlValue = sensorCtrls.get(V4L2_CID_ANALOGUE_GAIN);\n> +\tctrlValue = sensorControls.get(V4L2_CID_ANALOGUE_GAIN);\n>  \tif (!ctrlValue.isNone())\n>  \t\teffectiveGain = ctrlValue.get<int32_t>();\n>  \n> @@ -472,6 +431,35 @@ void IPAIPU3::parseStatistics(unsigned int frame,\n>  \tmetadataReady.emit(frame, ctrls);\n>  }\n>  \n> +void IPAIPU3::runAiq([[maybe_unused]] unsigned int frame)\n> +{\n> +\t/* Run algorithms into/using this context structure */\n> +\tresultsHistory_.extendOne();\n> +\taiq::AiqResults& latestResults = resultsHistory_.latest();\n> +\n> +\t/* Todo: Refactor AiqInputParameters interface to set following parameters. */\n> +\taiqInputParams_.afParams.lens_position = lensPosition_;\n> +\taiqInputParams_.afParams.lens_movement_start_timestamp = lensMovementStartTime_;\n> +\n> +\taiq_.run2a(frame, aiqInputParams_, latestResults);\n> +\n> +\texposure_ = latestResults.ae()->exposures[0].sensor_exposure->coarse_integration_time;\n> +\tgain_ = latestResults.ae()->exposures[0].sensor_exposure->analog_gain_code_global;\n> +\n> +\t/*\n> +\t * Af algorithm compares the timestamp of start of the lens movement and\n> +\t * that of the statistics generated to estimate whether next lens\n> +\t * position should be produced.\n> +\t * \\todo use the lens movement start time reported by the pipeline handler.\n> +\t */\n> +\tif (lensPosition_ != latestResults.af()->next_lens_position) {\n> +\t\tutils::time_point time = utils::clock::now();\n> +\t\tuint64_t usecs = std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch()).count();\n> +\t\tlensMovementStartTime_ = usecs;\n> +\t}\n> +\tlensPosition_ = latestResults.af()->next_lens_position;\n> +}\n> +\n>  void IPAIPU3::setControls(unsigned int frame)\n>  {\n>  \tControlList sensorCtrls(ctrls_);\n> -- \n> 2.31.0\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 88744C0F1B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  8 Apr 2022 07:19:55 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3E34C65642;\n\tFri,  8 Apr 2022 09:19:55 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E297A61FBA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  8 Apr 2022 09:19:53 +0200 (CEST)","from pyrite.rasen.tech (softbank036240056250.bbtec.net\n\t[36.240.56.250])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 6027E499;\n\tFri,  8 Apr 2022 09:19:52 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1649402395;\n\tbh=9t56k+AULcbZBr9mp8VzPkgR5O4lwjl36Z1dsRGsHxQ=;\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=1Exi89i7NzELOxk537S6CutvruVNAdL++6x08SuhWHDJ3usbh0CcRXF8cNQnvWArv\n\t0ECzjg9u1xld+91tophYAQRuw7PVuFVLCKDnD8vGgypdINXWlg0/7rXG4/MeoAYSvE\n\tVL6RqzdF1sBb+49rBIog5drfDVjJ3JnpRU2BLgScbSsavdFAlzlM5CkhlqBf/V8DPM\n\tjuVRz5CuLiX8cT/9NRZlduKPmmj4SL+LMKm20fZAIGvQph17NClLd5EExhfsKLywZi\n\ttOfCkQibH9rBzHm74jzoHgpYMetOGyUErOfg64Lg/RfBmUas8vau31y8az9yQJr1TU\n\tcqV4/RirJLvEg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1649402393;\n\tbh=9t56k+AULcbZBr9mp8VzPkgR5O4lwjl36Z1dsRGsHxQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=sA1dz5GkACNaCWh1UThSoEzwFPNhv2UezhFvLfQIKFujIX8CovmxMFuZ9vDHPQTcj\n\tQ0vghfi1zuVGr4Z9HL30sylmbp7BEjPeC61yHO9xuxS6VK1UhwyNF1LOxjj87EPEGe\n\tdFzQou0u1PQEwLH2qRds35H6ZklBy1/2O5zh4O48="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"sA1dz5Gk\"; dkim-atps=neutral","Date":"Fri, 8 Apr 2022 16:19:46 +0900","To":"Umang Jain <umang.jain@ideasonboard.com>","Message-ID":"<20220408071946.GR3237525@pyrite.rasen.tech>","References":"<20220406141709.164794-1-umang.jain@ideasonboard.com>\n\t<20220406141709.164794-7-umang.jain@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20220406141709.164794-7-umang.jain@ideasonboard.com>","Subject":"Re: [libcamera-devel] [IPAIPU3 PATCH v5 6/6] ipa: ipu3: Inline\n\tparseStatistics() into processStatsBuffer()","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":"Paul Elder via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"paul.elder@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>"}}]