@@ -170,21 +170,22 @@ int Agc::configure(IPAContext &context,
context.activeState.agc.exposureMode = exposureModeHelpers().begin()->first;
ControlInfo &frameDurationLimits = context.ctrlMap[&controls::FrameDurationLimits];
+ context.activeState.agc.minFrameDuration =
+ std::chrono::microseconds(frameDurationLimits.min().get<int64_t>());
+ context.activeState.agc.maxFrameDuration =
+ std::chrono::microseconds(frameDurationLimits.max().get<int64_t>());
AgcMeanLuminance::AgcSensorConfiguration sensorConfig;
sensorConfig.lineDuration = context.configuration.sensor.lineDuration;
sensorConfig.minExposureTime = context.configuration.agc.minShutterSpeed;
sensorConfig.maxExposureTime = context.configuration.agc.maxShutterSpeed;
- sensorConfig.minFrameDuration =
- std::chrono::microseconds(frameDurationLimits.min().get<int64_t>());
- sensorConfig.maxFrameDuration =
- std::chrono::microseconds(frameDurationLimits.max().get<int64_t>());
+ sensorConfig.minFrameDuration = context.activeState.agc.minFrameDuration;
+ sensorConfig.maxFrameDuration = context.activeState.agc.maxFrameDuration;
sensorConfig.minAnalogueGain = context.configuration.agc.minAnalogueGain;
sensorConfig.maxAnalogueGain = context.configuration.agc.maxAnalogueGain;
AgcMeanLuminance::configure(&sensorConfig, context.camHelper.get());
-
- /* \todo Update AGC limits when FrameDurationLimits is passed in */
+ context.activeState.agc.maxFrameDuration = sensorConfig.maxFrameDuration;
resetFrameCount();
@@ -212,6 +213,25 @@ void Agc::queueRequest(IPAContext &context, const uint32_t frame,
<< " AGC";
}
+ const auto &frameDurationLimits = controls.get(controls::FrameDurationLimits);
+ if (frameDurationLimits) {
+ /* Limit the control value to the limits in ControlInfo */
+ ControlInfo &limits = context.ctrlMap[&controls::FrameDurationLimits];
+ int64_t minFrameDuration =
+ std::clamp((*frameDurationLimits).front(),
+ limits.min().get<int64_t>(),
+ limits.max().get<int64_t>());
+ int64_t maxFrameDuration =
+ std::clamp((*frameDurationLimits).back(),
+ limits.min().get<int64_t>(),
+ limits.max().get<int64_t>());
+
+ agc.minFrameDuration = std::chrono::microseconds(minFrameDuration);
+ agc.maxFrameDuration = std::chrono::microseconds(maxFrameDuration);
+ }
+ frameContext.agc.minFrameDuration = agc.minFrameDuration;
+ frameContext.agc.maxFrameDuration = agc.maxFrameDuration;
+
/*
* If the automatic exposure and gain is enabled we have no further work
* to do here...
@@ -375,6 +395,21 @@ void Agc::process(IPAContext &context,
return;
}
+ /*
+ * Update the AGC limits using the frame duration.
+ *
+ * \todo Handle ExposureTime and AnalogueGain controls to support
+ * manual mode.
+ */
+ utils::Duration minExposureTime = context.configuration.agc.minShutterSpeed;
+ utils::Duration maxExposureTime = context.configuration.agc.maxShutterSpeed;
+ utils::Duration maxFrameDuration = frameContext.agc.maxFrameDuration;
+
+ setLimits(minExposureTime, maxExposureTime, maxFrameDuration,
+ context.configuration.agc.minAnalogueGain,
+ context.configuration.agc.maxAnalogueGain,
+ {});
+
statistics_.parseStatistics(stats);
context.activeState.agc.temperatureK = estimateCCT({ { statistics_.rHist.interQuantileMean(0, 1),
statistics_.gHist.interQuantileMean(0, 1),
@@ -402,13 +437,23 @@ void Agc::process(IPAContext &context,
dGain = std::clamp(dGain, kMinDigitalGain, kMaxDigitalGain);
LOG(MaliC55Agc, Debug)
- << "Divided up shutter, analogue gain and digital gain are "
- << shutterTime << ", " << aGain << " and " << dGain;
+ << "Divided up shutter, frame duration, analogue gain and digital gain are "
+ << shutterTime << ", " << frameDuration << ", " << aGain
+ << " and " << dGain;
+
+ /* Use the frame duration to calculate the desired vblank. */
+ utils::Duration lineDuration = configuration.sensor.lineDuration;
+ IPACameraSensorInfo &sensorInfo = context.sensorInfo;
+
+ frameContext.agc.vblank = (frameDuration / lineDuration)
+ - sensorInfo.outputSize.height;
- activeState.agc.automatic.exposure = shutterTime / configuration.sensor.lineDuration;
+ /* Populate the active state. */
+ activeState.agc.automatic.exposure = shutterTime / lineDuration;
activeState.agc.automatic.sensorGain = aGain;
activeState.agc.automatic.ispGain = dGain;
+ metadata.set(controls::FrameDuration, frameDuration.get<std::micro>());
metadata.set(controls::ExposureTime, currentShutter.get<std::micro>());
metadata.set(controls::AnalogueGain, frameContext.agc.sensorGain);
metadata.set(controls::DigitalGain, frameContext.agc.ispGain);
@@ -53,6 +53,8 @@ struct IPAActiveState {
uint32_t constraintMode;
uint32_t exposureMode;
uint32_t temperatureK;
+ utils::Duration minFrameDuration;
+ utils::Duration maxFrameDuration;
} agc;
struct {
@@ -66,6 +68,9 @@ struct IPAFrameContext : public FrameContext {
uint32_t exposure;
double sensorGain;
double ispGain;
+ uint32_t vblank;
+ utils::Duration minFrameDuration;
+ utils::Duration maxFrameDuration;
} agc;
struct {
@@ -80,6 +85,7 @@ struct IPAContext {
{
}
+ IPACameraSensorInfo sensorInfo;
IPASessionConfiguration configuration;
IPAActiveState activeState;
@@ -68,7 +68,7 @@ private:
void updateControls(const IPACameraSensorInfo &sensorInfo,
const ControlInfoMap &sensorControls,
ControlInfoMap *ipaControls);
- void setControls();
+ void setControls(unsigned int frame);
std::map<unsigned int, MappedFrameBuffer> buffers_;
@@ -126,14 +126,17 @@ int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig
if (ret)
return ret;
+ context_.sensorInfo = ipaConfig.sensorInfo;
updateControls(ipaConfig.sensorInfo, ipaConfig.sensorControls, ipaControls);
return 0;
}
-void IPAMaliC55::setControls()
+void IPAMaliC55::setControls(unsigned int frame)
{
+ IPAFrameContext &frameContext = context_.frameContexts.get(frame);
IPAActiveState &activeState = context_.activeState;
+ uint32_t vblank = frameContext.agc.vblank;
uint32_t exposure;
uint32_t gain;
@@ -148,6 +151,7 @@ void IPAMaliC55::setControls()
ControlList ctrls(sensorControls_);
ctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure));
ctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast<int32_t>(gain));
+ ctrls.set(V4L2_CID_VBLANK, static_cast<int32_t>(vblank));
setSensorControls.emit(ctrls);
}
@@ -368,7 +372,7 @@ void IPAMaliC55::processStats(unsigned int request, unsigned int bufferId,
algo->process(context_, request, frameContext, stats, metadata);
}
- setControls();
+ setControls(request);
statsProcessed.emit(request, metadata);
}
Handle the FrameDurationLimits control for the Mali C55 platform. The frame duration is: 1) Adjuted at configure() time to what the AGC algorithm computed 2) Stored at queueRequest() time in the active state and in the per-frame context 3) Computed at process() time by the AGC calculateNewEV() function and used to compute the desired vblank The VBLANK control is now handled by both the IPA and the pipeline handler and correctly programmed on the sensor. Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> --- src/ipa/mali-c55/algorithms/agc.cpp | 63 +++++++++++++++++++++++++++++++------ src/ipa/mali-c55/ipa_context.h | 6 ++++ src/ipa/mali-c55/mali-c55.cpp | 10 ++++-- 3 files changed, 67 insertions(+), 12 deletions(-)