From patchwork Thu Oct 17 17:04:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 21660 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 58E25C32FC for ; Thu, 17 Oct 2024 17:24:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CC1FD65385; Thu, 17 Oct 2024 19:24:27 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ziska.de header.i=@ziska.de header.b="R36dKBjX"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="7mtVtO/0"; dkim-atps=neutral Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [85.215.255.23]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7391965381 for ; Thu, 17 Oct 2024 19:24:25 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1729185864; cv=none; d=strato.com; s=strato-dkim-0002; b=HmVfs/TKxtErqQe8Av56ojXrpR2wRbmQIg0ljrHh7fOCBP+2RYG+55Zwmc1FOw2sp/ /xQ7gROCD5UmIUqs+x21wW3S8Y4/9Okt9v9xS4vUK8Po5n9WNavlVVrLVXNbwg2j/hQg FJymV5qr8c4RIeEo4R8I9JFkU9mHEDHZHyRiRWHJySNwiHHwNgIL3Vd00k0QeDxKg/Jm ClBHV8wQK3Q7BvUrw2WqstH8gJOZeD2RDCum82p+x6toIIFBb7/a10laIRRv2uw8W70g aTju9EcYtk5p+hL1P6xXSf8VH620EXG/jXt9Ikxw0TmbocdXsG27nRl0rWpiINBIjaR0 Yqhw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1729185864; s=strato-dkim-0002; d=strato.com; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=T7O4CLfRFc2ELT+Lz3DYYfyc9JF05zwpoxEZNXxoYao=; b=jkxopZEzc6k2Qdk0VtHG59ij4L3HOJlAoEXArd19YmkGPIBicgJts+fFSFqlfRysDs sAdaH4Fe3YUTcKbpuMo/JGLfiN29o3zNli58zAcOhVvHfq0FnHcBKEM872SPHOToGZu2 fH6+G+EhauHqphqRpnh0mk/Jax2raDZrF69uDBD9jsLV8r+32fzygDBkyubchKpSJL2V BKPzoSB3v7wN5tJCWQ3ngsgskn+G1o54H0YqRBbDIfJ1veOCP2vZVOBznBiB2RRPa/y7 jq+UTlhHz/eto5tJo+PhNsdQ8pCeGB7Y6YVRn1Tw9YCgJ5XjxznHAzWKiTccUmNZZpNn I0OQ== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo00 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1729185864; s=strato-dkim-0002; d=ziska.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=T7O4CLfRFc2ELT+Lz3DYYfyc9JF05zwpoxEZNXxoYao=; b=R36dKBjXOWrnnCa32qvfNOZaXtP6JEkyrMgW/VDlauNatiHnbPOQC4Zgr+vV++nzhe 2Vf6I0UxrmfxJ5q0n6Kh4iSpTHvJmnTMpEBEBAVpk8yC1iEjJ4w1FExJSOlw32YzrTfJ 7J/JTjDWj3peiNVWIyN8Ohzgo4KUFMUU028cSMjvh8QtcCSF2uC6hLPwKId/JkMBl+2N wQ2byWSTVUrLcDPkqh0l0f9OMBBr7NgaWV9ztYT9Oud47CQ1nZm3JIum/GEn1N455rgd bNi8+TSU0qKyYYdzsYgwTceGsX7MQMeG+1/5x7LBHgQWiDWaQoSupli0RDuMO0r9Brs8 PPsQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1729185864; s=strato-dkim-0003; d=ziska.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=T7O4CLfRFc2ELT+Lz3DYYfyc9JF05zwpoxEZNXxoYao=; b=7mtVtO/0Em4X1p9eyj0Cmd7EsBNDKraoj0f4wjURTZsa30PSRcMbr5uka9XqAeo/zs nX9aU7E2AVjllaE5wSAw== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cChoruAPJaMLnEXgE4US4SwNHvFuM4Ih4GFfdN" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.2.11 AUTH) with ESMTPSA id zf9ba109HHOOI7H (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Thu, 17 Oct 2024 19:24:24 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska , Laurent Pinchart Subject: [PATCH v3 1/3] gstreamer: Remove auto-focus-mode property from device provider Date: Thu, 17 Oct 2024 19:04:13 +0200 Message-ID: <20241017172331.16377-2-jaslo@ziska.de> X-Mailer: git-send-email 2.46.2 In-Reply-To: <20241017172331.16377-1-jaslo@ziska.de> References: <20241017172331.16377-1-jaslo@ziska.de> MIME-Version: 1.0 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 device provider is not supposed to have control properties, remove the auto-focus-mode property which was introduced by accident. Fixes: 5a142438b025 ("gstreamer: Add enable_auto_focus option to the GStreamer plugin") Signed-off-by: Jaslo Ziska Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/gstreamer/gstlibcameraprovider.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/gstreamer/gstlibcameraprovider.cpp b/src/gstreamer/gstlibcameraprovider.cpp index 4fb1b007..5da96ea3 100644 --- a/src/gstreamer/gstlibcameraprovider.cpp +++ b/src/gstreamer/gstlibcameraprovider.cpp @@ -33,7 +33,6 @@ GST_DEBUG_CATEGORY_STATIC(provider_debug); enum { PROP_DEVICE_NAME = 1, - PROP_AUTO_FOCUS_MODE = 2, }; #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type() @@ -43,7 +42,6 @@ G_DECLARE_FINAL_TYPE(GstLibcameraDevice, gst_libcamera_device, struct _GstLibcameraDevice { GstDevice parent; gchar *name; - controls::AfModeEnum auto_focus_mode = controls::AfModeManual; }; G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE) @@ -60,7 +58,6 @@ gst_libcamera_device_create_element(GstDevice *device, const gchar *name) g_assert(source); g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name, nullptr); - g_object_set(source, "auto-focus-mode", GST_LIBCAMERA_DEVICE(device)->auto_focus_mode, nullptr); return source; } @@ -87,9 +84,6 @@ gst_libcamera_device_set_property(GObject *object, guint prop_id, case PROP_DEVICE_NAME: device->name = g_value_dup_string(value); break; - case PROP_AUTO_FOCUS_MODE: - device->auto_focus_mode = static_cast(g_value_get_enum(value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -129,15 +123,6 @@ gst_libcamera_device_class_init(GstLibcameraDeviceClass *klass) (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec); - - pspec = g_param_spec_enum("auto-focus-mode", - "Set auto-focus mode", - "Available options: AfModeManual, " - "AfModeAuto or AfModeContinuous.", - gst_libcamera_auto_focus_get_type(), - static_cast(controls::AfModeManual), - G_PARAM_WRITABLE); - g_object_class_install_property(object_class, PROP_AUTO_FOCUS_MODE, pspec); } static GstDevice * From patchwork Thu Oct 17 17:04:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 21661 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 A6797C32FC for ; Thu, 17 Oct 2024 17:24:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 427BD65383; Thu, 17 Oct 2024 19:24:31 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ziska.de header.i=@ziska.de header.b="TtQBYMzt"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="DgEk5foa"; dkim-atps=neutral Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [81.169.146.221]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 53D1065383 for ; Thu, 17 Oct 2024 19:24:27 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1729185866; cv=none; d=strato.com; s=strato-dkim-0002; b=n+Rgxl3VKZnUc1vpED35xWeAvkWvwZtqWoxM5oceEjodPII0cXHHQOtSHLusBVJ/C4 KP9Cij8qzytffci/24caRieZQgPFZZT9T3xBwdywmGzA/KZvUHcGVk2RP8WWkhquzRIY uohR9fkK4urqxOBQho5bXfrhkBfifo1SsdNs5KRoObLEn0/TYXYn1QurmXCSrp9+swdh jr2Zh17v4V5WNARz2Cn+ETrjFF4O8uBsv1bLSDZ3zBIPeTJ5jnyT3/ARFV1pKtvL3wVa fTVOvsKb8OfHZZQvIjMd9g3Jhl03x5IG5arlwGDA3EHokALAQGJoA6pbk0qrEIUUql24 Y4Iw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1729185866; s=strato-dkim-0002; d=strato.com; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=ZKf/n02rjzMepGpSkuuXmnPJ1Dn+plIEKRrTMDtLW3A=; b=P+uN531fiEd17K5ujB6YetOcAG5B2QFM0B+LErvkahwDSs6gcqyaBnMVzZRvGxh++b pDAko+4VnLIe4jts62EJjjBCCsosKSufTEXFWhN8XJZg1spQ+PND85fgqNfsnx1vcInw 7L3E9Hh45daq/oivo7Ak6097YXOfRUMxVQLLOCgIfWKV8UBHMAWV0sDzWswqgESCG0iP NbwZhtOirjcOfSakKdp0cBIETweUASBOxhep8DI/Vjaq6THdJfJowAaOEdoIVgszjCwx H3ZWjpz14lTI17TrER6rqwsPepnROEegPfxUCo92nKWqoMtjM7PeQ8dYcoe/XrzReXEO RV6w== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo00 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1729185866; s=strato-dkim-0002; d=ziska.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=ZKf/n02rjzMepGpSkuuXmnPJ1Dn+plIEKRrTMDtLW3A=; b=TtQBYMztX42SObr45b11YmDhfam6h7uaTd6h2d/2h7n7igLTJOTp2i/5UYnroQ+AJH 5sFMIAAST5LZUJOBUOjLo3Gq65037He3ZnRzyiNziP5Lb8fQbnbTxRugaqSVW6guLVWR 8WsjUq7Boycr9WjjU5nNV5fsQCPGNU6ELaLeg15xmJeb3rZUFZQVZ9ra2riZ7ZSNEwsd 9h+qvieuigm/zd0kfOP7Q1TabvYUA/reKJRRyWiDFw2I//IIbTK+bOxCPR4CKVGgQA9S KYQ7u+zcOSivrCxtJFHV8doOoYwCqGwhyIWP/uZfJMVBIiTguasrhJNrFiSCdm/ICKec JXoA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1729185866; s=strato-dkim-0003; d=ziska.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=ZKf/n02rjzMepGpSkuuXmnPJ1Dn+plIEKRrTMDtLW3A=; b=DgEk5foaTzlBMfVVFPEF16/+yC2HhVBAl81iwQkapn7v9hjbQ45jgNuuB9QUx+pMD3 iJ+idkE5H8nAQY5BzgCg== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cChoruAPJaMLnEXgE4US4SwNHvFuM4Ih4GFfdN" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.2.11 AUTH) with ESMTPSA id zf9ba109HHOQI7I (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Thu, 17 Oct 2024 19:24:26 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska , Laurent Pinchart Subject: [PATCH v3 2/3] gstreamer: Remove auto-focus-mode property from libcamerasrc Date: Thu, 17 Oct 2024 19:04:14 +0200 Message-ID: <20241017172331.16377-3-jaslo@ziska.de> X-Mailer: git-send-email 2.46.2 In-Reply-To: <20241017172331.16377-1-jaslo@ziska.de> References: <20241017172331.16377-1-jaslo@ziska.de> MIME-Version: 1.0 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" In preparation for generic support of all libcamera controls, remove the manual handling of the auto-focus-mode property from the libcamerasrc element. Signed-off-by: Jaslo Ziska Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/gstreamer/gstlibcamerasrc.cpp | 28 ---------------------------- src/gstreamer/gstlibcamerasrc.h | 31 ------------------------------- 2 files changed, 59 deletions(-) diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 912a8d55..40b787c8 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -142,7 +142,6 @@ struct _GstLibcameraSrc { GstTask *task; gchar *camera_name; - controls::AfModeEnum auto_focus_mode = controls::AfModeManual; std::atomic pending_eos; @@ -154,7 +153,6 @@ struct _GstLibcameraSrc { enum { PROP_0, PROP_CAMERA_NAME, - PROP_AUTO_FOCUS_MODE, }; static void gst_libcamera_src_child_proxy_init(gpointer g_iface, @@ -663,18 +661,6 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread, gst_pad_push_event(srcpad, gst_event_new_segment(&segment)); } - if (self->auto_focus_mode != controls::AfModeManual) { - const ControlInfoMap &infoMap = state->cam_->controls(); - if (infoMap.find(&controls::AfMode) != infoMap.end()) { - state->initControls_.set(controls::AfMode, self->auto_focus_mode); - } else { - GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS, - ("Failed to enable auto focus"), - ("AfMode not supported by this camera, " - "please retry with 'auto-focus-mode=AfModeManual'")); - } - } - ret = state->cam_->start(&state->initControls_); if (ret) { GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS, @@ -742,9 +728,6 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id, g_free(self->camera_name); self->camera_name = g_value_dup_string(value); break; - case PROP_AUTO_FOCUS_MODE: - self->auto_focus_mode = static_cast(g_value_get_enum(value)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -762,9 +745,6 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value, case PROP_CAMERA_NAME: g_value_set_string(value, self->camera_name); break; - case PROP_AUTO_FOCUS_MODE: - g_value_set_enum(value, static_cast(self->auto_focus_mode)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -967,14 +947,6 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass) | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec); - spec = g_param_spec_enum("auto-focus-mode", - "Set auto-focus mode", - "Available options: AfModeManual, " - "AfModeAuto or AfModeContinuous.", - gst_libcamera_auto_focus_get_type(), - static_cast(controls::AfModeManual), - G_PARAM_WRITABLE); - g_object_class_install_property(object_class, PROP_AUTO_FOCUS_MODE, spec); } /* GstChildProxy implementation */ diff --git a/src/gstreamer/gstlibcamerasrc.h b/src/gstreamer/gstlibcamerasrc.h index fd1f8193..a27db9ca 100644 --- a/src/gstreamer/gstlibcamerasrc.h +++ b/src/gstreamer/gstlibcamerasrc.h @@ -8,8 +8,6 @@ #pragma once -#include - #include G_BEGIN_DECLS @@ -19,32 +17,3 @@ G_DECLARE_FINAL_TYPE(GstLibcameraSrc, gst_libcamera_src, GST_LIBCAMERA, SRC, GstElement) G_END_DECLS - -inline GType -gst_libcamera_auto_focus_get_type() -{ - static GType type = 0; - static const GEnumValue values[] = { - { - static_cast(libcamera::controls::AfModeManual), - "AfModeManual", - "manual-focus", - }, - { - static_cast(libcamera::controls::AfModeAuto), - "AfModeAuto", - "automatic-auto-focus", - }, - { - static_cast(libcamera::controls::AfModeContinuous), - "AfModeContinuous", - "continuous-auto-focus", - }, - { 0, NULL, NULL } - }; - - if (!type) - type = g_enum_register_static("GstLibcameraAutoFocus", values); - - return type; -} From patchwork Thu Oct 17 17:04:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 21662 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 A5EA0C32FF for ; Thu, 17 Oct 2024 17:24:33 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D792065387; Thu, 17 Oct 2024 19:24:32 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ziska.de header.i=@ziska.de header.b="jOtqkBAU"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="o9R30SQj"; dkim-atps=neutral Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [85.215.255.21]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7BF5F65389 for ; Thu, 17 Oct 2024 19:24:28 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1729185867; cv=none; d=strato.com; s=strato-dkim-0002; b=IAtPP+FVloofE3mF4vhQ0LzlJ4qjgPbS9aiKmgSiwp00VJVQqz88Htxkm17mH8DkNi 3EjI2g/IOPw0z5F+geZH6FSLn7NwtW0zyWpg46H7m7/7SKi4VwDZlZceXPhziMqJbgVR 2PpHa5Uh1acTWeh0qIYGqMv+ikSD1IXtszwAH+HcK/fS0ifYOuGWQ1h74qg0/JMCt5wx 3+Zl3jGApkG2Bry//WkqOuf7WmwGnpxF/O7JHlo/mlfjjMpaG5Qrp6OwCUvZZPHgHo1O rYc+ebd7RxNnHX+6yZJHDaoKBpEqkmt9yXfA5IHhylrlftXQFKDzV71Igil/jscuYXnP rQQA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1729185867; s=strato-dkim-0002; d=strato.com; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=2q9LS1/9Xq8TdIYsVc5uEx0uRtdR7rWyK5e5YA12+1E=; b=DvGLq5SuxoCPyLhj/y+LLQrnqXrAA94S4AFRP8XNnGRwThRwvDDac85iGqx6bXLB4H V6tbK5ctFLGIIyQ9zgsxxkSq9xqmqAfGgSj268DBv/BRuREkDk6OftigEaMSDZESPGwP telTqbIRSkbgn8qO3KxFgsIUvLm1WbFqIWe05J3NXnO2oWJ7GCN0Cy12pytRK+eK2Be8 UPqSmBrVFJXHAsfNzj9pdx04cnPiV+ysL9mu9V3BKw0ZnzIHy9raYbi8dX98galzwQxM nPBQ04djTfy5JxYKL3BwSayiKNV5rsGdOaNtz/Vr2biwfASmqS2XvXCq1v4KP3MNMxBt b8AQ== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo00 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1729185867; s=strato-dkim-0002; d=ziska.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=2q9LS1/9Xq8TdIYsVc5uEx0uRtdR7rWyK5e5YA12+1E=; b=jOtqkBAUWD6YuJA8/MjfI67VGN5Xzjnywzmgrhke72dJBvcX3N8HNTRotbrcv5ZVFS eYC4AzYEhC7Vbfp0ndStlOpFyo2IKFjoFUdBCV9/MVK5VeAHHP8UUacabfW3YqopfWCn BdckWNwhEa6cChHYk2W/9KwtaFTJ8hxiyTh+uc9D4BiHK4cM0hEB3FJtJKe5HP5D1YeL HQp3q3Zt8bTUMLZM65OeqCcYXpam1pdBL3FpZBs9g4313b29E7/Gbnd1/a5GTLx3mFrk Gc9eyfqWYgI/y0luLFsM6KrzkxMkOgzQEV03RMg01lqh0X5nGgHM3lOgNm55vHATxygT xSLA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1729185867; s=strato-dkim-0003; d=ziska.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=2q9LS1/9Xq8TdIYsVc5uEx0uRtdR7rWyK5e5YA12+1E=; b=o9R30SQjYM7l8m57Lq4a5r6pa6pdWTJ4OGEpEh6e4xrvGcvA7d5NMC41AJ7//P2OA+ P5S46nFf+H2PdI+TdQCw== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cChoruAPJaMLnEXgE4US4SwNHvFuM4Ih4GFfdN" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.2.11 AUTH) with ESMTPSA id zf9ba109HHORI7J (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Thu, 17 Oct 2024 19:24:27 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska Subject: [PATCH v3 3/3] gstreamer: Generate controls from control_ids_*.yaml files Date: Thu, 17 Oct 2024 19:04:15 +0200 Message-ID: <20241017172331.16377-4-jaslo@ziska.de> X-Mailer: git-send-email 2.46.2 In-Reply-To: <20241017172331.16377-1-jaslo@ziska.de> References: <20241017172331.16377-1-jaslo@ziska.de> MIME-Version: 1.0 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" This commit implements gstreamer controls for the libcamera element by generating the controls from the control_ids_*.yaml files using a new gen-gst-controls.py script. The appropriate meson files are also changed to automatically run the script when building. The gen-gst-controls.py script works similar to the gen-controls.py script by parsing the control_ids_*.yaml files and generating C++ code for each exposed control. For the controls to be used as gstreamer properties the type for each control needs to be translated to the appropriate glib type and a GEnumValue is generated for each enum control. Then a g_object_install_property(), _get_property() and _set_property() function is generated for each control. The vendor controls get prefixed with "$vendor-" in the final gstreamer property name. The C++ code generated by the gen-gst-controls.py script is written into the template gstlibcamerasrc-controls.cpp.in file. The matching gstlibcamerasrc-controls.h header defines the GstCameraControls class which handles the installation of the gstreamer properties as well as keeping track of the control values and setting and getting the controls. The content of these functions is generated in the Python script. Finally the libcamerasrc element itself is edited to make use of the new GstCameraControls class. The way this works is by defining a PROP_LAST enum variant which is passed to the installProperties() function so the properties are defined with the appropriate offset. When getting or setting a property PROP_LAST is subtracted from the requested property to translate the control back into a libcamera::controls:: enum variant. Signed-off-by: Jaslo Ziska --- src/gstreamer/gstlibcamera-controls.cpp.in | 332 +++++++++++++++++++++ src/gstreamer/gstlibcamera-controls.h | 43 +++ src/gstreamer/gstlibcamerasrc.cpp | 22 +- src/gstreamer/meson.build | 10 + utils/codegen/controls.py | 8 + utils/codegen/gen-gst-controls.py | 166 +++++++++++ utils/codegen/meson.build | 1 + 7 files changed, 579 insertions(+), 3 deletions(-) create mode 100644 src/gstreamer/gstlibcamera-controls.cpp.in create mode 100644 src/gstreamer/gstlibcamera-controls.h create mode 100755 utils/codegen/gen-gst-controls.py diff --git a/src/gstreamer/gstlibcamera-controls.cpp.in b/src/gstreamer/gstlibcamera-controls.cpp.in new file mode 100644 index 00000000..6861f5d1 --- /dev/null +++ b/src/gstreamer/gstlibcamera-controls.cpp.in @@ -0,0 +1,332 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Jaslo Ziska + * + * GStreamer Camera Controls + * + * This file is auto-generated. Do not edit. + */ + +#include + +#include +#include +#include + +#include "gstlibcamera-controls.h" + +using namespace libcamera; + +static void value_set_rectangle(GValue *value, const Rectangle &rect) +{ + Point top_left = rect.topLeft(); + Size size = rect.size(); + + GValue x = G_VALUE_INIT; + g_value_init(&x, G_TYPE_INT); + g_value_set_int(&x, top_left.x); + gst_value_array_append_and_take_value(value, &x); + + GValue y = G_VALUE_INIT; + g_value_init(&y, G_TYPE_INT); + g_value_set_int(&y, top_left.y); + gst_value_array_append_and_take_value(value, &y); + + GValue width = G_VALUE_INIT; + g_value_init(&width, G_TYPE_INT); + g_value_set_int(&width, size.width); + gst_value_array_append_and_take_value(value, &width); + + GValue height = G_VALUE_INIT; + g_value_init(&height, G_TYPE_INT); + g_value_set_int(&x, size.height); + gst_value_array_append_and_take_value(value, &height); +} + +static Rectangle value_get_rectangle(const GValue *value) +{ + const GValue *r; + r = gst_value_array_get_value(value, 0); + int x = g_value_get_int(r); + r = gst_value_array_get_value(value, 1); + int y = g_value_get_int(r); + r = gst_value_array_get_value(value, 2); + int w = g_value_get_int(r); + r = gst_value_array_get_value(value, 3); + int h = g_value_get_int(r); + + return Rectangle(x, y, w, h); +} + +{% for vendor, ctrls in controls %} +{%- for ctrl in ctrls if ctrl.is_enum %} +static const GEnumValue {{ ctrl.name|snake_case }}_types[] = { +{%- for enum in ctrl.enum_values %} + { + controls::{{ ctrl.namespace }}{{ enum.name }}, + {{ enum.description|format_description|indent('\t\t') }}, + "{{ enum.gst_name }}" + }, +{%- endfor %} + {0, NULL, NULL} +}; + +#define TYPE_{{ ctrl.name|snake_case|upper }} \ + ({{ ctrl.name|snake_case }}_get_type()) +static GType {{ ctrl.name|snake_case }}_get_type() +{ + static GType {{ ctrl.name|snake_case }}_type = 0; + + if (!{{ ctrl.name|snake_case }}_type) + {{ ctrl.name|snake_case }}_type = + g_enum_register_static("{{ ctrl.name }}", + {{ ctrl.name|snake_case }}_types); + + return {{ ctrl.name|snake_case }}_type; +} +{% endfor %} +{%- endfor %} + +void GstCameraControls::installProperties(GObjectClass *klass, int lastPropId) +{ +{%- for vendor, ctrls in controls %} +{%- for ctrl in ctrls %} + +{%- set spec %} +{%- if ctrl.is_rectangle -%} +gst_param_spec_array( +{%- else -%} +g_param_spec_{{ ctrl.gtype }}( +{%- endif -%} +{%- if ctrl.is_array %} + "{{ ctrl.vendor_prefix }}{{ ctrl.name|kebab_case }}-value", + "{{ ctrl.name }} Value", + "One {{ ctrl.name }} element value", +{%- else %} + "{{ ctrl.vendor_prefix }}{{ ctrl.name|kebab_case }}", + "{{ ctrl.name }}", + {{ ctrl.description|format_description|indent('\t') }}, +{%- endif %} +{%- if ctrl.is_enum %} + TYPE_{{ ctrl.name|snake_case|upper }}, + {{ ctrl.default }}, +{%- elif ctrl.is_rectangle %} + g_param_spec_int( + "rectangle-value", + "Rectangle Value", + "One rectangle value, either x, y, width or height.", + {{ ctrl.min }}, {{ ctrl.max }}, {{ ctrl.default }}, + (GParamFlags) (GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS) + ), +{%- elif ctrl.gtype == 'boolean' %} + {{ ctrl.default }}, +{%- elif ctrl.gtype in ['float', 'int', 'int64', 'uchar'] %} + {{ ctrl.min }}, {{ ctrl.max }}, {{ ctrl.default }}, +{%- endif %} + (GParamFlags) (GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS) +) +{%- endset %} + + g_object_class_install_property( + klass, + lastPropId + controls::{{ ctrl.namespace }}{{ ctrl.name|snake_case|upper }}, +{%- if ctrl.is_array %} + gst_param_spec_array( + "{{ ctrl.vendor_prefix }}{{ ctrl.name|kebab_case }}", + "{{ ctrl.name }}", + {{ ctrl.description|format_description|indent('\t\t\t') }}, + {{ spec|indent('\t\t\t') }}, + (GParamFlags) (GST_PARAM_CONTROLLABLE | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS) + ) +{%- else %} + {{ spec|indent('\t\t') }} +{%- endif %} + ); +{%- endfor %} +{%- endfor %} +} + +bool GstCameraControls::getProperty(guint propId, GValue *value, + [[maybe_unused]] GParamSpec *pspec) +{ + if (!controls_acc_.contains(propId)) { + GST_WARNING("Control '%s' is not available, default value will " + "be returned", + controls::controls.at(propId)->name().c_str()); + return true; + } + const ControlValue &cv = controls_acc_.get(propId); + + switch (propId) { +{%- for vendor, ctrls in controls %} +{%- for ctrl in ctrls %} + + case controls::{{ ctrl.namespace }}{{ ctrl.name|snake_case|upper }}: { + auto control = cv.get<{{ ctrl.type }}>(); + +{%- if ctrl.is_array %} + for (size_t i = 0; i < control.size(); ++i) { + GValue element = G_VALUE_INIT; +{%- if ctrl.is_rectangle %} + g_value_init(&element, GST_TYPE_PARAM_ARRAY_LIST); + value_set_rectangle(&element, control[i]); +{%- else %} + g_value_init(&element, G_TYPE_{{ ctrl.gtype|upper }}); + g_value_set_{{ ctrl.gtype }}(&element, control[i]); +{%- endif %} + gst_value_array_append_and_take_value(value, &element); + } +{%- else %} +{%- if ctrl.is_rectangle %} + value_set_rectangle(value, control); +{%- else %} + g_value_set_{{ ctrl.gtype }}(value, control); +{%- endif %} +{%- endif %} + + return true; + } +{%- endfor %} +{%- endfor %} + + default: + return false; + } +} + +bool GstCameraControls::setProperty(guint propId, const GValue *value, + [[maybe_unused]] GParamSpec *pspec) +{ + /* + * Check whether the camera capabilities are already available. + * They might not be available if the pipeline has not started yet. + */ + if (!capabilities_.empty()) { + /* If so, check that the control is supported by the camera. */ + const ControlId *cid = capabilities_.idmap().at(propId); + auto info = capabilities_.find(cid); + + if (info == capabilities_.end()) { + GST_WARNING("Control '%s' is not supported by the " + "camera and will be ignored", + cid->name().c_str()); + return true; + } + } + + switch (propId) { +{%- for vendor, ctrls in controls %} +{%- for ctrl in ctrls %} + + case controls::{{ ctrl.namespace }}{{ ctrl.name|snake_case|upper }}: { + ControlValue control; +{%- if ctrl.is_array %} + size_t size = gst_value_array_get_size(value); +{%- if ctrl.size != 0 %} + if (size != {{ ctrl.size }}) { + GST_ERROR("Incorrect array size for control " + "'{{ ctrl.name|kebab_case }}', must be of " + "size {{ ctrl.size }}"); + return true; + } +{%- endif %} + + std::vector<{{ ctrl.element_type }}> values(size); + for (size_t i = 0; i < size; ++i) { + const GValue *element = + gst_value_array_get_value(value, i); +{%- if ctrl.is_rectangle %} + if (gst_value_array_get_size(element) != 4) { + GST_ERROR("Rectangle in control " + "'{{ ctrl.name|kebab_case }}' at" + "index %lu must be an array of size 4", + i); + return true; + } + values[i] = value_get_rectangle(element); +{%- else %} + values[i] = g_value_get_{{ ctrl.gtype }}(element); +{%- endif %} + } + +{%- if ctrl.size == 0 %} + control.set(Span(values.data(), + size)); +{%- else %} + control.set(Span(values.data(), + {{ ctrl.size }})); +{%- endif %} +{%- else %} +{%- if ctrl.is_rectangle %} + if (gst_value_array_get_size(value) != 4) { + GST_ERROR("Rectangle in control " + "'{{ ctrl.name|kebab_case }}' must be an " + "array of size 4"); + return true; + } + Rectangle val = value_get_rectangle(value); +{%- else %} + auto val = g_value_get_{{ ctrl.gtype }}(value); +{%- endif %} + control.set(val); +{%- endif %} + controls_.set(propId, control); + controls_acc_.set(propId, control); + return true; + } +{%- endfor %} +{%- endfor %} + + default: + return false; + } +} + +void GstCameraControls::setCamera(const std::shared_ptr &cam) +{ + capabilities_ = cam->controls(); + + /* + * Check the controls which were set before the camera capabilities were + * known. This is required because GStreamer may set properties before + * the pipeline has started and thus before the camera was known. + */ + ControlList new_controls; + for (auto control = controls_acc_.begin(); + control != controls_acc_.end(); + ++control) { + unsigned int id = control->first; + ControlValue value = control->second; + + const ControlId *cid = capabilities_.idmap().at(id); + auto info = capabilities_.find(cid); + + /* Only add controls which are supported. */ + if (info != capabilities_.end()) + new_controls.set(id, value); + else + GST_WARNING("Control '%s' is not supported by the " + "camera and will be ignored", + cid->name().c_str()); + } + + controls_acc_ = new_controls; + controls_ = new_controls; +} + +void GstCameraControls::applyControls(std::unique_ptr &request) +{ + request->controls().merge(controls_); + controls_.clear(); +} + +void GstCameraControls::readMetadata(libcamera::Request *request) +{ + controls_acc_.merge(request->metadata(), + ControlList::MergePolicy::OverwriteExisting); +} diff --git a/src/gstreamer/gstlibcamera-controls.h b/src/gstreamer/gstlibcamera-controls.h new file mode 100644 index 00000000..749220b5 --- /dev/null +++ b/src/gstreamer/gstlibcamera-controls.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Collabora Ltd. + * Author: Nicolas Dufresne + * + * GStreamer Camera Controls + */ + +#pragma once + +#include + +#include +#include +#include + +#include "gstlibcamerasrc.h" + +namespace libcamera { + +class GstCameraControls +{ +public: + static void installProperties(GObjectClass *klass, int lastProp); + + bool getProperty(guint propId, GValue *value, GParamSpec *pspec); + bool setProperty(guint propId, const GValue *value, GParamSpec *pspec); + + void setCamera(const std::shared_ptr &cam); + + void applyControls(std::unique_ptr &request); + void readMetadata(libcamera::Request *request); + +private: + /* Supported controls and limits of camera. */ + ControlInfoMap capabilities_; + /* Set of user modified controls. */ + ControlList controls_; + /* Accumulator of all controls ever set and metadata returned by camera */ + ControlList controls_acc_; +}; + +} /* namespace libcamera */ diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 40b787c8..8efa25f4 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -37,10 +37,11 @@ #include +#include "gstlibcamera-controls.h" +#include "gstlibcamera-utils.h" #include "gstlibcameraallocator.h" #include "gstlibcamerapad.h" #include "gstlibcamerapool.h" -#include "gstlibcamera-utils.h" using namespace libcamera; @@ -128,6 +129,7 @@ struct GstLibcameraSrcState { ControlList initControls_; guint group_id_; + GstCameraControls controls_; int queueRequest(); void requestCompleted(Request *request); @@ -153,6 +155,7 @@ struct _GstLibcameraSrc { enum { PROP_0, PROP_CAMERA_NAME, + PROP_LAST }; static void gst_libcamera_src_child_proxy_init(gpointer g_iface, @@ -183,6 +186,9 @@ int GstLibcameraSrcState::queueRequest() if (!request) return -ENOMEM; + /* Apply controls */ + controls_.applyControls(request); + std::unique_ptr wrap = std::make_unique(std::move(request)); @@ -226,6 +232,9 @@ GstLibcameraSrcState::requestCompleted(Request *request) { GLibLocker locker(&lock_); + + controls_.readMetadata(request); + wrap = std::move(queuedRequests_.front()); queuedRequests_.pop(); } @@ -408,6 +417,8 @@ gst_libcamera_src_open(GstLibcameraSrc *self) return false; } + self->state->controls_.setCamera(cam); + cam->requestCompleted.connect(self->state, &GstLibcameraSrcState::requestCompleted); /* No need to lock here, we didn't start our threads yet. */ @@ -722,6 +733,7 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id, { GLibLocker lock(GST_OBJECT(object)); GstLibcameraSrc *self = GST_LIBCAMERA_SRC(object); + GstLibcameraSrcState *state = self->state; switch (prop_id) { case PROP_CAMERA_NAME: @@ -729,7 +741,8 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id, self->camera_name = g_value_dup_string(value); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + if (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec)) + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } @@ -740,13 +753,15 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value, { GLibLocker lock(GST_OBJECT(object)); GstLibcameraSrc *self = GST_LIBCAMERA_SRC(object); + GstLibcameraSrcState *state = self->state; switch (prop_id) { case PROP_CAMERA_NAME: g_value_set_string(value, self->camera_name); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + if (!state->controls_.getProperty(prop_id - PROP_LAST, value, pspec)) + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } @@ -947,6 +962,7 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass) | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec); + GstCameraControls::installProperties(object_class, PROP_LAST); } /* GstChildProxy implementation */ diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build index c2a01e7b..6b7e53b5 100644 --- a/src/gstreamer/meson.build +++ b/src/gstreamer/meson.build @@ -25,6 +25,16 @@ libcamera_gst_sources = [ 'gstlibcamerasrc.cpp', ] +# Generate gstreamer control properties + +gen_gst_controls_template = files('gstlibcamera-controls.cpp.in') +libcamera_gst_sources += custom_target('gstlibcamera-controls.cpp', + input : controls_files, + output : 'gstlibcamera-controls.cpp', + command : [gen_gst_controls, '-o', '@OUTPUT@', + '-t', gen_gst_controls_template, '@INPUT@'], + env : py_build_env) + libcamera_gst_cpp_args = [ '-DVERSION="@0@"'.format(libcamera_git_version), '-DPACKAGE="@0@"'.format(meson.project_name()), diff --git a/utils/codegen/controls.py b/utils/codegen/controls.py index 7bafee59..03c77cc6 100644 --- a/utils/codegen/controls.py +++ b/utils/codegen/controls.py @@ -110,3 +110,11 @@ class Control(object): return f"Span" else: return f"Span" + + @property + def element_type(self): + return self.__data.get('type') + + @property + def size(self): + return self.__size diff --git a/utils/codegen/gen-gst-controls.py b/utils/codegen/gen-gst-controls.py new file mode 100755 index 00000000..0b899258 --- /dev/null +++ b/utils/codegen/gen-gst-controls.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019, Google Inc. +# Copyright (C) 2024, Jaslo Ziska +# +# Authors: +# Laurent Pinchart +# Jaslo Ziska +# +# Generate gstreamer control properties from YAML + +import argparse +import jinja2 +import re +import sys +import yaml + +from controls import Control + + +exposed_controls = [ + "AeEnable", "AeLocked", "AeMeteringMode", "AeConstraintMode", + "AeExposureMode", "ExposureValue", "ExposureTime", "AnalogueGain", + "AeFlickerMode", "AeFlickerPeriod", "AeFlickerDetected", "Brightness", + "Contrast", "Lux", "AwbEnable", "AwbMode", "AwbLocked", "ColourGains", + "ColourTemperature", "Saturation", "SensorBlackLevels", "Sharpness", + "FocusFoM", "ColourCorrectionMatrix", "ScalerCrop", "DigitalGain", + "FrameDuration", "SensorTemperature", "SensorTimestamp", "AfMode", + "AfRange", "AfSpeed", "AfMetering", "AfWindows", "LensPosition", "AfState", + "AfPauseState", "Gamma", +] + + +def find_common_prefix(strings): + prefix = strings[0] + + for string in strings[1:]: + while string[:len(prefix)] != prefix and prefix: + prefix = prefix[:len(prefix) - 1] + if not prefix: + break + + return prefix + + +def format_description(description): + # Substitute doxygen keywords \sa (see also) and \todo + description = re.sub(r'\\sa((?: \w+)+)', + lambda match: 'See also: ' + ', '.join( + map(kebab_case, match.group(1).strip().split(' ')) + ) + '.', description) + description = re.sub(r'\\todo', 'Todo:', description) + + description = description.strip().split('\n') + return '\n'.join([ + '"' + line.replace('\\', r'\\').replace('"', r'\"') + ' "' for line in description if line + ]).rstrip() + + +def snake_case(s): + return ''.join([ + c.isupper() and ('_' + c.lower()) or c for c in s + ]).strip('_') + + +def kebab_case(s): + return snake_case(s).replace('_', '-') + + +def extend_control(ctrl): + if ctrl.vendor != 'libcamera': + ctrl.namespace = f'{ctrl.vendor}::' + ctrl.vendor_prefix = f'{ctrl.vendor}-' + else: + ctrl.namespace = '' + ctrl.vendor_prefix = '' + + ctrl.is_array = ctrl.size is not None + + if ctrl.is_enum: + # Remove common prefix from enum variant names + prefix = find_common_prefix([enum.name for enum in ctrl.enum_values]) + for enum in ctrl.enum_values: + enum.gst_name = kebab_case(enum.name.removeprefix(prefix)) + + ctrl.gtype = 'enum' + ctrl.default = '0' + elif ctrl.element_type == 'bool': + ctrl.gtype = 'boolean' + ctrl.default = 'false' + elif ctrl.element_type == 'float': + ctrl.gtype = 'float' + ctrl.default = '0' + ctrl.min = '-G_MAXFLOAT' + ctrl.max = 'G_MAXFLOAT' + elif ctrl.element_type == 'int32_t': + ctrl.gtype = 'int' + ctrl.default = '0' + ctrl.min = 'G_MININT' + ctrl.max = 'G_MAXINT' + elif ctrl.element_type == 'int64_t': + ctrl.gtype = 'int64' + ctrl.default = '0' + ctrl.min = 'G_MININT64' + ctrl.max = 'G_MAXINT64' + elif ctrl.element_type == 'uint8_t': + ctrl.gtype = 'uchar' + ctrl.default = '0' + ctrl.min = '0' + ctrl.max = 'G_MAXUINT8' + elif ctrl.element_type == 'Rectangle': + ctrl.is_rectangle = True + ctrl.default = '0' + ctrl.min = '0' + ctrl.max = 'G_MAXINT' + else: + raise RuntimeError(f'The type `{ctrl.element_type}` is unknown') + + return ctrl + + +def main(argv): + # Parse command line arguments + parser = argparse.ArgumentParser() + parser.add_argument('--output', '-o', metavar='file', type=str, + help='Output file name. Defaults to standard output if not specified.') + parser.add_argument('--template', '-t', dest='template', type=str, required=True, + help='Template file name.') + parser.add_argument('input', type=str, nargs='+', + help='Input file name.') + + args = parser.parse_args(argv[1:]) + + controls = {} + for input in args.input: + data = yaml.safe_load(open(input, 'rb').read()) + + vendor = data['vendor'] + ctrls = controls.setdefault(vendor, []) + + for ctrl in data['controls']: + ctrl = Control(*ctrl.popitem(), vendor) + + if ctrl.name in exposed_controls: + ctrls.append(extend_control(ctrl)) + + data = {'controls': list(controls.items())} + + env = jinja2.Environment() + env.filters['format_description'] = format_description + env.filters['snake_case'] = snake_case + env.filters['kebab_case'] = kebab_case + template = env.from_string(open(args.template, 'r', encoding='utf-8').read()) + string = template.render(data) + + if args.output: + with open(args.output, 'w', encoding='utf-8') as output: + output.write(string) + else: + sys.stdout.write(string) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/utils/codegen/meson.build b/utils/codegen/meson.build index adf33bba..904dd66d 100644 --- a/utils/codegen/meson.build +++ b/utils/codegen/meson.build @@ -11,6 +11,7 @@ py_modules += ['jinja2', 'yaml'] gen_controls = files('gen-controls.py') gen_formats = files('gen-formats.py') +gen_gst_controls = files('gen-gst-controls.py') gen_header = files('gen-header.sh') gen_ipa_pub_key = files('gen-ipa-pub-key.py') gen_tracepoints = files('gen-tp-header.py')