@@ -66,12 +66,12 @@ Agc::Agc()
*/
int Agc::init(IPAContext &context, const ValueNode &tuningData)
{
- return agc_.init(tuningData, context.configuration.agc, context.activeState.agc, {
- .sensor = context.camHelper.get(),
- .sensorInfo = context.sensorInfo,
- .sensorControls = context.sensorControls,
- .ctrlMap = context.ctrlMap,
- });
+ return agc_.init(tuningData, context.camHelper.get(),
+ context.configuration.agc, context.activeState.agc, {
+ .sensorInfo = context.sensorInfo,
+ .sensorControls = context.sensorControls,
+ .ctrlMap = context.ctrlMap,
+ });
}
/**
@@ -88,7 +88,6 @@ int Agc::configure(IPAContext &context,
bdsGrid_ = context.configuration.grid.bdsGrid;
return agc_.configure(context.configuration.agc, context.activeState.agc, {
- .sensor = context.camHelper.get(),
.sensorInfo = context.sensorInfo,
.sensorControls = context.sensorControls,
.ctrlMap = context.ctrlMap,
@@ -11,10 +11,12 @@
#include <array>
#include <chrono>
#include <optional>
+#include <variant>
#include <linux/v4l2-controls.h>
#include <libcamera/base/log.h>
+#include <libcamera/base/utils.h>
#include <libcamera/control_ids.h>
#include <libcamera/controls.h>
@@ -79,6 +81,9 @@ namespace agc {
* \var agc::Session::maxAnalogueGain
* \brief Maximum analogue gain for the streaming session
*
+ * \var agc::Session::defAnalogueGain
+ * \brief Default analogue gain of the configured sensor
+ *
* \var agc::Session::minFrameDuration
* \brief Minimum frame duration for the streaming session
*
@@ -217,9 +222,6 @@ namespace agc {
* \struct AgcAlgorithm::ConfigurationParams
* \brief Parameters for AgcAlgorithm::configure()
*
- * \var AgcAlgorithm::ConfigurationParams::sensor
- * \brief CameraSensorHelper for the sensor
- *
* \var AgcAlgorithm::ConfigurationParams::sensorInfo
* \brief Current configuration of the sensor
*
@@ -264,13 +266,20 @@ namespace agc {
/**
* \brief Load tuning data and configure
*/
-int AgcAlgorithm::init(const ValueNode &tuningData,
+int AgcAlgorithm::init(const ValueNode &tuningData, CameraSensorHelper *sensor,
agc::Session &session, agc::ActiveState &state,
const ConfigurationParams &config)
{
- int ret = impl_.parseTuningData(tuningData);
- if (ret)
- return ret;
+ if (sensor) {
+ auto &impl = impl_.emplace<AgcMeanLuminance>();
+ int ret = impl.parseTuningData(tuningData);
+ if (ret)
+ return ret;
+ } else {
+ impl_.emplace<AgcMSV>();
+ }
+
+ sensor_ = sensor;
return configure(session, state, config);
}
@@ -301,10 +310,14 @@ int AgcAlgorithm::configure(agc::Session &session, agc::ActiveState &state,
int32_t defExposure = v4l2Exposure.def().get<int32_t>();
/* Compute the analogue gain limits. */
+ const auto extractGain = [&](const ControlValue &v) {
+ auto gainCode = v.get<int32_t>();
+ return sensor_ ? sensor_->gain(gainCode) : gainCode;
+ };
const ControlInfo &v4l2Gain = config.sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;
- float minGain = config.sensor->gain(v4l2Gain.min().get<int32_t>());
- float maxGain = config.sensor->gain(v4l2Gain.max().get<int32_t>());
- float defGain = config.sensor->gain(v4l2Gain.def().get<int32_t>());
+ float minGain = extractGain(v4l2Gain.min());
+ float maxGain = extractGain(v4l2Gain.max());
+ float defGain = extractGain(v4l2Gain.def());
LOG(Agc, Debug)
<< "exposure: [" << minExposure << ',' << maxExposure << "], "
@@ -343,28 +356,21 @@ int AgcAlgorithm::configure(agc::Session &session, agc::ActiveState &state,
session.maxExposureTime = maxExposure * session.lineDuration;
session.minAnalogueGain = minGain;
session.maxAnalogueGain = maxGain;
+ session.defAnalogueGain = defGain;
session.minFrameDuration = std::chrono::microseconds(frameDurations[0]);
session.maxFrameDuration = std::chrono::microseconds(frameDurations[1]);
- impl_.configure(session.lineDuration, config.sensor);
- impl_.resetFrameCount();
-
/* Configure the default exposure and gain. */
state = {};
state.automatic.gain = session.minAnalogueGain;
state.automatic.exposure = defExposure;
state.automatic.quantizationGain = 1;
state.automatic.digitalGain = 1;
- state.automatic.yTarget = impl_.effectiveYTarget(0, 1);
state.manual.gain = state.automatic.gain;
state.manual.exposure = state.automatic.exposure;
state.autoExposureEnabled = session.autoAllowed;
state.autoGainEnabled = session.autoAllowed;
state.exposureValue = 0;
- state.constraintMode =
- static_cast<controls::AeConstraintModeEnum>(impl_.constraintModes().begin()->first);
- state.exposureMode =
- static_cast<controls::AeExposureModeEnum>(impl_.exposureModeHelpers().begin()->first);
state.minFrameDuration = session.minFrameDuration;
state.maxFrameDuration = session.maxFrameDuration;
@@ -415,25 +421,52 @@ int AgcAlgorithm::configure(agc::Session &session, agc::ActiveState &state,
add(controls::AnalogueGainMode,
controls::AnalogueGainModeAuto, controls::AnalogueGainModeManual);
- if (session.autoAllowed) {
- config.ctrlMap[&controls::ExposureValue] = ControlInfo(-8.0f, 8.0f, 0.0f);
+ std::visit(utils::overloaded{
+ [&](AgcMSV &) {
+ /* No constraint/exposure mode support. */
+ state.constraintMode = controls::AeConstraintModeEnum::ConstraintNormal;
+ state.exposureMode = controls::AeExposureModeEnum::ExposureNormal;
- {
- std::vector<ControlValue> options;
- for (const auto &[id, _] : impl_.constraintModes())
- options.emplace_back(id);
+ state.automatic.yTarget = 0; /* Not supported. */
- config.ctrlMap[&controls::AeConstraintMode] = ControlInfo(options);
- }
+ if (!session.autoAllowed)
+ return;
+
+ config.ctrlMap[&controls::AeConstraintMode] = ControlInfo(
+ std::array{ ControlValue(state.constraintMode) }
+ );
+
+ config.ctrlMap[&controls::AeExposureMode] = ControlInfo(
+ std::array{ ControlValue(state.exposureMode) }
+ );
+ },
+ [&](AgcMeanLuminance &impl) {
+ state.constraintMode =
+ static_cast<controls::AeConstraintModeEnum>(impl.constraintModes().begin()->first);
+ state.exposureMode =
+ static_cast<controls::AeExposureModeEnum>(impl.exposureModeHelpers().begin()->first);
+
+ state.automatic.yTarget = impl.effectiveYTarget(0, 1);
+
+ impl.configure(session.lineDuration, sensor_);
+ impl.resetFrameCount();
+
+ if (!session.autoAllowed)
+ return;
+
+ config.ctrlMap[&controls::ExposureValue] = ControlInfo(-8.0f, 8.0f, 0.0f);
- {
std::vector<ControlValue> options;
- for (const auto &[id, _] : impl_.exposureModeHelpers())
+ for (const auto &[id, _] : impl.constraintModes())
options.emplace_back(id);
+ config.ctrlMap[&controls::AeConstraintMode] = ControlInfo(options);
+ options.clear();
+ for (const auto &[id, _] : impl.exposureModeHelpers())
+ options.emplace_back(id);
config.ctrlMap[&controls::AeExposureMode] = ControlInfo(options);
- }
- }
+ },
+ }, impl_);
return 0;
}
@@ -623,36 +656,68 @@ void AgcAlgorithm::process(const agc::Session &session, agc::ActiveState &state,
maxAnalogueGain = frameContext.gain;
}
- /*
- * The Agc algorithm needs to know the effective exposure value that was
- * applied to the sensor when the statistics were collected.
- */
- utils::Duration effectiveExposureValue =
- lineDuration * params->exposure * params->gain;
-
- impl_.setLimits(minExposureTime, maxExposureTime,
- minAnalogueGain, maxAnalogueGain,
- std::move(params->additionalConstraints));
-
- const auto &newEv = impl_.calculateNewEv({
- .traits = params->traits,
- .yHist = params->yHist,
- .effectiveExposureValue = effectiveExposureValue,
- .constraintModeIndex = frameContext.constraintMode,
- .exposureModeIndex = frameContext.exposureMode,
- .lux = params->lux,
- .exposureCompensation = pow(2.0, frameContext.exposureValue),
- });
-
- /* Update the estimated exposure and gain. */
- state.automatic.exposure = newEv.exposureTime / lineDuration;
- state.automatic.gain = newEv.analogueGain;
- state.automatic.quantizationGain = newEv.quantizationGain;
- state.automatic.digitalGain = newEv.digitalGain;
- state.automatic.yTarget = newEv.yTarget;
+ std::visit(utils::overloaded{
+ [&](AgcMSV& impl) {
+ impl.setLimits({
+ .exposure = {
+ uint32_t(minExposureTime / lineDuration),
+ uint32_t(maxExposureTime / lineDuration),
+ },
+ .gain = {
+ minAnalogueGain,
+ maxAnalogueGain,
+ },
+ /* gain codes -> step size of 1 */
+ .gainMinStep = 1,
+ /* assume default gain is close to 1.0 */
+ .gain1 = session.defAnalogueGain,
+ });
+
+ const auto& newEv = impl.calculateNewEv({
+ .yHist = params->yHist,
+ .exposure = params->exposure,
+ .gain = params->gain,
+ });
+
+ state.automatic.exposure = newEv.exposure;
+ state.automatic.gain = newEv.analogueGain;
+ },
+ [&](AgcMeanLuminance& impl) {
+ /*
+ * The Agc algorithm needs to know the effective exposure
+ * value that was applied to the sensor when the statistics
+ * were collected.
+ */
+ utils::Duration effectiveExposureValue =
+ lineDuration * params->exposure * params->gain;
+
+ impl.setLimits(minExposureTime, maxExposureTime,
+ minAnalogueGain, maxAnalogueGain,
+ std::move(params->additionalConstraints));
+
+ const auto &newEv = impl.calculateNewEv({
+ .traits = params->traits,
+ .yHist = params->yHist,
+ .effectiveExposureValue = effectiveExposureValue,
+ .constraintModeIndex = frameContext.constraintMode,
+ .exposureModeIndex = frameContext.exposureMode,
+ .lux = params->lux,
+ .exposureCompensation = pow(2.0, frameContext.exposureValue),
+ });
+
+ /* Update the estimated exposure and gain. */
+ state.automatic.exposure = newEv.exposureTime / lineDuration;
+ state.automatic.gain = newEv.analogueGain;
+ state.automatic.quantizationGain = newEv.quantizationGain;
+ state.automatic.digitalGain = newEv.digitalGain;
+ state.automatic.yTarget = newEv.yTarget;
+ },
+ }, impl_);
+
+ const utils::Duration newExposureTime = state.automatic.exposure * lineDuration;
LOG(Agc, Debug)
- << "exposure-time: " << newEv.exposureTime << ", "
+ << "exposure-time: " << newExposureTime << ", "
<< "analogue-gain: " << state.automatic.gain << ", "
<< "quantization-gain: " << state.automatic.quantizationGain << ", "
<< "digital-gain: " << state.automatic.digitalGain;
@@ -662,7 +727,7 @@ void AgcAlgorithm::process(const agc::Session &session, agc::ActiveState &state,
* the minimum frame duration when we have short exposures.
*/
processFrameDuration(session, frameContext,
- std::max(frameContext.minFrameDuration, newEv.exposureTime));
+ std::max(frameContext.minFrameDuration, newExposureTime));
fillMetadata(session, frameContext, metadata);
}
@@ -10,6 +10,7 @@
#include <optional>
#include <stdint.h>
#include <utility>
+#include <variant>
#include <linux/v4l2-controls.h>
@@ -19,6 +20,7 @@
#include <libcamera/ipa/core_ipa_interface.h>
#include "agc_mean_luminance.h"
+#include "agc_msv.h"
#include "camera_sensor_helper.h"
#include "histogram.h"
@@ -33,6 +35,7 @@ struct Session {
utils::Duration maxExposureTime;
double minAnalogueGain;
double maxAnalogueGain;
+ double defAnalogueGain;
utils::Duration minFrameDuration;
utils::Duration maxFrameDuration;
utils::Duration lineDuration;
@@ -114,7 +117,6 @@ class AgcAlgorithm
{
public:
struct ConfigurationParams {
- const CameraSensorHelper *sensor;
const IPACameraSensorInfo &sensorInfo;
const ControlInfoMap &sensorControls;
ControlInfoMap::Map &ctrlMap;
@@ -130,7 +132,7 @@ public:
double lux = 0;
};
- int init(const ValueNode &tuningData,
+ int init(const ValueNode &tuningData, CameraSensorHelper *sensor,
agc::Session &session, agc::ActiveState &state,
const ConfigurationParams &config);
@@ -154,7 +156,8 @@ private:
const agc::FrameContext &frameContext,
ControlList &metadata);
- AgcMeanLuminance impl_;
+ std::variant<AgcMSV, AgcMeanLuminance> impl_;
+ CameraSensorHelper *sensor_ = nullptr;
};
} /* namespace ipa */
@@ -122,12 +122,12 @@ Agc::Agc()
int Agc::init(IPAContext &context, const ValueNode &tuningData)
{
- return agc_.init(tuningData, context.configuration.agc, context.activeState.agc, {
- .sensor = context.camHelper.get(),
- .sensorInfo = context.sensorInfo,
- .sensorControls = context.sensorControls,
- .ctrlMap = context.ctrlMap,
- });
+ return agc_.init(tuningData, context.camHelper.get(),
+ context.configuration.agc, context.activeState.agc, {
+ .sensorInfo = context.sensorInfo,
+ .sensorControls = context.sensorControls,
+ .ctrlMap = context.ctrlMap,
+ });
}
int Agc::configure(IPAContext &context,
@@ -138,7 +138,6 @@ int Agc::configure(IPAContext &context,
return ret;
ret = agc_.configure(context.configuration.agc, context.activeState.agc, {
- .sensor = context.camHelper.get(),
.sensorInfo = context.sensorInfo,
.sensorControls = context.sensorControls,
.ctrlMap = context.ctrlMap,
@@ -136,12 +136,12 @@ int Agc::init(IPAContext &context, const ValueNode &tuningData)
{
int ret;
- ret = agc_.init(tuningData, context.configuration.agc, context.activeState.agc, {
- .sensor = context.camHelper.get(),
- .sensorInfo = context.sensorInfo,
- .sensorControls = context.sensorControls,
- .ctrlMap = context.ctrlMap,
- });
+ ret = agc_.init(tuningData, context.camHelper.get(),
+ context.configuration.agc, context.activeState.agc, {
+ .sensorInfo = context.sensorInfo,
+ .sensorControls = context.sensorControls,
+ .ctrlMap = context.ctrlMap,
+ });
if (ret)
return ret;
@@ -163,7 +163,6 @@ int Agc::init(IPAContext &context, const ValueNode &tuningData)
int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
{
int ret = agc_.configure(context.configuration.agc, context.activeState.agc, {
- .sensor = context.camHelper.get(),
.sensorInfo = context.sensorInfo,
.sensorControls = context.sensorControls,
.ctrlMap = context.ctrlMap,