rkisp1: Honor the FrameDurationLimits control

Add support to rkisp1 for controlling the framerate via the
FrameDurationLimits control.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Paul Elder 2024-10-14 16:47:47 +01:00
parent 2abfcac1c3
commit f72c76eb6e
6 changed files with 74 additions and 12 deletions

View file

@ -190,6 +190,7 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
/* Limit the frame duration to match current initialisation */ /* Limit the frame duration to match current initialisation */
ControlInfo &frameDurationLimits = context.ctrlMap[&controls::FrameDurationLimits]; 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>()); context.activeState.agc.maxFrameDuration = std::chrono::microseconds(frameDurationLimits.max().get<int64_t>());
/* /*
@ -307,10 +308,21 @@ void Agc::queueRequest(IPAContext &context,
const auto &frameDurationLimits = controls.get(controls::FrameDurationLimits); const auto &frameDurationLimits = controls.get(controls::FrameDurationLimits);
if (frameDurationLimits) { if (frameDurationLimits) {
utils::Duration maxFrameDuration = /* Limit the control value to the limits in ControlInfo */
std::chrono::milliseconds((*frameDurationLimits).back()); ControlInfo &limits = context.ctrlMap[&controls::FrameDurationLimits];
agc.maxFrameDuration = maxFrameDuration; 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; frameContext.agc.maxFrameDuration = agc.maxFrameDuration;
} }
@ -387,6 +399,7 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext,
* frameContext.sensor.exposure; * frameContext.sensor.exposure;
metadata.set(controls::AnalogueGain, frameContext.sensor.gain); metadata.set(controls::AnalogueGain, frameContext.sensor.gain);
metadata.set(controls::ExposureTime, exposureTime.get<std::micro>()); metadata.set(controls::ExposureTime, exposureTime.get<std::micro>());
metadata.set(controls::FrameDuration, frameContext.agc.frameDuration.get<std::micro>());
metadata.set(controls::ExposureTimeMode, metadata.set(controls::ExposureTimeMode,
frameContext.agc.autoExposureEnabled frameContext.agc.autoExposureEnabled
? controls::ExposureTimeModeAuto ? controls::ExposureTimeModeAuto
@ -396,13 +409,6 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext,
? controls::AnalogueGainModeAuto ? controls::AnalogueGainModeAuto
: controls::AnalogueGainModeManual); : controls::AnalogueGainModeManual);
/* \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>());
metadata.set(controls::AeMeteringMode, frameContext.agc.meteringMode); metadata.set(controls::AeMeteringMode, frameContext.agc.meteringMode);
metadata.set(controls::AeExposureMode, frameContext.agc.exposureMode); metadata.set(controls::AeExposureMode, frameContext.agc.exposureMode);
metadata.set(controls::AeConstraintMode, frameContext.agc.constraintMode); metadata.set(controls::AeConstraintMode, frameContext.agc.constraintMode);
@ -444,6 +450,27 @@ double Agc::estimateLuminance(double gain) const
return ySum / expMeans_.size() / 255; return ySum / expMeans_.size() / 255;
} }
/**
* \brief Process frame duration and compute vblank
* \param[in] context The shared IPA context
* \param[in] frameContext The current frame context
* \param[in] frameDuration The target frame duration
*
* Compute and populate vblank from the target frame duration.
*/
void Agc::processFrameDuration(IPAContext &context,
IPAFrameContext &frameContext,
utils::Duration frameDuration)
{
IPACameraSensorInfo &sensorInfo = context.sensorInfo;
utils::Duration lineDuration = context.configuration.sensor.lineDuration;
frameContext.agc.vblank = (frameDuration / lineDuration) - sensorInfo.outputSize.height;
/* Update frame duration accounting for line length quantization. */
frameContext.agc.frameDuration = (sensorInfo.outputSize.height + frameContext.agc.vblank) * lineDuration;
}
/** /**
* \brief Process RkISP1 statistics, and run AGC operations * \brief Process RkISP1 statistics, and run AGC operations
* \param[in] context The shared IPA context * \param[in] context The shared IPA context
@ -460,6 +487,8 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
ControlList &metadata) ControlList &metadata)
{ {
if (!stats) { if (!stats) {
processFrameDuration(context, frameContext,
frameContext.agc.minFrameDuration);
fillMetadata(context, frameContext, metadata); fillMetadata(context, frameContext, metadata);
return; return;
} }
@ -497,7 +526,9 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
double maxAnalogueGain; double maxAnalogueGain;
if (frameContext.agc.autoExposureEnabled) { if (frameContext.agc.autoExposureEnabled) {
minExposureTime = context.configuration.sensor.minExposureTime; minExposureTime = std::clamp(frameContext.agc.minFrameDuration,
context.configuration.sensor.minExposureTime,
context.configuration.sensor.maxExposureTime);
maxExposureTime = std::clamp(frameContext.agc.maxFrameDuration, maxExposureTime = std::clamp(frameContext.agc.maxFrameDuration,
context.configuration.sensor.minExposureTime, context.configuration.sensor.minExposureTime,
context.configuration.sensor.maxExposureTime); context.configuration.sensor.maxExposureTime);
@ -541,6 +572,13 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
activeState.agc.automatic.exposure = newExposureTime / lineDuration; activeState.agc.automatic.exposure = newExposureTime / lineDuration;
activeState.agc.automatic.gain = aGain; activeState.agc.automatic.gain = aGain;
/*
* 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));
fillMetadata(context, frameContext, metadata); fillMetadata(context, frameContext, metadata);
expMeans_ = {}; expMeans_ = {};
} }

View file

@ -50,6 +50,9 @@ private:
void fillMetadata(IPAContext &context, IPAFrameContext &frameContext, void fillMetadata(IPAContext &context, IPAFrameContext &frameContext,
ControlList &metadata); ControlList &metadata);
double estimateLuminance(double gain) const override; double estimateLuminance(double gain) const override;
void processFrameDuration(IPAContext &context,
IPAFrameContext &frameContext,
utils::Duration frameDuration);
Span<const uint8_t> expMeans_; Span<const uint8_t> expMeans_;

View file

@ -180,6 +180,9 @@ namespace libcamera::ipa::rkisp1 {
* \var IPAActiveState::agc.meteringMode * \var IPAActiveState::agc.meteringMode
* \brief Metering mode as set by the AeMeteringMode control * \brief Metering mode as set by the AeMeteringMode control
* *
* \var IPAActiveState::agc.minFrameDuration
* \brief Minimum frame duration as set by the FrameDurationLimits control
*
* \var IPAActiveState::agc.maxFrameDuration * \var IPAActiveState::agc.maxFrameDuration
* \brief Maximum frame duration as set by the FrameDurationLimits control * \brief Maximum frame duration as set by the FrameDurationLimits control
*/ */
@ -282,7 +285,9 @@ namespace libcamera::ipa::rkisp1 {
* \brief Automatic Gain Control parameters for this frame * \brief Automatic Gain Control parameters for this frame
* *
* The exposure and gain are provided by the AGC algorithm, and are to be * The exposure and gain are provided by the AGC algorithm, and are to be
* applied to the sensor in order to take effect for this frame. * applied to the sensor in order to take effect for this frame. Additionally
* the vertical blanking period is determined to maintain a consistent frame
* rate matched to the FrameDurationLimits as set by the user.
* *
* \var IPAFrameContext::agc.exposure * \var IPAFrameContext::agc.exposure
* \brief Exposure time expressed as a number of lines computed by the algorithm * \brief Exposure time expressed as a number of lines computed by the algorithm
@ -292,6 +297,9 @@ namespace libcamera::ipa::rkisp1 {
* *
* The gain should be adapted to the sensor specific gain code before applying. * The gain should be adapted to the sensor specific gain code before applying.
* *
* \var IPAFrameContext::agc.vblank
* \brief Vertical blanking parameter computed by the algorithm
*
* \var IPAFrameContext::agc.autoExposureEnabled * \var IPAFrameContext::agc.autoExposureEnabled
* \brief Manual/automatic AGC state (exposure) as set by the ExposureTimeMode control * \brief Manual/automatic AGC state (exposure) as set by the ExposureTimeMode control
* *
@ -307,9 +315,15 @@ namespace libcamera::ipa::rkisp1 {
* \var IPAFrameContext::agc.meteringMode * \var IPAFrameContext::agc.meteringMode
* \brief Metering mode as set by the AeMeteringMode control * \brief Metering mode as set by the AeMeteringMode control
* *
* \var IPAFrameContext::agc.minFrameDuration
* \brief Minimum frame duration as set by the FrameDurationLimits control
*
* \var IPAFrameContext::agc.maxFrameDuration * \var IPAFrameContext::agc.maxFrameDuration
* \brief Maximum frame duration as set by the FrameDurationLimits control * \brief Maximum frame duration as set by the FrameDurationLimits control
* *
* \var IPAFrameContext::agc.frameDuration
* \brief The actual FrameDuration used by the algorithm for the frame
*
* \var IPAFrameContext::agc.updateMetering * \var IPAFrameContext::agc.updateMetering
* \brief Indicate if new ISP AGC metering parameters need to be applied * \brief Indicate if new ISP AGC metering parameters need to be applied
* *

View file

@ -84,6 +84,7 @@ struct IPAActiveState {
controls::AeConstraintModeEnum constraintMode; controls::AeConstraintModeEnum constraintMode;
controls::AeExposureModeEnum exposureMode; controls::AeExposureModeEnum exposureMode;
controls::AeMeteringModeEnum meteringMode; controls::AeMeteringModeEnum meteringMode;
utils::Duration minFrameDuration;
utils::Duration maxFrameDuration; utils::Duration maxFrameDuration;
} agc; } agc;
@ -125,12 +126,15 @@ struct IPAFrameContext : public FrameContext {
struct { struct {
uint32_t exposure; uint32_t exposure;
double gain; double gain;
uint32_t vblank;
bool autoExposureEnabled; bool autoExposureEnabled;
bool autoGainEnabled; bool autoGainEnabled;
controls::AeConstraintModeEnum constraintMode; controls::AeConstraintModeEnum constraintMode;
controls::AeExposureModeEnum exposureMode; controls::AeExposureModeEnum exposureMode;
controls::AeMeteringModeEnum meteringMode; controls::AeMeteringModeEnum meteringMode;
utils::Duration minFrameDuration;
utils::Duration maxFrameDuration; utils::Duration maxFrameDuration;
utils::Duration frameDuration;
bool updateMetering; bool updateMetering;
bool autoExposureModeChange; bool autoExposureModeChange;
bool autoGainModeChange; bool autoGainModeChange;

View file

@ -453,10 +453,12 @@ void IPARkISP1::setControls(unsigned int frame)
IPAFrameContext &frameContext = context_.frameContexts.get(frame); IPAFrameContext &frameContext = context_.frameContexts.get(frame);
uint32_t exposure = frameContext.agc.exposure; uint32_t exposure = frameContext.agc.exposure;
uint32_t gain = context_.camHelper->gainCode(frameContext.agc.gain); uint32_t gain = context_.camHelper->gainCode(frameContext.agc.gain);
uint32_t vblank = frameContext.agc.vblank;
ControlList ctrls(sensorControls_); ControlList ctrls(sensorControls_);
ctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure)); 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_ANALOGUE_GAIN, static_cast<int32_t>(gain));
ctrls.set(V4L2_CID_VBLANK, static_cast<int32_t>(vblank));
setSensorControls.emit(frame, ctrls); setSensorControls.emit(frame, ctrls);
} }

View file

@ -1325,6 +1325,7 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)
std::unordered_map<uint32_t, DelayedControls::ControlParams> params = { std::unordered_map<uint32_t, DelayedControls::ControlParams> params = {
{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } }, { V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },
{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } }, { V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },
{ V4L2_CID_VBLANK, { 1, false } },
}; };
data->delayedCtrls_ = data->delayedCtrls_ =