@@ -309,14 +309,14 @@ void Agc::setFixedShutter(Duration fixedShutter)
{
fixedShutter_ = fixedShutter;
/* Set this in case someone calls disableAuto() straight after. */
- status_.shutterTime = clipShutter(fixedShutter_);
+ status_.shutterTime = limitShutter(fixedShutter_);
}
void Agc::setFixedAnalogueGain(double fixedAnalogueGain)
{
fixedAnalogueGain_ = fixedAnalogueGain;
/* Set this in case someone calls disableAuto() straight after. */
- status_.analogueGain = fixedAnalogueGain;
+ status_.analogueGain = limitGain(fixedAnalogueGain);
}
void Agc::setMeteringMode(std::string const &meteringModeName)
@@ -342,7 +342,14 @@ void Agc::switchMode(CameraMode const &cameraMode,
housekeepConfig();
- Duration fixedShutter = clipShutter(fixedShutter_);
+ /*
+ * Store the mode in the local state. We must cache the sensitivity of
+ * of the previous mode for the calculations below.
+ */
+ double lastSensitivity = mode_.sensitivity;
+ mode_ = cameraMode;
+
+ Duration fixedShutter = limitShutter(fixedShutter_);
if (fixedShutter && fixedAnalogueGain_) {
/* We're going to reset the algorithm here with these fixed values. */
@@ -371,7 +378,7 @@ void Agc::switchMode(CameraMode const &cameraMode,
* current exposure profile, which takes care of everything else.
*/
- double ratio = lastSensitivity_ / cameraMode.sensitivity;
+ double ratio = lastSensitivity / cameraMode.sensitivity;
target_.totalExposureNoDG *= ratio;
target_.totalExposure *= ratio;
filtered_.totalExposureNoDG *= ratio;
@@ -392,9 +399,6 @@ void Agc::switchMode(CameraMode const &cameraMode,
}
writeAndFinish(metadata, false);
-
- /* We must remember the sensitivity of this mode for the next SwitchMode. */
- lastSensitivity_ = cameraMode.sensitivity;
}
void Agc::prepare(Metadata *imageMetadata)
@@ -516,7 +520,7 @@ void Agc::housekeepConfig()
{
/* First fetch all the up-to-date settings, so no one else has to do it. */
status_.ev = ev_;
- status_.fixedShutter = clipShutter(fixedShutter_);
+ status_.fixedShutter = limitShutter(fixedShutter_);
status_.fixedAnalogueGain = fixedAnalogueGain_;
status_.flickerPeriod = flickerPeriod_;
LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixedShutter "
@@ -703,7 +707,7 @@ void Agc::computeTargetExposure(double gain)
Duration maxShutter = status_.fixedShutter
? status_.fixedShutter
: exposureMode_->shutter.back();
- maxShutter = clipShutter(maxShutter);
+ maxShutter = limitShutter(maxShutter);
Duration maxTotalExposure =
maxShutter *
(status_.fixedAnalogueGain != 0.0
@@ -803,15 +807,16 @@ void Agc::divideUpExposure()
double analogueGain;
shutterTime = status_.fixedShutter ? status_.fixedShutter
: exposureMode_->shutter[0];
- shutterTime = clipShutter(shutterTime);
+ shutterTime = limitShutter(shutterTime);
analogueGain = status_.fixedAnalogueGain != 0.0 ? status_.fixedAnalogueGain
: exposureMode_->gain[0];
+ analogueGain = limitGain(analogueGain);
if (shutterTime * analogueGain < exposureValue) {
for (unsigned int stage = 1;
stage < exposureMode_->gain.size(); stage++) {
if (!status_.fixedShutter) {
Duration stageShutter =
- clipShutter(exposureMode_->shutter[stage]);
+ limitShutter(exposureMode_->shutter[stage]);
if (stageShutter * analogueGain >= exposureValue) {
shutterTime = exposureValue / analogueGain;
break;
@@ -824,6 +829,7 @@ void Agc::divideUpExposure()
break;
}
analogueGain = exposureMode_->gain[stage];
+ analogueGain = limitGain(analogueGain);
}
}
}
@@ -846,6 +852,7 @@ void Agc::divideUpExposure()
* gain as a side-effect.
*/
analogueGain = std::min(analogueGain, exposureMode_->gain.back());
+ analogueGain = limitGain(analogueGain);
shutterTime = newShutterTime;
}
LOG(RPiAgc, Debug) << "After flicker avoidance, shutter "
@@ -872,13 +879,36 @@ void Agc::writeAndFinish(Metadata *imageMetadata, bool desaturate)
<< " analogue gain " << filtered_.analogueGain;
}
-Duration Agc::clipShutter(Duration shutter)
+Duration Agc::limitShutter(Duration shutter)
{
- if (maxShutter_)
- shutter = std::min(shutter, maxShutter_);
+ /*
+ * shutter == 0 is a special case for fixed shutter values, and must pass
+ * through unchanged
+ */
+ if (!shutter)
+ return shutter;
+
+ shutter = std::clamp(shutter, mode_.minShutter, maxShutter_);
return shutter;
}
+double Agc::limitGain(double gain) const
+{
+ /*
+ * Only limit the lower bounds of the gain value to what the sensor limits.
+ * The upper bound on analogue gain will be made up with additional digital
+ * gain applied by the ISP.
+ *
+ * gain == 0.0 is a special case for fixed shutter values, and must pass
+ * through unchanged
+ */
+ if (!gain)
+ return gain;
+
+ gain = std::max(gain, mode_.minAnalogueGain);
+ return gain;
+}
+
/* Register algorithm with the system. */
static Algorithm *create(Controller *controller)
{
@@ -103,10 +103,12 @@ private:
void filterExposure(bool desaturate);
void divideUpExposure();
void writeAndFinish(Metadata *imageMetadata, bool desaturate);
- libcamera::utils::Duration clipShutter(libcamera::utils::Duration shutter);
+ libcamera::utils::Duration limitShutter(libcamera::utils::Duration shutter);
+ double limitGain(double gain) const;
AgcMeteringMode *meteringMode_;
AgcExposureMode *exposureMode_;
AgcConstraintMode *constraintMode_;
+ CameraMode mode_;
uint64_t frameCount_;
AwbStatus awb_;
struct ExposureValues {
@@ -124,7 +126,6 @@ private:
int lockCount_;
DeviceStatus lastDeviceStatus_;
libcamera::utils::Duration lastTargetExposure_;
- double lastSensitivity_; /* sensitivity of the previous camera mode */
/* Below here the "settings" that applications can change. */
std::string meteringModeName_;
std::string exposureModeName_;