From patchwork Sun Sep 15 14:31:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Cl=C3=A1udio_Paulo?= X-Patchwork-Id: 21269 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 CA93FC324C for ; Sun, 15 Sep 2024 14:31:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4E2B4634FC; Sun, 15 Sep 2024 16:31:14 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=makewise.pt header.i=@makewise.pt header.b="FLXlWQV0"; dkim=pass (1024-bit key; unprotected) header.d=amazonses.com header.i=@amazonses.com header.b="MS/cOchO"; dkim-atps=neutral Received: from a7-19.smtp-out.eu-west-1.amazonses.com (a7-19.smtp-out.eu-west-1.amazonses.com [54.240.7.19]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A8BB3634F4 for ; Sun, 15 Sep 2024 16:31:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=4ymqmigrodjwq5luewph2eedidgwlpqq; d=makewise.pt; t=1726410672; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type:Content-Transfer-Encoding; bh=iDFSTNnUYEk1/+j3ZEtc+GCdKO/AFUXH2UVmfKFukLw=; b=FLXlWQV0jo2LPLZvP+HGTRI4ZcsrnpCQQHQtcomn1Z6n8iP/DUaC+hQgFPlu8YjV Rs94gheKxn8IY5+0KTE2QU52iDTAK583FqMpoECpoPqPrhQlkF/dxB4QV2MyBW3rb+Q BCxDf2qW3Av1hFgtBqpTB4wH64h+wgA7yNIXf/4UeYcLzGDrfToqx11YGGZx8KuRx06 nWO93OfCUMzceEaaci7fnQHVKDQ7bO4PzMAywqxTUv3OqKKCPN7ITHN/QB3v019PBG7 n2CKYwt0vBjLAlogcJ46T8pzTbwp3Yv23KAWxlKSgp2E1D4zx5XhLU5ynm0/LCsJMLn iVrWowU4zQ== DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=uku4taia5b5tsbglxyj6zym32efj7xqv; d=amazonses.com; t=1726410672; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type:Content-Transfer-Encoding:Feedback-ID; bh=iDFSTNnUYEk1/+j3ZEtc+GCdKO/AFUXH2UVmfKFukLw=; b=MS/cOchOlRG/0/UNhk0bQq0Uue7OOORzL6a+vAarxfc7x9hTaJaiwKS+c7NRKEfy oO5+xuHnJAshGKyFSIMUchgWOvK4/nQRdIMP8N8kUBu9g/RlVW2F4scg7Uu2vHGh7ZQ yNYnw5D0SLZ1MN0xYklDcHq2r2aT+MenICzKGPx0= From: =?utf-8?q?Cl=C3=A1udio_Paulo?= To: libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Cl=C3=A1udio_Paulo?= Subject: [PATCH v3] libcamera: pipeline: uvcvideo: Map focus controls Date: Sun, 15 Sep 2024 14:31:11 +0000 Message-ID: <01020191f6184753-fa7f549e-0b7c-4f7a-9bcf-c9389c9f6fd1-000000@eu-west-1.amazonses.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Feedback-ID: ::1.eu-west-1.z8xjvhxVxUk+kM5mx7i/KMS/a2avhcAXFe/noI67NVQ=:AmazonSES X-SES-Outgoing: 2024.09.15-54.240.7.19 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" Added mapping of controls::LensPosition and controls::AfMode to v4l2 controls V4L2_CID_FOCUS_ABSOLUTE and V4L2_CID_FOCUS_AUTO respectively when the device supports them. If not supported, they are not registered. Signed-off-by: Cláudio Paulo --- Fixed more issues raised in review. src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 97 ++++++++++++++++++-- 1 file changed, 91 insertions(+), 6 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 6b32fa18..401d3052 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -304,13 +304,26 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, cid = V4L2_CID_EXPOSURE_ABSOLUTE; else if (id == controls::AnalogueGain) cid = V4L2_CID_GAIN; + else if (id == controls::LensPosition) + cid = V4L2_CID_FOCUS_ABSOLUTE; + else if (id == controls::AfMode) + cid = V4L2_CID_FOCUS_AUTO; else return -EINVAL; + /* Check if the device supports this control. */ + if (controls->idMap()->find(cid) == controls->idMap()->end()) + return -EINVAL; + const ControlInfo &v4l2Info = controls->infoMap()->at(cid); - int32_t min = v4l2Info.min().get(); - int32_t def = v4l2Info.def().get(); - int32_t max = v4l2Info.max().get(); + + int32_t min = -1, def = -1, max = -1; + if (v4l2Info.min().type() == ControlTypeInteger32) + min = v4l2Info.min().get(); + if (v4l2Info.min().type() == ControlTypeInteger32) + def = v4l2Info.def().get(); + if (v4l2Info.min().type() == ControlTypeInteger32) + max = v4l2Info.max().get(); /* * See UVCCameraData::addControl() for explanations of the different @@ -358,6 +371,21 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, break; } + case V4L2_CID_FOCUS_ABSOLUTE: { + float focusedAt50Cm = 0.15f * (max - min); + float scale = focusedAt50Cm / 2.0f; + + float fvalue = value.get() * scale + min; + controls->set(cid, static_cast(lroundf(fvalue))); + break; + } + + case V4L2_CID_FOCUS_AUTO: { + int32_t ivalue = value.get() != controls::AfModeManual; + controls->set(cid, ivalue); + break; + } + default: { int32_t ivalue = value.get(); controls->set(cid, ivalue); @@ -655,14 +683,32 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, case V4L2_CID_GAIN: id = &controls::AnalogueGain; break; + case V4L2_CID_FOCUS_ABSOLUTE: + id = &controls::LensPosition; + break; + case V4L2_CID_FOCUS_AUTO: + id = &controls::AfMode; + break; default: return; } /* Map the control info. */ - int32_t min = v4l2Info.min().get(); - int32_t max = v4l2Info.max().get(); - int32_t def = v4l2Info.def().get(); + int32_t min = -1, def = -1, max = -1; + if (v4l2Info.min().type() == ControlTypeInteger32) + min = v4l2Info.min().get(); + else if (v4l2Info.min().type() == ControlTypeBool) + min = v4l2Info.min().get(); + + if (v4l2Info.def().type() == ControlTypeInteger32) + def = v4l2Info.def().get(); + else if (v4l2Info.def().type() == ControlTypeBool) + def = v4l2Info.def().get(); + + if (v4l2Info.max().type() == ControlTypeInteger32) + max = v4l2Info.max().get(); + else if (v4l2Info.max().type() == ControlTypeBool) + max = v4l2Info.max().get(); switch (cid) { case V4L2_CID_BRIGHTNESS: { @@ -738,6 +784,45 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, }; break; } + case V4L2_CID_FOCUS_ABSOLUTE: { + /* + * LensPosition expects values to be in the range of + * [0.0f, maxDioptres], while a value of 0 means focused to + * infinity, 0.5 means focused at 2m, 2 means focused at 50cm + * and maxDioptres will be the closest possible focus which + * will equate to a focus distance of (1 / maxDioptres) metres. + * + * \todo These values will definitely vary for each different + * hardware, so this should be tunable somehow. In this case + * 0.15f (~= 150 / (1023 - 1)) was a value read from + * V4L2_CID_FOCUS_ABSOLUTE control when using a random camera + * and having it autofocus at a distance of about 50cm. + * This means the minimum focus distance of this camera should + * be 75mm (0.15 / 2) which equals a maxDioptres value of ~= + * 13.3333 (2 / 0.15). Also, the values might not scale + * linearly, but this implementation assumes they do. + */ + float focusedAt50Cm = 0.15f * (max - min); + float scale = 2.0f / focusedAt50Cm; + + info = ControlInfo{ + { 0.0f }, + { (max - min) * scale }, + { (def - min) * scale } + }; + break; + } + case V4L2_CID_FOCUS_AUTO: { + int32_t manual = controls::AfModeManual; + int32_t continuous = controls::AfModeContinuous; + + info = ControlInfo{ + { manual }, + { continuous }, + { def ? continuous : manual }, + }; + break; + } default: info = v4l2Info;