From patchwork Mon Oct 21 16:45:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 21721 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 2083FBD808 for ; Mon, 21 Oct 2024 16:50:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C26FE65393; Mon, 21 Oct 2024 18:50:19 +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="jr53Ic8w"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="qF/byXMG"; 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 217DD65392 for ; Mon, 21 Oct 2024 18:50:18 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1729529417; cv=none; d=strato.com; s=strato-dkim-0002; b=RcEzFhtjA2OmKFzqvM5DyfYQoqIg8W4IvhkuuLPX3NqK8NIgTALghN9vx7mdqKpAHM dmYGHUqS1pkV23IGEzYf/0+zqgfQYWlJlpuCceMOxn+zHxfwni9J4OKd0kYpQBfOS8kb 2NKFQuu6gDB5oq+/MlIWzTxyi1zc6HiS50yl+CBjGgwi87kv/pSAiL3EZWAbcTTm5fYK yNbgykdxOGpaGRRiaHrgwhzyUEgITmnXfU16Y8It/lJ4xBN/dzFNUdooDPZrqUVWSx3R uz+cKEHpLkXOVLc9cF2Nm3Ezfu/zbrjVxNaUUE2zP7BTPAOZjcDGFzmELn5lfcR982Pd bazQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1729529417; 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=xOSoFeA0z8O9FKjGXe4HKPUWSnHPlBoUHZc6/XPEKjs=; b=nhubI8S1aqfQ6iyPrMVIyYZOxEs50Vm3lIYTy3tC7VvaiKCBhsVq3Z+MfvSWG5PS39 10NdMzfEYimOrqzkayoY21AxlB6ygdG9XDE1wLXROZAcZ6WVjIxX3ou1H15K+f0N3DBY o5TKbbvuE1enrSqgbiLi3JM49A+D05rwYlEQG5wbgWdEDi923mN5svpwtXZSa9yJFp4I yzGNjuu62U/hafFVJsZFDJvR2KWvwVfhpKn2S1HXO4vkOyAeT2MFQzQtjmkfnhkVIz+Y NKBkFKhfhoUCuBglPrRL916g8nK0K2S9Rk2Y1gsMY6lnUJ0GFm0wDVvtme7xG0JOka9M 6r8Q== 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=1729529417; 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=xOSoFeA0z8O9FKjGXe4HKPUWSnHPlBoUHZc6/XPEKjs=; b=jr53Ic8wPIfG8hF2Z2zxEcSmhZOPVL/0k/6YwGbGucqwKa5Izys5ualuuTja9K4W4y CnJUzlDVXesX4sbku4sA01HaG6joyRbfP+TndCOoQ7YeGruHT8RIjRhBPTnB7GgnqoWO DzDdVBf24940wd01YyfIUsmMtmB7BaBw1o3N85uyM9/B5mcQ+Tuyk9As+rxl7TLFtmjZ orWKJub2bJHOdZfXYXjV2GbLiUUYiNxH3Di4HvhNynk0hv+cwNt5dcyUpwTa2h1G0CGQ axhtSmwzqbiDuZaLcnTxSuVoLe3R9DnU838Kire6/nlrFBKID0Yj97vlEXjAT6uvMPv5 hEiQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1729529417; 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=xOSoFeA0z8O9FKjGXe4HKPUWSnHPlBoUHZc6/XPEKjs=; b=qF/byXMGflEgOlXPCL4PeFCvZakc/LdwqHjBtlKqR1pS6XRoTEm6Tyogg8LvlyAd+z 3kxsDFRN/OtRRRqvbzCw== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cEiIqwXfJa0UVFIOBpUYAtVOpHIoJG1qZybSPb" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.2.11 AUTH) with ESMTPSA id zf9ba109LGoHVdB (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Mon, 21 Oct 2024 18:50:17 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska , Laurent Pinchart , Kieran Bingham Subject: [PATCH v4 1/3] gstreamer: Remove auto-focus-mode property from device provider Date: Mon, 21 Oct 2024 18:45:31 +0200 Message-ID: <20241021164946.11111-2-jaslo@ziska.de> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241021164946.11111-1-jaslo@ziska.de> References: <20241021164946.11111-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 Mon Oct 21 16:45:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 21722 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 305EDBD808 for ; Mon, 21 Oct 2024 16:50:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DCD9C6538B; Mon, 21 Oct 2024 18:50:28 +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="m710lVeX"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="xpZqeDqr"; dkim-atps=neutral Received: from mo4-p01-ob.smtp.rzone.de (mo4-p01-ob.smtp.rzone.de [85.215.255.51]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9A27865393 for ; Mon, 21 Oct 2024 18:50:26 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1729529425; cv=none; d=strato.com; s=strato-dkim-0002; b=qwaFzV6LAw4i/yC45mHNLmqUxk9VGcL65Dw2/UZqt+kJv1V9n5AuThMpykrc8Mm4cS 4LuLs/RRCNpoo7iZvpdCe0MzgAqbF2nF7V8dMKfv2H9jfElL/BIzib8R3VlVbG8l+hGL NCm/AZRAe69Vj3/mgQFJOjMppxuZg2vf9viHy/Gem0e85oxjPuVgn/59Y33zSw/NjBmb MUh6KCy3CcnsKjg+YoN0j8AUivcyYkBlewxv3aLjRiZkKJS5WI3S2kWgbBW6iaF4qoBl 66L9jtzgIwK2C4LXV6Onolvnkj5tWsW8eC7WPfKn1Tz3A/ZgwbRpqk39uANwc8AB5NuH 85Eg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1729529425; 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=uO2vpQC7FEHevnqhfg6TMwrXpF5yoNqnsB+djCdaeYE=; b=UuNN+QmXolhLo2L1te3q06hteiPSEzr3jwt+ASfJr2s6ezPdBBt4lnaIK56ZWTbrvA Ql62/bXf5cH3D06yQINGYNaITl2SQ7iaFU4C40KDTF5sD0Dyjs+ysLz2L4QXnsINWVIk SSeGMSOewQjwF5bMW7eWt1V5OzxgbUXUPuNsew1yB20S9EHuAXMWLJ65VWOxvgFDzMR8 RZjU0EamBwedq/ge/ipCu0IMV7nSxKoBPKkdDGwqkZ8TuZaBRsYQPwKsr5gxkPND4MlO mi4rmHDmhHPJ5L0vrhwjg2XO+OTInku63Zs9d/slSGe9qfLZhIT4JMb2GXYIzsibHGnw bt8g== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo01 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1729529425; 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=uO2vpQC7FEHevnqhfg6TMwrXpF5yoNqnsB+djCdaeYE=; b=m710lVeXZWzVttigD7yFOO2l+o6mrFwtSA1ka8el3KEbumPS85xGqThyWzxyU2N3Eu UBI9VbBp/818aHOGurKgqo4SZXSCX0tpQBSHp5jjvjNP0FWWzYA5ohpTCXCSkXW30h+f T9kuU5qryBK+KsTqOXJI+ajPg3r1bVSGhxRAdaLt/tBGobNj7dcs0qVW5MKKgDG+D6H/ fnqK9zAe+i7LuQV7K+y2Zl2GE4R6I5iB4EC2Ek2ftuDBapZr7s404KG3ijQt/TDGk8As 5mJDWRFTVqh+N8jFAEw/ygsq5sWbpHvdh45Ldcz9OXfF/sQz1TlADTfrGrsq6IXT9SS0 /pJw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1729529425; 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=uO2vpQC7FEHevnqhfg6TMwrXpF5yoNqnsB+djCdaeYE=; b=xpZqeDqrp1C7CWcCnA78Bu4+FMM8A/7DU2D7qEkYDBlkC30GQNDLzjbXdGxSGpDOCX qOQS7luBkwmtFbcp4/DA== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cEiIqwXfJa0UVFIOBpUYAtVOpHIoJG1qZybSPb" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.2.11 AUTH) with ESMTPSA id zf9ba109LGoPVdD (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Mon, 21 Oct 2024 18:50:25 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska , Laurent Pinchart , Kieran Bingham Subject: [PATCH v4 2/3] gstreamer: Remove auto-focus-mode property from libcamerasrc Date: Mon, 21 Oct 2024 18:45:32 +0200 Message-ID: <20241021164946.11111-3-jaslo@ziska.de> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241021164946.11111-1-jaslo@ziska.de> References: <20241021164946.11111-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 Mon Oct 21 16:45:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaslo Ziska X-Patchwork-Id: 21723 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 51002BD808 for ; Mon, 21 Oct 2024 16:50:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F163F65397; Mon, 21 Oct 2024 18:50:36 +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="Z+Y549CK"; dkim=permerror (0-bit key) header.d=ziska.de header.i=@ziska.de header.b="Sz2XDXOv"; dkim-atps=neutral Received: from mo4-p01-ob.smtp.rzone.de (mo4-p01-ob.smtp.rzone.de [85.215.255.52]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5E0496538B for ; Mon, 21 Oct 2024 18:50:35 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; t=1729529434; cv=none; d=strato.com; s=strato-dkim-0002; b=HnoYzZF1QS+07EWYf8vVf6Qdj+dDXga6tw9hEg2u+uQIr7aYvdh7VW4pF3XF5ejeKN 9hCokMZMZQ0mDGEd+56BbtJTM0IUDktfAPjAifbMsvxmp+ZNea15y0hOyoKH3SmskSVG Sc2Wn7teBDt6RgLcaJ6MkDa1XJeKVOMEfbgNzn0MYYg2YOCmd71D54BEmvOgOLmXuZoe YDxdv+4JJz8ORn5tVUbpNTgG/IZQp40G5zaarGiX5UPU/zsa2ZcTFXdDSCtLamd49ihn JEB4LeoR9lOXwstos1BEz/jpSRCL4zRZbYE8MHR3UI+c2gywZVRfLB9C9nZfKimqnFFr giJQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1729529434; 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=2GVkLbtXokZEQjtpZFSla8dMUR5L7GZFdxJ3IYE56Go=; b=HNrx8/EktNu60muOcqLLdCoXAzt7gqj7A/RzPY74xwM/RhSGWnu7IcbkMYIdt7R8YZ 3fqNM6/foqOR0x3Cn4O3tCuk+PROkgdQIu4ZrD/NB0I9rGNKXQrYMLYRmxAYXDx8TAy+ E1yyxsdgsj56gqktiPuqszLYtZgrubPnPMc7O02hJ7vmfjcjUbDsa/HP+iBz2BiM2P73 szzwxjZpTgdLfz2JHg4oLdZQRM7YnHBWIqYazVan4Xf2rOP69O+MbN18Gr4RD43M2pVt p8ZswO6YTxphiE/wjDFtcxzxgR4kPPtpF7gHhKG8Hzw04of4QtgB/FqYjC0w5yrtVm2P r0nw== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo01 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1729529434; 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=2GVkLbtXokZEQjtpZFSla8dMUR5L7GZFdxJ3IYE56Go=; b=Z+Y549CKTMIqMPxhPxmRTAFcWoQAe0dAGMQ4cWnuWaFBK9+dbXHqD18ep+xckPvx5B M4ewg5ujZBzlUic/id7/SAsRqWFx+8HwvyYQ9uYfIm3lW2tjQXD60N1rQf+7Ac+Il6Wl 6OsSEqNxGWnp6qjKS4prFlZlPdm1uUi/IvSO77+QK8z/rlMbE7aylt/SGkKj8MpG9i+s 5E01QTimBHfUcql7tgu8eqjN1GSvjolrztIoD4jGvLDsZ/nC2DGG4u0G3gDTImVUsdIr 4nB0ZJ7nZDK14mX/VvkpZDKjIPEqa9dA3Yaj0kHM6WtVyrlqloXZ13qqCgmpAMUIJ3au XCMA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1729529434; 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=2GVkLbtXokZEQjtpZFSla8dMUR5L7GZFdxJ3IYE56Go=; b=Sz2XDXOvnUFQond112NNhZLaFhIfiPOLaqZHE0iupTLa1dU/VlpeqlrYTukDk/Df+5 wtB0f0mPFdMakH3hcVBw== X-RZG-AUTH: ":Jm0XeU+IYfb0x77LHmrjN5Wlb7TBwusDqIM6Hizy8VdfzvKi4yoFC9cEiIqwXfJa0UVFIOBpUYAtVOpHIoJG1qZybSPb" Received: from archlinux.fritz.box by smtp.strato.de (RZmta 51.2.11 AUTH) with ESMTPSA id zf9ba109LGoYVdE (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Mon, 21 Oct 2024 18:50:34 +0200 (CEST) From: Jaslo Ziska To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska Subject: [PATCH v4 3/3] gstreamer: Generate controls from control_ids_*.yaml files Date: Mon, 21 Oct 2024 18:45:33 +0200 Message-ID: <20241021164946.11111-4-jaslo@ziska.de> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241021164946.11111-1-jaslo@ziska.de> References: <20241021164946.11111-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 Reviewed-by: Nicolas Dufresne --- 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 | 182 +++++++++++ utils/codegen/meson.build | 1 + 7 files changed, 595 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..ace36b71 --- /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_str('\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_str('\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_str('\t\t\t') }}, + {{ spec|indent_str('\t\t\t') }}, + (GParamFlags) (GST_PARAM_CONTROLLABLE | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS) + ) +{%- else %} + {{ spec|indent_str('\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 %zu 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..2601a675 --- /dev/null +++ b/utils/codegen/gen-gst-controls.py @@ -0,0 +1,182 @@ +#!/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', 'AeMeteringMode', 'AeConstraintMode', 'AeExposureMode', + 'ExposureValue', 'ExposureTime', 'AnalogueGain', 'AeFlickerPeriod', + 'Brightness', 'Contrast', 'AwbEnable', 'AwbMode', 'ColourGains', + 'Saturation', 'Sharpness', 'ColourCorrectionMatrix', 'ScalerCrop', + 'DigitalGain', 'AfMode', 'AfRange', 'AfSpeed', 'AfMetering', 'AfWindows', + 'LensPosition', '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() + + +# Custom filter to allow indenting by a string prior to Jinja version 3.0 +# +# This function can be removed and the calls to indent_str() replaced by the +# built-in indent() filter when dropping Jinja versions older than 3.0 +def indent_str(s, indention): + s += '\n' + + lines = s.splitlines() + rv = lines.pop(0) + + if lines: + rv += '\n' + '\n'.join( + indention + line if line else line for line in lines + ) + + return rv + + +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['indent_str'] = indent_str + 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')