@@ -14,6 +14,8 @@
#include <optional>
#include <ratio>
#include <span>
+#include <string_view>
+#include <tuple>
#include <variant>
#include <linux/v4l2-controls.h>
@@ -26,6 +28,8 @@
#include <libcamera/ipa/core_ipa_interface.h>
+#include "exposure_mode_helper.h"
+
/**
* \file agc.h
* \brief libipa AGC algorithm
@@ -222,6 +226,245 @@ namespace agc {
} /* namespace agc */
+namespace {
+
+/*
+ * Default relative luminance target
+ *
+ * This value should be chosen so that when the camera points at a grey target,
+ * the resulting image brightness looks "right". Custom values can be passed
+ * as the relativeLuminanceTarget value in sensor tuning files.
+ */
+static constexpr double kDefaultRelativeLuminanceTarget = 0.16;
+
+int parseRelativeLuminanceTarget(AgcMeanLuminance::Configuration &config, const ValueNode &tuningData)
+{
+ auto &target = tuningData["relativeLuminanceTarget"];
+ if (!target) {
+ config.relativeLuminanceTarget = { { { { 0.0, kDefaultRelativeLuminanceTarget } } } };
+ return 0;
+ }
+
+ auto pwl = target.get<Pwl>();
+ if (!pwl) {
+ LOG(Agc, Error)
+ << "Failed to load relative luminance target.";
+ return -EINVAL;
+ }
+
+ config.relativeLuminanceTarget = std::move(*pwl);
+ return 0;
+}
+
+int parseConstraint(AgcMeanLuminance::Configuration &config, const ValueNode &modeDict, int32_t id)
+{
+ for (const auto &[boundName, content] : modeDict.asDict()) {
+ if (boundName != "upper" && boundName != "lower") {
+ LOG(Agc, Warning)
+ << "Ignoring unknown constraint bound '" << boundName << "'";
+ continue;
+ }
+
+ unsigned int idx = static_cast<unsigned int>(boundName == "upper");
+ auto bound = static_cast<AgcMeanLuminance::AgcConstraint::Bound>(idx);
+ double qLo = content["qLo"].get<double>().value_or(0.98);
+ double qHi = content["qHi"].get<double>().value_or(1.0);
+ auto yTarget = content["yTarget"].get<Pwl>();
+ if (!yTarget) {
+ LOG(Agc, Error)
+ << "Failed to parse yTarget";
+ return -EINVAL;
+ }
+
+ AgcMeanLuminance::AgcConstraint constraint = {
+ bound,
+ qLo,
+ qHi,
+ std::move(*yTarget),
+ };
+ auto &constraints = config.constraintModes[id];
+
+ if (idx)
+ constraints.push_back(std::move(constraint));
+ else
+ constraints.insert(constraints.begin(), std::move(constraint));
+ }
+
+ return 0;
+}
+
+int parseConstraintModes(AgcMeanLuminance::Configuration &config, const ValueNode &tuningData)
+{
+ static constexpr std::tuple<std::string_view, std::string_view, controls::AeConstraintModeEnum> compat[] = {
+ { "ConstraintNormal", "Normal", controls::AeConstraintModeNormal },
+ { "ConstraintHighlight", "Highlight", controls::AeConstraintModeHighlight },
+ { "ConstraintShadows", "Shadows", controls::AeConstraintModeShadows },
+ { "ConstraintCustom", "Custom", controls::AeConstraintModeCustom },
+ };
+
+ const ValueNode &constraintModes = tuningData[controls::AeConstraintMode.name()];
+ if (constraintModes.isDictionary()) {
+ for (const auto &[modeName, modeDict] : constraintModes.asDict()) {
+ std::optional<controls::AeConstraintModeEnum> modeValue;
+
+ auto it = controls::AeConstraintModeNameValueMap.find(modeName);
+ if (it == controls::AeConstraintModeNameValueMap.end()) {
+ for (const auto &[oldName, newName, v] : compat) {
+ if (modeName != oldName)
+ continue;
+
+ modeValue = v;
+
+ LOG(Agc, Warning)
+ << "Constraint mode '" << oldName << "' has been renamed to '"
+ << newName << "', please fix the tuning file";
+ break;
+ }
+ } else {
+ modeValue = static_cast<controls::AeConstraintModeEnum>(it->second);
+ }
+
+ if (!modeValue) {
+ LOG(Agc, Warning)
+ << "Skipping unknown constraint mode '" << modeName << "'";
+ continue;
+ }
+
+ if (!modeDict.isDictionary()) {
+ LOG(Agc, Error)
+ << "Invalid constraint mode '" << modeName << "'";
+ return -EINVAL;
+ }
+
+ int ret = parseConstraint(config, modeDict, *modeValue);
+ if (ret)
+ return ret;
+ }
+ }
+
+ /*
+ * If the tuning data file contains no constraints then we use the
+ * default constraint that the IPU3/RkISP1 Agc algorithms were adhering
+ * to anyway before centralisation; this constraint forces the top 2% of
+ * the histogram to be at least 0.5.
+ */
+ if (config.constraintModes.empty()) {
+ AgcMeanLuminance::AgcConstraint constraint = {
+ AgcMeanLuminance::AgcConstraint::Bound::Lower,
+ 0.98,
+ 1.0,
+ Pwl({ { { 0.0, 0.5 } } }),
+ };
+
+ config.constraintModes[controls::AeConstraintModeNormal].push_back(std::move(constraint));
+ }
+
+ return 0;
+}
+
+int parseExposureModes(AgcMeanLuminance::Configuration &config, const ValueNode &tuningData)
+{
+ static constexpr std::tuple<std::string_view, std::string_view, controls::AeExposureModeEnum> compat[] = {
+ { "ExposureNormal", "Normal", controls::AeExposureModeNormal },
+ { "ExposureShort", "Short", controls::AeExposureModeShort },
+ { "ExposureLong", "Long", controls::AeExposureModeLong },
+ { "ExposureCustom", "Custom", controls::AeExposureModeCustom },
+ };
+
+ const ValueNode &exposureModes = tuningData[controls::AeExposureMode.name()];
+ if (exposureModes.isDictionary()) {
+ for (const auto &[modeName, modeValues] : exposureModes.asDict()) {
+ std::optional<controls::AeExposureModeEnum> modeValue;
+
+ auto it = controls::AeExposureModeNameValueMap.find(modeName);
+ if (it == controls::AeExposureModeNameValueMap.end()) {
+ for (const auto &[oldName, newName, v] : compat) {
+ if (modeName != oldName)
+ continue;
+
+ modeValue = v;
+
+ LOG(Agc, Warning)
+ << "Exposure mode '" << oldName << "' has been renamed to '"
+ << newName << "', please fix the tuning file";
+ break;
+ }
+ } else {
+ modeValue = static_cast<controls::AeExposureModeEnum>(it->second);
+ }
+
+ if (!modeValue) {
+ LOG(Agc, Warning)
+ << "Skipping unknown exposure mode '" << modeName << "'";
+ continue;
+ }
+
+ if (!modeValues.isDictionary()) {
+ LOG(Agc, Error)
+ << "Invalid exposure mode '" << modeName << "'";
+ return -EINVAL;
+ }
+
+ std::vector<uint32_t> exposureTimes =
+ modeValues["exposureTime"].get<std::vector<uint32_t>>().value_or(utils::defopt);
+ std::vector<double> gains =
+ modeValues["gain"].get<std::vector<double>>().value_or(utils::defopt);
+
+ if (exposureTimes.size() != gains.size()) {
+ LOG(Agc, Error)
+ << "Exposure time and gain array sizes unequal";
+ return -EINVAL;
+ }
+
+ if (exposureTimes.empty()) {
+ LOG(Agc, Error)
+ << "Exposure time and gain arrays are empty";
+ return -EINVAL;
+ }
+
+ std::vector<ExposureModeHelper::Stage> stages;
+ for (size_t i = 0; i < exposureTimes.size(); i++) {
+ stages.push_back({
+ .exposureTime = std::chrono::microseconds(exposureTimes[i]),
+ .gain = gains[i],
+ });
+ }
+
+ config.exposureModeHelpers.try_emplace(*modeValue, std::move(stages));
+ }
+ }
+
+ /*
+ * If we don't have any exposure modes in the tuning data we create an
+ * ExposureModeHelper using an empty vector of stages. This will result
+ * in the ExposureModeHelper simply driving the exposure time as high as
+ * possible before touching gain.
+ */
+ if (config.exposureModeHelpers.empty())
+ config.exposureModeHelpers.try_emplace(
+ controls::AeExposureModeNormal,
+ std::vector<ExposureModeHelper::Stage>{});
+
+ return 0;
+}
+
+int parseTuningData(AgcMeanLuminance::Configuration &config, const ValueNode &tuningData)
+{
+ int ret;
+
+ ret = parseRelativeLuminanceTarget(config, tuningData);
+ if (ret)
+ return ret;
+
+ ret = parseConstraintModes(config, tuningData);
+ if (ret)
+ return ret;
+
+ return parseExposureModes(config, tuningData);
+}
+
+} /* namespace */
+
/**
* \class AgcAlgorithm
* \brief libIPA LSC algorithm algorithm
@@ -238,6 +481,57 @@ namespace agc {
* virtual function, they should simply call the identically named member
* function of AgcAlgorithm.
*
+ * When a CameraSensorHelper is provided, AgcMeanLuminance is used and support for
+ * exposure (controls::AeExposureMode) and constraint (controls::AeConstraintMode)
+ * modes, and specifying the default luminance target is available via the tuning data.
+ *
+ * For controls::AeConstraintMode, the dictionary under the key "AeConstraintMode"
+ * is parsed: per-mode setting dictionaries with the key being a value from
+ * controls::AeConstraintModeNameValueMap. The yTarget can either be provided
+ * as single value or as array in which case it is interpreted as a PWL mapping
+ * lux levels to yTarget values. Each mode dict may contain either a "lower" or
+ * "upper" key or both, for example:
+ *
+ * \code{.unparsed}
+ * algorithms:
+ * - Agc:
+ * AeConstraintMode:
+ * Normal:
+ * lower:
+ * qLo: 0.98
+ * qHi: 1.0
+ * yTarget: 0.5
+ * Highlight:
+ * lower:
+ * qLo: 0.98
+ * qHi: 1.0
+ * yTarget: 0.5
+ * upper:
+ * qLo: 0.98
+ * qHi: 1.0
+ * yTarget: [ 100, 0.8, 20000, 0.5 ]
+ *
+ * \endcode
+ *
+ * For controls::AeExposureMode, the dictionary under the key AeExposureMode
+ * is parsed: per-mode setting dictionaries with the key being a value from
+ * controls::AeExposureModeNameValueMap. Each mode dict should contain
+ * an array of exposure times with the key "exposureTime" and an array of gain
+ * values with the key "gain", in this format:
+ *
+ * \code{.unparsed}
+ * algorithms:
+ * - Agc:
+ * AeExposureMode:
+ * Normal:
+ * exposureTime: [ 100, 10000, 30000, 60000, 120000 ]
+ * gain: [ 2.0, 4.0, 6.0, 8.0, 10.0 ]
+ * Short:
+ * exposureTime: [ 100, 10000, 30000, 60000, 120000 ]
+ * gain: [ 2.0, 4.0, 6.0, 8.0, 10.0 ]
+ *
+ * \endcode
+ *
* \todo DigitalGain, DigitalGainMode
* \todo Expand documentation
*/
@@ -298,9 +592,8 @@ namespace agc {
* in ConfigurationParams::ctrlMap.
*
* If a CameraSensorHelper is provided in \a sensor, an instance of
- * AgcMeanLuminance is instantiated and the tuning data is loaded by
- * calling AgcMeanLuminance::parseTuningData(). Otherwise an instance
- * of AgcMSV is instantiated, and in this case the tuning data is ignored.
+ * AgcMeanLuminance is instantiated. Otherwise an instance of AgcMSV
+ * is instantiated, and in this case the tuning data is ignored.
*
* \return 0 on success, or a negative error code
*
@@ -310,10 +603,12 @@ int AgcAlgorithm::init(const ValueNode &tuningData, CameraSensorHelper *sensor,
const ConfigurationParams &config)
{
if (sensor) {
- auto &impl = impl_.emplace<AgcMeanLuminance>();
- int ret = impl.parseTuningData(tuningData);
+ AgcMeanLuminance::Configuration agcConfig;
+ int ret = parseTuningData(agcConfig, tuningData);
if (ret)
return ret;
+
+ impl_.emplace<AgcMeanLuminance>(std::move(agcConfig));
} else {
impl_.emplace<AgcMSV>();
}
@@ -9,7 +9,6 @@
#include <algorithm>
#include <cmath>
-#include <span>
#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>
@@ -18,8 +17,6 @@
#include "exposure_mode_helper.h"
-using namespace libcamera::controls;
-
/**
* \file agc_mean_luminance.h
* \brief Class implementing mean luminance AEGC
@@ -39,15 +36,6 @@ namespace ipa {
*/
static constexpr uint32_t kNumStartupFrames = 10;
-/*
- * Default relative luminance target
- *
- * This value should be chosen so that when the camera points at a grey target,
- * the resulting image brightness looks "right". Custom values can be passed
- * as the relativeLuminanceTarget value in sensor tuning files.
- */
-static constexpr double kDefaultRelativeLuminanceTarget = 0.16;
-
/*
* Maximum relative luminance target
*
@@ -148,17 +136,13 @@ static constexpr unsigned int kDefaultLuxLevel = 500;
* section of a histogram to a target value, where the target and the boundaries
* of the section of the histogram used in the calculation are taken from the
* values defined for the currently configured AeConstraintMode within the
- * tuning data. This class provides a helper function to parse those tuning data
- * to discover the constraints, and so requires a specific format for those
- * data which is described in \ref parseTuningData(). The gain from the first
- * stage is then clamped to the gain from this stage.
+ * tuning data. The gain from the first stage is then clamped to the gain from
+ * this stage.
*
* The final gain is used to adjust the effective exposure value of the image,
* and that new exposure value is divided into exposure time, analogue gain and
* digital gain according to the selected AeExposureMode. This class uses the
- * \ref ExposureModeHelper class to assist in that division, and expects the
- * data needed to initialise that class to be present in tuning data in a
- * format described in \ref parseTuningData().
+ * \ref ExposureModeHelper class to assist in that division.
*
* In order to be able to use this algorithm an IPA module needs to be able to
* do the following:
@@ -170,225 +154,23 @@ static constexpr unsigned int kDefaultLuxLevel = 500;
*
* IPA modules that want to use this class to implement their AEGC algorithm
* should derive AgcMeanLuminance::Traits and override the necessary functions.
- * The users must call parseTuningData() in init(), and must also call configure()
- * and setLimits() in configure(). They may then use calculateNewEv() in process().
- * If the limits passed to setLimits() change for any reason (for example, in
- * response to a FrameDurationLimit control being passed in queueRequest()) then
- * setLimits() must be called again with the new values.
+ * The users must call configure() and setLimits() in configure(). They may
+ * then use calculateNewEv() in process(). If the limits passed to setLimits()
+ * change for any reason (for example, in response to a FrameDurationLimit control
+ * being passed in queueRequest()) then setLimits() must be called again with the
+ * new values.
*/
-AgcMeanLuminance::AgcMeanLuminance()
- : filteredExposure_(0s), luxWarningEnabled_(true), frameCount_(0)
+AgcMeanLuminance::AgcMeanLuminance(Configuration &&config)
+ : filteredExposure_(0s), luxWarningEnabled_(true), frameCount_(0),
+ relativeLuminanceTarget_(std::move(config.relativeLuminanceTarget)),
+ constraintModes_(std::move(config.constraintModes)),
+ exposureModeHelpers_(std::move(config.exposureModeHelpers))
{
}
AgcMeanLuminance::~AgcMeanLuminance() = default;
-int AgcMeanLuminance::parseRelativeLuminanceTarget(const ValueNode &tuningData)
-{
- auto &target = tuningData["relativeLuminanceTarget"];
- if (!target) {
- relativeLuminanceTarget_ = { { { { 0.0, kDefaultRelativeLuminanceTarget } } } };
- return 0;
- }
-
- auto pwl = target.get<Pwl>();
- if (!pwl) {
- LOG(AgcMeanLuminance, Error)
- << "Failed to load relative luminance target.";
- return -EINVAL;
- }
-
- relativeLuminanceTarget_ = std::move(*pwl);
- return 0;
-}
-
-int AgcMeanLuminance::parseConstraint(const ValueNode &modeDict, int32_t id)
-{
- for (const auto &[boundName, content] : modeDict.asDict()) {
- if (boundName != "upper" && boundName != "lower") {
- LOG(AgcMeanLuminance, Warning)
- << "Ignoring unknown constraint bound '" << boundName << "'";
- continue;
- }
-
- unsigned int idx = static_cast<unsigned int>(boundName == "upper");
- AgcConstraint::Bound bound = static_cast<AgcConstraint::Bound>(idx);
- double qLo = content["qLo"].get<double>().value_or(0.98);
- double qHi = content["qHi"].get<double>().value_or(1.0);
- auto yTarget = content["yTarget"].get<Pwl>();
- if (!yTarget) {
- LOG(AgcMeanLuminance, Error)
- << "Failed to parse yTarget";
- return -EINVAL;
- }
-
- AgcConstraint constraint = { bound, qLo, qHi, std::move(*yTarget) };
- auto &constraints = constraintModes_[id];
-
- if (idx)
- constraints.push_back(std::move(constraint));
- else
- constraints.insert(constraints.begin(), std::move(constraint));
- }
-
- return 0;
-}
-
-int AgcMeanLuminance::parseConstraintModes(const ValueNode &tuningData)
-{
- static constexpr std::tuple<std::string_view, std::string_view, controls::AeConstraintModeEnum> compat[] = {
- { "ConstraintNormal", "Normal", controls::AeConstraintModeNormal },
- { "ConstraintHighlight", "Highlight", controls::AeConstraintModeHighlight },
- { "ConstraintShadows", "Shadows", controls::AeConstraintModeShadows },
- { "ConstraintCustom", "Custom", controls::AeConstraintModeCustom },
- };
-
- const ValueNode &constraintModes = tuningData[controls::AeConstraintMode.name()];
- if (constraintModes.isDictionary()) {
- for (const auto &[modeName, modeDict] : constraintModes.asDict()) {
- std::optional<controls::AeConstraintModeEnum> modeValue;
-
- auto it = AeConstraintModeNameValueMap.find(modeName);
- if (it == AeConstraintModeNameValueMap.end()) {
- for (const auto &[oldName, newName, v] : compat) {
- if (modeName != oldName)
- continue;
-
- modeValue = v;
-
- LOG(AgcMeanLuminance, Warning)
- << "Constraint mode '" << oldName << "' has been renamed to '"
- << newName << "', please fix the tuning file";
- break;
- }
- } else {
- modeValue = static_cast<controls::AeConstraintModeEnum>(it->second);
- }
-
- if (!modeValue) {
- LOG(AgcMeanLuminance, Warning)
- << "Skipping unknown constraint mode '" << modeName << "'";
- continue;
- }
-
- if (!modeDict.isDictionary()) {
- LOG(AgcMeanLuminance, Error)
- << "Invalid constraint mode '" << modeName << "'";
- return -EINVAL;
- }
-
- int ret = parseConstraint(modeDict, *modeValue);
- if (ret)
- return ret;
- }
- }
-
- /*
- * If the tuning data file contains no constraints then we use the
- * default constraint that the IPU3/RkISP1 Agc algorithms were adhering
- * to anyway before centralisation; this constraint forces the top 2% of
- * the histogram to be at least 0.5.
- */
- if (constraintModes_.empty()) {
- AgcConstraint constraint = {
- AgcConstraint::Bound::Lower,
- 0.98,
- 1.0,
- Pwl({ { { 0.0, 0.5 } } })
- };
-
- constraintModes_[controls::AeConstraintModeNormal].push_back(std::move(constraint));
- }
-
- return 0;
-}
-
-int AgcMeanLuminance::parseExposureModes(const ValueNode &tuningData)
-{
- static constexpr std::tuple<std::string_view, std::string_view, controls::AeExposureModeEnum> compat[] = {
- { "ExposureNormal", "Normal", controls::AeExposureModeNormal },
- { "ExposureShort", "Short", controls::AeExposureModeShort },
- { "ExposureLong", "Long", controls::AeExposureModeLong },
- { "ExposureCustom", "Custom", controls::AeExposureModeCustom },
- };
-
- const ValueNode &exposureModes = tuningData[controls::AeExposureMode.name()];
- if (exposureModes.isDictionary()) {
- for (const auto &[modeName, modeValues] : exposureModes.asDict()) {
- std::optional<controls::AeExposureModeEnum> modeValue;
-
- auto it = AeExposureModeNameValueMap.find(modeName);
- if (it == AeExposureModeNameValueMap.end()) {
- for (const auto &[oldName, newName, v] : compat) {
- if (modeName != oldName)
- continue;
-
- modeValue = v;
-
- LOG(AgcMeanLuminance, Warning)
- << "Exposure mode '" << oldName << "' has been renamed to '"
- << newName << "', please fix the tuning file";
- break;
- }
- } else {
- modeValue = static_cast<controls::AeExposureModeEnum>(it->second);
- }
-
- if (!modeValue) {
- LOG(AgcMeanLuminance, Warning)
- << "Skipping unknown exposure mode '" << modeName << "'";
- continue;
- }
-
- if (!modeValues.isDictionary()) {
- LOG(AgcMeanLuminance, Error)
- << "Invalid exposure mode '" << modeName << "'";
- return -EINVAL;
- }
-
- std::vector<uint32_t> exposureTimes =
- modeValues["exposureTime"].get<std::vector<uint32_t>>().value_or(utils::defopt);
- std::vector<double> gains =
- modeValues["gain"].get<std::vector<double>>().value_or(utils::defopt);
-
- if (exposureTimes.size() != gains.size()) {
- LOG(AgcMeanLuminance, Error)
- << "Exposure time and gain array sizes unequal";
- return -EINVAL;
- }
-
- if (exposureTimes.empty()) {
- LOG(AgcMeanLuminance, Error)
- << "Exposure time and gain arrays are empty";
- return -EINVAL;
- }
-
- std::vector<ExposureModeHelper::Stage> stages;
- for (size_t i = 0; i < exposureTimes.size(); i++) {
- stages.push_back({
- .exposureTime = std::chrono::microseconds(exposureTimes[i]),
- .gain = gains[i],
- });
- }
-
- exposureModeHelpers_.try_emplace(*modeValue, std::move(stages));
- }
- }
-
- /*
- * If we don't have any exposure modes in the tuning data we create an
- * ExposureModeHelper using an empty vector of stages. This will result
- * in the ExposureModeHelper simply driving the exposure time as high as
- * possible before touching gain.
- */
- if (exposureModeHelpers_.empty())
- exposureModeHelpers_.try_emplace(controls::AeExposureModeNormal,
- std::vector<ExposureModeHelper::Stage>{});
-
- return 0;
-}
-
/**
* \brief Configure the exposure mode helpers
* \param[in] lineDuration The sensor line length
@@ -408,76 +190,6 @@ void AgcMeanLuminance::configure(utils::Duration lineDuration,
frameCount_ = 0;
}
-/**
- * \brief Parse tuning data for AeConstraintMode and AeExposureMode controls
- * \param[in] tuningData the ValueNode representing the tuning data
- *
- * This function parses tuning data to build the list of allowed values for the
- * AeConstraintMode and AeExposureMode controls. Those tuning data must provide
- * the data in a specific format; the Agc algorithm's tuning data should contain
- * a dictionary called AeConstraintMode containing per-mode setting dictionaries
- * with the key being a value from \ref controls::AeConstraintModeNameValueMap.
- * The yTarget can either be provided as single value or as array in which case
- * it is interpreted as a PWL mapping lux levels to yTarget values. Each mode
- * dict may contain either a "lower" or "upper" key or both, for example:
- *
- * \code{.unparsed}
- * algorithms:
- * - Agc:
- * AeConstraintMode:
- * Normal:
- * lower:
- * qLo: 0.98
- * qHi: 1.0
- * yTarget: 0.5
- * Highlight:
- * lower:
- * qLo: 0.98
- * qHi: 1.0
- * yTarget: 0.5
- * upper:
- * qLo: 0.98
- * qHi: 1.0
- * yTarget: [ 100, 0.8, 20000, 0.5 ]
- *
- * \endcode
- *
- * For the AeExposureMode control the data should contain a dictionary called
- * AeExposureMode containing per-mode setting dictionaries with the key being a
- * value from \ref controls::AeExposureModeNameValueMap. Each mode dict should
- * contain an array of exposure times with the key "exposureTime" and an array
- * of gain values with the key "gain", in this format:
- *
- * \code{.unparsed}
- * algorithms:
- * - Agc:
- * AeExposureMode:
- * Normal:
- * exposureTime: [ 100, 10000, 30000, 60000, 120000 ]
- * gain: [ 2.0, 4.0, 6.0, 8.0, 10.0 ]
- * Short:
- * exposureTime: [ 100, 10000, 30000, 60000, 120000 ]
- * gain: [ 2.0, 4.0, 6.0, 8.0, 10.0 ]
- *
- * \endcode
- *
- * \return 0 on success or a negative error code
- */
-int AgcMeanLuminance::parseTuningData(const ValueNode &tuningData)
-{
- int ret;
-
- ret = parseRelativeLuminanceTarget(tuningData);
- if (ret)
- return ret;
-
- ret = parseConstraintModes(tuningData);
- if (ret)
- return ret;
-
- return parseExposureModes(tuningData);
-}
-
/**
* \brief Set the ExposureModeHelper limits for this class
* \param[in] minExposureTime Minimum exposure time to allow
@@ -502,12 +214,12 @@ void AgcMeanLuminance::setLimits(utils::Duration minExposureTime,
/**
* \fn AgcMeanLuminance::constraintModes()
- * \brief Get the constraint modes that have been parsed from tuning data
+ * \brief Get the available constraint modes
*/
/**
* \fn AgcMeanLuminance::exposureModeHelpers()
- * \brief Get the ExposureModeHelpers that have been parsed from tuning data
+ * \brief Get the available ExposureModeHelpers
*/
/**
@@ -8,13 +8,10 @@
#pragma once
#include <map>
-#include <memory>
#include <vector>
#include <libcamera/base/utils.h>
-#include "libcamera/internal/value_node.h"
-
#include "exposure_mode_helper.h"
#include "histogram.h"
#include "pwl.h"
@@ -26,9 +23,6 @@ namespace ipa {
class AgcMeanLuminance
{
public:
- AgcMeanLuminance();
- ~AgcMeanLuminance();
-
struct AgcConstraint {
enum class Bound {
Lower = 0,
@@ -40,6 +34,15 @@ public:
Pwl yTarget;
};
+ struct Configuration {
+ Pwl relativeLuminanceTarget;
+ std::map<int32_t, std::vector<AgcConstraint>> constraintModes;
+ std::map<int32_t, ExposureModeHelper> exposureModeHelpers;
+ };
+
+ AgcMeanLuminance(Configuration &&config);
+ ~AgcMeanLuminance();
+
struct Traits {
virtual ~Traits() = default;
virtual double estimateLuminance(double gain) const = 0;
@@ -80,20 +83,17 @@ public:
double effectiveYTarget(double lux, double exposureCompensation) const;
private:
- int parseRelativeLuminanceTarget(const ValueNode &tuningData);
- int parseConstraint(const ValueNode &modeDict, int32_t id);
- int parseConstraintModes(const ValueNode &tuningData);
- int parseExposureModes(const ValueNode &tuningData);
double estimateInitialGain(const Traits &traits, double yTarget) const;
double constraintClampGain(const Params ¶ms, double gain) const;
utils::Duration filterExposure(utils::Duration exposureValue);
utils::Duration filteredExposure_;
mutable bool luxWarningEnabled_;
- Pwl relativeLuminanceTarget_;
uint64_t frameCount_;
std::vector<AgcConstraint> additionalConstraints_;
+
+ Pwl relativeLuminanceTarget_;
std::map<int32_t, std::vector<AgcConstraint>> constraintModes_;
std::map<int32_t, ExposureModeHelper> exposureModeHelpers_;
};