From patchwork Tue Jul 29 15:39:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 24024 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 7BD55BDCC1 for ; Tue, 29 Jul 2025 15:39:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5DF76691EA; Tue, 29 Jul 2025 17:39:19 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=igalia.com header.i=@igalia.com header.b="Bz0s1LK9"; dkim-atps=neutral Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8C64C691DA for ; Tue, 29 Jul 2025 17:39:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=sVZAg6thdnSiFRJYsLla6vN7DmdHXrAeqYK4TQ2Nw7k=; b=Bz0s1LK9Lg/8s2w8CCOV499jor uyjzObo7VMza/64BAUm9tPUEhJGIpjf+woRrLiqKyNC0eub1KlReSYZ+x6Xx4hHL6T8PZeXpDSScC sU+AzyenkAZdMBNUPTcw1eC8NpvxARdCTxR4/NmEauyfedZbIYa6soow00Uj6f/Qt+UMjyj6XuEBj F5pUcABYSKuMZY3E0Pua9e8JqBaglnQYwMQn7jPqcxCVLgZR6gsjOuELB3aUPMP+QLT+P9CxFD93+ 79VwsbZ4Pqpe6019lGG960P0ocOJe6GXM8Ms5CqHDgYkE1UBK94IOjkicurUSurBipLdY3JvsgneV pK8TBotw==; Received: from [49.36.71.87] (helo=uajain) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1ugmQ5-005UrS-HJ; Tue, 29 Jul 2025 17:39:13 +0200 From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska , Nicolas Dufresne , Umang Jain Subject: [PATCH v5 1/3] gstreamer: Split value_set_rectangle() GValue helper Date: Tue, 29 Jul 2025 21:09:13 +0530 Message-ID: <20250729153915.159243-2-uajain@igalia.com> X-Mailer: git-send-email 2.50.0 In-Reply-To: <20250729153915.159243-1-uajain@igalia.com> References: <20250729153915.159243-1-uajain@igalia.com> 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" Split the value_set_rectangle() GValue helper into further helpers pertaining to libcamera::Point and libcamera::Size. This would help to cover additional cases where helpers are needed for Point and Size individually (in subsequent commits). The libcamera::Rectangle's GValue helper can be easily constructed with the new Point and Size helpers. Hence, this patch does not introduce any functional changes. Signed-off-by: Umang Jain Reviewed-by: Nicolas Dufresne --- src/gstreamer/gstlibcamera-controls.cpp.in | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/gstreamer/gstlibcamera-controls.cpp.in b/src/gstreamer/gstlibcamera-controls.cpp.in index 2a16b39a..1bc781cc 100644 --- a/src/gstreamer/gstlibcamera-controls.cpp.in +++ b/src/gstreamer/gstlibcamera-controls.cpp.in @@ -17,21 +17,21 @@ using namespace libcamera; -static void value_set_rectangle(GValue *value, const Rectangle &rect) +static void value_set_point(GValue *value, const Point &point) { - 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); + g_value_set_int(&x, point.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); + g_value_set_int(&y, point.y); gst_value_array_append_and_take_value(value, &y); +} +static void value_set_size(GValue *value, const Size &size) +{ GValue width = G_VALUE_INIT; g_value_init(&width, G_TYPE_INT); g_value_set_int(&width, size.width); @@ -43,6 +43,12 @@ static void value_set_rectangle(GValue *value, const Rectangle &rect) gst_value_array_append_and_take_value(value, &height); } +static void value_set_rectangle(GValue *value, const Rectangle &rect) +{ + value_set_point(value, rect.topLeft()); + value_set_size(value, rect.size()); +} + static Rectangle value_get_rectangle(const GValue *value) { const GValue *r; From patchwork Tue Jul 29 15:39:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 24025 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 47230BDCC1 for ; Tue, 29 Jul 2025 15:39:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B664B691E3; Tue, 29 Jul 2025 17:39:20 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=igalia.com header.i=@igalia.com header.b="qJPWarSJ"; dkim-atps=neutral Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 54C4D691DF for ; Tue, 29 Jul 2025 17:39:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=9jVbr35+9uY5BjBQRrH243IuCTaDVtSj1oyPbVCwzPg=; b=qJPWarSJxn0bT48gi8WC5dpxPY p1+HlxzryTWrxmTF+qwOi2VsHZYu9v/psLAkPuMvF0UhsQLJCFwnZUqsWblMQhzISAa39FoqxvRfG nomfZQS9HpCZ4pnDyp8kxur7fXQdxZuvSa8npv0wabh0l05CqDEBvt8GboPI9zwmrcP5Mwg7pfUF0 U/GhuAq2NLI8KPsHBLZ5nYOZDnK9QSYmY24cfRybmyRDiIWaOQAxFq1uCI7TfVFTfG4Zb1oGZ0A8x 3hkoD08SM8h36hLlNjVrSwaaK87UesakzupSzJtAe43T4Cj4/0l4GOK9R7KYVYaZSxWuodsv8b4Tr 7GpDXGiQ==; Received: from [49.36.71.87] (helo=uajain) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1ugmQ7-005UrS-BK; Tue, 29 Jul 2025 17:39:15 +0200 From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska , Nicolas Dufresne , Umang Jain Subject: [PATCH v5 2/3] gstreamer: Move existing GValue helpers to gstreamer-utils Date: Tue, 29 Jul 2025 21:09:14 +0530 Message-ID: <20250729153915.159243-3-uajain@igalia.com> X-Mailer: git-send-email 2.50.0 In-Reply-To: <20250729153915.159243-1-uajain@igalia.com> References: <20250729153915.159243-1-uajain@igalia.com> 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" Move the existing GValue helpers from gstlibcamera-controls.cpp.in to gstreamer-utils.cpp. The intention here is to make these helpers available to other parts of gstreamer source element, for example, reporting camera properties in GstDeviceProvider. The function signature has been changed to match with the other gstreamer-utils utility functions: value_get_rectangle() => gst_libcamera_gvalue_get_rectangle() value_set_rectangle() => gst_libcamera_gvalue_set_rectangle() value_set_point() => gst_libcamera_gvalue_set_point() value_set_size() => gst_libcamera_gvalue_set_size() Signed-off-by: Umang Jain Reviewed-by: Nicolas Dufresne --- src/gstreamer/gstlibcamera-controls.cpp.in | 56 ++-------------------- src/gstreamer/gstlibcamera-utils.cpp | 47 ++++++++++++++++++ src/gstreamer/gstlibcamera-utils.h | 4 ++ 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/gstreamer/gstlibcamera-controls.cpp.in b/src/gstreamer/gstlibcamera-controls.cpp.in index 1bc781cc..6faf3ee7 100644 --- a/src/gstreamer/gstlibcamera-controls.cpp.in +++ b/src/gstreamer/gstlibcamera-controls.cpp.in @@ -14,56 +14,10 @@ #include #include "gstlibcamera-controls.h" +#include "gstlibcamera-utils.h" using namespace libcamera; -static void value_set_point(GValue *value, const Point &point) -{ - GValue x = G_VALUE_INIT; - g_value_init(&x, G_TYPE_INT); - g_value_set_int(&x, point.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, point.y); - gst_value_array_append_and_take_value(value, &y); -} - -static void value_set_size(GValue *value, const Size &size) -{ - 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(&height, size.height); - gst_value_array_append_and_take_value(value, &height); -} - -static void value_set_rectangle(GValue *value, const Rectangle &rect) -{ - value_set_point(value, rect.topLeft()); - value_set_size(value, rect.size()); -} - -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[] = { @@ -179,7 +133,7 @@ bool GstCameraControls::getProperty(guint propId, GValue *value, GValue element = G_VALUE_INIT; {%- if ctrl.is_rectangle %} g_value_init(&element, GST_TYPE_PARAM_ARRAY_LIST); - value_set_rectangle(&element, control[i]); + gst_libcamera_gvalue_set_rectangle(&element, control[i]); {%- else %} g_value_init(&element, G_TYPE_{{ ctrl.gtype|upper }}); g_value_set_{{ ctrl.gtype }}(&element, control[i]); @@ -188,7 +142,7 @@ bool GstCameraControls::getProperty(guint propId, GValue *value, } {%- else %} {%- if ctrl.is_rectangle %} - value_set_rectangle(value, control); + gst_libcamera_gvalue_set_rectangle(value, control); {%- else %} g_value_set_{{ ctrl.gtype }}(value, control); {%- endif %} @@ -252,7 +206,7 @@ bool GstCameraControls::setProperty(guint propId, const GValue *value, i); return true; } - values[i] = value_get_rectangle(element); + values[i] = gst_libcamera_gvalue_get_rectangle(element); {%- else %} values[i] = g_value_get_{{ ctrl.gtype }}(element); {%- endif %} @@ -271,7 +225,7 @@ bool GstCameraControls::setProperty(guint propId, const GValue *value, "array of size 4"); return true; } - Rectangle val = value_get_rectangle(value); + Rectangle val = gst_libcamera_gvalue_get_rectangle(value); {%- else %} auto val = g_value_get_{{ ctrl.gtype }}(value); {%- endif %} diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp index a548b0c1..63e00fe0 100644 --- a/src/gstreamer/gstlibcamera-utils.cpp +++ b/src/gstreamer/gstlibcamera-utils.cpp @@ -584,6 +584,53 @@ void gst_libcamera_framerate_to_caps(GstCaps *caps, const GstStructure *element_ gst_structure_set(s, "framerate", GST_TYPE_FRACTION, fps_caps_n, fps_caps_d, nullptr); } +void gst_libcamera_gvalue_set_point(GValue *value, const Point &point) +{ + GValue x = G_VALUE_INIT; + g_value_init(&x, G_TYPE_INT); + g_value_set_int(&x, point.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, point.y); + gst_value_array_append_and_take_value(value, &y); +} + +void gst_libcamera_gvalue_set_size(GValue *value, const Size &size) +{ + 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(&height, size.height); + gst_value_array_append_and_take_value(value, &height); +} + +void gst_libcamera_gvalue_set_rectangle(GValue *value, const Rectangle &rect) +{ + gst_libcamera_gvalue_set_point(value, rect.topLeft()); + gst_libcamera_gvalue_set_size(value, rect.size()); +} + +Rectangle gst_libcamera_gvalue_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); +} + #if !GST_CHECK_VERSION(1, 17, 1) gboolean gst_task_resume(GstTask *task) diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h index 5f4e8a0f..1812be75 100644 --- a/src/gstreamer/gstlibcamera-utils.h +++ b/src/gstreamer/gstlibcamera-utils.h @@ -25,6 +25,10 @@ void gst_libcamera_clamp_and_set_frameduration(libcamera::ControlList &controls, const libcamera::ControlInfoMap &camera_controls, GstStructure *element_caps); void gst_libcamera_framerate_to_caps(GstCaps *caps, const GstStructure *element_caps); +void gst_libcamera_gvalue_set_point(GValue *value, const libcamera::Point &point); +void gst_libcamera_gvalue_set_size(GValue *value, const libcamera::Size &size); +void gst_libcamera_gvalue_set_rectangle(GValue *value, const libcamera::Rectangle &rect); +libcamera::Rectangle gst_libcamera_gvalue_get_rectangle(const GValue *value); #if !GST_CHECK_VERSION(1, 16, 0) static inline void gst_clear_event(GstEvent **event_ptr) From patchwork Tue Jul 29 15:39:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 24026 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 6DFC1C32B5 for ; Tue, 29 Jul 2025 15:39:26 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7F914691E5; Tue, 29 Jul 2025 17:39:22 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=igalia.com header.i=@igalia.com header.b="fdETgNSD"; dkim-atps=neutral Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0003F691DA for ; Tue, 29 Jul 2025 17:39:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=4oM8h1Cm2UpiVFNygcYR7/Sj0iJl8N9WFVTiTbztvCQ=; b=fdETgNSDXaMJKBTpGOhOrAScfk XYfoZo6BtTc9weiXO8fpkmU3MPvzIYNeieRBnN/Gk8L4yJ+OhM0cDmrADmDy/fdtc5MbpIHd5oOf0 iNQfhauvt7jQDrres/2SU0FmS0pkjhpju32LUG0UKp5/xRYFQDzMnFt5rW7kOuBYI/BKQvTAAR7XR uHdB2ngK5Y3piN3Bd9+r9zbcJijNVsAUTu4Y36PZPLnt1quF2QjQGqxLTorCavsKGajwsDlWkpqvz CvKoRAqJlVuAcbkwA3MfWUV100aW/95jTrFTnMn/qgmv1NmCAR2ObWl6l2DgFQ44h6UFlkDjnJRN4 SOVK9Nig==; Received: from [49.36.71.87] (helo=uajain) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1ugmQ8-005UrS-Vv; Tue, 29 Jul 2025 17:39:17 +0200 From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Jaslo Ziska , Nicolas Dufresne , Umang Jain Subject: [PATCH v5 3/3] gstreamer: Report camera properties as device properties Date: Tue, 29 Jul 2025 21:09:15 +0530 Message-ID: <20250729153915.159243-4-uajain@igalia.com> X-Mailer: git-send-email 2.50.0 In-Reply-To: <20250729153915.159243-1-uajain@igalia.com> References: <20250729153915.159243-1-uajain@igalia.com> 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" Iterate over all libcamera camera properties and report them as device properties. Each libcamera ControlType is mapped to the corresponding gstreamer GType. If the ControlValue is an array of values (ControlValue::isArray()), GValue with type GST_TYPE_ARRAY is used to set the value of that ControlValue with the corresponding GType. Signed-off-by: Umang Jain Reviewed-by: Nicolas Dufresne --- src/gstreamer/gstlibcamera-utils.cpp | 197 +++++++++++++++++++++++++ src/gstreamer/gstlibcamera-utils.h | 3 + src/gstreamer/gstlibcameraprovider.cpp | 13 ++ 3 files changed, 213 insertions(+) diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp index 63e00fe0..d11d7ba9 100644 --- a/src/gstreamer/gstlibcamera-utils.cpp +++ b/src/gstreamer/gstlibcamera-utils.cpp @@ -8,6 +8,8 @@ #include "gstlibcamera-utils.h" +#include + #include #include @@ -333,6 +335,33 @@ bare_structure_from_format(const PixelFormat &format) } } +static const struct { + ControlType c_type; + GType g_type; +} control_type_gtype_map[] = { + { ControlTypeBool, G_TYPE_BOOLEAN }, + { ControlTypeByte, G_TYPE_UINT }, + { ControlTypeUnsigned16, G_TYPE_UINT }, + { ControlTypeUnsigned32, G_TYPE_UINT }, + { ControlTypeInteger32, G_TYPE_INT }, + { ControlTypeInteger64, G_TYPE_INT64 }, + { ControlTypeFloat, G_TYPE_FLOAT }, + { ControlTypeString, G_TYPE_STRING }, + { ControlTypeRectangle, GST_TYPE_ARRAY }, + { ControlTypeSize, GST_TYPE_ARRAY }, + { ControlTypePoint, GST_TYPE_ARRAY }, +}; + +static GType +control_type_to_gtype(const ControlType &type) +{ + for (auto &a : control_type_gtype_map) { + if (a.c_type == type) + return a.g_type; + } + return G_TYPE_INVALID; +} + GstCaps * gst_libcamera_stream_formats_to_caps(const StreamFormats &formats) { @@ -706,3 +735,171 @@ gst_libcamera_get_camera_manager(int &ret) return cm; } + +int gst_libcamera_set_structure_field(GstStructure *structure, const ControlId *id, + const ControlValue &value) +{ + std::string prop = "api.libcamera." + id->name(); + g_auto(GValue) v = G_VALUE_INIT; + g_auto(GValue) x = G_VALUE_INIT; + gboolean is_array = value.isArray(); + + GType type = control_type_to_gtype(value.type()); + if (type == G_TYPE_INVALID) + return -EINVAL; + + if (is_array || type == GST_TYPE_ARRAY) + g_value_init(&v, GST_TYPE_ARRAY); + + switch (value.type()) { + case ControlTypeBool: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) { + g_value_init(&x, type); + g_value_set_boolean(&x, *it); + gst_value_array_append_and_take_value(&v, &x); + } + } else { + gst_structure_set(structure, prop.c_str(), G_TYPE_BOOLEAN, + value.get(), nullptr); + } + break; + case ControlTypeByte: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) { + g_value_init(&x, type); + g_value_set_uint(&x, *it); + gst_value_array_append_and_take_value(&v, &x); + } + } else { + gst_structure_set(structure, prop.c_str(), G_TYPE_UINT, + value.get(), nullptr); + } + break; + case ControlTypeUnsigned16: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) { + g_value_init(&x, type); + g_value_set_uint(&x, *it); + gst_value_array_append_and_take_value(&v, &x); + } + } else { + gst_structure_set(structure, prop.c_str(), G_TYPE_UINT, + value.get(), nullptr); + } + break; + case ControlTypeUnsigned32: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) { + g_value_init(&x, type); + g_value_set_uint(&x, *it); + gst_value_array_append_and_take_value(&v, &x); + } + } else { + gst_structure_set(structure, prop.c_str(), G_TYPE_UINT, + value.get(), nullptr); + } + break; + case ControlTypeInteger32: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) { + g_value_init(&x, type); + g_value_set_int(&x, *it); + gst_value_array_append_and_take_value(&v, &x); + } + } else { + if (!id->enumerators().empty()) { + int32_t val = value.get(); + const auto &iter = id->enumerators().find(val); + if (iter != id->enumerators().end()) { + gst_structure_set(structure, prop.c_str(), + G_TYPE_STRING, + iter->second.c_str(), + nullptr); + } else { + return -EINVAL; + } + } else { + gst_structure_set(structure, prop.c_str(), G_TYPE_INT, + value.get(), nullptr); + } + } + break; + case ControlTypeInteger64: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) { + g_value_init(&x, type); + g_value_set_int64(&x, *it); + gst_value_array_append_and_take_value(&v, &x); + } + } else { + gst_structure_set(structure, prop.c_str(), G_TYPE_INT64, + value.get(), nullptr); + } + break; + case ControlTypeFloat: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) { + g_value_init(&x, type); + g_value_set_float(&x, *it); + gst_value_array_append_and_take_value(&v, &x); + } + } else { + gst_structure_set(structure, prop.c_str(), G_TYPE_FLOAT, + value.get(), nullptr); + } + break; + case ControlTypeString: + /* + * isArray() is always true for strings hence, unset the GValue + * array because we are going to the toString() helper directly. + */ + g_value_unset(&v); + gst_structure_set(structure, prop.c_str(), G_TYPE_STRING, + value.toString().c_str(), nullptr); + break; + case ControlTypeSize: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) + gst_libcamera_gvalue_set_size(&v, *it); + } else { + gst_libcamera_gvalue_set_size(&v, value.get()); + } + break; + case ControlTypePoint: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) + gst_libcamera_gvalue_set_point(&v, *it); + } else { + gst_libcamera_gvalue_set_point(&v, value.get()); + } + break; + case ControlTypeRectangle: + if (is_array) { + Span data = value.get>(); + for (auto it = data.begin(); it != data.end(); ++it) + gst_libcamera_gvalue_set_rectangle(&v, *it); + } else { + gst_libcamera_gvalue_set_rectangle(&v, value.get()); + } + break; + case ControlTypeNone: + [[fallthrough]]; + default: + return -EINVAL; + } + + if (GST_VALUE_HOLDS_ARRAY(&v)) + gst_structure_set_value(structure, prop.c_str(), &v); + + return 0; +} diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h index 1812be75..35df56fb 100644 --- a/src/gstreamer/gstlibcamera-utils.h +++ b/src/gstreamer/gstlibcamera-utils.h @@ -29,6 +29,9 @@ void gst_libcamera_gvalue_set_point(GValue *value, const libcamera::Point &point void gst_libcamera_gvalue_set_size(GValue *value, const libcamera::Size &size); void gst_libcamera_gvalue_set_rectangle(GValue *value, const libcamera::Rectangle &rect); libcamera::Rectangle gst_libcamera_gvalue_get_rectangle(const GValue *value); +int gst_libcamera_set_structure_field(GstStructure *structure, + const libcamera::ControlId *id, + const libcamera::ControlValue &value); #if !GST_CHECK_VERSION(1, 16, 0) static inline void gst_clear_event(GstEvent **event_ptr) diff --git a/src/gstreamer/gstlibcameraprovider.cpp b/src/gstreamer/gstlibcameraprovider.cpp index 5da96ea3..1545c856 100644 --- a/src/gstreamer/gstlibcameraprovider.cpp +++ b/src/gstreamer/gstlibcameraprovider.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "gstlibcamerasrc.h" #include "gstlibcamera-utils.h" @@ -144,12 +145,24 @@ gst_libcamera_device_new(const std::shared_ptr &camera) gst_caps_append(caps, sub_caps); } + g_autoptr(GstStructure) props = gst_structure_new_empty("camera-properties"); + for (const auto &[key, value] : camera->properties()) { + const ControlId *id = properties::properties.at(key); + + int ret = gst_libcamera_set_structure_field(props, id, value); + if (ret < 0) { + GST_ERROR("Failed to retrieve value for %s property", id->name().c_str()); + return nullptr; + } + } + return GST_DEVICE(g_object_new(GST_TYPE_LIBCAMERA_DEVICE, /* \todo Use a unique identifier instead of camera name. */ "name", name, "display-name", name, "caps", caps, "device-class", "Source/Video", + "properties", props, nullptr)); }