@@ -48,17 +48,10 @@ namespace ipa::ipu3::algorithms {
LOG_DEFINE_CATEGORY(IPU3Agc)
-/* Minimum limit for analogue gain value */
-static constexpr double kMinAnalogueGain = 1.0;
-
-/* \todo Honour the FrameDurationLimits control instead of hardcoding a limit */
-static constexpr utils::Duration kMaxExposureTime = 60ms;
-
/* Histogram constants */
static constexpr uint32_t knumHistogramBins = 256;
Agc::Agc()
- : minExposureTime_(0s), maxExposureTime_(0s)
{
}
@@ -76,11 +69,18 @@ int Agc::init(IPAContext &context, const ValueNode &tuningData)
{
int ret;
- ret = agc_.parseTuningData(tuningData);
+ ret = agc_.init(tuningData);
if (ret)
return ret;
- context.ctrlMap.merge(agc_.controls());
+ ret = agc_.configure(context.configuration.agc, context.activeState.agc, {
+ .sensor = *context.camHelper,
+ .sensorInfo = context.sensorInfo,
+ .sensorControls = context.sensorControls,
+ .ctrlMap = context.ctrlMap,
+ });
+ if (ret)
+ return ret;
return 0;
}
@@ -95,32 +95,36 @@ int Agc::init(IPAContext &context, const ValueNode &tuningData)
int Agc::configure(IPAContext &context,
[[maybe_unused]] const IPAConfigInfo &configInfo)
{
- const IPASessionConfiguration &configuration = context.configuration;
- IPAActiveState &activeState = context.activeState;
-
- stride_ = configuration.grid.stride;
- bdsGrid_ = configuration.grid.bdsGrid;
-
- minExposureTime_ = configuration.agc.minExposureTime;
- maxExposureTime_ = std::min(configuration.agc.maxExposureTime,
- kMaxExposureTime);
-
- minAnalogueGain_ = std::max(configuration.agc.minAnalogueGain, kMinAnalogueGain);
- maxAnalogueGain_ = configuration.agc.maxAnalogueGain;
-
- /* Configure the default exposure and gain. */
- activeState.agc.gain = minAnalogueGain_;
- activeState.agc.exposure = 10ms / configuration.sensor.lineDuration;
-
- context.activeState.agc.constraintMode = agc_.constraintModes().begin()->first;
- context.activeState.agc.exposureMode = agc_.exposureModeHelpers().begin()->first;
+ stride_ = context.configuration.grid.stride;
+ bdsGrid_ = context.configuration.grid.bdsGrid;
+
+ return agc_.configure(context.configuration.agc, context.activeState.agc, {
+ .sensor = *context.camHelper,
+ .sensorInfo = context.sensorInfo,
+ .sensorControls = context.sensorControls,
+ .ctrlMap = context.ctrlMap,
+ .autoAllowed = true, // \todo if not raw?
+ });
+}
- /* \todo Run this again when FrameDurationLimits is passed in */
- agc_.setLimits(minExposureTime_, maxExposureTime_, minAnalogueGain_,
- maxAnalogueGain_, {});
- agc_.resetFrameCount();
+/**
+ * \copydoc libcamera::ipa::Algorithm::queueRequest
+ */
+void Agc::queueRequest(IPAContext &context, [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext, const ControlList &controls)
+{
+ agc_.queueRequest(context.configuration.agc, context.activeState.agc,
+ frameContext.agc, controls);
+}
- return 0;
+/**
+ * \copydoc libcamera::ipa::Algorithm::prepare
+ */
+void Agc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext,
+ [[maybe_unused]] ipu3_uapi_params *params)
+{
+ agc_.prepare(context.activeState.agc, frameContext.agc);
}
Histogram Agc::parseStatistics(const ipu3_uapi_stats_3a *stats,
@@ -229,50 +233,20 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
Histogram hist = parseStatistics(stats, context.configuration.grid.bdsGrid);
- /*
- * The Agc algorithm needs to know the effective exposure value that was
- * applied to the sensor when the statistics were collected.
- */
- utils::Duration exposureTime = context.configuration.sensor.lineDuration
- * frameContext.sensor.exposure;
- double analogueGain = frameContext.sensor.gain;
- utils::Duration effectiveExposureValue = exposureTime * analogueGain;
-
- AgcTraits agcTraits{
- rgbTriples_,
- {{
- context.activeState.awb.gains.red,
- context.activeState.awb.gains.blue,
- context.activeState.awb.gains.green,
- }},
- bdsGrid_,
- };
-
- utils::Duration newExposureTime;
- double aGain, qGain, dGain;
- std::tie(newExposureTime, aGain, qGain, dGain) =
- agc_.calculateNewEv(context.activeState.agc.constraintMode,
- context.activeState.agc.exposureMode, hist,
- effectiveExposureValue, agcTraits);
-
- LOG(IPU3Agc, Debug)
- << "Divided up exposure time, analogue gain and digital gain are "
- << newExposureTime << ", " << aGain << " and " << dGain;
-
- IPAActiveState &activeState = context.activeState;
- /* Update the estimated exposure time and gain. */
- activeState.agc.exposure = newExposureTime / context.configuration.sensor.lineDuration;
- activeState.agc.gain = aGain;
-
- metadata.set(controls::AnalogueGain, frameContext.sensor.gain);
- metadata.set(controls::ExposureTime, exposureTime.get<std::micro>());
-
- /* \todo Use VBlank value calculated from each frame exposure. */
- uint32_t vTotal = context.configuration.sensor.size.height
- + context.configuration.sensor.defVBlank;
- utils::Duration frameDuration = context.configuration.sensor.lineDuration
- * vTotal;
- metadata.set(controls::FrameDuration, frameDuration.get<std::micro>());
+ agc_.process(context.configuration.agc, context.activeState.agc, frameContext.agc, {{
+ .traits = AgcTraits{
+ rgbTriples_,
+ {{
+ context.activeState.awb.gains.red,
+ context.activeState.awb.gains.blue,
+ context.activeState.awb.gains.green,
+ }},
+ bdsGrid_,
+ },
+ .hist = hist,
+ .exposure = frameContext.sensor.exposure,
+ .gain = frameContext.sensor.gain,
+ }}, metadata);
}
REGISTER_IPA_ALGORITHM(Agc, "Agc")
@@ -32,6 +32,11 @@ public:
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,
+ ipu3_uapi_params *params) override;
void process(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
const ipu3_uapi_stats_3a *stats,
@@ -41,17 +46,11 @@ private:
Histogram parseStatistics(const ipu3_uapi_stats_3a *stats,
const ipu3_uapi_grid_config &grid);
- utils::Duration minExposureTime_;
- utils::Duration maxExposureTime_;
-
- double minAnalogueGain_;
- double maxAnalogueGain_;
-
uint32_t stride_;
ipu3_uapi_grid_config bdsGrid_;
std::vector<std::tuple<uint8_t, uint8_t, uint8_t>> rgbTriples_;
- AgcMeanLuminance agc_;
+ AgcMeanLuminanceAlgorithm agc_;
};
} /* namespace ipa::ipu3::algorithms */
@@ -46,12 +46,21 @@ namespace libcamera::ipa::ipu3 {
* \var IPAContext::configuration
* \brief The IPA session configuration, immutable during the session
*
+ * \var IPAContext::sensorInfo
+ * \brief The IPA camera session details, immutable during the session
+ *
+ * \var IPAContext::sensorControls
+ * \brief The camera sensor controls, immutable during the session
+ *
* \var IPAContext::frameContexts
* \brief Ring buffer of the IPAFrameContext(s)
*
* \var IPAContext::activeState
* \brief The current state of IPA algorithms
*
+ * \var IPAContext::camHelper
+ * \brief The camera sensor helper
+ *
* \var IPAContext::ctrlMap
* \brief A ControlInfoMap::Map of controls populated by the algorithms
*/
@@ -95,48 +104,11 @@ namespace libcamera::ipa::ipu3 {
/**
* \var IPASessionConfiguration::agc
* \brief AGC parameters configuration of the IPA
- *
- * \var IPASessionConfiguration::agc.minExposureTime
- * \brief Minimum exposure time supported with the configured sensor
- *
- * \var IPASessionConfiguration::agc.maxExposureTime
- * \brief Maximum exposure time supported with the configured sensor
- *
- * \var IPASessionConfiguration::agc.minAnalogueGain
- * \brief Minimum analogue gain supported with the configured sensor
- *
- * \var IPASessionConfiguration::agc.maxAnalogueGain
- * \brief Maximum analogue gain supported with the configured sensor
- */
-
-/**
- * \var IPASessionConfiguration::sensor
- * \brief Sensor-specific configuration of the IPA
- *
- * \var IPASessionConfiguration::sensor.lineDuration
- * \brief Line duration in microseconds
- *
- * \var IPASessionConfiguration::sensor.defVBlank
- * \brief The default vblank value of the sensor
- *
- * \var IPASessionConfiguration::sensor.size
- * \brief Sensor output resolution
*/
/**
* \var IPAActiveState::agc
* \brief Context for the Automatic Gain Control algorithm
- *
- * The exposure and gain determined are expected to be applied to the sensor
- * at the earliest opportunity.
- *
- * \var IPAActiveState::agc.exposure
- * \brief Exposure time expressed as a number of lines
- *
- * \var IPAActiveState::agc.gain
- * \brief Analogue gain multiplier
- *
- * The gain should be adapted to the sensor specific gain code before applying.
*/
/**
@@ -185,6 +157,9 @@ namespace libcamera::ipa::ipu3 {
*
* \var IPAFrameContext::sensor.gain
* \brief Analogue gain multiplier
+ *
+ * \var IPAFrameContext::agc
+ * \brief Per-frame state for the AGC algorithm
*/
} /* namespace libcamera::ipa::ipu3 */
@@ -15,6 +15,8 @@
#include <libcamera/controls.h>
#include <libcamera/geometry.h>
+#include <libipa/agc_mean_luminance.h>
+#include <libipa/camera_sensor_helper.h>
#include <libipa/fc_queue.h>
namespace libcamera {
@@ -32,18 +34,8 @@ struct IPASessionConfiguration {
ipu3_uapi_grid_config afGrid;
} af;
- struct {
- utils::Duration minExposureTime;
- utils::Duration maxExposureTime;
- double minAnalogueGain;
- double maxAnalogueGain;
+ struct Agc : AgcMeanLuminanceAlgorithm::Session {
} agc;
-
- struct {
- int32_t defVBlank;
- utils::Duration lineDuration;
- Size size;
- } sensor;
};
struct IPAActiveState {
@@ -53,11 +45,7 @@ struct IPAActiveState {
bool stable;
} af;
- struct {
- uint32_t exposure;
- double gain;
- uint32_t constraintMode;
- uint32_t exposureMode;
+ struct Agc : AgcMeanLuminanceAlgorithm::ActiveState {
} agc;
struct {
@@ -81,6 +69,9 @@ struct IPAFrameContext : public FrameContext {
uint32_t exposure;
double gain;
} sensor;
+
+ struct Agc : AgcMeanLuminanceAlgorithm::FrameContext {
+ } agc;
};
struct IPAContext {
@@ -90,10 +81,14 @@ struct IPAContext {
}
IPASessionConfiguration configuration;
+ IPACameraSensorInfo sensorInfo;
+ ControlInfoMap sensorControls;
IPAActiveState activeState;
FCQueue<IPAFrameContext> frameContexts;
+ std::unique_ptr<CameraSensorHelper> camHelper;
+
ControlInfoMap::Map ctrlMap;
};
@@ -165,24 +165,15 @@ protected:
std::string logPrefix() const override;
private:
- void updateControls(const IPACameraSensorInfo &sensorInfo,
- const ControlInfoMap &sensorControls,
- ControlInfoMap *ipaControls);
- void updateSessionConfiguration(const ControlInfoMap &sensorControls);
+ void updateControls(ControlInfoMap *ipaControls);
void setControls(unsigned int frame);
void calculateBdsGrid(const Size &bdsOutputSize);
std::map<unsigned int, MappedFrameBuffer> buffers_;
- ControlInfoMap sensorCtrls_;
ControlInfoMap lensCtrls_;
- IPACameraSensorInfo sensorInfo_;
-
- /* Interface to the Camera Helper */
- std::unique_ptr<CameraSensorHelper> camHelper_;
-
/* Local parameter storage */
struct IPAContext context_;
};
@@ -197,36 +188,6 @@ std::string IPAIPU3::logPrefix() const
return "ipu3";
}
-/**
- * \brief Compute IPASessionConfiguration using the sensor information and the
- * sensor V4L2 controls
- */
-void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)
-{
- const ControlInfo vBlank = sensorControls.find(V4L2_CID_VBLANK)->second;
- context_.configuration.sensor.defVBlank = vBlank.def().get<int32_t>();
-
- const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;
- int32_t minExposure = v4l2Exposure.min().get<int32_t>();
- int32_t maxExposure = v4l2Exposure.max().get<int32_t>();
-
- const ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;
- int32_t minGain = v4l2Gain.min().get<int32_t>();
- int32_t maxGain = v4l2Gain.max().get<int32_t>();
-
- /*
- * When the AGC computes the new exposure values for a frame, it needs
- * to know the limits for exposure time and analogue gain.
- * As it depends on the sensor, update it with the controls.
- *
- * \todo take VBLANK into account for maximum exposure time
- */
- context_.configuration.agc.minExposureTime = minExposure * context_.configuration.sensor.lineDuration;
- context_.configuration.agc.maxExposureTime = maxExposure * context_.configuration.sensor.lineDuration;
- context_.configuration.agc.minAnalogueGain = camHelper_->gain(minGain);
- context_.configuration.agc.maxAnalogueGain = camHelper_->gain(maxGain);
-}
-
/**
* \brief Compute camera controls using the sensor information and the sensor
* V4L2 controls
@@ -239,54 +200,12 @@ void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)
* - controls::ExposureTime
* - controls::FrameDurationLimits
*/
-void IPAIPU3::updateControls(const IPACameraSensorInfo &sensorInfo,
- const ControlInfoMap &sensorControls,
- ControlInfoMap *ipaControls)
+void IPAIPU3::updateControls(ControlInfoMap *ipaControls)
{
- ControlInfoMap::Map controls{};
- double lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();
-
- /*
- * Compute exposure time limits by using line length and pixel rate
- * converted to microseconds. Use the V4L2_CID_EXPOSURE control to get
- * exposure min, max and default and convert it from lines to
- * microseconds.
- */
- const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;
- int32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;
- int32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;
- int32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;
- controls[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure,
- defExposure);
-
- /*
- * Compute the frame duration limits.
- *
- * The frame length is computed assuming a fixed line length combined
- * with the vertical frame sizes.
- */
- const ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second;
- uint32_t hblank = v4l2HBlank.def().get<int32_t>();
- uint32_t lineLength = sensorInfo.outputSize.width + hblank;
-
- const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second;
- std::array<uint32_t, 3> frameHeights{
- v4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height,
- v4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height,
- v4l2VBlank.def().get<int32_t>() + sensorInfo.outputSize.height,
- };
+ ControlInfoMap::Map ctrlMap;
- std::array<int64_t, 3> frameDurations;
- for (unsigned int i = 0; i < frameHeights.size(); ++i) {
- uint64_t frameSize = lineLength * frameHeights[i];
- frameDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U);
- }
- controls[&controls::FrameDurationLimits] = ControlInfo(frameDurations[0],
- frameDurations[1],
- Span<const int64_t, 2>{ { frameDurations[2], frameDurations[2] } });
-
- controls.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());
- *ipaControls = ControlInfoMap(std::move(controls), controls::controls);
+ ctrlMap.insert(context_.ctrlMap.begin(), context_.ctrlMap.end());
+ *ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls);
}
/**
@@ -301,18 +220,19 @@ int IPAIPU3::init(const IPASettings &settings,
const ControlInfoMap &sensorControls,
ControlInfoMap *ipaControls)
{
- camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
- if (camHelper_ == nullptr) {
+ context_.camHelper = CameraSensorHelperFactoryBase::create(settings.sensorModel);
+ if (!context_.camHelper) {
LOG(IPAIPU3, Error)
<< "Failed to create camera sensor helper for "
<< settings.sensorModel;
return -ENODEV;
}
+ context_.sensorInfo = sensorInfo;
+ context_.sensorControls = sensorControls;
+
/* Clean context */
context_.configuration = {};
- context_.configuration.sensor.lineDuration =
- sensorInfo.minLineLength * 1.0s / sensorInfo.pixelRate;
/* Load the tuning data file. */
File file(settings.configurationFile);
@@ -346,7 +266,7 @@ int IPAIPU3::init(const IPASettings &settings,
return ret;
/* Initialize controls. */
- updateControls(sensorInfo, sensorControls, ipaControls);
+ updateControls(ipaControls);
return 0;
}
@@ -465,7 +385,8 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo,
return -ENODATA;
}
- sensorInfo_ = configInfo.sensorInfo;
+ context_.sensorInfo = configInfo.sensorInfo;
+ context_.sensorControls = configInfo.sensorControls;
lensCtrls_ = configInfo.lensControls;
@@ -474,31 +395,16 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo,
context_.configuration = {};
context_.frameContexts.clear();
- /* Initialise the sensor configuration. */
- context_.configuration.sensor.lineDuration =
- sensorInfo_.minLineLength * 1.0s / sensorInfo_.pixelRate;
- context_.configuration.sensor.size = sensorInfo_.outputSize;
-
- /*
- * Compute the sensor V4L2 controls to be used by the algorithms and
- * to be set on the sensor.
- */
- sensorCtrls_ = configInfo.sensorControls;
-
calculateBdsGrid(configInfo.bdsOutputSize);
- /* Update the camera controls using the new sensor settings. */
- updateControls(sensorInfo_, sensorCtrls_, ipaControls);
-
- /* Update the IPASessionConfiguration using the sensor settings. */
- updateSessionConfiguration(sensorCtrls_);
-
for (const auto &algo : algorithms()) {
int ret = algo->configure(context_, configInfo);
if (ret)
return ret;
}
+ updateControls(ipaControls);
+
return 0;
}
@@ -596,8 +502,10 @@ void IPAIPU3::processStats(const uint32_t frame,
IPAFrameContext &frameContext = context_.frameContexts.get(frame);
- frameContext.sensor.exposure = sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();
- frameContext.sensor.gain = camHelper_->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>());
+ frameContext.sensor = {
+ .exposure = static_cast<uint32_t>(sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>()),
+ .gain = context_.camHelper->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>()),
+ };
ControlList metadata(controls::controls);
@@ -642,10 +550,12 @@ void IPAIPU3::queueRequest(const uint32_t frame, const ControlList &controls)
*/
void IPAIPU3::setControls(unsigned int frame)
{
- int32_t exposure = context_.activeState.agc.exposure;
- int32_t gain = camHelper_->gainCode(context_.activeState.agc.gain);
+ IPAFrameContext &frameContext = context_.frameContexts.get(frame);
+
+ int32_t exposure = frameContext.agc.exposure;
+ int32_t gain = context_.camHelper->gainCode(frameContext.agc.gain);
- ControlList ctrls(sensorCtrls_);
+ ControlList ctrls(context_.sensorControls);
ctrls.set(V4L2_CID_EXPOSURE, exposure);
ctrls.set(V4L2_CID_ANALOGUE_GAIN, gain);
Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> --- src/ipa/ipu3/algorithms/agc.cpp | 128 ++++++++++++----------------- src/ipa/ipu3/algorithms/agc.h | 13 ++- src/ipa/ipu3/ipa_context.cpp | 49 +++--------- src/ipa/ipu3/ipa_context.h | 27 +++---- src/ipa/ipu3/ipu3.cpp | 138 ++++++-------------------------- 5 files changed, 104 insertions(+), 251 deletions(-)