From 0e454d335ba23c306e7c8f011ef7d5234dd3aa9a Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Mon, 17 Aug 2026 01:58:59 +0200 Subject: [PATCH] libcamera: software_isp: af: Harden the lens control handling Three defects in the focus control patch that show up on a camera without a focus lens, which on the FP6 is the ultra-wide: - configure() dereferences the result of ControlInfoMap::find() for V4L2_CID_FOCUS_ABSOLUTE whenever the lens control map is non-empty, without checking that the control is actually there. - processStats() unconditionally sets V4L2_CID_FOCUS_ABSOLUTE on a ControlList built from an empty ControlInfoMap, which logs a control validation error for every frame of every capture. - the lens position is computed as a fraction of the travel but the minimum is never added back, so a lens whose range does not start at zero is driven past its near end. Also demote the "found a lens" message to Info and fix its spelling. Signed-off-by: Jorijn van der Graaf --- src/ipa/simple/algorithms/af.cpp | 8 +++++++- src/ipa/simple/ipa_context.h | 1 + src/ipa/simple/soft_simple.cpp | 24 +++++++++++++++--------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/ipa/simple/algorithms/af.cpp b/src/ipa/simple/algorithms/af.cpp index 19235a567..43d4a41c4 100644 --- a/src/ipa/simple/algorithms/af.cpp +++ b/src/ipa/simple/algorithms/af.cpp @@ -8,6 +8,7 @@ #include "af.h" #include +#include #include #include @@ -80,7 +81,12 @@ void Af::queueRequest([[maybe_unused]] typename Module::Context &context, void Af::updateFocus([[maybe_unused]] IPAContext &context, [[maybe_unused]] IPAFrameContext &frameContext, [[maybe_unused]] double exposureMSV) { - frameContext.lens.focus_pos = context.activeState.knobs.focus_pos.value_or(50.0) / 100.0 * (context.configuration.focus.focus_max - context.configuration.focus.focus_min); + const auto &focus = context.configuration.focus; + const double pos = std::clamp(context.activeState.knobs.focus_pos.value_or(50.0), + 0.0, 100.0); + + frameContext.lens.focus_pos = focus.focus_min + + std::lround(pos / 100.0 * (focus.focus_max - focus.focus_min)); } void Af::restart(IPAContext &context) diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index 4fc9c7cdf..ccc938ce9 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -34,6 +34,7 @@ struct IPASessionConfiguration { std::optional level; } black; struct { + bool available; int32_t focus_min, focus_max; double focus_max_pos; uint64_t sharpness_max; diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp index dcf746cb2..51a73d2dd 100644 --- a/src/ipa/simple/soft_simple.cpp +++ b/src/ipa/simple/soft_simple.cpp @@ -213,15 +213,20 @@ int IPASoftSimple::configure(const IPAConfigInfo &configInfo) context_.activeState = {}; context_.frameContexts.clear(); - if (lensInfoMap_.empty()) { - LOG(IPASoft, Warning) << "No camera leans found! Focus control disabled."; + const auto lensFocus = lensInfoMap_.find(V4L2_CID_FOCUS_ABSOLUTE); + if (lensFocus == lensInfoMap_.end()) { + LOG(IPASoft, Info) << "No focus lens, focus control disabled"; + context_.configuration.focus.available = false; context_.configuration.focus.focus_min = 0; context_.configuration.focus.focus_max = 0; } else { - const ControlInfo &lensInfo = lensInfoMap_.find(V4L2_CID_FOCUS_ABSOLUTE)->second; - context_.configuration.focus.focus_min = lensInfo.min().get(); - context_.configuration.focus.focus_max = lensInfo.max().get(); - LOG(IPASoft, Warning) << "Camera leans found! Focus: " << context_.configuration.focus.focus_min << "-" << context_.configuration.focus.focus_max; + context_.configuration.focus.available = true; + context_.configuration.focus.focus_min = lensFocus->second.min().get(); + context_.configuration.focus.focus_max = lensFocus->second.max().get(); + LOG(IPASoft, Info) + << "Focus lens range " + << context_.configuration.focus.focus_min << "-" + << context_.configuration.focus.focus_max; } context_.configuration.agc.lineDuration = @@ -338,10 +343,11 @@ void IPASoftSimple::processStats(const uint32_t frame, ctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast(camHelper_ ? camHelper_->gainCode(againNew) : againNew)); - ControlList lens_ctrls(lensInfoMap_); - lens_ctrls.set(V4L2_CID_FOCUS_ABSOLUTE, frameContext.lens.focus_pos); + ControlList lensCtrls(lensInfoMap_); + if (context_.configuration.focus.available) + lensCtrls.set(V4L2_CID_FOCUS_ABSOLUTE, frameContext.lens.focus_pos); - setSensorControls.emit(ctrls, lens_ctrls); + setSensorControls.emit(ctrls, lensCtrls); } std::string IPASoftSimple::logPrefix() const