From patchwork Fri Sep 27 15:12: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: 21412 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 2B618C0F1B for ; Fri, 27 Sep 2024 15:12:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 020026350F; Fri, 27 Sep 2024 17:12:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=makewise.pt header.i=@makewise.pt header.b="b4jfirpV"; dkim=pass (1024-bit key; unprotected) header.d=amazonses.com header.i=@amazonses.com header.b="eUv6/bHh"; dkim-atps=neutral Received: from a7-18.smtp-out.eu-west-1.amazonses.com (a7-18.smtp-out.eu-west-1.amazonses.com [54.240.7.18]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B2007634F2 for ; Fri, 27 Sep 2024 17:12:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=4ymqmigrodjwq5luewph2eedidgwlpqq; d=makewise.pt; t=1727449969; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type:Content-Transfer-Encoding; bh=fv4guwdRbWMWTLVxG7Nu2PNb9x5IRezKZuInNz8fXFA=; b=b4jfirpVFBzsO2ayDNk0i1M/5rq7CDpFS66GKQ4KO8EH7XMu4lbGCOMWgfseVSva FkCyjd5R4zfAIRZuz2l4Hn+J8gpCvZx65inVStRs9PhlIhHEovitdetaGG54oizIOTo 6ycZQrA9Jg4K2Szp9dVLHNOCUg88Ma9kSp5xQJwAYd2G0snswkmstCiyLKwN4KgR+tV RW8DGVDlgUrL9Xv8iopAe3hU6bgFBXaCO2QJcJ5Frk/fIbXpKZuH/oE6PwfDakr/KQ+ ye5XVz/qxOVYZwiz/oseQPCBBcQ+GiC2301TTJYvQ7zrsdBSby4cqwDfwAhVJ79LrgC Yg/hNHc5PQ== DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=uku4taia5b5tsbglxyj6zym32efj7xqv; d=amazonses.com; t=1727449969; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type:Content-Transfer-Encoding:Feedback-ID; bh=fv4guwdRbWMWTLVxG7Nu2PNb9x5IRezKZuInNz8fXFA=; b=eUv6/bHhg5PQp5U000sP72rovypl6CXSxcQqT5T3+81QJvlUSpY5ZmH2YuZUeLLJ d5HSnxnNFIFCEC3rpgYHwjXR30KwhvmCnwyOYVM0fwXlQUPWcVYc8ekSwytBeo0uj+b j5soiju2cb8bNAUOoAleCnjiR3VBcCdyxjfiKsV8= From: =?utf-8?q?Cl=C3=A1udio_Paulo?= To: libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Cl=C3=A1udio_Paulo?= Subject: [PATCH v4] libcamera: pipeline: uvcvideo: Map focus controls Date: Fri, 27 Sep 2024 15:12:49 +0000 Message-ID: <01020192340ab214-3d46266e-b780-407e-941f-8f8d5a841007-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.27-54.240.7.18 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 issues raised in review. src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 107 +++++++++++++++++-- 1 file changed, 100 insertions(+), 7 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 6b32fa18..3a0d6ab6 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -6,9 +6,9 @@ */ #include +#include #include #include -#include #include #include #include @@ -304,13 +304,33 @@ 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, def, max; + if (v4l2Info.min().type() == ControlTypeInteger32) { + min = v4l2Info.min().get(); + def = v4l2Info.def().get(); + max = v4l2Info.max().get(); + } else if (v4l2Info.min().type() == ControlTypeBool) { + min = v4l2Info.min().get(); + def = v4l2Info.def().get(); + max = v4l2Info.max().get(); + } else { + LOG(UVC, Error) << "v4l2 ControlInfo with value type " + << v4l2Info.min().type() << " not mapped"; + return -EINVAL; + } /* * See UVCCameraData::addControl() for explanations of the different @@ -358,6 +378,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(std::lround(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 +690,31 @@ 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, def, max; + if (v4l2Info.min().type() == ControlTypeInteger32) { + min = v4l2Info.min().get(); + def = v4l2Info.def().get(); + max = v4l2Info.max().get(); + } else if (v4l2Info.min().type() == ControlTypeBool) { + min = v4l2Info.min().get(); + def = v4l2Info.def().get(); + max = v4l2Info.max().get(); + } else { + LOG(UVC, Error) << "v4l2 ControlInfo with value type " + << v4l2Info.min().type() << " not mapped"; + return; + } switch (cid) { case V4L2_CID_BRIGHTNESS: { @@ -739,6 +791,47 @@ 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: { + std::vector values; + + if (!min || !max) + values.emplace_back(static_cast(controls::AfModeManual)); + if (min || max) + values.emplace_back(static_cast(controls::AfModeContinuous)); + + info = ControlInfo{ values, values.back() }; + break; + } + default: info = v4l2Info; break;