@@ -148,7 +148,14 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)
if (ret)
return ret;
- context.ctrlMap[&controls::AeEnable] = ControlInfo(false, true);
+ context.ctrlMap[&controls::ExposureTimeMode] =
+ ControlInfo(static_cast<int32_t>(controls::ExposureTimeModeAuto),
+ static_cast<int32_t>(controls::ExposureTimeModeManual),
+ static_cast<int32_t>(controls::ExposureTimeModeAuto));
+ context.ctrlMap[&controls::AnalogueGainMode] =
+ ControlInfo(static_cast<int32_t>(controls::AnalogueGainModeAuto),
+ static_cast<int32_t>(controls::AnalogueGainModeManual),
+ static_cast<int32_t>(controls::AnalogueGainModeAuto));
context.ctrlMap.merge(controls());
return 0;
@@ -169,7 +176,8 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
10ms / context.configuration.sensor.lineDuration;
context.activeState.agc.manual.gain = context.activeState.agc.automatic.gain;
context.activeState.agc.manual.exposure = context.activeState.agc.automatic.exposure;
- context.activeState.agc.autoEnabled = !context.configuration.raw;
+ context.activeState.agc.autoExposureEnabled = !context.configuration.raw;
+ context.activeState.agc.autoGainEnabled = !context.configuration.raw;
context.activeState.agc.constraintMode =
static_cast<controls::AeConstraintModeEnum>(constraintModes().begin()->first);
@@ -215,18 +223,47 @@ void Agc::queueRequest(IPAContext &context,
auto &agc = context.activeState.agc;
if (!context.configuration.raw) {
- const auto &agcEnable = controls.get(controls::AeEnable);
- if (agcEnable && *agcEnable != agc.autoEnabled) {
- agc.autoEnabled = *agcEnable;
+ const auto &aeEnable = controls.get(controls::ExposureTimeMode);
+ if (aeEnable &&
+ (*aeEnable == controls::ExposureTimeModeAuto) != agc.autoExposureEnabled) {
+ agc.autoExposureEnabled = (*aeEnable == controls::ExposureTimeModeAuto);
LOG(RkISP1Agc, Debug)
- << (agc.autoEnabled ? "Enabling" : "Disabling")
- << " AGC";
+ << (agc.autoExposureEnabled ? "Enabling" : "Disabling")
+ << " AGC (exposure)";
+
+ /*
+ * If we go from auto -> manual with no manual control
+ * set, use the last computed value, which we don't
+ * know until prepare() so save this information.
+ *
+ * \todo Check the previous frame at prepare() time
+ * instead of saving a flag here
+ */
+ if (!agc.autoExposureEnabled && !controls.get(controls::ExposureTime))
+ frameContext.agc.autoExposureModeChange = true;
+ }
+
+ const auto &agEnable = controls.get(controls::AnalogueGainMode);
+ if (agEnable &&
+ (*agEnable == controls::AnalogueGainModeAuto) != agc.autoGainEnabled) {
+ agc.autoGainEnabled = (*agEnable == controls::AnalogueGainModeAuto);
+
+ LOG(RkISP1Agc, Debug)
+ << (agc.autoGainEnabled ? "Enabling" : "Disabling")
+ << " AGC (gain)";
+ /*
+ * If we go from auto -> manual with no manual control
+ * set, use the last computed value, which we don't
+ * know until prepare() so save this information.
+ */
+ if (!agc.autoGainEnabled && !controls.get(controls::AnalogueGain))
+ frameContext.agc.autoGainModeChange = true;
}
}
const auto &exposure = controls.get(controls::ExposureTime);
- if (exposure && !agc.autoEnabled) {
+ if (exposure && !agc.autoExposureEnabled) {
agc.manual.exposure = *exposure * 1.0us
/ context.configuration.sensor.lineDuration;
@@ -235,18 +272,19 @@ void Agc::queueRequest(IPAContext &context,
}
const auto &gain = controls.get(controls::AnalogueGain);
- if (gain && !agc.autoEnabled) {
+ if (gain && !agc.autoGainEnabled) {
agc.manual.gain = *gain;
LOG(RkISP1Agc, Debug) << "Set gain to " << agc.manual.gain;
}
- frameContext.agc.autoEnabled = agc.autoEnabled;
+ frameContext.agc.autoExposureEnabled = agc.autoExposureEnabled;
+ frameContext.agc.autoGainEnabled = agc.autoGainEnabled;
- if (!frameContext.agc.autoEnabled) {
+ if (!frameContext.agc.autoExposureEnabled)
frameContext.agc.exposure = agc.manual.exposure;
+ if (!frameContext.agc.autoGainEnabled)
frameContext.agc.gain = agc.manual.gain;
- }
const auto &meteringMode = controls.get(controls::AeMeteringMode);
if (meteringMode) {
@@ -283,9 +321,26 @@ void Agc::queueRequest(IPAContext &context,
void Agc::prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext, RkISP1Params *params)
{
- if (frameContext.agc.autoEnabled) {
- frameContext.agc.exposure = context.activeState.agc.automatic.exposure;
- frameContext.agc.gain = context.activeState.agc.automatic.gain;
+ uint32_t activeAutoExposure = context.activeState.agc.automatic.exposure;
+ double activeAutoGain = context.activeState.agc.automatic.gain;
+
+ /* Populate exposure and gain in auto mode */
+ if (frameContext.agc.autoExposureEnabled)
+ frameContext.agc.exposure = activeAutoExposure;
+ if (frameContext.agc.autoGainEnabled)
+ frameContext.agc.gain = activeAutoGain;
+
+ /*
+ * Populate manual exposure and gain from the active auto values when
+ * transitioning from auto to manual
+ */
+ if (!frameContext.agc.autoExposureEnabled && frameContext.agc.autoExposureModeChange) {
+ context.activeState.agc.manual.exposure = activeAutoExposure;
+ frameContext.agc.exposure = activeAutoExposure;
+ }
+ if (!frameContext.agc.autoGainEnabled && frameContext.agc.autoGainModeChange) {
+ context.activeState.agc.manual.gain = activeAutoGain;
+ frameContext.agc.gain = activeAutoGain;
}
if (frame > 0 && !frameContext.agc.updateMetering)
@@ -333,7 +388,14 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext,
* frameContext.sensor.exposure;
metadata.set(controls::AnalogueGain, frameContext.sensor.gain);
metadata.set(controls::ExposureTime, exposureTime.get<std::micro>());
- metadata.set(controls::AeEnable, frameContext.agc.autoEnabled);
+ metadata.set(controls::ExposureTimeMode,
+ frameContext.agc.autoExposureEnabled
+ ? controls::ExposureTimeModeAuto
+ : controls::ExposureTimeModeManual);
+ metadata.set(controls::AnalogueGainMode,
+ frameContext.agc.autoGainEnabled
+ ? controls::AnalogueGainModeAuto
+ : controls::AnalogueGainModeManual);
/* \todo Use VBlank value calculated from each frame exposure. */
uint32_t vTotal = context.configuration.sensor.size.height
@@ -424,14 +486,35 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
[](uint32_t x) { return x >> 4; });
expMeans_ = { params->ae.exp_mean, context.hw->numAeCells };
- utils::Duration maxExposureTime =
- std::clamp(frameContext.agc.maxFrameDuration,
- context.configuration.sensor.minExposureTime,
- context.configuration.sensor.maxExposureTime);
- setLimits(context.configuration.sensor.minExposureTime,
- maxExposureTime,
- context.configuration.sensor.minAnalogueGain,
- context.configuration.sensor.maxAnalogueGain);
+ /*
+ * Set the AGC limits using the fixed exposure time and/or gain in
+ * manual mode, or the sensor limits in auto mode.
+ */
+ utils::Duration minExposureTime;
+ utils::Duration maxExposureTime;
+ double minAnalogueGain;
+ double maxAnalogueGain;
+
+ if (frameContext.agc.autoExposureEnabled) {
+ minExposureTime = context.configuration.sensor.minExposureTime;
+ maxExposureTime = std::clamp(frameContext.agc.maxFrameDuration,
+ context.configuration.sensor.minExposureTime,
+ context.configuration.sensor.maxExposureTime);
+ } else {
+ minExposureTime = context.configuration.sensor.lineDuration
+ * frameContext.agc.exposure;
+ maxExposureTime = minExposureTime;
+ }
+
+ if (frameContext.agc.autoGainEnabled) {
+ minAnalogueGain = context.configuration.sensor.minAnalogueGain;
+ maxAnalogueGain = context.configuration.sensor.maxAnalogueGain;
+ } else {
+ minAnalogueGain = frameContext.agc.gain;
+ maxAnalogueGain = frameContext.agc.gain;
+ }
+
+ setLimits(minExposureTime, maxExposureTime, minAnalogueGain, maxAnalogueGain);
/*
* The Agc algorithm needs to know the effective exposure value that was
@@ -165,8 +165,11 @@ namespace libcamera::ipa::rkisp1 {
* \var IPAActiveState::agc.automatic.gain
* \brief Automatic analogue gain multiplier
*
- * \var IPAActiveState::agc.autoEnabled
- * \brief Manual/automatic AGC state as set by the AeEnable control
+ * \var IPAActiveState::agc.autoExposureEnabled
+ * \brief Manual/automatic AGC state (exposure) as set by the ExposureTimeMode control
+ *
+ * \var IPAActiveState::agc.autoGainEnabled
+ * \brief Manual/automatic AGC state (gain) as set by the AnalogueGainMode control
*
* \var IPAActiveState::agc.constraintMode
* \brief Constraint mode as set by the AeConstraintMode control
@@ -289,8 +292,11 @@ namespace libcamera::ipa::rkisp1 {
*
* The gain should be adapted to the sensor specific gain code before applying.
*
- * \var IPAFrameContext::agc.autoEnabled
- * \brief Manual/automatic AGC state as set by the AeEnable control
+ * \var IPAFrameContext::agc.autoExposureEnabled
+ * \brief Manual/automatic AGC state (exposure) as set by the ExposureTimeMode control
+ *
+ * \var IPAFrameContext::agc.autoGainEnabled
+ * \brief Manual/automatic AGC state (gain) as set by the AnalogueGainMode control
*
* \var IPAFrameContext::agc.constraintMode
* \brief Constraint mode as set by the AeConstraintMode control
@@ -306,6 +312,16 @@ namespace libcamera::ipa::rkisp1 {
*
* \var IPAFrameContext::agc.updateMetering
* \brief Indicate if new ISP AGC metering parameters need to be applied
+ *
+ * \var IPAFrameContext::agc.autoExposureModeChange
+ * \brief Indicate if autoExposureEnabled has changed from true in the previous
+ * frame to false in the current frame, and no manual exposure value has been
+ * supplied in the current frame.
+ *
+ * \var IPAFrameContext::agc.autoGainModeChange
+ * \brief Indicate if autoGainEnabled has changed from true in the previous
+ * frame to false in the current frame, and no manual gain value has been
+ * supplied in the current frame.
*/
/**
@@ -79,7 +79,8 @@ struct IPAActiveState {
double gain;
} automatic;
- bool autoEnabled;
+ bool autoExposureEnabled;
+ bool autoGainEnabled;
controls::AeConstraintModeEnum constraintMode;
controls::AeExposureModeEnum exposureMode;
controls::AeMeteringModeEnum meteringMode;
@@ -124,12 +125,15 @@ struct IPAFrameContext : public FrameContext {
struct {
uint32_t exposure;
double gain;
- bool autoEnabled;
+ bool autoExposureEnabled;
+ bool autoGainEnabled;
controls::AeConstraintModeEnum constraintMode;
controls::AeExposureModeEnum exposureMode;
controls::AeMeteringModeEnum meteringMode;
utils::Duration maxFrameDuration;
bool updateMetering;
+ bool autoExposureModeChange;
+ bool autoGainModeChange;
} agc;
struct {