Message ID | 20240405144729.2992219-6-paul.elder@ideasonboard.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
Hi Paul On 05/04/2024 15:47, Paul Elder wrote: > Plumb controls for setting metering mode, exposure mode, constraint > mode, and frame duration limits. Also report them as available controls, > as well as in metadata. > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> > --- > src/ipa/rkisp1/algorithms/agc.cpp | 67 ++++++++++++++++++++------- > src/ipa/rkisp1/algorithms/agc.h | 5 ++ > src/ipa/rkisp1/algorithms/algorithm.h | 2 + > src/ipa/rkisp1/ipa_context.h | 4 ++ > src/ipa/rkisp1/rkisp1.cpp | 10 ++++ > 5 files changed, 72 insertions(+), 16 deletions(-) > > diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp > index a1b6eb39..ed4d6330 100644 > --- a/src/ipa/rkisp1/algorithms/agc.cpp > +++ b/src/ipa/rkisp1/algorithms/agc.cpp > @@ -11,6 +11,7 @@ > #include <chrono> > #include <cmath> > #include <tuple> > +#include <vector> > > #include <libcamera/base/log.h> > #include <libcamera/base/utils.h> > @@ -49,6 +50,7 @@ int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData, > return -EINVAL; > } > > + std::vector<ControlValue> availableMeteringModes; > for (const auto &[key, value] : yamlMeteringModes.asDict()) { > if (controls::AeMeteringModeNameValueMap.find(key) == > controls::AeMeteringModeNameValueMap.end()) { > @@ -67,9 +69,14 @@ int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData, > return -ENODATA; > } > > - meteringModes_[controls::AeMeteringModeNameValueMap.at(key)] = weights; > + int32_t control = controls::AeMeteringModeNameValueMap.at(key); > + meteringModes_[control] = weights; > + availableMeteringModes.push_back(control); > } > > + Algorithm::controls_[&controls::AeMeteringMode] = > + ControlInfo(availableMeteringModes); > + > return 0; > } > > @@ -131,9 +138,25 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData) > > context.ctrlMap.merge(controls()); > > + defaultConstraintMode_ = constraintModes().begin()->first; > + defaultExposureMode_ = exposureModeHelpers().begin()->first; > + defaultMeteringMode_ = meteringModes_.begin()->first; > + > + Algorithm::controls_.merge(ControlInfoMap::Map(controls())); > + > return 0; > } > > +void Agc::configureExposureModeHelpers(IPAContext &context, utils::Duration maxShutterSpeed) > +{ > + for (auto &[id, helper] : exposureModeHelpers()) { > + helper->configure(context.configuration.sensor.minShutterSpeed, > + maxShutterSpeed, > + context.configuration.sensor.minAnalogueGain, > + context.configuration.sensor.maxAnalogueGain); > + } > +} > + > /** > * \brief Configure the AGC given a configInfo > * \param[in] context The shared IPA context > @@ -153,12 +176,8 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) > context.activeState.agc.manual.dgain = 1; > context.activeState.agc.autoEnabled = !context.configuration.raw; > > - /* > - * \todo We should use the first available mode rather than assume that > - * the "Normal" modes are present in tuning data. > - */ > - context.activeState.agc.constraintMode = controls::ConstraintNormal; > - context.activeState.agc.exposureMode = controls::ExposureNormal; > + context.activeState.agc.constraintMode = defaultConstraintMode_; > + context.activeState.agc.exposureMode = defaultExposureMode_; > > /* > * Define the measurement window for AGC as a centered rectangle > @@ -169,13 +188,7 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) > context.configuration.agc.measureWindow.h_size = 3 * configInfo.outputSize.width / 4; > context.configuration.agc.measureWindow.v_size = 3 * configInfo.outputSize.height / 4; > > - for (auto &[id, helper] : exposureModeHelpers()) { > - /* \todo Run this again when FrameDurationLimits is passed in */ > - helper->configure(context.configuration.sensor.minShutterSpeed, > - context.configuration.sensor.maxShutterSpeed, > - context.configuration.sensor.minAnalogueGain, > - context.configuration.sensor.maxAnalogueGain); > - } > + configureExposureModeHelpers(context, context.configuration.sensor.maxShutterSpeed); > > return 0; > } > @@ -223,6 +236,20 @@ void Agc::queueRequest(IPAContext &context, > frameContext.agc.exposure = agc.manual.exposure; > frameContext.agc.gain = agc.manual.gain; > } > + > + const auto &meteringMode = controls.get(controls::AeMeteringMode); > + frameContext.agc.meteringMode = meteringMode.value_or(defaultMeteringMode_); > + > + const auto &exposureMode = controls.get(controls::AeExposureMode); > + frameContext.agc.exposureMode = exposureMode.value_or(defaultExposureMode_); > + > + const auto &constraintMode = controls.get(controls::AeConstraintMode); > + frameContext.agc.constraintMode = constraintMode.value_or(defaultConstraintMode_); Wouldn't this mean the modes revert to default unless we pass in those controls with every request? I have this same operation as: frameContext.agc.exposureMode = exposureMode.value_or(frameContext.agc.exposureMode) so that we keep the already configured value instead. > + > + const auto &frameDurationLimits = controls.get(controls::FrameDurationLimits); > + frameContext.agc.maxShutterSpeed = frameDurationLimits > + ? std::chrono::milliseconds((*frameDurationLimits).back()) > + : 60ms; > } > > /** > @@ -262,8 +289,7 @@ void Agc::prepare(IPAContext &context, const uint32_t frame, > params->meas.hst_config.hist_weight, > context.hw->numHistogramWeights > }; > - /* \todo Get this from control */ > - std::vector<uint8_t> &modeWeights = meteringModes_.at(controls::MeteringMatrix); > + std::vector<uint8_t> &modeWeights = meteringModes_.at(frameContext.agc.meteringMode); > std::copy(modeWeights.begin(), modeWeights.end(), weights.begin()); > > std::stringstream str; > @@ -290,6 +316,7 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, > * frameContext.sensor.exposure; > metadata.set(controls::AnalogueGain, frameContext.sensor.gain); > metadata.set(controls::ExposureTime, exposureTime.get<std::micro>()); > + metadata.set(controls::AeEnable, frameContext.agc.autoEnabled); > > /* \todo Use VBlank value calculated from each frame exposure. */ > uint32_t vTotal = context.configuration.sensor.size.height > @@ -297,6 +324,10 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, > 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::AeExposureMode, frameContext.agc.exposureMode); > + metadata.set(controls::AeConstraintMode, frameContext.agc.constraintMode); > } > > void Agc::parseStatistics(const rkisp1_stat_buffer *stats, > @@ -378,6 +409,10 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, > > ASSERT(stats->meas_type & RKISP1_CIF_ISP_STAT_AUTOEXP); > > + utils::Duration maxShutterSpeed = std::min(context.configuration.sensor.maxShutterSpeed, > + frameContext.agc.maxShutterSpeed); > + configureExposureModeHelpers(context, maxShutterSpeed); > + > parseStatistics(stats, context); > > /* > diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h > index 43e3d5b2..c05ba4be 100644 > --- a/src/ipa/rkisp1/algorithms/agc.h > +++ b/src/ipa/rkisp1/algorithms/agc.h > @@ -47,6 +47,7 @@ private: > int parseMeteringModes(IPAContext &context, const YamlObject &tuningData, > const char *prop); > uint8_t predivider(Size &size); > + void configureExposureModeHelpers(IPAContext &context, utils::Duration maxShutterSpeed); > > void fillMetadata(IPAContext &context, IPAFrameContext &frameContext, > ControlList &metadata); > @@ -58,6 +59,10 @@ private: > Span<const uint8_t> expMeans_; > > std::map<int32_t, std::vector<uint8_t>> meteringModes_; > + > + int32_t defaultConstraintMode_; > + int32_t defaultExposureMode_; > + int32_t defaultMeteringMode_; > }; > > } /* namespace ipa::rkisp1::algorithms */ > diff --git a/src/ipa/rkisp1/algorithms/algorithm.h b/src/ipa/rkisp1/algorithms/algorithm.h > index 9454c9a1..c3a002b8 100644 > --- a/src/ipa/rkisp1/algorithms/algorithm.h > +++ b/src/ipa/rkisp1/algorithms/algorithm.h > @@ -25,6 +25,8 @@ public: > > bool disabled_; > bool supportsRaw_; > + > + ControlInfoMap::Map controls_; > }; > > } /* namespace ipa::rkisp1 */ > diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h > index a70c7eb3..dc876da0 100644 > --- a/src/ipa/rkisp1/ipa_context.h > +++ b/src/ipa/rkisp1/ipa_context.h > @@ -114,6 +114,10 @@ struct IPAFrameContext : public FrameContext { > double gain; > double dgain; > bool autoEnabled; > + int32_t meteringMode; > + int32_t exposureMode; > + int32_t constraintMode; > + utils::Duration maxShutterSpeed; > } agc; > > struct { > diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp > index d66dfdd7..3654b5a6 100644 > --- a/src/ipa/rkisp1/rkisp1.cpp > +++ b/src/ipa/rkisp1/rkisp1.cpp > @@ -80,6 +80,7 @@ private: > std::map<unsigned int, MappedFrameBuffer> mappedBuffers_; > > ControlInfoMap sensorControls_; > + ControlInfoMap::Map algoControls_; > > /* Interface to the Camera Helper */ > std::unique_ptr<CameraSensorHelper> camHelper_; > @@ -193,6 +194,14 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision, > if (ret) > return ret; > > + for (auto const &a : algorithms()) { > + Algorithm *algo = static_cast<Algorithm *>(a.get()); > + > + /* \todo Avoid merging duplicate controls */ > + if (!algo->controls_.empty()) > + algoControls_.merge(ControlInfoMap::Map(algo->controls_)); > + } > + > /* Initialize controls. */ > updateControls(sensorInfo, sensorControls, ipaControls); > > @@ -377,6 +386,7 @@ void IPARkISP1::updateControls(const IPACameraSensorInfo &sensorInfo, > ControlInfoMap *ipaControls) > { > ControlInfoMap::Map ctrlMap = rkisp1Controls; > + ctrlMap.merge(algoControls_); > > /* > * Compute exposure time limits from the V4L2_CID_EXPOSURE control
diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index a1b6eb39..ed4d6330 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -11,6 +11,7 @@ #include <chrono> #include <cmath> #include <tuple> +#include <vector> #include <libcamera/base/log.h> #include <libcamera/base/utils.h> @@ -49,6 +50,7 @@ int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData, return -EINVAL; } + std::vector<ControlValue> availableMeteringModes; for (const auto &[key, value] : yamlMeteringModes.asDict()) { if (controls::AeMeteringModeNameValueMap.find(key) == controls::AeMeteringModeNameValueMap.end()) { @@ -67,9 +69,14 @@ int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData, return -ENODATA; } - meteringModes_[controls::AeMeteringModeNameValueMap.at(key)] = weights; + int32_t control = controls::AeMeteringModeNameValueMap.at(key); + meteringModes_[control] = weights; + availableMeteringModes.push_back(control); } + Algorithm::controls_[&controls::AeMeteringMode] = + ControlInfo(availableMeteringModes); + return 0; } @@ -131,9 +138,25 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData) context.ctrlMap.merge(controls()); + defaultConstraintMode_ = constraintModes().begin()->first; + defaultExposureMode_ = exposureModeHelpers().begin()->first; + defaultMeteringMode_ = meteringModes_.begin()->first; + + Algorithm::controls_.merge(ControlInfoMap::Map(controls())); + return 0; } +void Agc::configureExposureModeHelpers(IPAContext &context, utils::Duration maxShutterSpeed) +{ + for (auto &[id, helper] : exposureModeHelpers()) { + helper->configure(context.configuration.sensor.minShutterSpeed, + maxShutterSpeed, + context.configuration.sensor.minAnalogueGain, + context.configuration.sensor.maxAnalogueGain); + } +} + /** * \brief Configure the AGC given a configInfo * \param[in] context The shared IPA context @@ -153,12 +176,8 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) context.activeState.agc.manual.dgain = 1; context.activeState.agc.autoEnabled = !context.configuration.raw; - /* - * \todo We should use the first available mode rather than assume that - * the "Normal" modes are present in tuning data. - */ - context.activeState.agc.constraintMode = controls::ConstraintNormal; - context.activeState.agc.exposureMode = controls::ExposureNormal; + context.activeState.agc.constraintMode = defaultConstraintMode_; + context.activeState.agc.exposureMode = defaultExposureMode_; /* * Define the measurement window for AGC as a centered rectangle @@ -169,13 +188,7 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo) context.configuration.agc.measureWindow.h_size = 3 * configInfo.outputSize.width / 4; context.configuration.agc.measureWindow.v_size = 3 * configInfo.outputSize.height / 4; - for (auto &[id, helper] : exposureModeHelpers()) { - /* \todo Run this again when FrameDurationLimits is passed in */ - helper->configure(context.configuration.sensor.minShutterSpeed, - context.configuration.sensor.maxShutterSpeed, - context.configuration.sensor.minAnalogueGain, - context.configuration.sensor.maxAnalogueGain); - } + configureExposureModeHelpers(context, context.configuration.sensor.maxShutterSpeed); return 0; } @@ -223,6 +236,20 @@ void Agc::queueRequest(IPAContext &context, frameContext.agc.exposure = agc.manual.exposure; frameContext.agc.gain = agc.manual.gain; } + + const auto &meteringMode = controls.get(controls::AeMeteringMode); + frameContext.agc.meteringMode = meteringMode.value_or(defaultMeteringMode_); + + const auto &exposureMode = controls.get(controls::AeExposureMode); + frameContext.agc.exposureMode = exposureMode.value_or(defaultExposureMode_); + + const auto &constraintMode = controls.get(controls::AeConstraintMode); + frameContext.agc.constraintMode = constraintMode.value_or(defaultConstraintMode_); + + const auto &frameDurationLimits = controls.get(controls::FrameDurationLimits); + frameContext.agc.maxShutterSpeed = frameDurationLimits + ? std::chrono::milliseconds((*frameDurationLimits).back()) + : 60ms; } /** @@ -262,8 +289,7 @@ void Agc::prepare(IPAContext &context, const uint32_t frame, params->meas.hst_config.hist_weight, context.hw->numHistogramWeights }; - /* \todo Get this from control */ - std::vector<uint8_t> &modeWeights = meteringModes_.at(controls::MeteringMatrix); + std::vector<uint8_t> &modeWeights = meteringModes_.at(frameContext.agc.meteringMode); std::copy(modeWeights.begin(), modeWeights.end(), weights.begin()); std::stringstream str; @@ -290,6 +316,7 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, * frameContext.sensor.exposure; metadata.set(controls::AnalogueGain, frameContext.sensor.gain); metadata.set(controls::ExposureTime, exposureTime.get<std::micro>()); + metadata.set(controls::AeEnable, frameContext.agc.autoEnabled); /* \todo Use VBlank value calculated from each frame exposure. */ uint32_t vTotal = context.configuration.sensor.size.height @@ -297,6 +324,10 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext, 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::AeExposureMode, frameContext.agc.exposureMode); + metadata.set(controls::AeConstraintMode, frameContext.agc.constraintMode); } void Agc::parseStatistics(const rkisp1_stat_buffer *stats, @@ -378,6 +409,10 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, ASSERT(stats->meas_type & RKISP1_CIF_ISP_STAT_AUTOEXP); + utils::Duration maxShutterSpeed = std::min(context.configuration.sensor.maxShutterSpeed, + frameContext.agc.maxShutterSpeed); + configureExposureModeHelpers(context, maxShutterSpeed); + parseStatistics(stats, context); /* diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h index 43e3d5b2..c05ba4be 100644 --- a/src/ipa/rkisp1/algorithms/agc.h +++ b/src/ipa/rkisp1/algorithms/agc.h @@ -47,6 +47,7 @@ private: int parseMeteringModes(IPAContext &context, const YamlObject &tuningData, const char *prop); uint8_t predivider(Size &size); + void configureExposureModeHelpers(IPAContext &context, utils::Duration maxShutterSpeed); void fillMetadata(IPAContext &context, IPAFrameContext &frameContext, ControlList &metadata); @@ -58,6 +59,10 @@ private: Span<const uint8_t> expMeans_; std::map<int32_t, std::vector<uint8_t>> meteringModes_; + + int32_t defaultConstraintMode_; + int32_t defaultExposureMode_; + int32_t defaultMeteringMode_; }; } /* namespace ipa::rkisp1::algorithms */ diff --git a/src/ipa/rkisp1/algorithms/algorithm.h b/src/ipa/rkisp1/algorithms/algorithm.h index 9454c9a1..c3a002b8 100644 --- a/src/ipa/rkisp1/algorithms/algorithm.h +++ b/src/ipa/rkisp1/algorithms/algorithm.h @@ -25,6 +25,8 @@ public: bool disabled_; bool supportsRaw_; + + ControlInfoMap::Map controls_; }; } /* namespace ipa::rkisp1 */ diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index a70c7eb3..dc876da0 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -114,6 +114,10 @@ struct IPAFrameContext : public FrameContext { double gain; double dgain; bool autoEnabled; + int32_t meteringMode; + int32_t exposureMode; + int32_t constraintMode; + utils::Duration maxShutterSpeed; } agc; struct { diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp index d66dfdd7..3654b5a6 100644 --- a/src/ipa/rkisp1/rkisp1.cpp +++ b/src/ipa/rkisp1/rkisp1.cpp @@ -80,6 +80,7 @@ private: std::map<unsigned int, MappedFrameBuffer> mappedBuffers_; ControlInfoMap sensorControls_; + ControlInfoMap::Map algoControls_; /* Interface to the Camera Helper */ std::unique_ptr<CameraSensorHelper> camHelper_; @@ -193,6 +194,14 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision, if (ret) return ret; + for (auto const &a : algorithms()) { + Algorithm *algo = static_cast<Algorithm *>(a.get()); + + /* \todo Avoid merging duplicate controls */ + if (!algo->controls_.empty()) + algoControls_.merge(ControlInfoMap::Map(algo->controls_)); + } + /* Initialize controls. */ updateControls(sensorInfo, sensorControls, ipaControls); @@ -377,6 +386,7 @@ void IPARkISP1::updateControls(const IPACameraSensorInfo &sensorInfo, ControlInfoMap *ipaControls) { ControlInfoMap::Map ctrlMap = rkisp1Controls; + ctrlMap.merge(algoControls_); /* * Compute exposure time limits from the V4L2_CID_EXPOSURE control
Plumb controls for setting metering mode, exposure mode, constraint mode, and frame duration limits. Also report them as available controls, as well as in metadata. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> --- src/ipa/rkisp1/algorithms/agc.cpp | 67 ++++++++++++++++++++------- src/ipa/rkisp1/algorithms/agc.h | 5 ++ src/ipa/rkisp1/algorithms/algorithm.h | 2 + src/ipa/rkisp1/ipa_context.h | 4 ++ src/ipa/rkisp1/rkisp1.cpp | 10 ++++ 5 files changed, 72 insertions(+), 16 deletions(-)