[libcamera-devel] [PATCH v4 4/9] ipa: rkisp1: Add support for manual gain and exposure
Paul Elder
paul.elder at ideasonboard.com
Fri Nov 25 08:17:42 CET 2022
On Thu, Nov 24, 2022 at 04:51:28AM +0200, Laurent Pinchart wrote:
> From: Paul Elder <paul.elder at ideasonboard.com>
>
> Add support for manual gain and exposure in the rkisp1 IPA.
>
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder at ideasonboard.com>
> ---
> Changes since v3:
>
> - Convert exposure and gain V4L2 controls limits to libcamera values
> - Convert exposure control from duration to lines in AGC
> - Initialize lineDuration in init()
> - Small fixes in debug messages
> - Drop unnecessary curly braces
> - Use std::piecewise_construct
> ---
> src/ipa/rkisp1/algorithms/agc.cpp | 63 +++++++++++++++++++++++++++----
> src/ipa/rkisp1/algorithms/agc.h | 4 ++
> src/ipa/rkisp1/ipa_context.h | 13 ++++++-
> src/ipa/rkisp1/rkisp1.cpp | 25 ++++++++++++
> 4 files changed, 96 insertions(+), 9 deletions(-)
>
> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp
> index 169afe372803..ccbcd4a9583d 100644
> --- a/src/ipa/rkisp1/algorithms/agc.cpp
> +++ b/src/ipa/rkisp1/algorithms/agc.cpp
> @@ -74,9 +74,14 @@ Agc::Agc()
> int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
> {
> /* Configure the default exposure and gain. */
> - context.activeState.agc.gain = std::max(context.configuration.sensor.minAnalogueGain,
> - kMinAnalogueGain);
> - context.activeState.agc.exposure = 10ms / context.configuration.sensor.lineDuration;
> + context.activeState.agc.automatic.gain =
> + std::max(context.configuration.sensor.minAnalogueGain,
> + kMinAnalogueGain);
> + context.activeState.agc.automatic.exposure =
> + 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 = true;
>
> /*
> * According to the RkISP1 documentation:
> @@ -108,14 +113,58 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
> return 0;
> }
>
> +/**
> + * \copydoc libcamera::ipa::Algorithm::queueRequest
> + */
> +void Agc::queueRequest(IPAContext &context,
> + [[maybe_unused]] const uint32_t frame,
> + IPAFrameContext &frameContext,
> + const ControlList &controls)
> +{
> + auto &agc = context.activeState.agc;
> +
> + const auto &agcEnable = controls.get(controls::AeEnable);
> + if (agcEnable && *agcEnable != agc.autoEnabled) {
> + agc.autoEnabled = *agcEnable;
> +
> + LOG(RkISP1Agc, Debug)
> + << (agc.autoEnabled ? "Enabling" : "Disabling") << " AGC";
> + }
> +
> + const auto &exposure = controls.get(controls::ExposureTime);
> + if (exposure && !agc.autoEnabled) {
> + agc.manual.exposure = *exposure * 1.0us
> + / context.configuration.sensor.lineDuration;
> +
> + LOG(RkISP1Agc, Debug)
> + << "Set exposure to " << agc.manual.exposure;
> + }
> +
> + const auto &gain = controls.get(controls::AnalogueGain);
> + if (gain && !agc.autoEnabled) {
> + agc.manual.gain = *gain;
> +
> + LOG(RkISP1Agc, Debug) << "Set gain to " << agc.manual.gain;
> + }
> +
> + frameContext.agc.autoEnabled = agc.autoEnabled;
> +
> + if (!frameContext.agc.autoEnabled) {
> + frameContext.agc.exposure = agc.manual.exposure;
> + frameContext.agc.gain = agc.manual.gain;
> + }
> +}
> +
> /**
> * \copydoc libcamera::ipa::Algorithm::prepare
> */
> void Agc::prepare(IPAContext &context, const uint32_t frame,
> IPAFrameContext &frameContext, rkisp1_params_cfg *params)
> {
> - frameContext.agc.exposure = context.activeState.agc.exposure;
> - frameContext.agc.gain = context.activeState.agc.gain;
> + if (frameContext.agc.autoEnabled) {
> + frameContext.agc.exposure = context.activeState.agc.automatic.exposure;
> + frameContext.agc.gain = context.activeState.agc.automatic.gain;
> + }
>
> if (frame > 0)
> return;
> @@ -263,8 +312,8 @@ void Agc::computeExposure(IPAContext &context, IPAFrameContext &frameContext,
> << stepGain;
>
> /* Update the estimated exposure and gain. */
> - activeState.agc.exposure = shutterTime / configuration.sensor.lineDuration;
> - activeState.agc.gain = stepGain;
> + activeState.agc.automatic.exposure = shutterTime / configuration.sensor.lineDuration;
> + activeState.agc.automatic.gain = stepGain;
> }
>
> /**
> diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h
> index da4d2d4e8359..a228d0c37768 100644
> --- a/src/ipa/rkisp1/algorithms/agc.h
> +++ b/src/ipa/rkisp1/algorithms/agc.h
> @@ -26,6 +26,10 @@ public:
> ~Agc() = default;
>
> int configure(IPAContext &context, const IPACameraSensorInfo &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,
> rkisp1_params_cfg *params) override;
> diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h
> index 3e47ac663c58..b9b2065328d6 100644
> --- a/src/ipa/rkisp1/ipa_context.h
> +++ b/src/ipa/rkisp1/ipa_context.h
> @@ -54,8 +54,16 @@ struct IPASessionConfiguration {
>
> struct IPAActiveState {
> struct {
> - uint32_t exposure;
> - double gain;
> + struct {
> + uint32_t exposure;
> + double gain;
> + } manual;
> + struct {
> + uint32_t exposure;
> + double gain;
> + } automatic;
> +
> + bool autoEnabled;
> } agc;
>
> struct {
> @@ -96,6 +104,7 @@ struct IPAFrameContext : public FrameContext {
> struct {
> uint32_t exposure;
> double gain;
> + bool autoEnabled;
> } agc;
>
> struct {
> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
> index 6ac29df8ec8d..76e818d2d11e 100644
> --- a/src/ipa/rkisp1/rkisp1.cpp
> +++ b/src/ipa/rkisp1/rkisp1.cpp
> @@ -158,6 +158,9 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,
> return -ENODEV;
> }
>
> + context_.configuration.sensor.lineDuration = sensorInfo.minLineLength
> + * 1.0s / sensorInfo.pixelRate;
> +
> /* Load the tuning data file. */
> File file(settings.configurationFile);
> if (!file.open(File::OpenModeFlag::ReadOnly)) {
> @@ -377,6 +380,28 @@ void IPARkISP1::updateControls(const IPACameraSensorInfo &sensorInfo,
> {
> ControlInfoMap::Map ctrlMap = rkisp1Controls;
>
> + /*
> + * Compute exposure time limits from the V4L2_CID_EXPOSURE control
> + * limits and the line duration.
> + */
> + double lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();
> + 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;
> + ctrlMap.emplace(std::piecewise_construct,
> + std::forward_as_tuple(&controls::ExposureTime),
> + std::forward_as_tuple(minExposure, maxExposure, defExposure));
> +
> + /* Compute the analogue gain limits. */
> + const ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second;
> + float minGain = camHelper_->gain(v4l2Gain.min().get<int32_t>());
> + float maxGain = camHelper_->gain(v4l2Gain.max().get<int32_t>());
> + float defGain = camHelper_->gain(v4l2Gain.def().get<int32_t>());
> + ctrlMap.emplace(std::piecewise_construct,
> + std::forward_as_tuple(&controls::AnalogueGain),
> + std::forward_as_tuple(minGain, maxGain, defGain));
> +
> /*
> * Compute the frame duration limits.
More information about the libcamera-devel
mailing list