[v2,08/10] ipa: libipa: agc: Initialize a sensible frame duration
diff mbox series

Message ID 20251028-exposure-limits-v2-8-a8b5a318323e@ideasonboard.com
State New
Headers show
Series
  • libipa: agc: Calculate exposure limits
Related show

Commit Message

Jacopo Mondi Oct. 28, 2025, 9:31 a.m. UTC
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 limit
computed by the AGC algorithm.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 src/ipa/ipu3/algorithms/agc.cpp         |  4 +++-
 src/ipa/libipa/agc_mean_luminance.cpp   | 20 ++++++++++++++------
 src/ipa/libipa/agc_mean_luminance.h     |  3 ++-
 src/ipa/libipa/exposure_mode_helper.cpp | 21 +++++++++++++++++----
 src/ipa/libipa/exposure_mode_helper.h   |  7 ++++---
 src/ipa/mali-c55/algorithms/agc.cpp     |  4 +++-
 src/ipa/rkisp1/algorithms/agc.cpp       | 13 +++++++++----
 7 files changed, 52 insertions(+), 20 deletions(-)

Patch
diff mbox series

diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp
index 3a9cde22323719d73ac125179dbfcd5158b352ea..51aa4e51841ca8c6363c0211819a7d14cc3baec6 100644
--- a/src/ipa/ipu3/algorithms/agc.cpp
+++ b/src/ipa/ipu3/algorithms/agc.cpp
@@ -120,13 +120,15 @@  int Agc::configure(IPAContext &context,
 	AgcMeanLuminance::AgcSensorConfiguration sensorConfig;
 	sensorConfig.lineDuration = context.configuration.sensor.lineDuration;
 	sensorConfig.minExposureTime = minExposureTime_;
+	sensorConfig.minFrameDuration =
+		std::chrono::microseconds(frameDurationLimits.min().get<int64_t>());
 	sensorConfig.maxFrameDuration =
 		std::chrono::microseconds(frameDurationLimits.max().get<int64_t>());
 	sensorConfig.maxExposureTime = maxExposureTime_;
 	sensorConfig.minAnalogueGain = minAnalogueGain_;
 	sensorConfig.maxAnalogueGain = maxAnalogueGain_;
 
-	AgcMeanLuminance::configure(sensorConfig, context.camHelper.get());
+	AgcMeanLuminance::configure(&sensorConfig, context.camHelper.get());
 
 	/* \todo Update AGC limits when FrameDurationLimits is passed in */
 
diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp
index 1098865519ca9ca2679331edd9441720366c717d..36bdf76dca45c837d5ef4eb03244a43d1262c675 100644
--- a/src/ipa/libipa/agc_mean_luminance.cpp
+++ b/src/ipa/libipa/agc_mean_luminance.cpp
@@ -121,6 +121,11 @@  static constexpr double kMaxRelativeLuminanceTarget = 0.95;
  * \brief The sensor maximum exposure time in microseconds
  */
 
+/**
+ * \var AgcMeanLuminance::AgcSensorConfiguration::minFrameDuration
+ * \brief The sensor minimum exposure time in microseconds
+ */
+
 /**
  * \var AgcMeanLuminance::AgcSensorConfiguration::maxFrameDuration
  * \brief The sensor maximum frame duration in microseconds
@@ -355,21 +360,24 @@  int AgcMeanLuminance::parseExposureModes(const YamlObject &tuningData)
 
 /**
  * \brief Configure the exposure mode helpers
- * \param[in] config The sensor configuration
+ * \param[inout] config The sensor configuration
  * \param[in] sensorHelper The sensor helper
  *
  * 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.
+ *
+ * The maximum frame duration passed in as a member of \a config is updated to
+ * the AGC algorithm startup value.
  */
-void AgcMeanLuminance::configure(const AgcSensorConfiguration &config,
+void AgcMeanLuminance::configure(AgcSensorConfiguration *config,
 				 const CameraSensorHelper *sensorHelper)
 {
 	for (auto &[id, helper] : exposureModeHelpers_)
-		helper->configure(config.lineDuration,
-				  config.minExposureTime, config.maxExposureTime,
-				  config.maxFrameDuration,
-				  config.minAnalogueGain, config.maxAnalogueGain,
+		helper->configure(config->lineDuration,
+				  config->minExposureTime, config->maxExposureTime,
+				  config->minFrameDuration, &config->maxFrameDuration,
+				  config->minAnalogueGain, config->maxAnalogueGain,
 				  sensorHelper);
 }
 
diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h
index 0f7a4f53188d8d2759076c37d186efc088ddd279..b00772760035a477152d638809ac71fcbc66cb68 100644
--- a/src/ipa/libipa/agc_mean_luminance.h
+++ b/src/ipa/libipa/agc_mean_luminance.h
@@ -46,12 +46,13 @@  public:
 		utils::Duration lineDuration;
 		utils::Duration minExposureTime;
 		utils::Duration maxExposureTime;
+		utils::Duration minFrameDuration;
 		utils::Duration maxFrameDuration;
 		double minAnalogueGain;
 		double maxAnalogueGain;
 	};
 
-	void configure(const AgcSensorConfiguration &config,
+	void configure(AgcSensorConfiguration *config,
 		       const CameraSensorHelper *sensorHelper);
 	int parseTuningData(const YamlObject &tuningData);
 
diff --git a/src/ipa/libipa/exposure_mode_helper.cpp b/src/ipa/libipa/exposure_mode_helper.cpp
index d1d94cf46d5ef2c077508fd94dfe9715fdbc6f03..46ba535c67d92bd384095b250b925cdc0da40b38 100644
--- a/src/ipa/libipa/exposure_mode_helper.cpp
+++ b/src/ipa/libipa/exposure_mode_helper.cpp
@@ -111,7 +111,8 @@  void ExposureModeHelper::setMaxExposure(utils::Duration minExposureTime,
  * \param[in] lineDuration The current line length of the sensor
  * \param[in] minExposureTime The minimum exposure time supported
  * \param[in] maxExposureTime The maximum exposure time supported
- * \param[in] maxFrameDuration The maximum frame duration
+ * \param[in] minFrameDuration The minimum frame duration
+ * \param[inout] maxFrameDuration The maximum frame duration
  * \param[in] minGain The minimum analogue gain supported
  * \param[in] maxGain The maximum analogue gain supported
  * \param[in] sensorHelper The sensor helper
@@ -128,17 +129,29 @@  void ExposureModeHelper::setMaxExposure(utils::Duration minExposureTime,
 void ExposureModeHelper::configure(utils::Duration lineDuration,
 				   utils::Duration minExposureTime,
 				   utils::Duration maxExposureTime,
-				   utils::Duration maxFrameDuration,
+				   utils::Duration minFrameDuration,
+				   utils::Duration *maxFrameDuration,
 				   double minGain, double maxGain,
 				   const CameraSensorHelper *sensorHelper)
 {
 	lineDuration_ = lineDuration;
-	maxFrameDuration_ = maxFrameDuration;
 	minGain_ = minGain;
 	maxGain_ = maxGain;
 	sensorHelper_ = sensorHelper;
 
-	setMaxExposure(minExposureTime, maxExposureTime, maxFrameDuration);
+	static constexpr utils::Duration duration30fps = 33.333 * 1ms;
+	static constexpr utils::Duration duration15fps = 66.666 * 1ms;
+	static constexpr utils::Duration duration10fps = 100.00 * 1ms;
+	utils::Duration frameDuration = minFrameDuration < duration30fps
+				      ? duration30fps
+				        : minFrameDuration < duration15fps
+					? duration15fps
+					  : minFrameDuration < duration10fps
+					  ? duration10fps : minFrameDuration;
+	frameDuration = std::min(frameDuration, *maxFrameDuration);
+	setMaxExposure(minExposureTime, maxExposureTime, frameDuration);
+
+	maxFrameDuration_ = *maxFrameDuration = frameDuration;
 }
 
 /**
diff --git a/src/ipa/libipa/exposure_mode_helper.h b/src/ipa/libipa/exposure_mode_helper.h
index b1de96d4a3a13e3771ff2162f11201e5f9253265..492d2787f75945fb487b351a60f13756caec66e0 100644
--- a/src/ipa/libipa/exposure_mode_helper.h
+++ b/src/ipa/libipa/exposure_mode_helper.h
@@ -27,11 +27,12 @@  public:
 	~ExposureModeHelper() = default;
 
 	void configure(utils::Duration lineLength, utils::Duration minExposureTime,
-		       utils::Duration maxExposureTime, utils::Duration maxFrameDuration,
-		       double minGain, double maxGain,
+		       utils::Duration maxExposureTime, utils::Duration minFrameDuration,
+		       utils::Duration *maxFrameDuration, double minGain, double maxGain,
 		       const CameraSensorHelper *sensorHelper);
 	void setLimits(utils::Duration minExposureTime, utils::Duration maxExposureTime,
-		       utils::Duration maxFrameDuration, double minGain, double maxGain);
+		       utils::Duration maxFrameDuration,
+		       double minGain, double maxGain);
 
 	std::tuple<utils::Duration, double, double, double>
 	splitExposure(utils::Duration exposure) const;
diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp
index 5bfb4ab17ecb3814a10baec0f619267772ed8b3f..4e2fa4386be621c63d992b75d3d9efc525c3d69c 100644
--- a/src/ipa/mali-c55/algorithms/agc.cpp
+++ b/src/ipa/mali-c55/algorithms/agc.cpp
@@ -175,12 +175,14 @@  int Agc::configure(IPAContext &context,
 	sensorConfig.lineDuration = context.configuration.sensor.lineDuration;
 	sensorConfig.minExposureTime = context.configuration.agc.minShutterSpeed;
 	sensorConfig.maxExposureTime = context.configuration.agc.maxShutterSpeed;
+	sensorConfig.minFrameDuration =
+		std::chrono::microseconds(frameDurationLimits.min().get<int64_t>());
 	sensorConfig.maxFrameDuration =
 		std::chrono::microseconds(frameDurationLimits.max().get<int64_t>());
 	sensorConfig.minAnalogueGain = context.configuration.agc.minAnalogueGain;
 	sensorConfig.maxAnalogueGain = context.configuration.agc.maxAnalogueGain;
 
-	AgcMeanLuminance::configure(sensorConfig, context.camHelper.get());
+	AgcMeanLuminance::configure(&sensorConfig, context.camHelper.get());
 
 	/* \todo Update AGC limits when FrameDurationLimits is passed in */
 
diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp
index 96189254885c47d29b92f3fb40f0e86d10e2a7fc..a983efbecbd84fa9e4af8b9642fbdda124ba0b9f 100644
--- a/src/ipa/rkisp1/algorithms/agc.cpp
+++ b/src/ipa/rkisp1/algorithms/agc.cpp
@@ -190,10 +190,13 @@  int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
 	context.activeState.agc.meteringMode =
 		static_cast<controls::AeMeteringModeEnum>(meteringModes_.begin()->first);
 
-	/* Limit the frame duration to match current initialisation */
+	/*
+	 * Initialize frame duration with the camera limits and update it to
+	 * the value computed by AgcMeanLuminance::configure().
+	 */
 	ControlInfo &frameDurationLimits = context.ctrlMap[&controls::FrameDurationLimits];
 	context.activeState.agc.minFrameDuration = std::chrono::microseconds(frameDurationLimits.min().get<int64_t>());
-	context.activeState.agc.maxFrameDuration = std::chrono::microseconds(frameDurationLimits.max().get<int64_t>());
+	utils::Duration maxFrameDuration = std::chrono::microseconds(frameDurationLimits.max().get<int64_t>());
 
 	context.configuration.agc.measureWindow.h_offs = 0;
 	context.configuration.agc.measureWindow.v_offs = 0;
@@ -204,12 +207,14 @@  int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
 	sensorConfig.lineDuration = context.configuration.sensor.lineDuration;
 	sensorConfig.minExposureTime = context.configuration.sensor.minExposureTime;
 	sensorConfig.maxExposureTime = context.configuration.sensor.maxExposureTime;
-	sensorConfig.maxFrameDuration = context.activeState.agc.maxFrameDuration;
+	sensorConfig.minFrameDuration = context.activeState.agc.minFrameDuration;
+	sensorConfig.maxFrameDuration = maxFrameDuration;
 	sensorConfig.minAnalogueGain = context.configuration.sensor.minAnalogueGain;
 	sensorConfig.maxAnalogueGain = context.configuration.sensor.maxAnalogueGain;
 
-	AgcMeanLuminance::configure(sensorConfig, context.camHelper.get());
+	AgcMeanLuminance::configure(&sensorConfig, context.camHelper.get());
 
+	context.activeState.agc.maxFrameDuration = sensorConfig.maxFrameDuration;
 	context.activeState.agc.automatic.yTarget = effectiveYTarget();
 
 	resetFrameCount();