mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-12 23:09:45 +03:00
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:
parent
2abfcac1c3
commit
f72c76eb6e
6 changed files with 74 additions and 12 deletions
|
@ -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_ = {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_ =
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue