From patchwork Tue Aug 13 12:25:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 20901 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 3685BBDB13 for ; Tue, 13 Aug 2024 12:48:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E8708633B5; Tue, 13 Aug 2024 14:48:17 +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="aI1KpMgD"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="ejcKC+5V"; dkim-atps=neutral Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [81.169.146.220]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 92AAC63382 for ; Tue, 13 Aug 2024 14:48:16 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1723553296; cv=none; d=strato.com; s=strato-dkim-0002; b=VCqnqBRR0EwLKq6C+HE4yYOeCSvTSGkhZTTZ0vhU6Bk52CWOu/A0WEH+2Il0CHsG9j dwzb3Gm2jS09Cbcox+kvCsc4wIC1j7RDrGkEsLwpzFp/q4rtRjSb4+5no8mmLKGiW8Td DbBAnm1uoYFRfoeYzrH8LO70/mng9Nc16DEPe5gXW+sw2ki3d/B6HRigZPizGcHsjOxc Q+9JR//deMf5fRGAHa4u+UwFIpC4XwCL8Nu2+/Vgh+FKUpyLFGUKRKPbwxOEr805cdgU Pre52ArYlfsmL2x/Vd+8FYk9y3CNd8hYyBUyvyD7e/Bf9HmnNNtRF7oCpKCJLsBjJqz2 02sA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1723553296; 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=VrgI6MUBEQZ4SixjjRaGQ1/YDwuso5jYmEdUtg1ppXs=; b=qaAOhF7/mMUchFrVE/VV80KoHpEM42sdjBjyHBkhD2qjHfthvGFotwlmZuRPELGHdL pt9T0QjHHw4X4acccZgO9wi9Km1GQu7jERvdc5m5KGIRdZ4bpGo5m4xSD8+JEo8/Ds9C 2ORc2g2hxBgR0sQqF1VGpbfpUZbU7LpzJ7RJ9pKLOhaaahM1UoXjrefyOE+OQjQatkCe 4F6r7v6eDDWJ1FF28ioox9A1gtx39TeVFEnVFM8qYhci+dwjjZOfau7oBph4oQnPkC7y TaQGeWQeGAjVIZyNKJ1rflm69FKuYOfcH3fJRfhmJjlpPk11Fu6J3q/R2HIcbgis+Qv9 DeMg== 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=1723553296; 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=VrgI6MUBEQZ4SixjjRaGQ1/YDwuso5jYmEdUtg1ppXs=; b=aI1KpMgDFJdGbePhSqx0OX+gnwTRuICZxW6Tknv+uKQWmmsHtZFqvPlYIJaWqZeXth gtZOT2641Cn7o7S9KpeLuzzMWpxjDtj4UC+h2W+VWCTDAXgM2VHfd3G1Yv6pXAu39+OD EWAc0mWwU77/JgaEQuskFaiEMpK4GDGmNWOpzz3fIAe7APGwBWyRb8TvjZlFeCMCxefl Ff/Tl8/v/0EgEqqEzJcza4LZT8zJKo0edO6XC4mgB1kyLBe/DfEFZNsqMR+zWTYeN1KR DCS7vCO8ETMJdeugEQQu9s3etnsHKRy+3hqO8whdwip0S7vSD1Ewj6kd5ochc4sgd6jS wDAw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1723553296; 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=VrgI6MUBEQZ4SixjjRaGQ1/YDwuso5jYmEdUtg1ppXs=; b=ejcKC+5VJJNaeyzUL94Ncc0UOq92HMz18mhq/QWFTmMpoYzKL6tGCtqJJ2/Ay+NifE BRmjbO3DJDvsqUt+ibDw== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cGhoqwVPJQb1HfVSED9d9Z5psVXjkhV67rRpA=" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.1.0 AUTH) with ESMTPSA id zb9f0a07DCmGU7g (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Tue, 13 Aug 2024 14:48:16 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska Subject: [PATCH v2 1/3] gstreamer: Remove auto-focus-mode property from device provider Date: Tue, 13 Aug 2024 14:25:05 +0200 Message-ID: <20240813124722.22425-2-jaslo@ziska.de> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240813124722.22425-1-jaslo@ziska.de> References: <20240813124722.22425-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 --- 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 Tue Aug 13 12:25:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 20902 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 26E23BDB13 for ; Tue, 13 Aug 2024 12:48:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C0BF8633BE; Tue, 13 Aug 2024 14:48: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="h7ZZevGZ"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="CDLsz2KX"; dkim-atps=neutral Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [85.215.255.25]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 20FE163398 for ; Tue, 13 Aug 2024 14:48:26 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1723553305; cv=none; d=strato.com; s=strato-dkim-0002; b=gU7iXpTS/HY1EUNs7l+LrxFIKAhDe7HUf7q3zWZ0aIVMx8X1k2LRpZu2kA2SE3RIZw UW7hK3aNdcYbK9laGpaGD6rOgLYlfB9CduoV+jikOaFWHlH8LT6uL6QKm2POzWSs/9rn /jX7toC02+d7L46IKTZssESLOBJc1cibVHDI9DqhyTAdwSckmoxNyVjk6s2OuGHXaxqW L2qRej0y3F9ZhSbQ7lsz+8gps8VvNAsrtI2C/kjvt5SpVXiosNAjgqse7pKsfU0d3CFy zkCZytrleworxz1+JQpqNv5RGs1L/jzTjteX6J6E+yGz2nhDDThR4unp0wuKzkJAwgqx AzBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1723553305; 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=zKfcHKf1QOPVdTHjg/UZOZmZ8CNKYu49n+dkOWwLGSw=; b=IdQs61lEYfkaiVVGKT36+avLL1ipvAB7BTY/V1eSVcikJJwHUUdvzkdvJjepwSWcu1 RXk6cZSV4TFAWp3j7t4eyWOHLUadyO7V2xRp6EJ0GKw219y6WiN0mkSxxgzk6a6Capdi W6LOPjAyuKbv571P7J4HdUsk6xBxZml9vGCT8RgPYkV/KNRVKP8dAkyIJ5n5Afb5N5vO lQ7X0K4QGcPzsyKqYvle3xljn508RStnbcoqLEA5+EgGU6Hc0KYjfTB3JZrsbMeX8ZLM kKAjOQ1UfSWRU4QPHLDb/myhgaBi3nxgcNZ5TDVz2vv82fSD16y4+4EHT/kH+APeo1eW UxYA== 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=1723553305; 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=zKfcHKf1QOPVdTHjg/UZOZmZ8CNKYu49n+dkOWwLGSw=; b=h7ZZevGZW6vfz3JHGcLHCYRKLZ1tZvdYHkBJKnM610mvDrzGkrJl/N2wl5gS4jzdI0 AdQZGKkzcpsdjUnpa/Mnqrfy6Ug7vXh8EAPGz6Ug8Epd4kKjXmyw/Y5THDLYIhJ4ox4r Wqa/TKLppqA+ZN/KsHOxvdzR3d/SsS4cZNTMx/R9nFQLErEq6NB6MLufPiWKN9tYQAJF pCnbQqwSZZb2Mt+YLujTNRp4aFSwYoEezJoR8TO8uLUakkpogBQO1TjnYnxq0T8nyTjb DkRtwzjsUPdmAWKTJjxPU/7H+anxpYeTJ8x//E8F2DklopZZsKh8NtVyYFIgP0XPhStV cuDA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1723553305; 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=zKfcHKf1QOPVdTHjg/UZOZmZ8CNKYu49n+dkOWwLGSw=; b=CDLsz2KXDLcRJI5FJSF9ZOzroPnWnb1aEuO5Ip4NaroCyFp8nRKPXOulwVCNcI62Ys JRG8p0FS4dgCSFYUS/BQ== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cGhoqwVPJQb1HfVSED9d9Z5psVXjkhV67rRpA=" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.1.0 AUTH) with ESMTPSA id zb9f0a07DCmPU7i (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Tue, 13 Aug 2024 14:48:25 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska Subject: [PATCH v2 2/3] gstreamer: Remove auto-focus-mode property from libcamerasrc Date: Tue, 13 Aug 2024 14:25:06 +0200 Message-ID: <20240813124722.22425-3-jaslo@ziska.de> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240813124722.22425-1-jaslo@ziska.de> References: <20240813124722.22425-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 --- src/gstreamer/gstlibcamerasrc.cpp | 28 ---------------------------- 1 file changed, 28 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 */ From patchwork Tue Aug 13 12:25:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 20903 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 5455BC32A9 for ; Tue, 13 Aug 2024 12:48:33 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D1616633BE; Tue, 13 Aug 2024 14:48: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="fcDRvIqO"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="GDErX7Ab"; 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 6970463398 for ; Tue, 13 Aug 2024 14:48:31 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1723553311; cv=none; d=strato.com; s=strato-dkim-0002; b=IBs6zkW3Rux7PsBb9m7pgU65v2dpqH4fhxLSuYl3FD1CQm+XWu499Jup2umbrLKd9a udn3+VFZ2By05atFxnaw3kY8e7zJT68o271/lGmG7aKcOEECoeEBs/fgW5gSoaKOq/CE Oj4A6w+rgz7grllBF4FfctYnz1oDOKTCBtF2rvtSxc+zJLok867WyhFKQzA6nMX+JQbX ktnGoZjvgQ8vOR6n1PIr1cgz0sAEwsZis3ApTF1c0zZLPOA2NBNyjO5f17oNxEIUT+ML q8GBwt3UZO0DkQQcV8LjQuSwgo2bSU3Dntvt0q2XKsK3FVwnXDcr9073F2SFQCT7r//P 4mYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1723553311; 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=v22c7NEinm69XCLgjn1/tsBCz3NPw9gI+IowkF3eajk=; b=TJ+3q13EFv+aFFK1gQK8rGy4pdSywwOdXPsymV8Djs/+JwFLcwvMPeTukp1SCzCB3C AKt2AuvO61WjidsNwS1mB9oQCyfJ/Cy+B/6DdINbfL4uYD7+r+TrNfA+WqM6UBE+Oftk 5LmDHvRnm30V4WIXGO0FflVSmK5Vn8yEC+Rhb5HQwfBRq4xr4GkjSt8Rn6spC+J/2ajH 1ipfc8EYXGUPa8c6h3bCTE2UEbapQcSf3o3Nyt/0M4ODMB80wdgTADyXPkU8a4lgiKiw jVfQy5Bg29cWIDpK6LKPzvnoPW1gGhA9686OyQyqmkq+pkhhAZP9Femglbd9ae5ih6n7 sviA== 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=1723553311; 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=v22c7NEinm69XCLgjn1/tsBCz3NPw9gI+IowkF3eajk=; b=fcDRvIqO4T2gKYGJWpiGVqDu1G+cy9yI4r6wyV4vaKqII7aW7T/Qpb8/hI0JlCq6zC EasV+Gr1yXUld/1zLWszZNLH5wKRaBpb/bUm2Kh03zyQinF/vmPFx4P5CQPuKoKEngkL Dd6B35abpxHXUSphkvOj85VUisA0BZreip3Qqd0UObzLxnFhNCQVM7uSlYOHtFhep5kh AB039WGVacaYQxyQLX/R3O1uFIZDTpszEDrifoY/Ochce/BGi7Dsn7q1gHTCLoD4Osfm L3l9ecoBdJg/Fk5GMAlj/qc0x0XqdlX8MkSL5e0QaKIEkdszH4pKaX1MSYzKEZlFj1lU VC7A== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1723553311; 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=v22c7NEinm69XCLgjn1/tsBCz3NPw9gI+IowkF3eajk=; b=GDErX7AbRy6A9NUV2jcVkaKy1VbWYw+/eTVCsm2MwovJIHFW6lcJWNxd4uL6zqF/Ch R/u8wRYWtpFOTgBHU1Bw== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cGhoqwVPJQb1HfVSED9d9Z5psVXjkhV67rRpA=" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.1.0 AUTH) with ESMTPSA id zb9f0a07DCmUU7j (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Tue, 13 Aug 2024 14:48:30 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska Subject: [PATCH v2 3/3] gstreamer: Generate controls from control_ids_*.yaml files Date: Tue, 13 Aug 2024 14:25:07 +0200 Message-ID: <20240813124722.22425-4-jaslo@ziska.de> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240813124722.22425-1-jaslo@ziska.de> References: <20240813124722.22425-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 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 | 296 +++++++++++++++++++++ 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 | 151 +++++++++++ utils/codegen/meson.build | 1 + 7 files changed, 528 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..aab7ae24 --- /dev/null +++ b/src/gstreamer/gstlibcamera-controls.cpp.in @@ -0,0 +1,296 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023, Collabora Ltd. + * Author: Nicolas Dufresne + * + * GStreamer Camera Controls + * + * This file is auto-generated. Do not edit. + */ + +#include + +#include + +#include "gstlibcamera-controls.h" + +using namespace libcamera; + +{% 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) +{ + switch (propId) { +{%- for vendor, ctrls in controls %} +{%- for ctrl in ctrls %} + +{%- set value_set %} +{%- if ctrl.is_rectangle -%} +Point top_left = val.topLeft(); +Size size = val.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(&element, &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(&element, &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(&element, &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(&element, &height); +{%- else -%} +g_value_set_{{ ctrl.gtype }}(&element, val); +{%- endif -%} +{%- endset %} + + case controls::{{ ctrl.namespace }}{{ ctrl.name|snake_case|upper }}: { + auto control = metadata_.get(controls::{{ ctrl.namespace }}{{ ctrl.name }}); + control = control ? control : + controls_.get(controls::{{ ctrl.namespace }}{{ ctrl.name }}); + if (!control) { + GST_WARNING("Control '%s' is not available, default value will be returned", + controls::{{ ctrl.namespace }}{{ ctrl.name }}.name().c_str()); + return true; + } + +{%- 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); +{%- else %} + g_value_init(&element, G_TYPE_{{ ctrl.gtype|upper }}); +{%- endif %} + auto val = (*control)[i]; + {{ value_set|indent('\t\t\t\t') }} + gst_value_array_append_and_take_value(value, &element); + } +{%- else %} + GValue element = *value; + auto val = *control; + {{ value_set|indent('\t\t\t') }} +{%- 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 available + if (!capabilities_.empty()) { + // if so, check that the control is supported + 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 %} + +{%- set value_get %} +{%- if ctrl.is_rectangle -%} +if (gst_value_array_get_size(element) != 4) { + GST_ERROR("Rectangle must be an array of size 4"); + return true; +} + +const GValue *r; +r = gst_value_array_get_value(element, 0); +int x = g_value_get_int(r); +r = gst_value_array_get_value(element, 1); +int y = g_value_get_int(r); +r = gst_value_array_get_value(element, 2); +int w = g_value_get_int(r); +r = gst_value_array_get_value(element, 3); +int h = g_value_get_int(r); + +auto val = Rectangle(x, y, w, h); +{%- else -%} +auto val = g_value_get_{{ ctrl.gtype }}(element); +{%- endif -%} +{%- endset %} + + case controls::{{ ctrl.namespace }}{{ ctrl.name|snake_case|upper }}: { +{%- 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, 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); + {{ value_get|indent('\t\t\t') }} + values[i] = val; + } + controls_.set(controls::{{ ctrl.namespace }}{{ ctrl.name }}, +{%- if ctrl.size == 0 %} + Span(values.data(), size)); +{%- else %} + Span(values.data(), {{ ctrl.size }})); +{%- endif %} +{%- else %} + const GValue *element = value; + {{ value_get|indent('\t\t') }} + controls_.set(controls::{{ ctrl.namespace }}{{ ctrl.name }}, val); +{%- endif %} + 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 + ControlList new_controls; + for (auto control = controls_.begin(); control != controls_.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_ = new_controls; +} + +void GstCameraControls::applyControls(std::unique_ptr &request) +{ + request->controls().merge(controls_); +} + +void GstCameraControls::readMetadata(libcamera::Request *request) +{ + metadata_ = request->metadata(); +} diff --git a/src/gstreamer/gstlibcamera-controls.h b/src/gstreamer/gstlibcamera-controls.h new file mode 100644 index 00000000..89b616ad --- /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_; + /* metadata returned by the camera */ + ControlList metadata_; +}; + +} /* 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..5ac8981f --- /dev/null +++ b/utils/codegen/gen-gst-controls.py @@ -0,0 +1,151 @@ +#!/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 + + +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) + 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')