diff options
-rw-r--r-- | src/ipa/raspberrypi/controller/rpi/agc.cpp | 61 | ||||
-rw-r--r-- | src/ipa/raspberrypi/controller/rpi/agc.h | 5 |
2 files changed, 48 insertions, 18 deletions
diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp index 4ea0dd41..f438cab8 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp @@ -223,8 +223,7 @@ Agc::Agc(Controller *controller) : AgcAlgorithm(controller), meteringMode_(nullptr), exposureMode_(nullptr), constraintMode_(nullptr), frameCount_(0), lockCount_(0), - lastTargetExposure_(0s), lastSensitivity_(0.0), - ev_(1.0), flickerPeriod_(0s), + lastTargetExposure_(0s), ev_(1.0), flickerPeriod_(0s), maxShutter_(0s), fixedShutter_(0s), fixedAnalogueGain_(0.0) { memset(&awb_, 0, sizeof(awb_)); @@ -309,14 +308,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 +341,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 +377,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 +398,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 +519,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 +706,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 +806,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 +828,7 @@ void Agc::divideUpExposure() break; } analogueGain = exposureMode_->gain[stage]; + analogueGain = limitGain(analogueGain); } } } @@ -846,6 +851,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 +878,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) { diff --git a/src/ipa/raspberrypi/controller/rpi/agc.h b/src/ipa/raspberrypi/controller/rpi/agc.h index f04896ca..4fa9b8de 100644 --- a/src/ipa/raspberrypi/controller/rpi/agc.h +++ b/src/ipa/raspberrypi/controller/rpi/agc.h @@ -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_; |