[libcamera-devel] [PATCH v1 2/3] ipa: raspberrypi: Populate SensorLimits

Naushir Patuck naush at raspberrypi.com
Wed Mar 22 17:13:16 CET 2023


Populate all the fields of the SensorLimits structure in configure().
This allows us to use the cached values instead of re-computing them
on every frame.

For the gain -> code convertion, ensure we clamp to the analogue gain
limits set in the SensorLimits structure.

Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
Reviewed-by: David Plowman <david.plowman at raspberrypi.com>
---
 src/ipa/raspberrypi/raspberrypi.cpp | 67 ++++++++++++++++-------------
 1 file changed, 38 insertions(+), 29 deletions(-)

diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
index c3b2c375036f..e8d8023bcfe7 100644
--- a/src/ipa/raspberrypi/raspberrypi.cpp
+++ b/src/ipa/raspberrypi/raspberrypi.cpp
@@ -224,8 +224,8 @@ private:
 	Duration minFrameDuration_;
 	Duration maxFrameDuration_;
 
-	/* Maximum gain code for the sensor. */
-	uint32_t maxSensorGainCode_;
+	/* Mode specific sensor gain/exposure limits. */
+	RPiController::AgcAlgorithm::SensorLimits sensorLimits_;
 
 	/* Track the frame length times over FrameLengthsQueueSize frames. */
 	std::deque<Duration> frameLengths_;
@@ -439,8 +439,6 @@ int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &ip
 		}
 	}
 
-	maxSensorGainCode_ = sensorCtrls_.at(V4L2_CID_ANALOGUE_GAIN).max().get<int32_t>();
-
 	/* Setup a metadata ControlList to output metadata. */
 	libcameraMetadata_ = ControlList(controls::controls);
 
@@ -473,6 +471,28 @@ int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &ip
 	/* Pass the camera mode to the CamHelper to setup algorithms. */
 	helper_->setCameraMode(mode_);
 
+	/*
+	 * Store the sensor gain and shutter limits for the mode.
+	 *
+	 * The maximum shutter value are calculated from the frame duration limit
+	 * as V4L2 will restrict the maximum control value based on the current
+	 * VBLANK value.
+	 *
+	 * These limits get set in the AGC algorithm through applyFrameDurations()
+	 * below.
+	 */
+	const ControlInfo &gainCtrl = sensorCtrls_.at(V4L2_CID_ANALOGUE_GAIN);
+	const ControlInfo &shutterCtrl = sensorCtrls_.at(V4L2_CID_EXPOSURE);
+
+	sensorLimits_.minAnalogueGain = helper_->gain(gainCtrl.min().get<int32_t>());
+	sensorLimits_.maxAnalogueGain = helper_->gain(gainCtrl.max().get<int32_t>());
+	sensorLimits_.minFrameDuration = mode_.minFrameLength * mode_.minLineLength;
+	sensorLimits_.maxFrameDuration = mode_.maxFrameLength * mode_.maxLineLength;
+	sensorLimits_.minShutter = helper_->exposure(shutterCtrl.min().get<int32_t>(), mode_.minLineLength);
+	sensorLimits_.maxShutter = Duration::max();
+	helper_->getBlanking(sensorLimits_.maxShutter,
+			     sensorLimits_.minFrameDuration, sensorLimits_.maxFrameDuration);
+
 	/*
 	 * Initialise this ControlList correctly, even if empty, in case the IPA is
 	 * running is isolation mode (passing the ControlList through the IPC layer).
@@ -501,26 +521,17 @@ int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &ip
 	 * based on the current sensor mode.
 	 */
 	ControlInfoMap::Map ctrlMap = ipaControls;
-	const Duration minSensorFrameDuration = mode_.minFrameLength * mode_.minLineLength;
-	const Duration maxSensorFrameDuration = mode_.maxFrameLength * mode_.maxLineLength;
 	ctrlMap[&controls::FrameDurationLimits] =
-		ControlInfo(static_cast<int64_t>(minSensorFrameDuration.get<std::micro>()),
-			    static_cast<int64_t>(maxSensorFrameDuration.get<std::micro>()));
+		ControlInfo(static_cast<int64_t>(sensorLimits_.minFrameDuration.get<std::micro>()),
+			    static_cast<int64_t>(sensorLimits_.maxFrameDuration.get<std::micro>()));
 
 	ctrlMap[&controls::AnalogueGain] =
-		ControlInfo(1.0f, static_cast<float>(helper_->gain(maxSensorGainCode_)));
-
-	/*
-	 * Calculate the max exposure limit from the frame duration limit as V4L2
-	 * will limit the maximum control value based on the current VBLANK value.
-	 */
-	Duration maxShutter = Duration::max();
-	helper_->getBlanking(maxShutter, minSensorFrameDuration, maxSensorFrameDuration);
-	const uint32_t exposureMin = sensorCtrls_.at(V4L2_CID_EXPOSURE).min().get<int32_t>();
+		ControlInfo(static_cast<float>(sensorLimits_.minAnalogueGain),
+			    static_cast<float>(sensorLimits_.maxAnalogueGain));
 
 	ctrlMap[&controls::ExposureTime] =
-		ControlInfo(static_cast<int32_t>(helper_->exposure(exposureMin, mode_.minLineLength).get<std::micro>()),
-			    static_cast<int32_t>(maxShutter.get<std::micro>()));
+		ControlInfo(static_cast<int32_t>(sensorLimits_.minShutter.get<std::micro>()),
+			    static_cast<int32_t>(sensorLimits_.maxShutter.get<std::micro>()));
 
 	/* Declare Autofocus controls, only if we have a controllable lens */
 	if (lensPresent_)
@@ -1480,9 +1491,6 @@ void IPARPi::applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls)
 
 void IPARPi::applyFrameDurations(Duration minFrameDuration, Duration maxFrameDuration)
 {
-	const Duration minSensorFrameDuration = mode_.minFrameLength * mode_.minLineLength;
-	const Duration maxSensorFrameDuration = mode_.maxFrameLength * mode_.maxLineLength;
-
 	/*
 	 * This will only be applied once AGC recalculations occur.
 	 * The values may be clamped based on the sensor mode capabilities as well.
@@ -1490,9 +1498,9 @@ void IPARPi::applyFrameDurations(Duration minFrameDuration, Duration maxFrameDur
 	minFrameDuration_ = minFrameDuration ? minFrameDuration : defaultMaxFrameDuration;
 	maxFrameDuration_ = maxFrameDuration ? maxFrameDuration : defaultMinFrameDuration;
 	minFrameDuration_ = std::clamp(minFrameDuration_,
-				       minSensorFrameDuration, maxSensorFrameDuration);
+				       sensorLimits_.minFrameDuration, sensorLimits_.maxFrameDuration);
 	maxFrameDuration_ = std::clamp(maxFrameDuration_,
-				       minSensorFrameDuration, maxSensorFrameDuration);
+				       sensorLimits_.minFrameDuration, sensorLimits_.maxFrameDuration);
 	maxFrameDuration_ = std::max(maxFrameDuration_, minFrameDuration_);
 
 	/* Return the validated limits via metadata. */
@@ -1505,17 +1513,18 @@ void IPARPi::applyFrameDurations(Duration minFrameDuration, Duration maxFrameDur
 	 * getBlanking() will update maxShutter with the largest exposure
 	 * value possible.
 	 */
-	RPiController::AgcAlgorithm::SensorLimits limits;
-	limits.maxShutter = Duration::max();
-	helper_->getBlanking(limits.maxShutter, minFrameDuration_, maxFrameDuration_);
+	sensorLimits_.maxShutter = Duration::max();
+	helper_->getBlanking(sensorLimits_.maxShutter, minFrameDuration_, maxFrameDuration_);
 
 	RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
 		controller_.getAlgorithm("agc"));
-	agc->setSensorLimits(limits);
+	agc->setSensorLimits(sensorLimits_);
 }
 
 void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)
 {
+	const int32_t minGainCode = helper_->gainCode(sensorLimits_.minAnalogueGain);
+	const int32_t maxGainCode = helper_->gainCode(sensorLimits_.maxAnalogueGain);
 	int32_t gainCode = helper_->gainCode(agcStatus->analogueGain);
 
 	/*
@@ -1523,7 +1532,7 @@ void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)
 	 * DelayedControls. The AGC will correctly handle a lower gain returned
 	 * by the sensor, provided it knows the actual gain used.
 	 */
-	gainCode = std::min<int32_t>(gainCode, maxSensorGainCode_);
+	gainCode = std::clamp<int32_t>(gainCode, minGainCode, maxGainCode);
 
 	/* getBlanking might clip exposure time to the fps limits. */
 	Duration exposure = agcStatus->shutterTime;
-- 
2.34.1



More information about the libcamera-devel mailing list