@@ -236,8 +236,9 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
utils::Duration effectiveExposureValue = exposureTime * analogueGain;
utils::Duration newExposureTime;
+ utils::Duration frameDuration;
double aGain, qGain, dGain;
- std::tie(newExposureTime, aGain, qGain, dGain) =
+ std::tie(newExposureTime, frameDuration, aGain, qGain, dGain) =
calculateNewEv(context.activeState.agc.constraintMode,
context.activeState.agc.exposureMode, hist,
effectiveExposureValue);
@@ -254,12 +255,13 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
metadata.set(controls::AnalogueGain, frameContext.sensor.gain);
metadata.set(controls::ExposureTime, exposureTime.get<std::micro>());
- /* \todo Use VBlank value calculated from each frame exposure. */
+ /* \todo Use frameDuration to calculate the right vblank. */
+
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>());
+ utils::Duration defFrameDuration = context.configuration.sensor.lineDuration
+ * vTotal;
+ metadata.set(controls::FrameDuration, defFrameDuration.get<std::micro>());
}
REGISTER_IPA_ALGORITHM(Agc, "Agc")
@@ -646,10 +646,10 @@ utils::Duration AgcMeanLuminance::filterExposure(utils::Duration exposureValue)
* exposure value is filtered to prevent rapid changes from frame to frame, and
* divided into exposure time, analogue, quantization and digital gain.
*
- * \return Tuple of exposure time, analogue gain, quantization gain and digital
- * gain
+ * \return Tuple of exposure time, frame duration analogue gain, quantization
+ * gain and digital gain
*/
-std::tuple<utils::Duration, double, double, double>
+std::tuple<utils::Duration, utils::Duration, double, double, double>
AgcMeanLuminance::calculateNewEv(uint32_t constraintModeIndex,
uint32_t exposureModeIndex,
const Histogram &yHist,
@@ -80,7 +80,7 @@ public:
return controls_;
}
- std::tuple<utils::Duration, double, double, double>
+ std::tuple<utils::Duration, utils::Duration, double, double, double>
calculateNewEv(uint32_t constraintModeIndex, uint32_t exposureModeIndex,
const Histogram &yHist, utils::Duration effectiveExposureValue);
@@ -100,9 +100,10 @@ void ExposureModeHelper::setMaxExposure(utils::Duration minExposureTime,
<< "Exposure margin not known. Default to 4";
margin = { 4 };
}
+ exposureMargin_ = margin.value() * lineDuration_;
maxExposureTime_ = minExposureTime != maxExposureTime
- ? maxFrameDuration - margin.value() * lineDuration_
+ ? maxFrameDuration - exposureMargin_
: minExposureTime;
}
@@ -152,6 +153,7 @@ void ExposureModeHelper::configure(utils::Duration lineDuration,
setMaxExposure(minExposureTime, maxExposureTime, frameDuration);
maxFrameDuration_ = *maxFrameDuration = frameDuration;
+ minFrameDuration_ = minFrameDuration;
}
/**
@@ -207,6 +209,17 @@ double ExposureModeHelper::clampGain(double gain, double *quantizationGain) cons
return sensorHelper_->quantizeGain(clamped, quantizationGain);
}
+utils::Duration ExposureModeHelper::frameDurationFromExposure(utils::Duration exposureTime) const
+{
+ /*
+ * The maximum exposure value has already been clamped to the maximum
+ * frame duration. Re-apply the exposure margin and make sure we don't
+ * go below the minium frame duration.
+ */
+ utils::Duration frameDuration = exposureTime + exposureMargin_;
+ return std::max(frameDuration, minFrameDuration_);
+}
+
/**
* \brief Split exposure into exposure time and gain
* \param[in] exposure Exposure value
@@ -244,7 +257,7 @@ double ExposureModeHelper::clampGain(double gain, double *quantizationGain) cons
* \return Tuple of exposure time, analogue gain, quantization gain and digital
* gain
*/
-std::tuple<utils::Duration, double, double, double>
+std::tuple<utils::Duration, utils::Duration, double, double, double>
ExposureModeHelper::splitExposure(utils::Duration exposure) const
{
ASSERT(maxExposureTime_);
@@ -266,8 +279,8 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const
gain = clampGain(minGain_, &quantGain2);
quantGain *= quantGain2;
- return { exposureTime, gain, quantGain,
- exposure / (exposureTime * gain * quantGain) };
+ return { exposureTime, frameDurationFromExposure(exposureTime),
+ gain, quantGain, exposure / (exposureTime * gain * quantGain) };
}
double stageGain = clampGain(1.0);
@@ -292,8 +305,8 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const
gain = clampGain(exposure / exposureTime, &quantGain2);
quantGain *= quantGain2;
- return { exposureTime, gain, quantGain,
- exposure / (exposureTime * gain * quantGain) };
+ return { exposureTime, frameDurationFromExposure(exposureTime),
+ gain, quantGain, exposure / (exposureTime * gain * quantGain) };
}
/* Clamp the exposureTime to stageExposureTime and regulate gain. */
@@ -302,8 +315,8 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const
gain = clampGain(exposure / exposureTime, &quantGain2);
quantGain *= quantGain2;
- return { exposureTime, gain, quantGain,
- exposure / (exposureTime * gain * quantGain) };
+ return { exposureTime, frameDurationFromExposure(exposureTime),
+ gain, quantGain, exposure / (exposureTime * gain * quantGain) };
}
lastStageGain = stageGain;
@@ -320,8 +333,8 @@ ExposureModeHelper::splitExposure(utils::Duration exposure) const
gain = clampGain(exposure / exposureTime, &quantGain2);
quantGain *= quantGain2;
- return { exposureTime, gain, quantGain,
- exposure / (exposureTime * gain * quantGain) };
+ return { exposureTime, frameDurationFromExposure(exposureTime),
+ gain, quantGain, exposure / (exposureTime * gain * quantGain) };
}
/**
@@ -34,7 +34,7 @@ public:
utils::Duration maxFrameDuration,
double minGain, double maxGain);
- std::tuple<utils::Duration, double, double, double>
+ std::tuple<utils::Duration, utils::Duration, double, double, double>
splitExposure(utils::Duration exposure) const;
utils::Duration minExposureTime() const { return minExposureTime_; }
@@ -50,6 +50,7 @@ private:
utils::Duration clampExposureTime(utils::Duration exposureTime,
double *quantizationGain = nullptr) const;
double clampGain(double gain, double *quantizationGain = nullptr) const;
+ utils::Duration frameDurationFromExposure(utils::Duration exposureTime) const;
std::vector<utils::Duration> exposureTimes_;
std::vector<double> gains_;
@@ -58,6 +59,8 @@ private:
utils::Duration minExposureTime_;
utils::Duration maxExposureTime_;
utils::Duration maxFrameDuration_;
+ utils::Duration minFrameDuration_;
+ utils::Duration exposureMargin_;
double minGain_;
double maxGain_;
const CameraSensorHelper *sensorHelper_;
@@ -391,9 +391,10 @@ void Agc::process(IPAContext &context,
utils::Duration currentShutter = exposure * configuration.sensor.lineDuration;
utils::Duration effectiveExposureValue = currentShutter * totalGain;
+ utils::Duration frameDuration;
utils::Duration shutterTime;
double aGain, qGain, dGain;
- std::tie(shutterTime, aGain, qGain, dGain) =
+ std::tie(shutterTime, frameDuration, aGain, qGain, dGain) =
calculateNewEv(activeState.agc.constraintMode,
activeState.agc.exposureMode, statistics_.yHist,
effectiveExposureValue);
@@ -625,15 +625,17 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
setExposureCompensation(pow(2.0, frameContext.agc.exposureValue));
utils::Duration newExposureTime;
+ utils::Duration frameDuration;
double aGain, qGain, dGain;
- std::tie(newExposureTime, aGain, qGain, dGain) =
+ std::tie(newExposureTime, frameDuration, aGain, qGain, dGain) =
calculateNewEv(frameContext.agc.constraintMode,
frameContext.agc.exposureMode,
hist, effectiveExposureValue);
LOG(RkISP1Agc, Debug)
- << "Divided up exposure time, analogue gain, quantization gain"
- << " and digital gain are " << newExposureTime << ", " << aGain
+ << "Divided up exposure time, frame duration, analogue gain,"
+ << "quantization gain and digital gain are "
+ << newExposureTime << ", " << frameDuration << ", " << aGain
<< ", " << qGain << " and " << dGain;
IPAActiveState &activeState = context.activeState;
@@ -646,8 +648,7 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
* Expand the target frame duration so that we do not run faster than
* the minimum frame duration when we have short exposures.
*/
- processFrameDuration(context, frameContext,
- std::max(frameContext.agc.minFrameDuration, newExposureTime));
+ processFrameDuration(context, frameContext, frameDuration);
fillMetadata(context, frameContext, metadata);
expMeans_ = {};
The RkISP1 IPA is the only IPA that derives from AgcMeanLuminance that populates the FrameDuration control. The way frame duration is calculated is by using the shutter time as returned by the Agc helpers and use that value to populate the FrameDuration metadata and calculate the vblank. This is however not correct as the exposure time shall be shorter than the frame duration by a sensor-specific margin. The AGC helpers are in charge of calculating the desired exposure and split it between shutter time and gains. They already use the exposure margin to limit the maximum shutter time to the maximum frame duration. Let the helpers calculate the frame duration and return it with shutter time and gains from calculateNewEv(). Also update the Mali C55 and IPU3 IPAs, however they do not currently handle the frame duration and never change vblank so they don't report the FrameDuration metadata (Mali C55) or return a fixed value (IPU3). Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> --- src/ipa/ipu3/algorithms/agc.cpp | 12 +++++++----- src/ipa/libipa/agc_mean_luminance.cpp | 6 +++--- src/ipa/libipa/agc_mean_luminance.h | 2 +- src/ipa/libipa/exposure_mode_helper.cpp | 33 +++++++++++++++++++++++---------- src/ipa/libipa/exposure_mode_helper.h | 5 ++++- src/ipa/mali-c55/algorithms/agc.cpp | 3 ++- src/ipa/rkisp1/algorithms/agc.cpp | 11 ++++++----- 7 files changed, 46 insertions(+), 26 deletions(-)