From patchwork Tue Oct 14 07:15:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 24615 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 C9284BF415 for ; Tue, 14 Oct 2025 07:15:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D88D360550; Tue, 14 Oct 2025 09:15:24 +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="Dlcm76zO"; dkim-atps=neutral Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 392E560316 for ; Tue, 14 Oct 2025 09:15:22 +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: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: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=YbNeUTL0/JQn6us9V2wbjOf97S1l6Oj9Ah5DrunJNE4=; b=Dlcm76zOP+Nv8HBUzGo5xEtrrg azq4QxS4UkqKxkA6ljyMZ2IqhGahDQDZYusJyBi3otiJXel6cqhsgddKTR9tWxy+DVBcHJF22SRFl zRiLrd4Zc2gzV4VUv4nopZ7ZENnrYDvIp7zWlmjXprvBTDlrfCMVVy50TmbHwQEp4UXIwWJAfG125 PEnHlGy8OgFpxqPnNz5sre3MYtUm56Q+9IJIUnllWZ22o796hKk4nEl6bo1RsJ2HqYEnpXTVGztTb l+7Vw5yENVV/M8bpmTV8lzOeAoUjSM8R9RQNqbLRIIge6ISf2ISIG0kKeI37s5pySAVtKHV2nbs1o e2IShzNQ==; Received: from [49.36.127.56] (helo=uajain) by fanzine2.igalia.com with esmtpsa (Cipher TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1v8ZFf-009IH4-Qt; Tue, 14 Oct 2025 09:15:20 +0200 From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Nicolas Dufresne , Giacomo Cappellini , Umang Jain Subject: [PATCH v5] gstreamer: Add support for Orientation Date: Tue, 14 Oct 2025 12:45:33 +0530 Message-ID: <20251014071533.270074-1-uajain@igalia.com> X-Mailer: git-send-email 2.51.0 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" From: Giacomo Cappellini Plumb the support for CameraConfiguration::orientation in libcamerasrc. A new "orientation" property is introduced and mappings for libcamera::Orientation <> GstVideoOrientationMethod are provided with helpers. Signed-off-by: Giacomo Cappellini Co-developed-by: Umang Jain Signed-off-by: Umang Jain --- Changes in v5: - patch scrubbing and cleanup - If different orientation is returned than requested, update the property - Minor string fixes, append appropriate tags Link to v4: https://patchwork.libcamera.org/patch/23965/ Note: Checkstyle will complain on this patch on a hunk, but the existing format is quite read-able IMO, hence ignored. --- src/gstreamer/gstlibcamera-utils.cpp | 36 ++++++++++++++++++++++++++++ src/gstreamer/gstlibcamera-utils.h | 3 +++ src/gstreamer/gstlibcamerasrc.cpp | 27 +++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp index bfb094c9..44050cbb 100644 --- a/src/gstreamer/gstlibcamera-utils.cpp +++ b/src/gstreamer/gstlibcamera-utils.cpp @@ -357,6 +357,42 @@ control_type_to_gtype(const ControlType &type) return G_TYPE_INVALID; } +static const struct { + Orientation orientation; + GstVideoOrientationMethod method; +} orientation_map[]{ + { Orientation::Rotate0, GST_VIDEO_ORIENTATION_IDENTITY }, + { Orientation::Rotate90, GST_VIDEO_ORIENTATION_90R }, + { Orientation::Rotate180, GST_VIDEO_ORIENTATION_180 }, + { Orientation::Rotate270, GST_VIDEO_ORIENTATION_90L }, + { Orientation::Rotate0Mirror, GST_VIDEO_ORIENTATION_HORIZ }, + { Orientation::Rotate180Mirror, GST_VIDEO_ORIENTATION_VERT }, + { Orientation::Rotate90Mirror, GST_VIDEO_ORIENTATION_UL_LR }, + { Orientation::Rotate270Mirror, GST_VIDEO_ORIENTATION_UR_LL }, +}; + +Orientation +gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method) +{ + for (auto &b : orientation_map) { + if (b.method == method) + return b.orientation; + } + + return Orientation::Rotate0; +} + +GstVideoOrientationMethod +libcamera_orientation_to_gst_video_orientation(Orientation orientation) +{ + for (auto &a : orientation_map) { + if (a.orientation == orientation) + return a.method; + } + + return GST_VIDEO_ORIENTATION_IDENTITY; +} + GstCaps * gst_libcamera_stream_formats_to_caps(const StreamFormats &formats) { diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h index 35df56fb..4364811e 100644 --- a/src/gstreamer/gstlibcamera-utils.h +++ b/src/gstreamer/gstlibcamera-utils.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -32,6 +33,8 @@ 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); +libcamera::Orientation gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method); +GstVideoOrientationMethod libcamera_orientation_to_gst_video_orientation(libcamera::Orientation orientation); #if !GST_CHECK_VERSION(1, 16, 0) static inline void gst_clear_event(GstEvent **event_ptr) diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 79a025a5..2d5f0bf5 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -146,6 +146,7 @@ struct _GstLibcameraSrc { GstTask *task; gchar *camera_name; + GstVideoOrientationMethod orientation; std::atomic pending_eos; @@ -157,6 +158,7 @@ struct _GstLibcameraSrc { enum { PROP_0, PROP_CAMERA_NAME, + PROP_ORIENTATION, PROP_LAST }; @@ -616,6 +618,10 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self) gst_libcamera_get_framerate_from_caps(caps, element_caps); } + /* Set orientation. */ + Orientation requestedOrientation = gst_video_orientation_to_libcamera_orientation(self->orientation); + state->config_->orientation = requestedOrientation; + /* Validate the configuration. */ CameraConfiguration::Status status = state->config_->validate(); if (status == CameraConfiguration::Invalid) @@ -637,6 +643,10 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self) gst_libcamera_clamp_and_set_frameduration(state->initControls_, state->cam_->controls(), element_caps); + /* If orientation is changed, update the property. */ + if (state->config_->orientation != requestedOrientation) + g_object_set(G_OBJECT(self), "orientation", state->config_->orientation, nullptr); + /* * Regardless if it has been modified, create clean caps and push the * caps event. Downstream will decide if the caps are acceptable. @@ -936,6 +946,9 @@ 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_ORIENTATION: + self->orientation = static_cast(g_value_get_enum(value)); + break; default: if (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec)) G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -955,6 +968,9 @@ 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_ORIENTATION: + g_value_set_enum(value, static_cast(self->orientation)); + break; default: if (!state->controls_.getProperty(prop_id - PROP_LAST, value, pspec)) G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -1164,6 +1180,17 @@ 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("orientation", "Orientation", + "Select the preferred image orientation.", + GST_TYPE_VIDEO_ORIENTATION_METHOD, + GST_VIDEO_ORIENTATION_IDENTITY, + (GParamFlags)(GST_PARAM_MUTABLE_READY + | G_PARAM_CONSTRUCT + | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(object_class, PROP_ORIENTATION, spec); + GstCameraControls::installProperties(object_class, PROP_LAST); }