From patchwork Fri Nov 14 14:17:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 25070 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 63296C3337 for ; Fri, 14 Nov 2025 14:17:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E7DC960ABA; Fri, 14 Nov 2025 15:17:43 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="wbyvHsUX"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CB54560ABA for ; Fri, 14 Nov 2025 15:17:24 +0100 (CET) Received: from [192.168.1.101] (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C86591F37; Fri, 14 Nov 2025 15:15:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1763129724; bh=h8FMFv/BsfC3u4TGP5N6VoUOd9JL4a85sWM8Gy+/rjs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=wbyvHsUXGRpC4by0p+TJItgaJNSBWadvRGvFjwS983PobJMRr8XZ1Vglu6gPczygo e3vw6LZxIGDiT+0GTLxzb03GJ96y6gPZtmk1B/5BObpbtAnBS9SxXNOJLeSZ/mB2T6 ChUY8P7pJQ6S2UbA2hrNzdUrSAuhGiVZtoae38LU= From: Jacopo Mondi Date: Fri, 14 Nov 2025 15:17:13 +0100 Subject: [PATCH v3 18/19] ipa: libipa: agc: Initialize a sensible frame duration MIME-Version: 1.0 Message-Id: <20251114-exposure-limits-v3-18-b7c07feba026@ideasonboard.com> References: <20251114-exposure-limits-v3-0-b7c07feba026@ideasonboard.com> In-Reply-To: <20251114-exposure-limits-v3-0-b7c07feba026@ideasonboard.com> To: =?utf-8?q?Niklas_S=C3=B6derlund?= , Robert Mader , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=5199; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=h8FMFv/BsfC3u4TGP5N6VoUOd9JL4a85sWM8Gy+/rjs=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBpFznsEddLKFNFfl9vWvFoI6CAFOdWVGdzpegVy lRSLD1/pk6JAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaRc57AAKCRByNAaPFqFW PDQ5D/4zVHEE1O/zQgHXy1zZdxs5e8011aT+U9w7aA1wPL26LdnwwWrUhEkjuLx5HIfvrJLegL/ +RKsMCe2kQKSFQGqqGfdY8zucBo0q9K+FVb08MzMO0yx/ES/xpGoMsIiVLJwpjkY9GFEfLPOLZF lS/IP0DByUBNOy8XrgTUuyfDGMWUgXW3km+FfB0h+8yy1O8lRO213M7A/NksgMCNPLj++N3np73 N9RjJZQ50rrJ7wMbxkrznAtPFUtZzw/kj+tbI2TBJMZQAp2XHVUHFhXLX8bo+wvsn/CwWniM3+b lrER80u9PaDctSzp3P9fJzC+/ms5aNok5ra+URAAiZw0xLbpw1EPTJfuMzEIJOdcxzSH8eJeOP0 QxK27H+owccPJ7Wu5zFK/ZARERWcgNMfOjb50oXr7qREhyXvL/v0QnHGiqO9jO+gL1A4fFAuoI1 4iBsV0Z2kZX0MdrzCdleRceVccwYTQwiFtE07/I8yyRmmGPbrAKm/Q7UgtH26npO5fefdhG3hx4 8ofLGjvj50ks6oCEqxQW536tchm61wDySFHKEyx6eddJqEQAl5EWa1kvk7Bw3msggibnxizBvw3 o2lELUjWUYD9ZhPdzVV1PvaR3cL0ESPHXC4lpoe6jVf+KXDVoJabM9anEu8uoK3X7wx8UZgKpnk pjM4QDEIH1F33vg== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The AGC algorithm implemented by AgcMeanLuminance splits the desired exposure between shutter time, analogue and digital gains. It tries to maximize the shutter time up to the specified limits and then increases the gains. When initializing the algorithm at configure() time the IPA modules have access to the Camera's absolute limits, which might include a very long maximum frame duration. If such duration is used to clamp the maximum exposure, the algorithm will maximize the shutter time, resulting in a very low frame rate. Try to pick a slighlty saner default of 30, 15 or 10 fps to limit the maximum shutter time with to provide a reasonable out-of-the-box behaviour for users. The new frame duration limit calculated by the AGC algorithm is passed back to the IPA module that shall use it to compute the right blankings to configure the camera with. At the moment, only the RkISP1 IPA actually controls the frame duration, and so it is the only IPA that needs to use the frame duration as computed by the AGC algorithm. Signed-off-by: Jacopo Mondi --- src/ipa/libipa/agc_mean_luminance.cpp | 27 ++++++++++++++++++++++++--- src/ipa/libipa/agc_mean_luminance.h | 4 ++-- src/ipa/rkisp1/algorithms/agc.cpp | 3 ++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp index b930e1f7240d4936aa8dc850657bbbf9c2f3a11f..f6768958c0d3d76108561b9455a15c715a89048e 100644 --- a/src/ipa/libipa/agc_mean_luminance.cpp +++ b/src/ipa/libipa/agc_mean_luminance.cpp @@ -353,10 +353,29 @@ int AgcMeanLuminance::parseExposureModes(const YamlObject &tuningData) * This function configures the exposure mode helpers by providing them the * sensor configuration parameters and the sensor helper, so they can correctly * take quantization effects into account. + * + * It computes a reasonable frame duration in the sensor's limits and returns it + * to the IPA for configuring the sensor's blankings. + * */ -void AgcMeanLuminance::configure(const SensorConfiguration &config, - const CameraSensorHelper *sensorHelper) +utils::Duration AgcMeanLuminance::configure(const SensorConfiguration &config, + const CameraSensorHelper *sensorHelper) { + + utils::Duration minFrameDuration = config.minFrameDuration; + utils::Duration maxFrameDuration = config.maxFrameDuration; + + static constexpr utils::Duration duration30fps = 33333 * 1us; + static constexpr utils::Duration duration15fps = 66666 * 1us; + static constexpr utils::Duration duration10fps = 100000 * 1us; + utils::Duration frameDuration = minFrameDuration < duration30fps + ? duration30fps + : minFrameDuration < duration15fps + ? duration15fps + : minFrameDuration < duration10fps + ? duration10fps : minFrameDuration; + frameDuration = std::min(frameDuration, maxFrameDuration); + for (auto &[id, helper] : exposureModeHelpers_) { /* * Translate from the SensorConfiguration to the @@ -370,7 +389,7 @@ void AgcMeanLuminance::configure(const SensorConfiguration &config, sensorConfig.lineDuration_ = config.lineDuration; sensorConfig.minExposureTime_ = config.minExposureTime; sensorConfig.minFrameDuration_ = config.minFrameDuration; - sensorConfig.maxFrameDuration_ = config.maxFrameDuration; + sensorConfig.maxFrameDuration_ = frameDuration; sensorConfig.minGain_ = config.minAnalogueGain; sensorConfig.maxGain_ = config.maxAnalogueGain; @@ -378,6 +397,8 @@ void AgcMeanLuminance::configure(const SensorConfiguration &config, } resetFrameCount(); + + return frameDuration; } /** diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h index 93a0959bbd9e0d6ec42248f2d3b19253ad389ae6..d66da7671c313e5acb959018b08a82335b7170b8 100644 --- a/src/ipa/libipa/agc_mean_luminance.h +++ b/src/ipa/libipa/agc_mean_luminance.h @@ -51,8 +51,8 @@ public: double maxAnalogueGain; }; - void configure(const SensorConfiguration &config, - const CameraSensorHelper *sensorHelper); + utils::Duration configure(const SensorConfiguration &config, + const CameraSensorHelper *sensorHelper); int parseTuningData(const YamlObject &tuningData); void setExposureCompensation(double gain) diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index 10498eb6357d8917e299ac24f6c8ba8c33af4eae..eac193b9aadfb17b7b6a02dcff2f3aa0b56dff84 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -207,7 +207,8 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) sensorConfig.minAnalogueGain = context.configuration.sensor.minAnalogueGain; sensorConfig.maxAnalogueGain = context.configuration.sensor.maxAnalogueGain; - AgcMeanLuminance::configure(sensorConfig, context.camHelper.get()); + context.activeState.agc.maxFrameDuration = + AgcMeanLuminance::configure(sensorConfig, context.camHelper.get()); context.activeState.agc.automatic.yTarget = effectiveYTarget();