[{"id":25889,"web_url":"https://patchwork.libcamera.org/comment/25889/","msgid":"<20221124122311.eqymp5ltjv6d2pqz@uno.localdomain>","date":"2022-11-24T12:23:11","subject":"Re: [libcamera-devel] [PATCH v4 4/9] ipa: rkisp1: Add support for\n\tmanual gain and exposure","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent\n\nOn Thu, Nov 24, 2022 at 04:51:28AM +0200, Laurent Pinchart via libcamera-devel wrote:\n> From: Paul Elder <paul.elder@ideasonboard.com>\n>\n> Add support for manual gain and exposure in the rkisp1 IPA.\n>\n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nLooks good!\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n  j\n\n> ---\n> Changes since v3:\n>\n> - Convert exposure and gain V4L2 controls limits to libcamera values\n> - Convert exposure control from duration to lines in AGC\n> - Initialize lineDuration in init()\n> - Small fixes in debug messages\n> - Drop unnecessary curly braces\n> - Use std::piecewise_construct\n> ---\n>  src/ipa/rkisp1/algorithms/agc.cpp | 63 +++++++++++++++++++++++++++----\n>  src/ipa/rkisp1/algorithms/agc.h   |  4 ++\n>  src/ipa/rkisp1/ipa_context.h      | 13 ++++++-\n>  src/ipa/rkisp1/rkisp1.cpp         | 25 ++++++++++++\n>  4 files changed, 96 insertions(+), 9 deletions(-)\n>\n> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> index 169afe372803..ccbcd4a9583d 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/agc.cpp\n> @@ -74,9 +74,14 @@ Agc::Agc()\n>  int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n>  {\n>  \t/* Configure the default exposure and gain. */\n> -\tcontext.activeState.agc.gain = std::max(context.configuration.sensor.minAnalogueGain,\n> -\t\t\t\t\t\tkMinAnalogueGain);\n> -\tcontext.activeState.agc.exposure = 10ms / context.configuration.sensor.lineDuration;\n> +\tcontext.activeState.agc.automatic.gain =\n> +\t\tstd::max(context.configuration.sensor.minAnalogueGain,\n> +\t\t\t kMinAnalogueGain);\n> +\tcontext.activeState.agc.automatic.exposure =\n> +\t\t10ms / context.configuration.sensor.lineDuration;\n> +\tcontext.activeState.agc.manual.gain = context.activeState.agc.automatic.gain;\n> +\tcontext.activeState.agc.manual.exposure = context.activeState.agc.automatic.exposure;\n> +\tcontext.activeState.agc.autoEnabled = true;\n>\n>  \t/*\n>  \t * According to the RkISP1 documentation:\n> @@ -108,14 +113,58 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n>  \treturn 0;\n>  }\n>\n> +/**\n> + * \\copydoc libcamera::ipa::Algorithm::queueRequest\n> + */\n> +void Agc::queueRequest(IPAContext &context,\n> +\t\t       [[maybe_unused]] const uint32_t frame,\n> +\t\t       IPAFrameContext &frameContext,\n> +\t\t       const ControlList &controls)\n> +{\n> +\tauto &agc = context.activeState.agc;\n> +\n> +\tconst auto &agcEnable = controls.get(controls::AeEnable);\n> +\tif (agcEnable && *agcEnable != agc.autoEnabled) {\n> +\t\tagc.autoEnabled = *agcEnable;\n> +\n> +\t\tLOG(RkISP1Agc, Debug)\n> +\t\t\t<< (agc.autoEnabled ? \"Enabling\" : \"Disabling\") << \" AGC\";\n> +\t}\n> +\n> +\tconst auto &exposure = controls.get(controls::ExposureTime);\n> +\tif (exposure && !agc.autoEnabled) {\n> +\t\tagc.manual.exposure = *exposure * 1.0us\n> +\t\t\t\t    / context.configuration.sensor.lineDuration;\n> +\n> +\t\tLOG(RkISP1Agc, Debug)\n> +\t\t\t<< \"Set exposure to \" << agc.manual.exposure;\n> +\t}\n> +\n> +\tconst auto &gain = controls.get(controls::AnalogueGain);\n> +\tif (gain && !agc.autoEnabled) {\n> +\t\tagc.manual.gain = *gain;\n> +\n> +\t\tLOG(RkISP1Agc, Debug) << \"Set gain to \" << agc.manual.gain;\n> +\t}\n> +\n> +\tframeContext.agc.autoEnabled = agc.autoEnabled;\n> +\n> +\tif (!frameContext.agc.autoEnabled) {\n> +\t\tframeContext.agc.exposure = agc.manual.exposure;\n> +\t\tframeContext.agc.gain = agc.manual.gain;\n> +\t}\n> +}\n> +\n>  /**\n>   * \\copydoc libcamera::ipa::Algorithm::prepare\n>   */\n>  void Agc::prepare(IPAContext &context, const uint32_t frame,\n>  \t\t  IPAFrameContext &frameContext, rkisp1_params_cfg *params)\n>  {\n> -\tframeContext.agc.exposure = context.activeState.agc.exposure;\n> -\tframeContext.agc.gain = context.activeState.agc.gain;\n> +\tif (frameContext.agc.autoEnabled) {\n> +\t\tframeContext.agc.exposure = context.activeState.agc.automatic.exposure;\n> +\t\tframeContext.agc.gain = context.activeState.agc.automatic.gain;\n> +\t}\n>\n>  \tif (frame > 0)\n>  \t\treturn;\n> @@ -263,8 +312,8 @@ void Agc::computeExposure(IPAContext &context, IPAFrameContext &frameContext,\n>  \t\t\t      << stepGain;\n>\n>  \t/* Update the estimated exposure and gain. */\n> -\tactiveState.agc.exposure = shutterTime / configuration.sensor.lineDuration;\n> -\tactiveState.agc.gain = stepGain;\n> +\tactiveState.agc.automatic.exposure = shutterTime / configuration.sensor.lineDuration;\n> +\tactiveState.agc.automatic.gain = stepGain;\n>  }\n>\n>  /**\n> diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\n> index da4d2d4e8359..a228d0c37768 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.h\n> +++ b/src/ipa/rkisp1/algorithms/agc.h\n> @@ -26,6 +26,10 @@ public:\n>  \t~Agc() = default;\n>\n>  \tint configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override;\n> +\tvoid queueRequest(IPAContext &context,\n> +\t\t\t  const uint32_t frame,\n> +\t\t\t  IPAFrameContext &frameContext,\n> +\t\t\t  const ControlList &controls) override;\n>  \tvoid prepare(IPAContext &context, const uint32_t frame,\n>  \t\t     IPAFrameContext &frameContext,\n>  \t\t     rkisp1_params_cfg *params) override;\n> diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\n> index 3e47ac663c58..b9b2065328d6 100644\n> --- a/src/ipa/rkisp1/ipa_context.h\n> +++ b/src/ipa/rkisp1/ipa_context.h\n> @@ -54,8 +54,16 @@ struct IPASessionConfiguration {\n>\n>  struct IPAActiveState {\n>  \tstruct {\n> -\t\tuint32_t exposure;\n> -\t\tdouble gain;\n> +\t\tstruct {\n> +\t\t\tuint32_t exposure;\n> +\t\t\tdouble gain;\n> +\t\t} manual;\n> +\t\tstruct {\n> +\t\t\tuint32_t exposure;\n> +\t\t\tdouble gain;\n> +\t\t} automatic;\n> +\n> +\t\tbool autoEnabled;\n>  \t} agc;\n>\n>  \tstruct {\n> @@ -96,6 +104,7 @@ struct IPAFrameContext : public FrameContext {\n>  \tstruct {\n>  \t\tuint32_t exposure;\n>  \t\tdouble gain;\n> +\t\tbool autoEnabled;\n>  \t} agc;\n>\n>  \tstruct {\n> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> index 6ac29df8ec8d..76e818d2d11e 100644\n> --- a/src/ipa/rkisp1/rkisp1.cpp\n> +++ b/src/ipa/rkisp1/rkisp1.cpp\n> @@ -158,6 +158,9 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,\n>  \t\treturn -ENODEV;\n>  \t}\n>\n> +\tcontext_.configuration.sensor.lineDuration = sensorInfo.minLineLength\n> +\t\t\t\t\t\t   * 1.0s / sensorInfo.pixelRate;\n> +\n>  \t/* Load the tuning data file. */\n>  \tFile file(settings.configurationFile);\n>  \tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n> @@ -377,6 +380,28 @@ void IPARkISP1::updateControls(const IPACameraSensorInfo &sensorInfo,\n>  {\n>  \tControlInfoMap::Map ctrlMap = rkisp1Controls;\n>\n> +\t/*\n> +\t * Compute exposure time limits from the V4L2_CID_EXPOSURE control\n> +\t * limits and the line duration.\n> +\t */\n> +\tdouble lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();\n> +\tconst ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;\n> +\tint32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;\n> +\tint32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;\n> +\tint32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;\n> +\tctrlMap.emplace(std::piecewise_construct,\n> +\t\t\tstd::forward_as_tuple(&controls::ExposureTime),\n> +\t\t\tstd::forward_as_tuple(minExposure, maxExposure, defExposure));\n> +\n> +\t/* Compute the analogue gain limits. */\n> +\tconst ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;\n> +\tfloat minGain = camHelper_->gain(v4l2Gain.min().get<int32_t>());\n> +\tfloat maxGain = camHelper_->gain(v4l2Gain.max().get<int32_t>());\n> +\tfloat defGain = camHelper_->gain(v4l2Gain.def().get<int32_t>());\n> +\tctrlMap.emplace(std::piecewise_construct,\n> +\t\t\tstd::forward_as_tuple(&controls::AnalogueGain),\n> +\t\t\tstd::forward_as_tuple(minGain, maxGain, defGain));\n> +\n>  \t/*\n>  \t * Compute the frame duration limits.\n>  \t *\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 31508BDE6B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 24 Nov 2022 12:23:16 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8FE0963313;\n\tThu, 24 Nov 2022 13:23:15 +0100 (CET)","from relay11.mail.gandi.net (relay11.mail.gandi.net\n\t[217.70.178.231])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 80369632EA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 24 Nov 2022 13:23:13 +0100 (CET)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id B810A100004;\n\tThu, 24 Nov 2022 12:23:12 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1669292595;\n\tbh=cmNWngdrch6Mto/ulPD4f+QZaJJTlkgFQvvBGVGDiF0=;\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=d9vzDvPpFzIsf0iRuC8x86MJTaXhVaywe6Qvxf/oj8rRErgqwCVL0CQuN3hncujQo\n\thxaTwiWZP0TeLylS1foctk3wbbZnA5FKISxuqotB+hLVZGvaH43Z9WuBMMmroR38A1\n\t5svmMrdhhK61cdth9D6403zmQw6DmAUQC79VJ1V4hbUo9bqL4f8UnwyGrsUojlyE7e\n\tVI2iNzwJ9RHK3joXGuuvh/RHOF5xyii+o2SpLgOtyMqwdAL6vXqXyIVAt8k/eO3guo\n\tDPSNBUqBxJlpoP2YQMhqzRKUKODxv2HVls2VRQrD7IqKf1Z3LAtE74KxGgYoE5MCTP\n\tP8qrOW5rG5m8w==","Date":"Thu, 24 Nov 2022 13:23:11 +0100","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20221124122311.eqymp5ltjv6d2pqz@uno.localdomain>","References":"<20221124025133.17875-1-laurent.pinchart@ideasonboard.com>\n\t<20221124025133.17875-5-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20221124025133.17875-5-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 4/9] ipa: rkisp1: Add support for\n\tmanual gain and exposure","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":25910,"web_url":"https://patchwork.libcamera.org/comment/25910/","msgid":"<Y4BsFqvl6i/BXSr+@pyrite.rasen.tech>","date":"2022-11-25T07:17:42","subject":"Re: [libcamera-devel] [PATCH v4 4/9] ipa: rkisp1: Add support for\n\tmanual gain and exposure","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"On Thu, Nov 24, 2022 at 04:51:28AM +0200, Laurent Pinchart wrote:\n> From: Paul Elder <paul.elder@ideasonboard.com>\n> \n> Add support for manual gain and exposure in the rkisp1 IPA.\n> \n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n> Changes since v3:\n> \n> - Convert exposure and gain V4L2 controls limits to libcamera values\n> - Convert exposure control from duration to lines in AGC\n> - Initialize lineDuration in init()\n> - Small fixes in debug messages\n> - Drop unnecessary curly braces\n> - Use std::piecewise_construct\n> ---\n>  src/ipa/rkisp1/algorithms/agc.cpp | 63 +++++++++++++++++++++++++++----\n>  src/ipa/rkisp1/algorithms/agc.h   |  4 ++\n>  src/ipa/rkisp1/ipa_context.h      | 13 ++++++-\n>  src/ipa/rkisp1/rkisp1.cpp         | 25 ++++++++++++\n>  4 files changed, 96 insertions(+), 9 deletions(-)\n> \n> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> index 169afe372803..ccbcd4a9583d 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.cpp\n> +++ b/src/ipa/rkisp1/algorithms/agc.cpp\n> @@ -74,9 +74,14 @@ Agc::Agc()\n>  int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n>  {\n>  \t/* Configure the default exposure and gain. */\n> -\tcontext.activeState.agc.gain = std::max(context.configuration.sensor.minAnalogueGain,\n> -\t\t\t\t\t\tkMinAnalogueGain);\n> -\tcontext.activeState.agc.exposure = 10ms / context.configuration.sensor.lineDuration;\n> +\tcontext.activeState.agc.automatic.gain =\n> +\t\tstd::max(context.configuration.sensor.minAnalogueGain,\n> +\t\t\t kMinAnalogueGain);\n> +\tcontext.activeState.agc.automatic.exposure =\n> +\t\t10ms / context.configuration.sensor.lineDuration;\n> +\tcontext.activeState.agc.manual.gain = context.activeState.agc.automatic.gain;\n> +\tcontext.activeState.agc.manual.exposure = context.activeState.agc.automatic.exposure;\n> +\tcontext.activeState.agc.autoEnabled = true;\n>  \n>  \t/*\n>  \t * According to the RkISP1 documentation:\n> @@ -108,14 +113,58 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n>  \treturn 0;\n>  }\n>  \n> +/**\n> + * \\copydoc libcamera::ipa::Algorithm::queueRequest\n> + */\n> +void Agc::queueRequest(IPAContext &context,\n> +\t\t       [[maybe_unused]] const uint32_t frame,\n> +\t\t       IPAFrameContext &frameContext,\n> +\t\t       const ControlList &controls)\n> +{\n> +\tauto &agc = context.activeState.agc;\n> +\n> +\tconst auto &agcEnable = controls.get(controls::AeEnable);\n> +\tif (agcEnable && *agcEnable != agc.autoEnabled) {\n> +\t\tagc.autoEnabled = *agcEnable;\n> +\n> +\t\tLOG(RkISP1Agc, Debug)\n> +\t\t\t<< (agc.autoEnabled ? \"Enabling\" : \"Disabling\") << \" AGC\";\n> +\t}\n> +\n> +\tconst auto &exposure = controls.get(controls::ExposureTime);\n> +\tif (exposure && !agc.autoEnabled) {\n> +\t\tagc.manual.exposure = *exposure * 1.0us\n> +\t\t\t\t    / context.configuration.sensor.lineDuration;\n> +\n> +\t\tLOG(RkISP1Agc, Debug)\n> +\t\t\t<< \"Set exposure to \" << agc.manual.exposure;\n> +\t}\n> +\n> +\tconst auto &gain = controls.get(controls::AnalogueGain);\n> +\tif (gain && !agc.autoEnabled) {\n> +\t\tagc.manual.gain = *gain;\n> +\n> +\t\tLOG(RkISP1Agc, Debug) << \"Set gain to \" << agc.manual.gain;\n> +\t}\n> +\n> +\tframeContext.agc.autoEnabled = agc.autoEnabled;\n> +\n> +\tif (!frameContext.agc.autoEnabled) {\n> +\t\tframeContext.agc.exposure = agc.manual.exposure;\n> +\t\tframeContext.agc.gain = agc.manual.gain;\n> +\t}\n> +}\n> +\n>  /**\n>   * \\copydoc libcamera::ipa::Algorithm::prepare\n>   */\n>  void Agc::prepare(IPAContext &context, const uint32_t frame,\n>  \t\t  IPAFrameContext &frameContext, rkisp1_params_cfg *params)\n>  {\n> -\tframeContext.agc.exposure = context.activeState.agc.exposure;\n> -\tframeContext.agc.gain = context.activeState.agc.gain;\n> +\tif (frameContext.agc.autoEnabled) {\n> +\t\tframeContext.agc.exposure = context.activeState.agc.automatic.exposure;\n> +\t\tframeContext.agc.gain = context.activeState.agc.automatic.gain;\n> +\t}\n>  \n>  \tif (frame > 0)\n>  \t\treturn;\n> @@ -263,8 +312,8 @@ void Agc::computeExposure(IPAContext &context, IPAFrameContext &frameContext,\n>  \t\t\t      << stepGain;\n>  \n>  \t/* Update the estimated exposure and gain. */\n> -\tactiveState.agc.exposure = shutterTime / configuration.sensor.lineDuration;\n> -\tactiveState.agc.gain = stepGain;\n> +\tactiveState.agc.automatic.exposure = shutterTime / configuration.sensor.lineDuration;\n> +\tactiveState.agc.automatic.gain = stepGain;\n>  }\n>  \n>  /**\n> diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\n> index da4d2d4e8359..a228d0c37768 100644\n> --- a/src/ipa/rkisp1/algorithms/agc.h\n> +++ b/src/ipa/rkisp1/algorithms/agc.h\n> @@ -26,6 +26,10 @@ public:\n>  \t~Agc() = default;\n>  \n>  \tint configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override;\n> +\tvoid queueRequest(IPAContext &context,\n> +\t\t\t  const uint32_t frame,\n> +\t\t\t  IPAFrameContext &frameContext,\n> +\t\t\t  const ControlList &controls) override;\n>  \tvoid prepare(IPAContext &context, const uint32_t frame,\n>  \t\t     IPAFrameContext &frameContext,\n>  \t\t     rkisp1_params_cfg *params) override;\n> diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\n> index 3e47ac663c58..b9b2065328d6 100644\n> --- a/src/ipa/rkisp1/ipa_context.h\n> +++ b/src/ipa/rkisp1/ipa_context.h\n> @@ -54,8 +54,16 @@ struct IPASessionConfiguration {\n>  \n>  struct IPAActiveState {\n>  \tstruct {\n> -\t\tuint32_t exposure;\n> -\t\tdouble gain;\n> +\t\tstruct {\n> +\t\t\tuint32_t exposure;\n> +\t\t\tdouble gain;\n> +\t\t} manual;\n> +\t\tstruct {\n> +\t\t\tuint32_t exposure;\n> +\t\t\tdouble gain;\n> +\t\t} automatic;\n> +\n> +\t\tbool autoEnabled;\n>  \t} agc;\n>  \n>  \tstruct {\n> @@ -96,6 +104,7 @@ struct IPAFrameContext : public FrameContext {\n>  \tstruct {\n>  \t\tuint32_t exposure;\n>  \t\tdouble gain;\n> +\t\tbool autoEnabled;\n>  \t} agc;\n>  \n>  \tstruct {\n> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> index 6ac29df8ec8d..76e818d2d11e 100644\n> --- a/src/ipa/rkisp1/rkisp1.cpp\n> +++ b/src/ipa/rkisp1/rkisp1.cpp\n> @@ -158,6 +158,9 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,\n>  \t\treturn -ENODEV;\n>  \t}\n>  \n> +\tcontext_.configuration.sensor.lineDuration = sensorInfo.minLineLength\n> +\t\t\t\t\t\t   * 1.0s / sensorInfo.pixelRate;\n> +\n>  \t/* Load the tuning data file. */\n>  \tFile file(settings.configurationFile);\n>  \tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n> @@ -377,6 +380,28 @@ void IPARkISP1::updateControls(const IPACameraSensorInfo &sensorInfo,\n>  {\n>  \tControlInfoMap::Map ctrlMap = rkisp1Controls;\n>  \n> +\t/*\n> +\t * Compute exposure time limits from the V4L2_CID_EXPOSURE control\n> +\t * limits and the line duration.\n> +\t */\n> +\tdouble lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();\n> +\tconst ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;\n> +\tint32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;\n> +\tint32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;\n> +\tint32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;\n> +\tctrlMap.emplace(std::piecewise_construct,\n> +\t\t\tstd::forward_as_tuple(&controls::ExposureTime),\n> +\t\t\tstd::forward_as_tuple(minExposure, maxExposure, defExposure));\n> +\n> +\t/* Compute the analogue gain limits. */\n> +\tconst ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;\n> +\tfloat minGain = camHelper_->gain(v4l2Gain.min().get<int32_t>());\n> +\tfloat maxGain = camHelper_->gain(v4l2Gain.max().get<int32_t>());\n> +\tfloat defGain = camHelper_->gain(v4l2Gain.def().get<int32_t>());\n> +\tctrlMap.emplace(std::piecewise_construct,\n> +\t\t\tstd::forward_as_tuple(&controls::AnalogueGain),\n> +\t\t\tstd::forward_as_tuple(minGain, maxGain, defGain));\n> +\n>  \t/*\n>  \t * Compute the frame duration limits.","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 6CF09BE08B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 25 Nov 2022 07:17:54 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B970B6331B;\n\tFri, 25 Nov 2022 08:17:53 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2A81F61F26\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 25 Nov 2022 08:17:52 +0100 (CET)","from pyrite.rasen.tech (UQ036011224114.au-net.ne.jp\n\t[36.11.224.114])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 2C3424D5;\n\tFri, 25 Nov 2022 08:17:49 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1669360673;\n\tbh=1ZJ3isxojsHG0Kgo0krAYNyFM0DgaGY7ixbAJPaRfzQ=;\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=IaygcGVpC+DkWllOnZw3xlbePDtSuxY1P/rovJlMjqApnrhKQ7dbBEAUo4z4EQn/H\n\tF75XSQIUzdezSdG1XQ1amiRn0IcH5LqjZX5PUZRqKrnPU1iLC8aa9DnJQiLoYPcDFi\n\tDtvSsrd7Qj6RcjuTNSaCVU59chXvWu/1CbH38/CqhOD6jZp80r8ABepwbx/KMQxqVi\n\tLEbH5Ja3uf4jwOwb3HKlhZ71+8xhYNfaHUniSUIxa4hN4esqRkeE5O+q+sajUjrQuu\n\tRHaj2jmw8A7LxfNtRlkmTZxohoEPBhjxfwaXpxSKonzsplLM1O9i2MU/oe5p81Poob\n\tdivAVroAXBZtg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1669360671;\n\tbh=1ZJ3isxojsHG0Kgo0krAYNyFM0DgaGY7ixbAJPaRfzQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=DtjYnPn1WXDiX0wA2AKmHVVe+Xw46vrQPsURt7XPUVpdJU9GgF2ZC/fGJR+COF9L8\n\tHnbmGetxCBiss50ClkLZuixRscovOAJa4bhifu62owhe7tL6gEJxkEG6s+Fegx2+m5\n\tghlpicL/+2CLpLG22r5EBoPxCPJQ5ARqyhSupcq8="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"DtjYnPn1\"; dkim-atps=neutral","Date":"Fri, 25 Nov 2022 16:17:42 +0900","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<Y4BsFqvl6i/BXSr+@pyrite.rasen.tech>","References":"<20221124025133.17875-1-laurent.pinchart@ideasonboard.com>\n\t<20221124025133.17875-5-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20221124025133.17875-5-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 4/9] ipa: rkisp1: Add support for\n\tmanual gain and exposure","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 <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>"}}]