From patchwork Fri Oct 17 09:00:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24694 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id EE99FBE080 for ; Fri, 17 Oct 2025 09:00:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E853F606AD; Fri, 17 Oct 2025 11:00:17 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dPwWkDM5"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0F4CB6069F for ; Fri, 17 Oct 2025 11:00:16 +0200 (CEST) Received: from [192.168.1.182] (93-46-82-201.ip106.fastwebnet.it [93.46.82.201]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 90C161574; Fri, 17 Oct 2025 10:58:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1760691515; bh=ivkONw8MteuR+PHl4uEkAsL1BGyqPJPYtaLN60opCDY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=dPwWkDM59niwrMM6u1rg46GAkmkvZEnhjvc889blIsnIyjmWWKdDwz64Nxj1ONPVY Nf4vymmuqBgpKBNAIkDfYw2FNaDSERFPfq4T8cTbHAzicxwHFNJC8x8mtaZo+4pZtV Pk99zB/or/z4xi2Zf5wGf4aNz94liFYL3Sbt9DbI= From: Jacopo Mondi Date: Fri, 17 Oct 2025 11:00:05 +0200 Subject: [PATCH 1/3] ipa: rkisp1: Update exposure limits on vblank change MIME-Version: 1.0 Message-Id: <20251017-exposure-limits-v1-1-6288cd86e719@ideasonboard.com> References: <20251017-exposure-limits-v1-0-6288cd86e719@ideasonboard.com> In-Reply-To: <20251017-exposure-limits-v1-0-6288cd86e719@ideasonboard.com> To: =?utf-8?q?Niklas_S=C3=B6derlund?= , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4625; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=ivkONw8MteuR+PHl4uEkAsL1BGyqPJPYtaLN60opCDY=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo8gWefIr52rmMDCzttbcJF4HrjIZPSbvc46TMw 7gOiTgjmvyJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaPIFngAKCRByNAaPFqFW PCkxD/9yGtj8x8o3TFHCHJyw5E3u76p5X9wmpO4V3fOOWBTKKsdapn/Fhs+0bv7Jq2Lw4HvO3CQ ZbKBuH9YjDLN6IeR9rT71xYQxFiM2exYmcLYT/uFCa/J90LE5BN9sKTm4/1J8fguYgb/+dFl+G0 gnEiWjqgoiyzuaKHo28TQzmpmFm4b7zw+N4KpnUrblb2CgeIHDUvLSc6yQR3Jc6EZCrwuSyJfLA HUaXZk+c8SE78OrqySbHPPztcfqgJLmjxsLRdJBG70t14Y1TcHtQSa+05LSfcg6MOD7s3YsjYEs UwgaatPLVwHMBLHYWdXnv03lfNkJiUSm9YzgzPxDjc7tACdVop7nkpjdtLXuHiqd05EK7TownzJ 4daJ+0PJ4Ig9YV7gx3i4Vi3K2u2Dmj/SnrhMIBxT6L1dGcWMDDrRbeSN62mEaejfUWG3iHiRa9Y vCCKQvnHPvSW9CwdfuHI4spKyZuLri/RkMFZddhSQ81Ro9Can4vO+q04k464g9a2I94B5S7dgdU mUe/dx5BMVxoOPqajaR80ac9eGBayOGdJ/68DnAtTcv36fJiLpEaRwRuyjNUyR4uQ48yf6jJIFR t2PI/4BA6q4rEmGTUR+cCEsb9JJ/KrtdileEYCMhjsSjk4Ts/lU9/ZOUt0+/u0untRPv0pz9Hjb CH45Yfvta/Al9aA== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The AGC algorithm implementation of the RkISP1 IPA is implemented deriving the generic AgcMeanLuminance class, which limits the achievable exposure time using a maxExposureTime parameter provided by the IPA module. The RkISP1 IPA fetches the maxExposureTime value from the IPAContext sensor.maxExposureTime value, which is initialized at IPA init() and configure() time, but never updated later on, effectively limiting the achievable exposure time to the frame duration programmed at startup time. Whenever the frame duration is changed, the maximum exposure time should change accordingly, but in the current implementation this doesn't happen. Fix this by updating the sensor.maxExposureTime value when a new set of controls is sent to the pipeline handler. Store the current VBLANK value in the IPAContext by replacing 'defVBlank' which is never used and use it to detect changes in the blanking value. Whenever the blanking changes, update the maximum exposure limit accordingly. As reported in a comment in the code, even if the new sensor controls will be programmed in the sensor with a delay of a few frames on the pipeline handler side, the limits for the algorithms should be updated immediately. Signed-off-by: Jacopo Mondi --- src/ipa/rkisp1/ipa_context.h | 2 +- src/ipa/rkisp1/rkisp1.cpp | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index f85a130d9c23dba7987f388e395239e4b141d776..af66a749052bc82bbbe7fbb0c4626f2422700926 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -65,7 +65,7 @@ struct IPASessionConfiguration { double minAnalogueGain; double maxAnalogueGain; - int32_t defVBlank; + unsigned int vBlank; utils::Duration lineDuration; Size size; } sensor; diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp index fa22bfc349043002345d275b11a60ac983e329d7..54bd1434e0f4e34834beb1f9e9c39b77590f8b34 100644 --- a/src/ipa/rkisp1/rkisp1.cpp +++ b/src/ipa/rkisp1/rkisp1.cpp @@ -250,7 +250,7 @@ int IPARkISP1::configure(const IPAConfigInfo &ipaConfig, const IPACameraSensorInfo &info = ipaConfig.sensorInfo; const ControlInfo vBlank = sensorControls_.find(V4L2_CID_VBLANK)->second; - context_.configuration.sensor.defVBlank = vBlank.def().get(); + context_.configuration.sensor.vBlank = vBlank.def().get(); context_.configuration.sensor.size = info.outputSize; context_.configuration.sensor.lineDuration = info.minLineLength * 1.0s / info.pixelRate; @@ -261,8 +261,6 @@ int IPARkISP1::configure(const IPAConfigInfo &ipaConfig, * When the AGC computes the new exposure values for a frame, it needs * to know the limits for exposure time and analogue gain. As it depends * on the sensor, update it with the controls. - * - * \todo take VBLANK into account for maximum exposure time */ context_.configuration.sensor.minExposureTime = minExposure * context_.configuration.sensor.lineDuration; @@ -457,6 +455,33 @@ void IPARkISP1::setControls(unsigned int frame) uint32_t gain = context_.camHelper->gainCode(frameContext.agc.gain); uint32_t vblank = frameContext.agc.vblank; + /* + * Update the exposure limits if vblank has changed. Even if the controls + * will actually be applied to the sensor with some frames of latency + * by DelayedControls, all the algorithms calculations from now on should + * use the new limits. + * + * \todo Sensors usually have a margin that limits the max exposure to + * be shorter by the full frame length: + * + * (max_exposure_lines = height + vblank - margin) + * + * As the margin is a sensor-specific parameter either: + * - Ignore the margin and rely on the driver clamping the exposure + * value correctly + * - Defer to the sensor helpers by creating an exposure() function that + * subtract the margin from the frame length + * + * For the time being ignore the margins and rely on the driver doing + * the adjustment. + */ + if (vblank != context_.configuration.sensor.vBlank) { + context_.configuration.sensor.vBlank = vblank; + context_.configuration.sensor.maxExposureTime = + (vblank + context_.configuration.sensor.size.height) * + context_.configuration.sensor.lineDuration; + } + LOG(IPARkISP1, Debug) << "Set controls for frame " << frame << ": exposure " << exposure << ", gain " << frameContext.agc.gain << ", vblank " << vblank; From patchwork Fri Oct 17 09:00:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24695 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 18A45C32CE for ; Fri, 17 Oct 2025 09:00:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B1202606A4; Fri, 17 Oct 2025 11:00:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PFzaoL3/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3E0D1606A3 for ; Fri, 17 Oct 2025 11:00:16 +0200 (CEST) Received: from [192.168.1.182] (93-46-82-201.ip106.fastwebnet.it [93.46.82.201]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C59041E2F; Fri, 17 Oct 2025 10:58:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1760691515; bh=EJcNXPRfts0MnODBTGcYhq7MQ3EqFRL97hh4t6jRWnM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=PFzaoL3/zi0p2bxAkohLny68KdstOr5PWYbrJiC1oBAUZcGjj5zYHDFhJ4igDN8hC 85RmwbQ9rlUQc04baNxuowzPlt3582TakoNNcpaPTQqzyEqjQmbCbnmvyr5btm/7TZ /pBOUM3tQevzCt9O+bE5HVauhk/PuFXS/HLi6Ifw= From: Jacopo Mondi Date: Fri, 17 Oct 2025 11:00:06 +0200 Subject: [PATCH 2/3] libcamera: rkisp1: Update camera::controls() on limit changes MIME-Version: 1.0 Message-Id: <20251017-exposure-limits-v1-2-6288cd86e719@ideasonboard.com> References: <20251017-exposure-limits-v1-0-6288cd86e719@ideasonboard.com> In-Reply-To: <20251017-exposure-limits-v1-0-6288cd86e719@ideasonboard.com> To: =?utf-8?q?Niklas_S=C3=B6derlund?= , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=6379; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=EJcNXPRfts0MnODBTGcYhq7MQ3EqFRL97hh4t6jRWnM=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo8gWfgDagLSWyzlIHi517Pg/KU/PtkrmBsS3CN i5qqDwVaCqJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaPIFnwAKCRByNAaPFqFW POHBD/9W5DRzUnEt6lR4BNjCUgXKIfgmT9yvt6nfsl6tzUlBIofk2ERChqGayQdIPV4eEGl7BNj PdxKOxjro8LB5D4VEpWA8ret4j1nuk4mgsc7o/4awHsikkG3f8YYxcE9+0nbBEhHvBLF2rk/ZAk RGdQ3fQxUphesTC9aI279wqO95jjzcAft5W+r3yZ5VcfdI0ObsaqoI2+Tc5U+rUcsYGeQqYJsZQ f5MTvWlhfniwvSJE3tRPX+TIPOWbvsNDLDHPcNyruehbTY0Kzdmo34cLO1Ots/T4nP9BFwWr+E2 FCBm+cLKfqZJ9BnweeidSDNrsrZVZeQ1infDAEtn/9PBe1d9RSKgVnfiq0CwhNSB//Xt00xbPfP 4SJ1YthLcn/R5e9WejMeel8qPpfNItl9Wt6G9zqoE/hUg9lB8rANX8pgwcmU04f+KL6vvD/QQED G9Hjbv0IoFU1qwneJCDQdfiY8Gib4VjXPr47ReIojjnkyeB5meqOXZJK8KDjGcEG1DpJRpANrIr hLJnGD9bJYv/P3HRge7IY58lUnPQ8E00lT9a59iw6g/MldDsucSfDQ0Ixt6jix0cga1aTAc9yCN xcI2gvH9f5uuv3jztG3iNqDpopIev2t7Npaxzvxtwht9gbGyNV/4SQDwmQhCbftTpNmF6mVuhCr qCYEAlOmKSyvRCQ== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The limits (min and max values) for the Camera controls are registered at Camera configuration time and never updated. Some controls, like FrameDurationLimits have a direct impact on the limits of other controls, such as the ExposureTime and as they can be configured by the application, this has to be taken into account. Currently, when a user changes the frame duration, the limits for both the ExposureTime and FrameDurationControls are not updated. The timing at which the controls limits should be updated is also critical: the new control values take effect once the Request they belong to is completed. To support this operation model introduce a new IPA function 'updateControlsLimits()' which the pipeline handler calls before completing a Request. Store the exposure time limits in the FrameContext (frame duration limits were already there) and update the Camera::controls() control info map with the limits as computed for the Request that has just completed. Signed-off-by: Jacopo Mondi --- include/libcamera/ipa/rkisp1.mojom | 2 ++ src/ipa/rkisp1/algorithms/agc.cpp | 3 +++ src/ipa/rkisp1/ipa_context.h | 3 +++ src/ipa/rkisp1/rkisp1.cpp | 26 ++++++++++++++++++++++++++ src/libcamera/pipeline/rkisp1/rkisp1.cpp | 3 +++ 5 files changed, 37 insertions(+) diff --git a/include/libcamera/ipa/rkisp1.mojom b/include/libcamera/ipa/rkisp1.mojom index 068e898848c4943282b4a6a05362a99016560afd..8d9446f5cbe9851886832f5cf7fd41d1a6d23a11 100644 --- a/include/libcamera/ipa/rkisp1.mojom +++ b/include/libcamera/ipa/rkisp1.mojom @@ -27,6 +27,8 @@ interface IPARkISP1Interface { map streamConfig) => (int32 ret, libcamera.ControlInfoMap ipaControls); + updateControlsLimits(uint32 frame) => (int32 ret, libcamera.ControlInfoMap ipaControls); + mapBuffers(array buffers); unmapBuffers(array ids); diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index f5a3c917cb6909f6ef918e5ee8e46cf97ba55010..0fd7541c9f1ab9b4cbae1f8fa60c39b032c3bcd1 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -585,6 +585,8 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, * frameContext.agc.exposure; maxExposureTime = minExposureTime; } + frameContext.agc.minExposureTime = minExposureTime; + frameContext.agc.maxExposureTime = maxExposureTime; if (frameContext.agc.autoGainEnabled) { minAnalogueGain = context.configuration.sensor.minAnalogueGain; @@ -606,6 +608,7 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame, * applied to the sensor when the statistics were collected. */ utils::Duration exposureTime = lineDuration * frameContext.sensor.exposure; + frameContext.agc.exposureTime = exposureTime; double analogueGain = frameContext.sensor.gain; utils::Duration effectiveExposureValue = exposureTime * analogueGain; diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index af66a749052bc82bbbe7fbb0c4626f2422700926..54ff5c114f5c6cdfaf515475a3892f76e2e022d6 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -143,6 +143,9 @@ struct IPAActiveState { struct IPAFrameContext : public FrameContext { struct { + utils::Duration minExposureTime; + utils::Duration maxExposureTime; + utils::Duration exposureTime; uint32_t exposure; double gain; double exposureValue; diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp index 54bd1434e0f4e34834beb1f9e9c39b77590f8b34..ad5c24a7159a8634aae883915b54ae0f4456692b 100644 --- a/src/ipa/rkisp1/rkisp1.cpp +++ b/src/ipa/rkisp1/rkisp1.cpp @@ -62,6 +62,8 @@ public: int configure(const IPAConfigInfo &ipaConfig, const std::map &streamConfig, ControlInfoMap *ipaControls) override; + int updateControlsLimits(const uint32_t frame, + ControlInfoMap *ipaControls) override; void mapBuffers(const std::vector &buffers) override; void unmapBuffers(const std::vector &ids) override; @@ -294,6 +296,30 @@ int IPARkISP1::configure(const IPAConfigInfo &ipaConfig, return 0; } +int IPARkISP1::updateControlsLimits(const uint32_t frame, ControlInfoMap *ipaControls) +{ + IPAFrameContext &frameContext = context_.frameContexts.get(frame); + + /* + * Update the exposure time and frame duration limits with the + * settings computed by the AGC for the frame at hand. + */ + assert(ipaControls->find(&controls::ExposureTime) != ipaControls->end()); + assert(ipaControls->find(&controls::FrameDurationLimits) != ipaControls->end()); + + ControlValue eMin(static_cast(frameContext.agc.minExposureTime.get())); + ControlValue eMax(static_cast(frameContext.agc.maxExposureTime.get())); + ControlValue eDef(static_cast(frameContext.agc.exposureTime.get())); + ipaControls->at(controls::ExposureTime.id()) = ControlInfo(eMin, eMax, eDef); + + ControlValue fMin(static_cast(frameContext.agc.minFrameDuration.get())); + ControlValue fMax(static_cast(frameContext.agc.maxFrameDuration.get())); + ControlValue fDef(static_cast(frameContext.agc.frameDuration.get())); + ipaControls->at(controls::FrameDurationLimits.id()) = ControlInfo(fMin, fMax, fDef); + + return 0; +} + void IPARkISP1::mapBuffers(const std::vector &buffers) { for (const IPABuffer &buffer : buffers) { diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index ecd13831539fdf5cb79da2ea4b33a353514328ae..ad1ff7a8be8d6e3268e21ec92ae4e07500b38c66 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -1494,6 +1494,9 @@ void PipelineHandlerRkISP1::tryCompleteRequest(RkISP1FrameInfo *info) if (!isRaw_ && !info->paramDequeued) return; + /* Update controls before completing the request */ + data->ipa_->updateControlsLimits(info->frame, &data->controlInfo_); + data->frameInfo_.destroy(info->frame); completeRequest(request); From patchwork Fri Oct 17 09:00:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 24696 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E176CC3331 for ; Fri, 17 Oct 2025 09:00:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 34639606AB; Fri, 17 Oct 2025 11:00:20 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FLH/GLMN"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 68754606A2 for ; Fri, 17 Oct 2025 11:00:16 +0200 (CEST) Received: from [192.168.1.182] (93-46-82-201.ip106.fastwebnet.it [93.46.82.201]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 06A931E33; Fri, 17 Oct 2025 10:58:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1760691516; bh=sPGToOju6+KA4WdoxnrOT31eTQJcw2spNsMittaieDY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=FLH/GLMNe5/k099IVUSJ6vKtmBqQ2/n9oICid042Y0QzqVr5xQqVW+57KyM65IRgW c2hAdQL1YOefUU3FxEPuNqHc1Ku3Y5lJ910yFkBXS6F7gRiGMYNC3ZAwYcGRnf7J4F jamJZ+zTACQaoypN3yjK6EsHlJsJkTwJri6gMef4= From: Jacopo Mondi Date: Fri, 17 Oct 2025 11:00:07 +0200 Subject: [PATCH 3/3] DNI: cam: Test Camera::controls() update with capture script MIME-Version: 1.0 Message-Id: <20251017-exposure-limits-v1-3-6288cd86e719@ideasonboard.com> References: <20251017-exposure-limits-v1-0-6288cd86e719@ideasonboard.com> In-Reply-To: <20251017-exposure-limits-v1-0-6288cd86e719@ideasonboard.com> To: =?utf-8?q?Niklas_S=C3=B6derlund?= , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=2583; i=jacopo.mondi@ideasonboard.com; h=from:subject:message-id; bh=sPGToOju6+KA4WdoxnrOT31eTQJcw2spNsMittaieDY=; b=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBo8gWfAoB9TVMVFIttj+YIZx1Q8mpMvfxG93C3G OXXNUohSMGJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaPIFnwAKCRByNAaPFqFW PCE9D/9Zl5RfOPvkaEkRp2qIhCVFKdu1FuQO4p8zTm70AqeoTkBKQJVigJctiizbZCcpwzdjemh Io3xfZzZH9n7kmnzwQn0DOlBYmFvB94qWx8AOsujLXKAfz+uWOF4Oj9FqfjnH+dAuHv1PiDa0ou Gvj7kn2RbuxnwxFJVdj1OqS4M55WCA5+CD52aJMesU4Td8koq6MBZKWHOO4rjxrngnRv/YGhVzL Y77hv8lXDZj8+sCryLMBxwL7cMDy/Ow+b9147vEddGY1Bndbxw6YI5l1hCXCrxq2LzHtQpXaG1S qi4bkDj9pgB0ls6sQguRqgLHs3IMedcH39WSPFiBsHUM3bSx3woQaackeVv+GqhDRM9kRPKJnFN YGE567MYelhXWdrtpeRNbZp1WIONt71d6VB5cIzqiCopR8FDA9Z5U2sV32M/uMlhCjHYNZ/C4SY 4HFO+UU/uH0r4bH6vfFhYZEdVJvUMyTFkcARMDRqmXF9hZcorMuM1rjbBQGiXtea9OpXyBKuJ+L bk92Ur9JXr/jfp23qyYt6i8joNkSuVnWJoBDymvNEblj8lqeB+PBTdRxOBPOp1pm/X7mAFI6AMP eyWitXrcomusJFCROHWEPZE7ijHsb4KZz2e8eC6YAi7uWkKIuZEZonV1p/wZvQR/aYcikutEXaM hlLGjkmDx+ToqbA== X-Developer-Key: i=jacopo.mondi@ideasonboard.com; a=openpgp; fpr=72392EDC88144A65C701EA9BA5826A2587AD026B X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a per-frame printout of the ExposureTime and FrameDurationLimits controls to the 'cam' tool and change the FrameDurationLimits value during a capture session using a capture script. $ cam -c1 -C100 --script ./capture-script.yaml up to frame 50: (30.07 fps) cam0-stream0 seq: 000050 bytesused: 2073600/1036800 FrameDurationLimits: [21751, 1281893] Exposure max: 33238 The FrameDuration is unbound and Exposure is limited by the driver programmed vblank of 627 lines (configuration for full-resolution 30 fps) to 33,238 msecs. After frame 50: (15.00 fps) cam0-stream0 seq: 000055 bytesused: 2073600/1036800 FrameDurationLimits: [66666, 66666] Exposure max: 66652 FrameDurationLimits is set to [66666, 66666] by the capture script and the control limits as fetched from the Camera are updated accordingly. The Exposure time is now bounded by a larger vblank of 2335 lines to 66,652 msecs. Signed-off-by: Jacopo Mondi --- change-frame-duration.yaml | 4 ++++ src/apps/cam/camera_session.cpp | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/change-frame-duration.yaml b/change-frame-duration.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b73d85b9a2625067e4955a7c1a15756ee08aec32 --- /dev/null +++ b/change-frame-duration.yaml @@ -0,0 +1,4 @@ +frames: + - 50: + FrameDurationLimits: [66666, 66666] + diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp index 1596a25a3abed9c2d93e6657b92e35fdfd3d1a26..dde4b7b5a7bb907192e6a0d3b5fd7d097a719cb9 100644 --- a/src/apps/cam/camera_session.cpp +++ b/src/apps/cam/camera_session.cpp @@ -544,6 +544,27 @@ void CameraSession::processRequest(Request *request) if (!requeue) return; + auto camera = this->camera(); + const auto controlInfo = camera->controls(); + for (const auto &[id, ctrlInfo] : controlInfo) { + if (id->id() != libcamera::controls::EXPOSURE_TIME && + id->id() != libcamera::controls::FRAME_DURATION_LIMITS) + continue; + + switch (id->id()) { + case libcamera::controls::EXPOSURE_TIME: + std::cout << "Exposure max: " + << ctrlInfo.max().get() << std::endl; + break; + case libcamera::controls::FRAME_DURATION_LIMITS: + std::cout << "FrameDurationLimits: [" + << ctrlInfo.min().get() << ", " + << ctrlInfo.max().get() << "]" + << std::endl; + break; + } + } + request->reuse(Request::ReuseBuffers); queueRequest(request); }