From patchwork Tue Jun 13 10:34:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Mader X-Patchwork-Id: 18733 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 9D6E5C3226 for ; Tue, 13 Jun 2023 10:36:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F18E461E59; Tue, 13 Jun 2023 12:36:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1686652591; bh=GUNI6TWGFRgy73Jg68alWddqXmN0nn6soGClbbcehZY=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=o1ZuIxXHZdcrW+gyWCfb9SS1KUy5J7vmbRDxlYDGPhRytd7DvNM++87mOp8PFj9jc EpfF+5yEhzNhO/Qwesg3HeWOu2OO+xDRPDu090a6OZY+iQxdmrLbJTC3xBdcZvEhIq p82y39k22+kASv+sW50PdEtJ9LCpVTCp3QqL8odElQmzZoT2schax0BGkrIwCdh5Nt R3eZABqVr57i9kh/fPomhDHPvrG0hvnBBIUU5STJsw+GGK9o7swThRc1pKTRh1Kmtp LAk0gzTzo4jotYHZBhkd6uIduSDwYMCy6karo4oahGfm6xr+8jup5mIiY58hN6tvi0 RnRDjdCmdHC8A== Received: from madras.collabora.co.uk (madras.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e5ab]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 732AF61E4E for ; Tue, 13 Jun 2023 12:36:29 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=collabora.com header.i=@collabora.com header.b="Fq48OVOE"; dkim-atps=neutral Received: from thinkpad-t460p.fritz.box (unknown [IPv6:2001:4090:a243:8015:93c:83c3:533:d433]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: rmader) by madras.collabora.co.uk (Postfix) with ESMTPSA id 1D7A16606F02; Tue, 13 Jun 2023 11:36:29 +0100 (BST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1686652589; bh=GUNI6TWGFRgy73Jg68alWddqXmN0nn6soGClbbcehZY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Fq48OVOEmYc0FnV71vHC4RiRo2esYAiMGKi15rN0oXBBGm8Oom/YOAB2i5ROgkuAc BH6YQLjEK9TDTYDK5exhDs4jneZM/jnT4xP5XvXOp5giy00oNVY369hFs6XYRzZVxH aI79bFyqX0Ya7EJMRCRmR1CMYEmtJKO8KDoZdmroavi0TXhVRRrbACy+XMw8QQAyKc PHj7QZHRxeEbey5NhfjL/K0OufhpIiUaNGBexJJi2C0l8ZLTS1wQA2KMR/ay/OTK7T 8VCBOWsdtJGHYEjh/B5VLjQ+b+IyNo3F2g8AA+VkzAo5B6DaJrTzPfHHLAYYrrhgt1 rdNdWPdZJnRsw== To: libcamera-devel@lists.libcamera.org Date: Tue, 13 Jun 2023 12:34:50 +0200 Message-ID: <20230613103519.91370-3-robert.mader@collabora.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230613103519.91370-1-robert.mader@collabora.com> References: <20230613103519.91370-1-robert.mader@collabora.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/2] gstreamer: src: Add transform property 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: , X-Patchwork-Original-From: Robert Mader via libcamera-devel From: Robert Mader Reply-To: Robert Mader Cc: Robert Mader Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" This allows users to request a transform using the Gstreamer equivalent. If the combined transform of the requested one and a possible rotation from the camera properties is not fully supported by the sensor, the remaining transform will be passed down to downstream elements as tag. The later is common for 90/270 degree rotations. Thus, a side effect of this feature is that libcamerasrc now behaves similar to pipewiresrc in regards to rotated cameras in e.g. phones, allowing apps to compensate accordingly. Signed-off-by: Robert Mader --- src/gstreamer/gstlibcamera-utils.cpp | 72 ++++++++++++++++++++++++++++ src/gstreamer/gstlibcamera-utils.h | 5 ++ src/gstreamer/gstlibcamerasrc.cpp | 41 +++++++++++++++- 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp index 750ec351..43ce75cb 100644 --- a/src/gstreamer/gstlibcamera-utils.cpp +++ b/src/gstreamer/gstlibcamera-utils.cpp @@ -553,3 +553,75 @@ gst_libcamera_get_camera_manager(int &ret) return cm; } + +libcamera::Transform +gst_libcamera_orientation_to_transform(GstVideoOrientationMethod orientation) +{ + switch (orientation) { + case GST_VIDEO_ORIENTATION_90R: + return Transform::Rot90; + case GST_VIDEO_ORIENTATION_180: + return Transform::Rot180; + case GST_VIDEO_ORIENTATION_90L: + return Transform::Rot270; + case GST_VIDEO_ORIENTATION_HORIZ: + return Transform::HFlip; + case GST_VIDEO_ORIENTATION_VERT: + return Transform::VFlip; + case GST_VIDEO_ORIENTATION_UL_LR: + return Transform::Transpose; + case GST_VIDEO_ORIENTATION_UR_LL: + return Transform::Rot180Transpose; + case GST_VIDEO_ORIENTATION_IDENTITY: + default: + return Transform::Identity; + } +} + +GstVideoOrientationMethod +gst_libcamera_transform_to_orientation(libcamera::Transform transform) +{ + switch (transform) { + case Transform::Rot90: + return GST_VIDEO_ORIENTATION_90R; + case Transform::Rot180: + return GST_VIDEO_ORIENTATION_180; + case Transform::Rot270: + return GST_VIDEO_ORIENTATION_90L; + case Transform::HFlip: + return GST_VIDEO_ORIENTATION_HORIZ; + case Transform::VFlip: + return GST_VIDEO_ORIENTATION_VERT; + case Transform::Transpose: + return GST_VIDEO_ORIENTATION_UL_LR; + case Transform::Rot180Transpose: + return GST_VIDEO_ORIENTATION_UR_LL; + case Transform::Identity: + default: + return GST_VIDEO_ORIENTATION_IDENTITY; + } +} + +const char * +gst_libcamera_transform_to_tag_string(libcamera::Transform transform) +{ + switch (transform) { + case Transform::Rot90: + return "rotate-90"; + case Transform::Rot180: + return "rotate-180"; + case Transform::Rot270: + return "rotate-270"; + case Transform::HFlip: + return "flip-rotate-0"; + case Transform::VFlip: + return "flip-rotate-180"; + case Transform::Transpose: + return "flip-rotate-270"; + case Transform::Rot180Transpose: + return "flip-rotate-90"; + case Transform::Identity: + default: + return "rotate-0"; + } +} diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h index fd304a8b..84d26c47 100644 --- a/src/gstreamer/gstlibcamera-utils.h +++ b/src/gstreamer/gstlibcamera-utils.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,10 @@ gboolean gst_task_resume(GstTask *task); #endif std::shared_ptr gst_libcamera_get_camera_manager(int &ret); +libcamera::Transform gst_libcamera_orientation_to_transform(GstVideoOrientationMethod orientation); +GstVideoOrientationMethod gst_libcamera_transform_to_orientation(libcamera::Transform transform); +const char *gst_libcamera_transform_to_tag_string(libcamera::Transform transform); + /** * \class GLibLocker * \brief A simple scoped mutex locker for GMutex diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 721b35c2..9d9437d0 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -147,6 +147,8 @@ struct _GstLibcameraSrc { gchar *camera_name; + GstVideoOrientationMethod transform; + GstLibcameraSrcState *state; GstLibcameraAllocator *allocator; GstFlowCombiner *flow_combiner; @@ -154,7 +156,9 @@ struct _GstLibcameraSrc { enum { PROP_0, - PROP_CAMERA_NAME + PROP_CAMERA_NAME, + PROP_TRANSFORM, + PROP_LAST }; G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT, @@ -461,6 +465,8 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread, GLibRecLocker lock(&self->stream_lock); GstLibcameraSrcState *state = self->state; GstFlowReturn flow_ret = GST_FLOW_OK; + libcamera::Transform tag_transform; + const char* tag_string; gint ret; g_autoptr(GstStructure) element_caps = gst_structure_new_empty("caps"); @@ -513,12 +519,27 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread, if (flow_ret != GST_FLOW_OK) goto done; + state->config_->transform = + gst_libcamera_orientation_to_transform (self->transform); + /* Validate the configuration. */ if (state->config_->validate() == CameraConfiguration::Invalid) { flow_ret = GST_FLOW_NOT_NEGOTIATED; goto done; } + tag_transform = (gst_libcamera_orientation_to_transform (self->transform) ^ + state->config_->transform); + tag_string = gst_libcamera_transform_to_tag_string(tag_transform); + for (gsize i = 0; i < state->srcpads_.size(); i++) { + GstPad *srcpad = state->srcpads_[i]; + GstEvent *tag_event; + + tag_event = gst_event_new_tag(gst_tag_list_new(GST_TAG_IMAGE_ORIENTATION, + tag_string, NULL)); + gst_pad_push_event (srcpad, tag_event); + } + ret = state->cam_->configure(state->config_.get()); if (ret) { GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS, @@ -659,6 +680,11 @@ 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_TRANSFORM: + self->transform = + static_cast( + g_value_get_enum(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -676,6 +702,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_TRANSFORM: + g_value_set_enum(value, self->transform); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -845,4 +874,14 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass) | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (object_class, PROP_TRANSFORM, + g_param_spec_enum ("transform", "Transform", + "Request a transform (rotation and/or flip).", + GST_TYPE_VIDEO_ORIENTATION_METHOD, + GST_VIDEO_ORIENTATION_IDENTITY, + (GParamFlags)(GST_PARAM_MUTABLE_READY + | G_PARAM_CONSTRUCT + | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS))); }