From patchwork Sat Sep 14 21:55:49 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: 21267 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 14BB2C324C for ; Sat, 14 Sep 2024 21:55:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D801E634FC; Sat, 14 Sep 2024 23:55:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=makewise.pt header.i=@makewise.pt header.b="R1gdLW3X"; dkim=pass (1024-bit key; unprotected) header.d=amazonses.com header.i=@amazonses.com header.b="Vo8VMTJA"; dkim-atps=neutral Received: from a7-10.smtp-out.eu-west-1.amazonses.com (a7-10.smtp-out.eu-west-1.amazonses.com [54.240.7.10]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EA8CD618F6 for ; Sat, 14 Sep 2024 23:55:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=4ymqmigrodjwq5luewph2eedidgwlpqq; d=makewise.pt; t=1726350950; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type:Content-Transfer-Encoding; bh=xF6krJ89uqGIlwL2dTBlR0Kqqx7t5lgn11B6INaGTOw=; b=R1gdLW3X69sX4JwCDs1RLGmIX2DCq2pRYMheg6Mui6frsoweo90TVp1SnIFqKEy/ Z3DWZgklBY6Fs5AaT1EivNQkenfpnHd070Ohi2w6PtzkehFhm2eBbwVnpKfe547enrC lar33QYfp4dsx/uQJbVBi3qt6dVgZhuby0BlY2w5lmATQB+9v4tvtZYyTOIl3ImKo8o lUetHKlH4tv+Fz5HR9w+lOexnd1MiuxXnakLtPVj+AvtDdIq8G4B7+qCqAJC4AcItut gSR9mlhRNyHkPqH2I1XWAsVsYopej5vzHEweDYHV9/Hmc503SQPJkSFJlgIzMBV0gGI fkD1wEKpYQ== DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=uku4taia5b5tsbglxyj6zym32efj7xqv; d=amazonses.com; t=1726350950; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type:Content-Transfer-Encoding:Feedback-ID; bh=xF6krJ89uqGIlwL2dTBlR0Kqqx7t5lgn11B6INaGTOw=; b=Vo8VMTJAF5Hz3JCHfIwwFDrm38sqU780b9ytPFIS+A27VbdQeDSp35ciyWR5sZza YOsGUb/Uxmc9UP631IFQoapkutIwEJ3W+mdpO2odM9OJxCjFL5KzAi9VTd+3X0K0hJ6 LQWrDtKgi5j57yvjgxKhQP1AK+VTuGG6MhNyuZm8= From: =?utf-8?q?Cl=C3=A1udio_Paulo?= To: libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Cl=C3=A1udio_Paulo?= Subject: [PATCH v2] libcamera: pipeline: uvcvideo: Map focus controls Date: Sat, 14 Sep 2024 21:55:49 +0000 Message-ID: <01020191f288fe5f-fb094635-2cc7-4e76-8492-a42e0b6978e3-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.14-54.240.7.10 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 Tested-by: Kieran Bingham --- Fixed issues pointed out on feedback. src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 101 +++++++++++++++++-- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 6b32fa18..11e34e95 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 @@ -333,8 +346,8 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, case V4L2_CID_EXPOSURE_AUTO: { int32_t ivalue = value.get() - ? V4L2_EXPOSURE_APERTURE_PRIORITY - : V4L2_EXPOSURE_MANUAL; + ? V4L2_EXPOSURE_APERTURE_PRIORITY + : V4L2_EXPOSURE_MANUAL; controls->set(V4L2_CID_EXPOSURE_AUTO, ivalue); break; } @@ -358,6 +371,20 @@ 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; + + controls->set(cid, static_cast(value.get() * scale + min)); + 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 +682,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 +783,46 @@ 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. + * + * 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). + * + * These values will definitely vary for each different + * hardware. 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;