[RFC,v1,13/17] ipa: ipu3: Port to `AgcMeanLuminanceAlgorithm`
diff mbox series

Message ID 20260703153819.1088752-14-barnabas.pocze@ideasonboard.com
State New
Headers show
Series
  • ipa: libipa: agc rework
Related show

Commit Message

Barnabás Pőcze July 3, 2026, 3:38 p.m. UTC
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(-)

Patch
diff mbox series

diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp
index 5b152dcda2..0ca02390bd 100644
--- a/src/ipa/ipu3/algorithms/agc.cpp
+++ b/src/ipa/ipu3/algorithms/agc.cpp
@@ -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")
diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h
index d08da7600e..d0a82949c7 100644
--- a/src/ipa/ipu3/algorithms/agc.h
+++ b/src/ipa/ipu3/algorithms/agc.h
@@ -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 */
diff --git a/src/ipa/ipu3/ipa_context.cpp b/src/ipa/ipu3/ipa_context.cpp
index 3b22f79176..c358b09981 100644
--- a/src/ipa/ipu3/ipa_context.cpp
+++ b/src/ipa/ipu3/ipa_context.cpp
@@ -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 */
diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h
index 97fcf06cd4..682fe4474f 100644
--- a/src/ipa/ipu3/ipa_context.h
+++ b/src/ipa/ipu3/ipa_context.h
@@ -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;
 };
 
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index 4bdc4b7677..fa8e1031f1 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -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);