From patchwork Fri Sep 13 17:22:03 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: 21264 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 12D30C3257 for ; Fri, 13 Sep 2024 17:31:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7EE21634F4; Fri, 13 Sep 2024 19:31:28 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=makewise.pt header.i=@makewise.pt header.b="MGBp1Gha"; dkim=pass (1024-bit key; unprotected) header.d=amazonses.com header.i=@amazonses.com header.b="j+5i2+Pu"; dkim-atps=neutral Received: from a7-12.smtp-out.eu-west-1.amazonses.com (a7-12.smtp-out.eu-west-1.amazonses.com [54.240.7.12]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 114A8634E3 for ; Fri, 13 Sep 2024 19:22:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=4ymqmigrodjwq5luewph2eedidgwlpqq; d=makewise.pt; t=1726248123; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type:Content-Transfer-Encoding; bh=JNQ8c3Ek95sIdioEgxD0pxBtdHdPC6snVfWSBO87c1w=; b=MGBp1GhaLKnr4q/ACcE0NKOFxN2c/OVSXR6BJSQCaf8HvCSWuAKAcjREBBJQRQvs iMNDqCyQ1wovW0PpbUakDd+93YwLlYLduPr5XDZY8GTLCKY25MagX1fiAsnKWTldvMd nzB8NI8IlMD6YE1/bD/EJ432RXnNK/eFBG9TVPYUSeQs4IpqUQcXLH02N4YwdSaz2Wh rxIfEC7kwYBkV9B7aAmx4EoldmDjBluX1QMabN+wbtPf+B8BdLMYinHwfMYPpJYFFNR t7Phn+N+DIt4ixpU485NbN4paZdNNJipYEvHJvVD6De6KWNXYqw2opFqblvS6f9HaYG zHJiErGlwg== DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=uku4taia5b5tsbglxyj6zym32efj7xqv; d=amazonses.com; t=1726248123; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version:Content-Type:Content-Transfer-Encoding:Feedback-ID; bh=JNQ8c3Ek95sIdioEgxD0pxBtdHdPC6snVfWSBO87c1w=; b=j+5i2+PuYyL3X08NkJRr8P731n6ziLkOI551ltiwHB+EiA3DUfQPgewDw3s+ZHRz c0Ic7446hbQP8/CiV+4C2hDClukswtFkHu4pjCozGnlZhted2CW2G1mr5SjKji4YiSO BCbWt/IOqkFODRQBkF+oaDTClIb1geDeYiHHpJR4= From: =?utf-8?q?Cl=C3=A1udio_Paulo?= To: libcamera-devel@lists.libcamera.org Cc: =?utf-8?q?Cl=C3=A1udio_Paulo?= Subject: [PATCH] libcamera: pipeline: uvcvideo: Map focus controls Date: Fri, 13 Sep 2024 17:22:03 +0000 Message-ID: <01020191ec67fb81-a9b3be00-461b-4814-a6bb-892404f7420f-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.13-54.240.7.12 X-Mailman-Approved-At: Fri, 13 Sep 2024 19:31:26 +0200 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 --- include/linux/v4l2-controls.h | 4 + src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 88 +++++++++++++++++--- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h index 882a8180..1ac85507 100644 --- a/include/linux/v4l2-controls.h +++ b/include/linux/v4l2-controls.h @@ -994,6 +994,10 @@ enum v4l2_exposure_auto_type { #define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+10) #define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+11) #define V4L2_CID_FOCUS_AUTO (V4L2_CID_CAMERA_CLASS_BASE+12) +enum v4l2_focus_auto_type { + V4L2_FOCUS_MANUAL = 0, + V4L2_FOCUS_AUTO = 1 +}; #define V4L2_CID_ZOOM_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+13) #define V4L2_CID_ZOOM_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+14) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 6b32fa18..fe3c71d0 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -304,13 +304,14 @@ 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 && controls->idMap()->count(V4L2_CID_FOCUS_ABSOLUTE)) // Check if device supports this control + cid = V4L2_CID_FOCUS_ABSOLUTE; + else if (id == controls::AfMode && controls->idMap()->count(V4L2_CID_FOCUS_AUTO)) // Check if device supports this control + cid = V4L2_CID_FOCUS_AUTO; else 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(); /* * See UVCCameraData::addControl() for explanations of the different @@ -318,6 +319,10 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, */ switch (cid) { case V4L2_CID_BRIGHTNESS: { + int32_t min = v4l2Info.min().get(); + int32_t def = v4l2Info.def().get(); + int32_t max = v4l2Info.max().get(); + float scale = std::max(max - def, def - min); float fvalue = value.get() * scale + def; controls->set(cid, static_cast(lroundf(fvalue))); @@ -325,6 +330,9 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, } case V4L2_CID_SATURATION: { + int32_t min = v4l2Info.min().get(); + int32_t def = v4l2Info.def().get(); + float scale = def - min; float fvalue = value.get() * scale + min; controls->set(cid, static_cast(lroundf(fvalue))); @@ -345,6 +353,10 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, case V4L2_CID_CONTRAST: case V4L2_CID_GAIN: { + int32_t min = v4l2Info.min().get(); + int32_t def = v4l2Info.def().get(); + int32_t max = v4l2Info.max().get(); + float m = (4.0f - 1.0f) / (max - def); float p = 1.0f - m * def; @@ -358,6 +370,22 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id, break; } + case V4L2_CID_FOCUS_ABSOLUTE: { + int32_t min = v4l2Info.min().get(); + int32_t max = v4l2Info.max().get(); + + float focusedAt50Cm = 0.15f * (max - min); + float scale = focusedAt50Cm / 2.0f; + + controls->set(cid, static_cast(min + value.get() * scale)); + break; + } + + case V4L2_CID_FOCUS_AUTO: { + controls->set(cid, static_cast(value.get() == 0 ? V4L2_FOCUS_MANUAL : V4L2_FOCUS_AUTO)); + break; + } + default: { int32_t ivalue = value.get(); controls->set(cid, ivalue); @@ -655,14 +683,17 @@ 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(); switch (cid) { case V4L2_CID_BRIGHTNESS: { @@ -673,6 +704,9 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, * Accommodate this by restricting the range of the libcamera * control, but always within the maximum limits. */ + int32_t min = v4l2Info.min().get(); + int32_t max = v4l2Info.max().get(); + int32_t def = v4l2Info.def().get(); float scale = std::max(max - def, def - min); info = ControlInfo{ @@ -683,36 +717,42 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, break; } - case V4L2_CID_SATURATION: + case V4L2_CID_SATURATION: { /* * The Saturation control is a float, with 0.0 mapped to the * minimum value (corresponding to a fully desaturated image) * and 1.0 mapped to the default value. Calculate the maximum * value accordingly. */ + int32_t min = v4l2Info.min().get(); + int32_t max = v4l2Info.max().get(); + int32_t def = v4l2Info.def().get(); info = ControlInfo{ { 0.0f }, { static_cast(max - min) / (def - min) }, { 1.0f } }; break; - + } case V4L2_CID_EXPOSURE_AUTO: info = ControlInfo{ false, true, true }; break; - case V4L2_CID_EXPOSURE_ABSOLUTE: + case V4L2_CID_EXPOSURE_ABSOLUTE: { /* * ExposureTime is in units of 1 µs, and UVC expects * V4L2_CID_EXPOSURE_ABSOLUTE in units of 100 µs. */ + int32_t min = v4l2Info.min().get(); + int32_t max = v4l2Info.max().get(); + int32_t def = v4l2Info.def().get(); info = ControlInfo{ { min * 100 }, { max * 100 }, { def * 100 } }; break; - + } case V4L2_CID_CONTRAST: case V4L2_CID_GAIN: { /* @@ -723,6 +763,9 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, * maximum values are respectively no lower than 0.5 and no * higher than 4.0. */ + int32_t min = v4l2Info.min().get(); + int32_t max = v4l2Info.max().get(); + int32_t def = v4l2Info.def().get(); float m = (4.0f - 1.0f) / (max - def); float p = 1.0f - m * def; @@ -738,6 +781,31 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info, }; break; } + case V4L2_CID_FOCUS_ABSOLUTE: { + int32_t min = v4l2Info.min().get(); + int32_t max = v4l2Info.max().get(); + int32_t def = v4l2Info.def().get(); + + float focusedAt50Cm = 0.15f * (max - min); + float scale = 2.0f / focusedAt50Cm; + + info = ControlInfo{ + { 0.0f }, + { scale * (max - min) }, + { scale * (def - min) } + }; + break; + } + case V4L2_CID_FOCUS_AUTO: { + bool def = v4l2Info.def().get(); + + info = ControlInfo{ + { static_cast(V4L2_FOCUS_MANUAL) }, + { static_cast(V4L2_FOCUS_AUTO) }, + { static_cast(def ? V4L2_FOCUS_AUTO : V4L2_FOCUS_MANUAL) }, + }; + break; + } default: info = v4l2Info;