new file mode 100644
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Red Hat Inc.
+ *
+ * Exposure and gain
+ */
+
+#include "agc_simple.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include <linux/v4l2-controls.h>
+
+#include <libcamera/base/log.h>
+
+namespace libcamera {
+
+namespace ipa::soft {
+
+LOG_DEFINE_CATEGORY(IPASoftAgcSimple)
+
+
+/*
+ * The number of bins to use for the optimal exposure calculations.
+ */
+static constexpr unsigned int kExposureBinsCount = 5;
+
+/*
+ * The exposure is optimal when the mean sample value of the histogram is
+ * in the middle of the range.
+ */
+static constexpr float kExposureOptimal = kExposureBinsCount / 2.0;
+
+/*
+ * This implements the hysteresis for the exposure adjustment.
+ * It is small enough to have the exposure close to the optimal, and is big
+ * enough to prevent the exposure from wobbling around the optimal value.
+ */
+static constexpr float kExposureSatisfactory = 0.2;
+
+/*
+ * Proportional gain for exposure/gain adjustment. Maps the MSV error to a
+ * multiplicative correction factor:
+ *
+ * factor = 1.0 + kExpProportionalGain * error
+ *
+ * With kExpProportionalGain = 0.04:
+ * - max error ~2.5 -> factor 1.10 (~10% step, same as before)
+ * - error 1.0 -> factor 1.04 (~4% step)
+ * - error 0.3 -> factor 1.012 (~1.2% step)
+ *
+ * This replaces the fixed 10% bang-bang step with a proportional correction
+ * that converges smoothly and avoids overshooting near the target.
+ */
+static constexpr float kExpProportionalGain = 0.04;
+
+/*
+ * Maximum multiplicative step per frame, to bound the correction when the
+ * scene changes dramatically.
+ */
+static constexpr float kExpMaxStep = 0.15;
+
+void AgcSimpleAlgorithm::updateExposure(const Session &session, ActiveState &state, FrameContext &frameContext,
+ const ProcessParams ¶ms, double exposureMSV)
+{
+ double error = kExposureOptimal - exposureMSV;
+ if (std::abs(error) <= kExposureSatisfactory)
+ return;
+
+ utils::Duration exposureDuration = params.exposure * session.lineDuration;
+ int32_t exposure = params.exposure;
+ double again = params.gain;
+
+ /*
+ * Compute a proportional correction factor. The sign of the error
+ * determines the direction: positive error means too dark (increase),
+ * negative means too bright (decrease).
+ */
+ float step = std::clamp(static_cast<float>(error) * kExpProportionalGain,
+ -kExpMaxStep, kExpMaxStep);
+ float factor = 1.0f + step;
+
+ const auto limits = AgcAlgorithm::calculateLimits(session, frameContext);
+
+ if (factor > 1.0f) {
+ /* Scene too dark: increase exposure first, then gain. */
+ if (exposureDuration < limits.exposure.second) {
+ int32_t next = static_cast<int32_t>(exposure * factor);
+ exposure = std::max(next, exposure + 1);
+ } else {
+ double next = again * factor;
+ if (next - again < session.gainMinStep)
+ again += session.gainMinStep;
+ else
+ again = next;
+ }
+ } else {
+ /* Scene too bright: decrease gain first, then exposure. */
+ if (again > std::max(session.gain10, limits.gain.first)) {
+ double next = again * factor;
+ if (again - next < session.gainMinStep)
+ again -= session.gainMinStep;
+ else
+ again = next;
+ } else {
+ int32_t next = static_cast<int32_t>(exposure * factor);
+ exposure = std::min(next, exposure - 1);
+ }
+ }
+
+ exposureDuration = std::clamp<utils::Duration>(
+ exposure * session.lineDuration,
+ limits.exposure.first, limits.exposure.second);
+ exposure = exposureDuration / session.lineDuration;
+ again = std::clamp(again, limits.gain.first, limits.gain.second);
+
+ state.automatic.exposure = exposure;
+ state.automatic.gain = again;
+
+ LOG(IPASoftAgcSimple, Debug)
+ << "exposureMSV " << exposureMSV
+ << " error " << error << " factor " << factor
+ << " exp " << exposure << " again " << again;
+}
+
+int AgcSimpleAlgorithm::configure(Session &session, ActiveState &state, const ConfigurationParams &config)
+{
+ int ret = AgcAlgorithm::configure(session, state, config);
+ if (ret)
+ return ret;
+
+ const ControlInfo &v4l2Gain = config.sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;
+ auto defGain = v4l2Gain.def().get<int32_t>();
+
+ if (config.sensor) {
+ session.gain10 = std::max(session.minAnalogueGain, 1.0);
+ session.gainMinStep = (session.maxAnalogueGain - session.minAnalogueGain) / 100.0;
+ } else {
+ session.gain10 = defGain;
+ session.gainMinStep = 1.0;
+ }
+
+ return 0;
+}
+
+void AgcSimpleAlgorithm::process(const Session &session, ActiveState &state,
+ FrameContext &frameContext, std::optional<ProcessParams> &¶ms,
+ ControlList &metadata)
+{
+ utils::Duration newExposureTime = {};
+
+ if (params) {
+ /*
+ * Calculate Mean Sample Value (MSV) according to formula from:
+ * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf
+ */
+ const auto &histogram = params->stats.yHistogram;
+ const unsigned int blackLevelHistIdx = params->blackLevel / (256 / SwIspStats::kYHistogramSize);
+ const unsigned int histogramSize =
+ SwIspStats::kYHistogramSize - blackLevelHistIdx;
+ const unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount;
+ const unsigned int yHistValsPerBinMod =
+ histogramSize / (histogramSize % kExposureBinsCount + 1);
+ int exposureBins[kExposureBinsCount] = {};
+ unsigned int denom = 0;
+ unsigned int num = 0;
+
+ if (yHistValsPerBin == 0) {
+ LOG(IPASoftAgcSimple, Debug)
+ << "Not adjusting exposure due to insufficient histogram data";
+ return;
+ }
+
+ for (unsigned int i = 0; i < histogramSize; i++) {
+ unsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin;
+ exposureBins[idx] += histogram[blackLevelHistIdx + i];
+ }
+
+ for (unsigned int i = 0; i < kExposureBinsCount; i++) {
+ LOG(IPASoftAgcSimple, Debug) << i << ": " << exposureBins[i];
+ denom += exposureBins[i];
+ num += exposureBins[i] * (i + 1);
+ }
+
+ float exposureMSV = (denom == 0 ? 0 : static_cast<float>(num) / denom);
+ updateExposure(session, state, frameContext, *params, exposureMSV);
+ newExposureTime = state.automatic.exposure * session.lineDuration;
+ }
+
+ AgcAlgorithm::process(session, frameContext, newExposureTime, metadata);
+}
+
+
+} /* namespace ipa::soft::algorithms */
+
+} /* namespace libcamera */
new file mode 100644
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024, Red Hat Inc.
+ *
+ * Exposure and gain
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <libipa/agc.h>
+
+#include "libcamera/internal/software_isp/swisp_stats.h"
+
+namespace libcamera {
+
+namespace ipa::soft {
+
+class AgcSimpleAlgorithm : public AgcAlgorithm
+{
+public:
+ struct Session : AgcAlgorithm::Session {
+ double gain10;
+ double gainMinStep;
+ };
+
+ struct ProcessParams {
+ int32_t exposure;
+ double gain;
+ const SwIspStats &stats;
+ unsigned int blackLevel;
+ };
+
+ int configure(Session &session, ActiveState &state, const ConfigurationParams &config);
+
+ void prepare(ActiveState &state, FrameContext &frameContext)
+ {
+ return AgcAlgorithm::prepare(state, frameContext);
+ }
+
+ void queueRequest(const Session &session, ActiveState &state,
+ FrameContext &frameContext, const ControlList &controls)
+ {
+ return AgcAlgorithm::queueRequest(session, state, frameContext, controls);
+ }
+
+ void process(const Session &session, ActiveState &state,
+ FrameContext &frameContext, std::optional<ProcessParams> &¶ms,
+ ControlList &metadata);
+
+private:
+ void updateExposure(const Session &session, ActiveState &state, FrameContext &frameContext,
+ const ProcessParams ¶ms, double exposureMSV);
+};
+
+} /* namepsace ipa::soft */
+
+} /* namespace libcamera */
@@ -7,124 +7,46 @@
#include "agc.h"
-#include <algorithm>
-#include <cmath>
-#include <stdint.h>
-
#include <libcamera/base/log.h>
-#include "control_ids.h"
-
namespace libcamera {
LOG_DEFINE_CATEGORY(IPASoftExposure)
namespace ipa::soft::algorithms {
-/*
- * The number of bins to use for the optimal exposure calculations.
- */
-static constexpr unsigned int kExposureBinsCount = 5;
-
-/*
- * The exposure is optimal when the mean sample value of the histogram is
- * in the middle of the range.
- */
-static constexpr float kExposureOptimal = kExposureBinsCount / 2.0;
-
-/*
- * This implements the hysteresis for the exposure adjustment.
- * It is small enough to have the exposure close to the optimal, and is big
- * enough to prevent the exposure from wobbling around the optimal value.
- */
-static constexpr float kExposureSatisfactory = 0.2;
-
-/*
- * Proportional gain for exposure/gain adjustment. Maps the MSV error to a
- * multiplicative correction factor:
- *
- * factor = 1.0 + kExpProportionalGain * error
- *
- * With kExpProportionalGain = 0.04:
- * - max error ~2.5 -> factor 1.10 (~10% step, same as before)
- * - error 1.0 -> factor 1.04 (~4% step)
- * - error 0.3 -> factor 1.012 (~1.2% step)
- *
- * This replaces the fixed 10% bang-bang step with a proportional correction
- * that converges smoothly and avoids overshooting near the target.
- */
-static constexpr float kExpProportionalGain = 0.04;
-
-/*
- * Maximum multiplicative step per frame, to bound the correction when the
- * scene changes dramatically.
- */
-static constexpr float kExpMaxStep = 0.15;
-
-Agc::Agc()
+int Agc::init(IPAContext &context, [[maybe_unused]] const ValueNode &tuningData)
{
+ return agc_.configure(context.configuration.agc.simple, context.activeState.agc.simple, {
+ .sensor = context.camHelper.get(),
+ .sensorInfo = context.sensorInfo,
+ .sensorControls = context.sensorControls,
+ .ctrlMap = context.ctrlMap,
+ .autoAllowed = true,
+ });
}
-void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV)
+int Agc::configure(IPAContext &context, [[maybe_unused]] const IPAConfigInfo &configInfo)
{
- int32_t exposure = frameContext.sensor.exposure;
- double again = frameContext.sensor.gain;
-
- double error = kExposureOptimal - exposureMSV;
-
- if (std::abs(error) <= kExposureSatisfactory)
- return;
-
- /*
- * Compute a proportional correction factor. The sign of the error
- * determines the direction: positive error means too dark (increase),
- * negative means too bright (decrease).
- */
- float step = std::clamp(static_cast<float>(error) * kExpProportionalGain,
- -kExpMaxStep, kExpMaxStep);
- float factor = 1.0f + step;
-
- if (factor > 1.0f) {
- /* Scene too dark: increase exposure first, then gain. */
- if (exposure < context.configuration.agc.exposureMax) {
- int32_t next = static_cast<int32_t>(exposure * factor);
- exposure = std::max(next, exposure + 1);
- } else {
- double next = again * factor;
- if (next - again < context.configuration.agc.againMinStep)
- again += context.configuration.agc.againMinStep;
- else
- again = next;
- }
- } else {
- /* Scene too bright: decrease gain first, then exposure. */
- if (again > context.configuration.agc.again10) {
- double next = again * factor;
- if (again - next < context.configuration.agc.againMinStep)
- again -= context.configuration.agc.againMinStep;
- else
- again = next;
- } else {
- int32_t next = static_cast<int32_t>(exposure * factor);
- exposure = std::min(next, exposure - 1);
- }
- }
-
- exposure = std::clamp(exposure, context.configuration.agc.exposureMin,
- context.configuration.agc.exposureMax);
- again = std::clamp(again, context.configuration.agc.againMin,
- context.configuration.agc.againMax);
-
- frameContext.agc.exposure = exposure;
- frameContext.agc.gain = again;
+ return agc_.configure(context.configuration.agc.simple, context.activeState.agc.simple, {
+ .sensor = context.camHelper.get(),
+ .sensorInfo = context.sensorInfo,
+ .sensorControls = context.sensorControls,
+ .ctrlMap = context.ctrlMap,
+ .autoAllowed = true, // \todo not if raw?
+ });
+}
- context.activeState.agc.exposure = exposure;
- context.activeState.agc.again = again;
+void Agc::queueRequest(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAFrameContext &frameContext, const ControlList &controls)
+{
+ agc_.queueRequest(context.configuration.agc.simple, context.activeState.agc.simple,
+ frameContext.agc.simple, controls);
+}
- LOG(IPASoftExposure, Debug)
- << "exposureMSV " << exposureMSV
- << " error " << error << " factor " << factor
- << " exp " << exposure << " again " << again;
+void Agc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params)
+{
+ agc_.prepare(context.activeState.agc.simple, frameContext.agc.simple);
}
void Agc::process(IPAContext &context,
@@ -133,66 +55,20 @@ void Agc::process(IPAContext &context,
const SwIspStats *stats,
ControlList &metadata)
{
- utils::Duration exposureTime =
- context.configuration.agc.lineDuration * frameContext.sensor.exposure;
- metadata.set(controls::ExposureTime, exposureTime.get<std::micro>());
- metadata.set(controls::AnalogueGain, frameContext.sensor.gain);
-
- if (!context.activeState.agc.valid) {
- /*
- * Init active-state from sensor values in case updateExposure()
- * does not run for the first frame.
- */
- context.activeState.agc.exposure = frameContext.sensor.exposure;
- context.activeState.agc.again = frameContext.sensor.gain;
- context.activeState.agc.valid = true;
- }
-
- if (!stats->valid) {
- /*
- * Use the new exposure and gain values calculated the last time
- * there were valid stats.
- */
- frameContext.agc.exposure = context.activeState.agc.exposure;
- frameContext.agc.gain = context.activeState.agc.again;
- return;
- }
-
- /*
- * Calculate Mean Sample Value (MSV) according to formula from:
- * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf
- */
- const auto &histogram = stats->yHistogram;
- const unsigned int blackLevelHistIdx =
- context.activeState.blc.level / (256 / SwIspStats::kYHistogramSize);
- const unsigned int histogramSize =
- SwIspStats::kYHistogramSize - blackLevelHistIdx;
- const unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount;
- const unsigned int yHistValsPerBinMod =
- histogramSize / (histogramSize % kExposureBinsCount + 1);
- int exposureBins[kExposureBinsCount] = {};
- unsigned int denom = 0;
- unsigned int num = 0;
-
- if (yHistValsPerBin == 0) {
- LOG(IPASoftExposure, Debug)
- << "Not adjusting exposure due to insufficient histogram data";
- return;
- }
-
- for (unsigned int i = 0; i < histogramSize; i++) {
- unsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin;
- exposureBins[idx] += histogram[blackLevelHistIdx + i];
- }
-
- for (unsigned int i = 0; i < kExposureBinsCount; i++) {
- LOG(IPASoftExposure, Debug) << i << ": " << exposureBins[i];
- denom += exposureBins[i];
- num += exposureBins[i] * (i + 1);
+ if (stats->valid) {
+ agc_.process(context.configuration.agc.simple, context.activeState.agc.simple, frameContext.agc.simple, {{
+ .exposure = frameContext.sensor.exposure,
+ .gain = frameContext.sensor.gain,
+ .stats = *stats,
+ .blackLevel = context.activeState.blc.level,
+ }}, metadata);
+ } else {
+ agc_.process(context.configuration.agc.simple, context.activeState.agc.simple,
+ frameContext.agc.simple, {}, metadata);
}
- float exposureMSV = (denom == 0 ? 0 : static_cast<float>(num) / denom);
- updateExposure(context, frameContext, exposureMSV);
+ frameContext.agc.exposure = frameContext.agc.simple.exposure;
+ frameContext.agc.gain = frameContext.agc.simple.gain;
}
REGISTER_IPA_ALGORITHM(Agc, "Agc")
@@ -8,6 +8,7 @@
#pragma once
#include "algorithm.h"
+#include "agc_simple.h"
namespace libcamera {
@@ -16,16 +17,20 @@ namespace ipa::soft::algorithms {
class Agc : public Algorithm
{
public:
- Agc();
+ Agc() = default;
~Agc() = default;
+ int init(IPAContext &context, const ValueNode &tuningData) override;
+ int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
+ void queueRequest(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const ControlList &controls) override;
+ void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, DebayerParams *params) override;
void process(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
const SwIspStats *stats,
ControlList &metadata) override;
private:
- void updateExposure(IPAContext &context, IPAFrameContext &frameContext, double exposureMSV);
+ AgcSimpleAlgorithm agc_;
};
} /* namespace ipa::soft::algorithms */
@@ -7,7 +7,6 @@
#pragma once
-#include <array>
#include <optional>
#include <stdint.h>
@@ -16,19 +15,21 @@
#include "libcamera/internal/matrix.h"
#include "libcamera/internal/vector.h"
+#include <libipa/camera_sensor_helper.h>
#include <libipa/fc_queue.h>
#include "core_ipa_interface.h"
+#include "agc_simple.h"
+
namespace libcamera {
namespace ipa::soft {
struct IPASessionConfiguration {
struct {
- int32_t exposureMin, exposureMax;
- double againMin, againMax, again10, againMinStep;
- utils::Duration lineDuration;
+ AgcSimpleAlgorithm::Session simple;
+ double again10, againMinStep;
} agc;
struct {
std::optional<uint8_t> level;
@@ -37,9 +38,7 @@ struct IPASessionConfiguration {
struct IPAActiveState {
struct {
- int32_t exposure;
- double again;
- bool valid;
+ AgcSimpleAlgorithm::ActiveState simple;
} agc;
struct {
@@ -67,6 +66,7 @@ struct IPAFrameContext : public FrameContext {
Matrix<float, 3, 3> ccm;
struct {
+ AgcSimpleAlgorithm::FrameContext simple;
int32_t exposure;
double gain;
} agc;
@@ -90,10 +90,12 @@ struct IPAContext {
}
IPACameraSensorInfo sensorInfo;
+ ControlInfoMap sensorControls;
IPASessionConfiguration configuration;
IPAActiveState activeState;
FCQueue<IPAFrameContext> frameContexts;
ControlInfoMap::Map ctrlMap;
+ std::unique_ptr<CameraSensorHelper> camHelper;
bool ccmEnabled = false;
};
@@ -6,6 +6,7 @@ subdir('data')
ipa_name = 'ipa_soft_simple'
soft_simple_sources = files([
+ 'agc_simple.cpp',
'ipa_context.cpp',
'soft_simple.cpp',
])
@@ -5,7 +5,6 @@
* Simple Software Image Processing Algorithm module
*/
-#include <chrono>
#include <stdint.h>
#include <sys/mman.h>
@@ -34,8 +33,6 @@
namespace libcamera {
LOG_DEFINE_CATEGORY(IPASoft)
-using namespace std::literals::chrono_literals;
-
namespace ipa::soft {
/* Maximum number of frame contexts to be held */
@@ -76,8 +73,6 @@ private:
DebayerParams *params_;
SwIspStats *stats_;
- std::unique_ptr<CameraSensorHelper> camHelper_;
- ControlInfoMap sensorInfoMap_;
/* Local parameter storage */
struct IPAContext context_;
@@ -99,14 +94,15 @@ int IPASoftSimple::init(const IPASettings &settings,
ControlInfoMap *ipaControls,
bool *ccmEnabled)
{
- camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
- if (!camHelper_) {
+ context_.camHelper = CameraSensorHelperFactoryBase::create(settings.sensorModel);
+ if (!context_.camHelper) {
LOG(IPASoft, Warning)
<< "Failed to create camera sensor helper for "
<< settings.sensorModel;
}
context_.sensorInfo = sensorInfo;
+ context_.sensorControls = sensorControls;
/* Load the tuning data file */
File file(settings.configurationFile);
@@ -201,38 +197,15 @@ int IPASoftSimple::init(const IPASettings &settings,
int IPASoftSimple::configure(const IPAConfigInfo &configInfo)
{
- sensorInfoMap_ = configInfo.sensorControls;
-
- const ControlInfo &exposureInfo = sensorInfoMap_.find(V4L2_CID_EXPOSURE)->second;
- const ControlInfo &gainInfo = sensorInfoMap_.find(V4L2_CID_ANALOGUE_GAIN)->second;
+ context_.sensorControls = configInfo.sensorControls;
/* Clear the IPA context before the streaming session. */
context_.configuration = {};
context_.activeState = {};
context_.frameContexts.clear();
- context_.configuration.agc.lineDuration =
- context_.sensorInfo.minLineLength * 1.0s / context_.sensorInfo.pixelRate;
- context_.configuration.agc.exposureMin = exposureInfo.min().get<int32_t>();
- context_.configuration.agc.exposureMax = exposureInfo.max().get<int32_t>();
- if (!context_.configuration.agc.exposureMin) {
- LOG(IPASoft, Warning) << "Minimum exposure is zero, that can't be linear";
- context_.configuration.agc.exposureMin = 1;
- }
-
- int32_t againMin = gainInfo.min().get<int32_t>();
- int32_t againMax = gainInfo.max().get<int32_t>();
- int32_t againDef = gainInfo.def().get<int32_t>();
-
- if (camHelper_) {
- context_.configuration.agc.againMin = camHelper_->gain(againMin);
- context_.configuration.agc.againMax = camHelper_->gain(againMax);
- context_.configuration.agc.again10 = std::max(context_.configuration.agc.againMin, 1.0);
- context_.configuration.agc.againMinStep =
- (context_.configuration.agc.againMax -
- context_.configuration.agc.againMin) /
- 100.0;
- if (camHelper_->blackLevel().has_value()) {
+ if (context_.camHelper) {
+ if (context_.camHelper->blackLevel().has_value()) {
/*
* The black level from camHelper_ is a 16 bit value, software ISP
* works with 8 bit pixel values, both regardless of the actual
@@ -240,13 +213,8 @@ int IPASoftSimple::configure(const IPAConfigInfo &configInfo)
* by dividing the value from the helper by 256.
*/
context_.configuration.black.level =
- camHelper_->blackLevel().value() / 256;
+ context_.camHelper->blackLevel().value() / 256;
}
- } else {
- context_.configuration.agc.againMax = againMax;
- context_.configuration.agc.again10 = againDef;
- context_.configuration.agc.againMin = againMin;
- context_.configuration.agc.againMinStep = 1.0;
}
for (const auto &algo : algorithms()) {
@@ -255,13 +223,6 @@ int IPASoftSimple::configure(const IPAConfigInfo &configInfo)
return ret;
}
- LOG(IPASoft, Info)
- << "Exposure " << context_.configuration.agc.exposureMin << "-"
- << context_.configuration.agc.exposureMax
- << ", gain " << context_.configuration.agc.againMin << "-"
- << context_.configuration.agc.againMax
- << " (" << context_.configuration.agc.againMinStep << ")";
-
return 0;
}
@@ -311,17 +272,17 @@ void IPASoftSimple::processStats(const uint32_t frame,
frameContext.sensor.exposure =
sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();
int32_t again = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();
- frameContext.sensor.gain = camHelper_ ? camHelper_->gain(again) : again;
+ frameContext.sensor.gain = context_.camHelper ? context_.camHelper->gain(again) : again;
ControlList metadata(controls::controls);
for (const auto &algo : algorithms())
algo->process(context_, frame, frameContext, stats_, metadata);
metadataReady.emit(frame, metadata);
- ControlList ctrls(sensorInfoMap_);
+ ControlList ctrls(context_.sensorControls);
- int32_t againNew = camHelper_
- ? camHelper_->gainCode(frameContext.agc.gain)
+ int32_t againNew = context_.camHelper
+ ? context_.camHelper->gainCode(frameContext.agc.gain)
: static_cast<int32_t>(frameContext.agc.gain);
ctrls.set(V4L2_CID_EXPOSURE, frameContext.agc.exposure);
ctrls.set(V4L2_CID_ANALOGUE_GAIN, againNew);
Move the agc algorithm into a separate class and use `AgcAlgorithm`. Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> --- src/ipa/simple/agc_simple.cpp | 197 +++++++++++++++++++++++++++++ src/ipa/simple/agc_simple.h | 59 +++++++++ src/ipa/simple/algorithms/agc.cpp | 200 ++++++------------------------ src/ipa/simple/algorithms/agc.h | 9 +- src/ipa/simple/ipa_context.h | 16 +-- src/ipa/simple/meson.build | 1 + src/ipa/simple/soft_simple.cpp | 61 ++------- 7 files changed, 322 insertions(+), 221 deletions(-) create mode 100644 src/ipa/simple/agc_simple.cpp create mode 100644 src/ipa/simple/agc_simple.h