[{"id":35177,"web_url":"https://patchwork.libcamera.org/comment/35177/","msgid":"<zsdwyphnk2bvchbxxzy25y3p7quoatt6xb7sj375tde46wrq5i@wmeee4hxc2vg>","date":"2025-07-28T04:39:46","subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","submitter":{"id":232,"url":"https://patchwork.libcamera.org/api/people/232/","name":"Umang Jain","email":"uajain@igalia.com"},"content":"Hi Giacomo,\n\nThere is one issue with the patch format. I think you have picked\nup Jaslo's series (right thing to do) but, you have squashed his\ncommit+orientation patch into one. This is not right thing to do\nand only makes reviews/merging almost impossible.\n\nWhat is generally done in cases like this:\nStep 1: Download the patch series which you want to base you work on\nStep 2: apply to a local git tree\nStep 3: Base your work on top of that tree with separate patches\n\tauthored by you, build+test+send.\n\nAfter Step 3:, you should only send out the patches authored by you\nto the mailing list. And in the cover/patch comment, mention you have\nbased your work based on XYZ series (in this case Jaslo's\nhttps://patchwork.libcamera.org/project/libcamera/list/?series=5311).\n\nFor Step 1 & 2, if it is unclear - You can simply download the patch\nseries by clicking on \"series\" on right hand side and apply locally\nwith `git am path_to_file.patch`. Alternatively, if you want to go\nadvanced simply use the `git-pw` utility\n(https://github.com/getpatchwork/git-pw) which simplies this process\neven further.\n\nI took a cursory look at the orientation related LOC, and it has started\nto look in the correct direction to me.\n\nOn Fri, Jul 25, 2025 at 01:30:46PM +0200, Giacomo Cappellini wrote:\n> libcamera allows to control the images orientation through the\n> CameraConfiguration::orientation field, expose a GST_PARAM_MUTABLE_READY\n> parameter of type GstVideoOrientationMethod in GstLibcameraSrc to\n> control it. Parameter is mapped internally to libcamera::Orientation via\n> new gstlibcamera-utils functions:\n> - gst_video_orientation_to_libcamera_orientation\n> - libcamera_orientation_to_gst_video_orientation\n> \n> Signed-off-by: Giacomo Cappellini <giacomo.cappellini.87@gmail.com>\n> ---\n>  src/gstreamer/gstlibcamera-utils.cpp | 58 ++++++++++++++++++++++------\n>  src/gstreamer/gstlibcamera-utils.h   |  4 ++\n>  src/gstreamer/gstlibcamerasrc.cpp    | 46 +++++++++++++++++-----\n>  3 files changed, 86 insertions(+), 22 deletions(-)\n> \n> diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\n> index a548b0c1..15069f98 100644\n> --- a/src/gstreamer/gstlibcamera-utils.cpp\n> +++ b/src/gstreamer/gstlibcamera-utils.cpp\n> @@ -10,6 +10,9 @@\n>  \n>  #include <libcamera/control_ids.h>\n>  #include <libcamera/formats.h>\n> +#include <libcamera/orientation.h>\n> +\n> +#include <gst/video/video.h>\n>  \n>  using namespace libcamera;\n>  \n> @@ -20,7 +23,7 @@ static struct {\n>  \t/* Compressed */\n>  \t{ GST_VIDEO_FORMAT_ENCODED, formats::MJPEG },\n>  \n> -\t/* Bayer formats, gstreamer only supports 8-bit */\n> +\t/* Bayer formats */\n>  \t{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR8 },\n>  \t{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG8 },\n>  \t{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG8 },\n> @@ -317,20 +320,15 @@ bare_structure_from_format(const PixelFormat &format)\n>  \t\treturn gst_structure_new(\"video/x-raw\", \"format\", G_TYPE_STRING,\n>  \t\t\t\t\t gst_video_format_to_string(gst_format), nullptr);\n>  \n> -\tswitch (format) {\n> -\tcase formats::MJPEG:\n> +\tif (format == formats::MJPEG)\n>  \t\treturn gst_structure_new_empty(\"image/jpeg\");\n>  \n> -\tcase formats::SBGGR8:\n> -\tcase formats::SGBRG8:\n> -\tcase formats::SGRBG8:\n> -\tcase formats::SRGGB8:\n> -\t\treturn gst_structure_new(\"video/x-bayer\", \"format\", G_TYPE_STRING,\n> -\t\t\t\t\t bayer_format_to_string(format), nullptr);\n> -\n> -\tdefault:\n> +\tconst gchar *s = bayer_format_to_string(format);\n> +\tif (s)\n> +\t\treturn gst_structure_new(\"video/x-bayer\", \"format\",\n> +\t\t\t\t\t G_TYPE_STRING, s, nullptr);\n> +\telse\n>  \t\treturn nullptr;\n> -\t}\n>  }\n>  \n>  GstCaps *\n> @@ -659,3 +657,39 @@ gst_libcamera_get_camera_manager(int &ret)\n>  \n>  \treturn cm;\n>  }\n> +\n> +static const struct {\n> +\tOrientation orientation;\n> +\tGstVideoOrientationMethod method;\n> +} orientation_map[]{\n> +\t{ Orientation::Rotate0, GST_VIDEO_ORIENTATION_IDENTITY },\n> +\t{ Orientation::Rotate90, GST_VIDEO_ORIENTATION_90R },\n> +\t{ Orientation::Rotate180, GST_VIDEO_ORIENTATION_180 },\n> +\t{ Orientation::Rotate270, GST_VIDEO_ORIENTATION_90L },\n> +\t{ Orientation::Rotate0Mirror, GST_VIDEO_ORIENTATION_HORIZ },\n> +\t{ Orientation::Rotate180Mirror, GST_VIDEO_ORIENTATION_VERT },\n> +\t{ Orientation::Rotate90Mirror, GST_VIDEO_ORIENTATION_UL_LR },\n> +\t{ Orientation::Rotate270Mirror, GST_VIDEO_ORIENTATION_UR_LL },\n> +};\n> +\n> +Orientation\n> +gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method)\n> +{\n> +\tfor (auto &b : orientation_map) {\n> +\t\tif (b.method == method)\n> +\t\t\treturn b.orientation;\n> +\t}\n> +\n> +\treturn Orientation::Rotate0;\n> +}\n> +\n> +GstVideoOrientationMethod\n> +libcamera_orientation_to_gst_video_orientation(Orientation orientation)\n> +{\n> +\tfor (auto &a : orientation_map) {\n> +\t\tif (a.orientation == orientation)\n> +\t\t\treturn a.method;\n> +\t}\n> +\n> +\treturn GST_VIDEO_ORIENTATION_IDENTITY;\n> +}\n> diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h\n> index 5f4e8a0f..bbbd33db 100644\n> --- a/src/gstreamer/gstlibcamera-utils.h\n> +++ b/src/gstreamer/gstlibcamera-utils.h\n> @@ -10,6 +10,7 @@\n>  \n>  #include <libcamera/camera_manager.h>\n>  #include <libcamera/controls.h>\n> +#include <libcamera/orientation.h>\n>  #include <libcamera/stream.h>\n>  \n>  #include <gst/gst.h>\n> @@ -92,3 +93,6 @@ public:\n>  private:\n>  \tGRecMutex *mutex_;\n>  };\n> +\n> +libcamera::Orientation gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method);\n> +GstVideoOrientationMethod libcamera_orientation_to_gst_video_orientation(libcamera::Orientation orientation);\n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index 3aca4eed..85add936 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -29,6 +29,7 @@\n>  \n>  #include <atomic>\n>  #include <queue>\n> +#include <sstream>\n>  #include <tuple>\n>  #include <utility>\n>  #include <vector>\n> @@ -38,6 +39,7 @@\n>  #include <libcamera/control_ids.h>\n>  \n>  #include <gst/base/base.h>\n> +#include <gst/video/video.h>\n>  \n>  #include \"gstlibcamera-controls.h\"\n>  #include \"gstlibcamera-utils.h\"\n> @@ -146,6 +148,7 @@ struct _GstLibcameraSrc {\n>  \tGstTask *task;\n>  \n>  \tgchar *camera_name;\n> +\tGstVideoOrientationMethod orientation;\n>  \n>  \tstd::atomic<GstEvent *> pending_eos;\n>  \n> @@ -157,6 +160,7 @@ struct _GstLibcameraSrc {\n>  enum {\n>  \tPROP_0,\n>  \tPROP_CAMERA_NAME,\n> +\tPROP_ORIENTATION,\n>  \tPROP_LAST\n>  };\n>  \n> @@ -166,8 +170,8 @@ static void gst_libcamera_src_child_proxy_init(gpointer g_iface,\n>  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,\n>  \t\t\tG_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY,\n>  \t\t\t\t\t      gst_libcamera_src_child_proxy_init)\n> -\t\t\tGST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> -\t\t\t\t\t\t\"libcamera Source\"))\n> +\t\t\t\tGST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> +\t\t\t\t\t\t\t\"libcamera Source\"))\n>  \n>  #define TEMPLATE_CAPS GST_STATIC_CAPS(\"video/x-raw; image/jpeg; video/x-bayer\")\n>  \n> @@ -225,8 +229,7 @@ int GstLibcameraSrcState::queueRequest()\n>  \treturn 0;\n>  }\n>  \n> -void\n> -GstLibcameraSrcState::requestCompleted(Request *request)\n> +void GstLibcameraSrcState::requestCompleted(Request *request)\n>  {\n>  \tGST_DEBUG_OBJECT(src_, \"buffers are ready\");\n>  \n> @@ -616,9 +619,17 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n>  \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n>  \t}\n>  \n> +\t/* Set orientation control. */\n> +\tstate->config_->orientation = gst_video_orientation_to_libcamera_orientation(self->orientation);\n> +\n>  \t/* Validate the configuration. */\n> -\tif (state->config_->validate() == CameraConfiguration::Invalid)\n> +\tCameraConfiguration::Status status = state->config_->validate();\n> +\tif (status == CameraConfiguration::Invalid)\n>  \t\treturn false;\n> +\telse if (status == CameraConfiguration::Adjusted)\n> +\t\tGST_ELEMENT_INFO(self, RESOURCE, SETTINGS,\n> +\t\t\t\t (\"Configuration was adjusted\"),\n> +\t\t\t\t (\"CameraConfiguration::validate() returned CameraConfiguration::Adjusted\"));\n>  \n>  \tint ret = state->cam_->configure(state->config_.get());\n>  \tif (ret) {\n> @@ -643,6 +654,10 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n>  \t\tg_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg, transfer[i]);\n>  \t\tgst_libcamera_framerate_to_caps(caps, element_caps);\n>  \n> +\t\tif (status == CameraConfiguration::Adjusted &&\n> +\t\t    !gst_pad_peer_query_accept_caps(srcpad, caps))\n> +\t\t\treturn false;\n> +\n>  \t\tif (!gst_pad_push_event(srcpad, gst_event_new_caps(caps)))\n>  \t\t\treturn false;\n>  \t}\n> @@ -730,7 +745,8 @@ gst_libcamera_src_task_run(gpointer user_data)\n>  \t\tif (gst_pad_check_reconfigure(srcpad)) {\n>  \t\t\t/* Check if the caps even need changing. */\n>  \t\t\tg_autoptr(GstCaps) caps = gst_pad_get_current_caps(srcpad);\n> -\t\t\tif (!gst_pad_peer_query_accept_caps(srcpad, caps)) {\n> +\t\t\tg_autoptr(GstCaps) peercaps = gst_pad_peer_query_caps(srcpad, caps);\n> +\t\t\tif (gst_caps_is_empty(peercaps)) {\n>  \t\t\t\treconfigure = true;\n>  \t\t\t\tbreak;\n>  \t\t\t}\n> @@ -926,6 +942,9 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id,\n>  \t\tg_free(self->camera_name);\n>  \t\tself->camera_name = g_value_dup_string(value);\n>  \t\tbreak;\n> +\tcase PROP_ORIENTATION:\n> +\t\tself->orientation = (GstVideoOrientationMethod)g_value_get_enum(value);\n> +\t\tbreak;\n>  \tdefault:\n>  \t\tif (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec))\n>  \t\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> @@ -945,6 +964,9 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,\n>  \tcase PROP_CAMERA_NAME:\n>  \t\tg_value_set_string(value, self->camera_name);\n>  \t\tbreak;\n> +\tcase PROP_ORIENTATION:\n> +\t\tg_value_set_enum(value, (gint)self->orientation);\n> +\t\tbreak;\n>  \tdefault:\n>  \t\tif (!state->controls_.getProperty(prop_id - PROP_LAST, value, pspec))\n>  \t\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> @@ -1148,12 +1170,16 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>  \n>  \tGParamSpec *spec = g_param_spec_string(\"camera-name\", \"Camera Name\",\n>  \t\t\t\t\t       \"Select by name which camera to use.\", nullptr,\n> -\t\t\t\t\t       (GParamFlags)(GST_PARAM_MUTABLE_READY\n> -\t\t\t\t\t\t\t     | G_PARAM_CONSTRUCT\n> -\t\t\t\t\t\t\t     | G_PARAM_READWRITE\n> -\t\t\t\t\t\t\t     | G_PARAM_STATIC_STRINGS));\n> +\t\t\t\t\t       (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n>  \tg_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);\n>  \n> +\t/* Register the orientation enum type. */\n> +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> +\t\t\t\t \"Select the orientation of the camera.\",\n> +\t\t\t\t GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,\n> +\t\t\t\t (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> +\n>  \tGstCameraControls::installProperties(object_class, PROP_LAST);\n>  }\n>  \n> -- \n> 2.43.0\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 16660C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Jul 2025 04:39:48 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3301269136;\n\tMon, 28 Jul 2025 06:39:47 +0200 (CEST)","from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 98AA86146B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Jul 2025 06:39:42 +0200 (CEST)","from [49.36.71.87] (helo=uajain) by fanzine2.igalia.com with\n\tesmtpsa \n\t(Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)\n\t(Exim) id 1ugFeG-004lBL-RL; Mon, 28 Jul 2025 06:39:41 +0200"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=igalia.com header.i=@igalia.com\n\theader.b=\"dQRtWeIT\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n\ts=20170329;\n\th=In-Reply-To:Content-Type:MIME-Version:References:Message-ID:\n\tSubject:Cc:To:From:Date:Sender:Reply-To:Content-Transfer-Encoding:Content-ID:\n\tContent-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc\n\t:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe:\n\tList-Post:List-Owner:List-Archive;\n\tbh=j/U7J1QWCNprCGV5CMP9DQoT0Yb1tdJZzntTXEm9Rlo=;\n\tb=dQRtWeITCXMTzAtqtJ2L9Xh9+m\n\teUBxyRSBHItgEkyNvvje9PjlvD2MQR8W3mcO3mVDZx1vFsE3bjPLaS4wrowSDh6ypUiFGUcJv17qz\n\t6n1CkCan9wP1QPko+ljVGq6mXC1QMH7mlopOd/stD9ecnBmcTp1F/DHt7/rxl9TM0uUU73AnHLXzT\n\t/14ahxExe18zhBe6e9nZYjID4OMoblfEee0pAXTzDh6M9umaDwtTFdULjGfkc+kuKo0n0ZXvfrgkk\n\tScJypBbNeRo4Mge3mS6+PG30FcnATnbsdoMhKyqQDIPgkzkOp7DpJbIbL/YjC1sMmRWzXfgsxwvyS\n\tVJvR9pfw==;","Date":"Mon, 28 Jul 2025 10:09:46 +0530","From":"Umang Jain <uajain@igalia.com>","To":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","Message-ID":"<zsdwyphnk2bvchbxxzy25y3p7quoatt6xb7sj375tde46wrq5i@wmeee4hxc2vg>","References":"<20250725115602.1477743-1-giacomo.cappellini.87@gmail.com>\n\t<20250725115602.1477743-2-giacomo.cappellini.87@gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20250725115602.1477743-2-giacomo.cappellini.87@gmail.com>","User-Agent":"NeoMutt/20250510-dirty","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35221,"web_url":"https://patchwork.libcamera.org/comment/35221/","msgid":"<f87475ab9bafe0e57abad2d3f857b3df623c7316.camel@ndufresne.ca>","date":"2025-07-28T21:27:46","subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","submitter":{"id":30,"url":"https://patchwork.libcamera.org/api/people/30/","name":"Nicolas Dufresne","email":"nicolas@ndufresne.ca"},"content":"Hi,\n\nLe vendredi 25 juillet 2025 à 13:30 +0200, Giacomo Cappellini a écrit :\n> libcamera allows to control the images orientation through the\n> CameraConfiguration::orientation field, expose a GST_PARAM_MUTABLE_READY\n> parameter of type GstVideoOrientationMethod in GstLibcameraSrc to\n> control it. Parameter is mapped internally to libcamera::Orientation via\n> new gstlibcamera-utils functions:\n> - gst_video_orientation_to_libcamera_orientation\n> - libcamera_orientation_to_gst_video_orientation\n> \n> Signed-off-by: Giacomo Cappellini <giacomo.cappellini.87@gmail.com>\n> ---\n>  src/gstreamer/gstlibcamera-utils.cpp | 58 ++++++++++++++++++++++------\n>  src/gstreamer/gstlibcamera-utils.h   |  4 ++\n>  src/gstreamer/gstlibcamerasrc.cpp    | 46 +++++++++++++++++-----\n>  3 files changed, 86 insertions(+), 22 deletions(-)\n> \n> diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\n> index a548b0c1..15069f98 100644\n> --- a/src/gstreamer/gstlibcamera-utils.cpp\n> +++ b/src/gstreamer/gstlibcamera-utils.cpp\n> @@ -10,6 +10,9 @@\n>  \n>  #include <libcamera/control_ids.h>\n>  #include <libcamera/formats.h>\n> +#include <libcamera/orientation.h>\n> +\n> +#include <gst/video/video.h>\n>  \n>  using namespace libcamera;\n>  \n> @@ -20,7 +23,7 @@ static struct {\n>  \t/* Compressed */\n>  \t{ GST_VIDEO_FORMAT_ENCODED, formats::MJPEG },\n>  \n> -\t/* Bayer formats, gstreamer only supports 8-bit */\n> +\t/* Bayer formats */\n\nUnrelated changes, but valid, what about giving it its own commit ?\n\n>  \t{ GST_VIDEO_FORMAT_ENCODED, formats::SBGGR8 },\n>  \t{ GST_VIDEO_FORMAT_ENCODED, formats::SGBRG8 },\n>  \t{ GST_VIDEO_FORMAT_ENCODED, formats::SGRBG8 },\n> @@ -317,20 +320,15 @@ bare_structure_from_format(const PixelFormat &format)\n>  \t\treturn gst_structure_new(\"video/x-raw\", \"format\", G_TYPE_STRING,\n>  \t\t\t\t\t gst_video_format_to_string(gst_format), nullptr);\n>  \n> -\tswitch (format) {\n> -\tcase formats::MJPEG:\n> +\tif (format == formats::MJPEG)\n>  \t\treturn gst_structure_new_empty(\"image/jpeg\");\n>  \n> -\tcase formats::SBGGR8:\n> -\tcase formats::SGBRG8:\n> -\tcase formats::SGRBG8:\n> -\tcase formats::SRGGB8:\n> -\t\treturn gst_structure_new(\"video/x-bayer\", \"format\", G_TYPE_STRING,\n> -\t\t\t\t\t bayer_format_to_string(format), nullptr);\n> -\n> -\tdefault:\n> +\tconst gchar *s = bayer_format_to_string(format);\n> +\tif (s)\n> +\t\treturn gst_structure_new(\"video/x-bayer\", \"format\",\n> +\t\t\t\t\t G_TYPE_STRING, s, nullptr);\n> +\telse\n>  \t\treturn nullptr;\n\nSame, please dedicate a patch for that.\n\n> -\t}\n>  }\n>  \n>  GstCaps *\n> @@ -659,3 +657,39 @@ gst_libcamera_get_camera_manager(int &ret)\n>  \n>  \treturn cm;\n>  }\n> +\n> +static const struct {\n> +\tOrientation orientation;\n> +\tGstVideoOrientationMethod method;\n> +} orientation_map[]{\n> +\t{ Orientation::Rotate0, GST_VIDEO_ORIENTATION_IDENTITY },\n> +\t{ Orientation::Rotate90, GST_VIDEO_ORIENTATION_90R },\n> +\t{ Orientation::Rotate180, GST_VIDEO_ORIENTATION_180 },\n> +\t{ Orientation::Rotate270, GST_VIDEO_ORIENTATION_90L },\n> +\t{ Orientation::Rotate0Mirror, GST_VIDEO_ORIENTATION_HORIZ },\n> +\t{ Orientation::Rotate180Mirror, GST_VIDEO_ORIENTATION_VERT },\n> +\t{ Orientation::Rotate90Mirror, GST_VIDEO_ORIENTATION_UL_LR },\n> +\t{ Orientation::Rotate270Mirror, GST_VIDEO_ORIENTATION_UR_LL },\n> +};\n> +\n> +Orientation\n> +gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method)\n> +{\n> +\tfor (auto &b : orientation_map) {\n> +\t\tif (b.method == method)\n> +\t\t\treturn b.orientation;\n> +\t}\n> +\n> +\treturn Orientation::Rotate0;\n> +}\n> +\n> +GstVideoOrientationMethod\n> +libcamera_orientation_to_gst_video_orientation(Orientation orientation)\n> +{\n> +\tfor (auto &a : orientation_map) {\n> +\t\tif (a.orientation == orientation)\n> +\t\t\treturn a.method;\n> +\t}\n> +\n> +\treturn GST_VIDEO_ORIENTATION_IDENTITY;\n> +}\n> diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h\n> index 5f4e8a0f..bbbd33db 100644\n> --- a/src/gstreamer/gstlibcamera-utils.h\n> +++ b/src/gstreamer/gstlibcamera-utils.h\n> @@ -10,6 +10,7 @@\n>  \n>  #include <libcamera/camera_manager.h>\n>  #include <libcamera/controls.h>\n> +#include <libcamera/orientation.h>\n>  #include <libcamera/stream.h>\n>  \n>  #include <gst/gst.h>\n> @@ -92,3 +93,6 @@ public:\n>  private:\n>  \tGRecMutex *mutex_;\n>  };\n> +\n> +libcamera::Orientation gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method);\n> +GstVideoOrientationMethod libcamera_orientation_to_gst_video_orientation(libcamera::Orientation orientation);\n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index 3aca4eed..85add936 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -29,6 +29,7 @@\n>  \n>  #include <atomic>\n>  #include <queue>\n> +#include <sstream>\n>  #include <tuple>\n>  #include <utility>\n>  #include <vector>\n> @@ -38,6 +39,7 @@\n>  #include <libcamera/control_ids.h>\n>  \n>  #include <gst/base/base.h>\n> +#include <gst/video/video.h>\n>  \n>  #include \"gstlibcamera-controls.h\"\n>  #include \"gstlibcamera-utils.h\"\n> @@ -146,6 +148,7 @@ struct _GstLibcameraSrc {\n>  \tGstTask *task;\n>  \n>  \tgchar *camera_name;\n> +\tGstVideoOrientationMethod orientation;\n>  \n>  \tstd::atomic<GstEvent *> pending_eos;\n>  \n> @@ -157,6 +160,7 @@ struct _GstLibcameraSrc {\n>  enum {\n>  \tPROP_0,\n>  \tPROP_CAMERA_NAME,\n> +\tPROP_ORIENTATION,\n>  \tPROP_LAST\n>  };\n>  \n> @@ -166,8 +170,8 @@ static void gst_libcamera_src_child_proxy_init(gpointer g_iface,\n>  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,\n>  \t\t\tG_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY,\n>  \t\t\t\t\t      gst_libcamera_src_child_proxy_init)\n> -\t\t\tGST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> -\t\t\t\t\t\t\"libcamera Source\"))\n> +\t\t\t\tGST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> +\t\t\t\t\t\t\t\"libcamera Source\"))\n\nNot sure why this change, it looked better before.\n\n>  \n>  #define TEMPLATE_CAPS GST_STATIC_CAPS(\"video/x-raw; image/jpeg; video/x-bayer\")\n>  \n> @@ -225,8 +229,7 @@ int GstLibcameraSrcState::queueRequest()\n>  \treturn 0;\n>  }\n>  \n> -void\n> -GstLibcameraSrcState::requestCompleted(Request *request)\n> +void GstLibcameraSrcState::requestCompleted(Request *request)\n\nWas GStreamer style, but at the same time, don't do style changes mixed with\nyour functional changes.\n\n>  {\n>  \tGST_DEBUG_OBJECT(src_, \"buffers are ready\");\n>  \n> @@ -616,9 +619,17 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n>  \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n>  \t}\n>  \n> +\t/* Set orientation control. */\n> +\tstate->config_->orientation = gst_video_orientation_to_libcamera_orientation(self->orientation);\n> +\n>  \t/* Validate the configuration. */\n> -\tif (state->config_->validate() == CameraConfiguration::Invalid)\n> +\tCameraConfiguration::Status status = state->config_->validate();\n> +\tif (status == CameraConfiguration::Invalid)\n>  \t\treturn false;\n> +\telse if (status == CameraConfiguration::Adjusted)\n> +\t\tGST_ELEMENT_INFO(self, RESOURCE, SETTINGS,\n> +\t\t\t\t (\"Configuration was adjusted\"),\n> +\t\t\t\t (\"CameraConfiguration::validate() returned CameraConfiguration::Adjusted\"));\n\nNot sure this is worth a message to the application using the bus.\n\n>  \n>  \tint ret = state->cam_->configure(state->config_.get());\n>  \tif (ret) {\n> @@ -643,6 +654,10 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n>  \t\tg_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg, transfer[i]);\n>  \t\tgst_libcamera_framerate_to_caps(caps, element_caps);\n>  \n> +\t\tif (status == CameraConfiguration::Adjusted &&\n> +\t\t    !gst_pad_peer_query_accept_caps(srcpad, caps))\n> +\t\t\treturn false;\n\nFair enough, this could though be done as its own patch, since it is valid\nwithout the orientation. In fact, orientation is not part of the caps.\n\n> +\n>  \t\tif (!gst_pad_push_event(srcpad, gst_event_new_caps(caps)))\n>  \t\t\treturn false;\n>  \t}\n> @@ -730,7 +745,8 @@ gst_libcamera_src_task_run(gpointer user_data)\n>  \t\tif (gst_pad_check_reconfigure(srcpad)) {\n>  \t\t\t/* Check if the caps even need changing. */\n>  \t\t\tg_autoptr(GstCaps) caps = gst_pad_get_current_caps(srcpad);\n> -\t\t\tif (!gst_pad_peer_query_accept_caps(srcpad, caps)) {\n> +\t\t\tg_autoptr(GstCaps) peercaps = gst_pad_peer_query_caps(srcpad, caps);\n> +\t\t\tif (gst_caps_is_empty(peercaps)) {\n\nThis patch I've seen as its own in some other submission, please drop.\n\n>  \t\t\t\treconfigure = true;\n>  \t\t\t\tbreak;\n>  \t\t\t}\n> @@ -926,6 +942,9 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id,\n>  \t\tg_free(self->camera_name);\n>  \t\tself->camera_name = g_value_dup_string(value);\n>  \t\tbreak;\n> +\tcase PROP_ORIENTATION:\n> +\t\tself->orientation = (GstVideoOrientationMethod)g_value_get_enum(value);\n> +\t\tbreak;\n>  \tdefault:\n>  \t\tif (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec))\n>  \t\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> @@ -945,6 +964,9 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,\n>  \tcase PROP_CAMERA_NAME:\n>  \t\tg_value_set_string(value, self->camera_name);\n>  \t\tbreak;\n> +\tcase PROP_ORIENTATION:\n> +\t\tg_value_set_enum(value, (gint)self->orientation);\n> +\t\tbreak;\n>  \tdefault:\n>  \t\tif (!state->controls_.getProperty(prop_id - PROP_LAST, value, pspec))\n>  \t\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> @@ -1148,12 +1170,16 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>  \n>  \tGParamSpec *spec = g_param_spec_string(\"camera-name\", \"Camera Name\",\n>  \t\t\t\t\t       \"Select by name which camera to use.\", nullptr,\n> -\t\t\t\t\t       (GParamFlags)(GST_PARAM_MUTABLE_READY\n> -\t\t\t\t\t\t\t     | G_PARAM_CONSTRUCT\n> -\t\t\t\t\t\t\t     | G_PARAM_READWRITE\n> -\t\t\t\t\t\t\t     | G_PARAM_STATIC_STRINGS));\n> +\t\t\t\t\t       (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n\nLooked fine before, and was accepted as such.\n\n>  \tg_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);\n>  \n> +\t/* Register the orientation enum type. */\n> +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n\nIs the name \"orientation\" proper ? In the wilderness of GStremer, I see rotate-\nmethod (glimagesink), video-direction (videoflip), I'd pick one of these.\n\n> +\t\t\t\t \"Select the orientation of the camera.\",\n> +\t\t\t\t GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,\n> +\t\t\t\t (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> +\n>  \tGstCameraControls::installProperties(object_class, PROP_LAST);\n>  }\n>  \n\ncheers,\nNicolas","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D971DBDCC1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Jul 2025 21:28:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CF09B691C1;\n\tMon, 28 Jul 2025 23:28:05 +0200 (CEST)","from mail-qv1-xf2f.google.com (mail-qv1-xf2f.google.com\n\t[IPv6:2607:f8b0:4864:20::f2f])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 418D469158\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Jul 2025 23:27:50 +0200 (CEST)","by mail-qv1-xf2f.google.com with SMTP id\n\t6a1803df08f44-6fadd3ad18eso42761636d6.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Jul 2025 14:27:50 -0700 (PDT)","from ?IPv6:2606:6d00:11:5a76::5ac? ([2606:6d00:11:5a76::5ac])\n\tby smtp.gmail.com with ESMTPSA id\n\t6a1803df08f44-70729aafa4csm35720446d6.42.2025.07.28.14.27.47\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 28 Jul 2025 14:27:47 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=ndufresne-ca.20230601.gappssmtp.com\n\theader.i=@ndufresne-ca.20230601.gappssmtp.com\n\theader.b=\"Jb5DSlic\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ndufresne-ca.20230601.gappssmtp.com; s=20230601; t=1753738069;\n\tx=1754342869; darn=lists.libcamera.org; \n\th=mime-version:user-agent:autocrypt:references:in-reply-to:date:to\n\t:from:subject:message-id:from:to:cc:subject:date:message-id:reply-to; \n\tbh=xPQcGS+K5dSc5Q0DSSf7RwBXhUKTbekU1dzaBqneCEE=;\n\tb=Jb5DSlicJZKy3Mhj+I8wSRDstqpsZVmQFzDJoW2r1RY7GAQKmJPWIMUgg1hLzUHo8o\n\t6NbsQrEeT0bwcVqApZKIoV7OSQl1GMdAanYQ23hwdht0vwNKBgt13TwbvJu9RXxMDTNg\n\ttlwj6npXxWShaede4hguFQq+ov3eJfOQSPTZl0dnuIcunnY4tm8IxplJ5f4sTWnNT/83\n\tna5nqIEhcJqn4iRbTbeAS48MGWoCpQ4Cvfiva4Gk4/Vd6ABQz76qO7uiwI2b9zB/xg3X\n\tAbFVDpAVnWZhvMxTQwUU7yTjhqdhp24mM6QwCGYmLB0CXy1RWs6BsxjlgjKCm3QAj/v5\n\tz7Kg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1753738069; x=1754342869;\n\th=mime-version:user-agent:autocrypt:references:in-reply-to:date:to\n\t:from:subject:message-id:x-gm-message-state:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=xPQcGS+K5dSc5Q0DSSf7RwBXhUKTbekU1dzaBqneCEE=;\n\tb=gF2fUgtcxycshmwdixyYmpUDvHRwKj/FjFHNhZj8a81BGxK2p0BeaSAawjo/3Ln6LW\n\tWD4XjspTHb7dVcJ5KEu/Xh5gVJ6TCLMw+3/vLdEQnnjImS9fpPqMKAKlUVsfAa7ibqEQ\n\txXXMT2MO9XVMrS19n5jkfueqrqSGdEinJ03w+EKEzJ5rDVm3G040+GJmzxPGVdTa/3vu\n\t7dEdZwwwNtdanX7TNMr1X4AcTxYPfaqgbTFsgDORR48TsRFkb0w23gB1OjI6kQz2Lqdu\n\tU5Rq35/DGewlZ138eIOpFoyRHouFzTcIKXZk9n9smUXwDgHCEIRvWiMFq9WwtI/lyJK6\n\t+Xsg==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCXuYLZ9+oVYHZxOTMUp7OGPYNc7k8iNPF0g/Q8mO0/fe2YLXPWVbQzf7ySuYG6aQjenPcCtayl6/aw2bObg1WQ=@lists.libcamera.org","X-Gm-Message-State":"AOJu0YwNlKK3Lc9Iqb9iE1PBROjFdMDDjR+3ssdW0SUXZTussDq3dX80\n\tnn6bL6KfkH25oaUceoUdvr9/O0Rhe+EvXurieykpZFiCUQ6fMv3q5t03VW+ZULAtmuo=","X-Gm-Gg":"ASbGncvj9Uz8EKx5cCCrzuVlGah4Iq1zvus3s6nxwsbzCnvYZdOiFz3S0s4fE+o/LXH\n\tO3Pmv3+in8mpcnKbrO6U3STXnwYn7FIBgPJkQ5eAOKaPecaBesW/FBiLwBI/CMGdebpHNQ8XPU2\n\ta7ZQkgRop3d9ioYkd8mrCyOCINBNNgOSg+482HfAolwOUXOQBY/jUD/OagzyYoluV4o/2kaRL+2\n\tMS+bAcowK7BW7EMzcUa4CL9UBgBY1AtNuAXCIHBzmX8GzTtEhuROb/NUXMJeipMvqIrG8AcP6Ma\n\taNoxNi4FrPD0agMzEnNmNeZObTS+6YcPIK8YdDN41Trp6TnihtTA17JcVoBL3A1ARQBy0G7+Pf4\n\t9UAKfLXVaxtJhlvVrMc8Yfa9sQ77ruYDhlxo7LA==","X-Google-Smtp-Source":"AGHT+IHDtJscO8Q3lbUBiDwbqZ+cP8v2PU9pRqT4XHB3ZpsV6coA3tREHWhe3NA0lqdjHKAiRgCFFg==","X-Received":"by 2002:a05:6214:5504:b0:707:4d17:e280 with SMTP id\n\t6a1803df08f44-7074d17e457mr56935956d6.28.1753738068535; \n\tMon, 28 Jul 2025 14:27:48 -0700 (PDT)","Message-ID":"<f87475ab9bafe0e57abad2d3f857b3df623c7316.camel@ndufresne.ca>","Subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","From":"Nicolas Dufresne <nicolas@ndufresne.ca>","To":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>, \n\tlibcamera-devel@lists.libcamera.org","Date":"Mon, 28 Jul 2025 17:27:46 -0400","In-Reply-To":"<20250725115602.1477743-2-giacomo.cappellini.87@gmail.com>","References":"<20250725115602.1477743-1-giacomo.cappellini.87@gmail.com>\n\t<20250725115602.1477743-2-giacomo.cappellini.87@gmail.com>","Autocrypt":"addr=nicolas@ndufresne.ca; prefer-encrypt=mutual;\n\tkeydata=mDMEaCN2ixYJKwYBBAHaRw8BAQdAM0EHepTful3JOIzcPv6ekHOenE1u0vDG1gdHFrChD\n\t/e0MU5pY29sYXMgRHVmcmVzbmUgPG5pY29sYXMuZHVmcmVzbmVAY29sbGFib3JhLmNvbT6ImQQTFg\n\toAQQIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgBYhBO8NUoEVxMPCGgRvEtlBlFEpYHL0BQJ\n\toLLLGBQkJZfd1AAoJENlBlFEpYHL0BEkA/3qkWYt99myYFSmTJUF8UB/7OroEm3vr1HRqXeQe9Qp2\n\tAP0bsoAe6KjEPa/pJfuJ2khrOPPHxvyt/PBNbI5BYcIABLQnTmljb2xhcyBEdWZyZXNuZSA8bmljb\n\t2xhc0BuZHVmcmVzbmUuY2E+iJkEExYKAEECGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AWIQ\n\tTvDVKBFcTDwhoEbxLZQZRRKWBy9AUCaCyy+AUJCWX3dQAKCRDZQZRRKWBy9FJ5AQCNy8SX8DpHbLa\n\tcy58vgDwyIpB89mok9eWGGejY9mqpRwEAhHzs+/n5xlVlM3bqy1yHnAzJqVwqBE1D0jG0a9V6VQI=","Content-Type":"multipart/signed; micalg=\"pgp-sha512\";\n\tprotocol=\"application/pgp-signature\";\n\tboundary=\"=-amLpF1HGXxxKXyYqppvW\"","User-Agent":"Evolution 3.56.2 (3.56.2-1.fc42) ","MIME-Version":"1.0","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35222,"web_url":"https://patchwork.libcamera.org/comment/35222/","msgid":"<CABXJd1n7Jsuk+dbc3oeywzGtuo1M+sC=Ubx6RoN-iT8_YZsXMw@mail.gmail.com>","date":"2025-07-28T22:12:42","subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","submitter":{"id":231,"url":"https://patchwork.libcamera.org/api/people/231/","name":"Giacomo Cappellini","email":"giacomo.cappellini.87@gmail.com"},"content":"Hi Umang Jain,\n\nthank you for the detailed instructions and sorry for the error, this\nis my first time doing dealing with this operation and with patchwork\nin general. I made another mistake and I'll send V5 asap as\ninstructed. I'm sorry for that.\n\nCheers,\n\nG.C.\n\nIl giorno lun 28 lug 2025 alle ore 06:39 Umang Jain\n<uajain@igalia.com> ha scritto:\n>\n> Hi Giacomo,\n>\n> There is one issue with the patch format. I think you have picked\n> up Jaslo's series (right thing to do) but, you have squashed his\n> commit+orientation patch into one. This is not right thing to do\n> and only makes reviews/merging almost impossible.\n>\n> What is generally done in cases like this:\n> Step 1: Download the patch series which you want to base you work on\n> Step 2: apply to a local git tree\n> Step 3: Base your work on top of that tree with separate patches\n>         authored by you, build+test+send.\n>\n> After Step 3:, you should only send out the patches authored by you\n> to the mailing list. And in the cover/patch comment, mention you have\n> based your work based on XYZ series (in this case Jaslo's\n> https://patchwork.libcamera.org/project/libcamera/list/?series=5311).\n>\n> For Step 1 & 2, if it is unclear - You can simply download the patch\n> series by clicking on \"series\" on right hand side and apply locally\n> with `git am path_to_file.patch`. Alternatively, if you want to go\n> advanced simply use the `git-pw` utility\n> (https://github.com/getpatchwork/git-pw) which simplies this process\n> even further.\n>\n> I took a cursory look at the orientation related LOC, and it has started\n> to look in the correct direction to me.\n>\n> On Fri, Jul 25, 2025 at 01:30:46PM +0200, Giacomo Cappellini wrote:\n> > libcamera allows to control the images orientation through the\n> > CameraConfiguration::orientation field, expose a GST_PARAM_MUTABLE_READY\n> > parameter of type GstVideoOrientationMethod in GstLibcameraSrc to\n> > control it. Parameter is mapped internally to libcamera::Orientation via\n> > new gstlibcamera-utils functions:\n> > - gst_video_orientation_to_libcamera_orientation\n> > - libcamera_orientation_to_gst_video_orientation\n> >\n> > Signed-off-by: Giacomo Cappellini <giacomo.cappellini.87@gmail.com>\n> > ---\n> >  src/gstreamer/gstlibcamera-utils.cpp | 58 ++++++++++++++++++++++------\n> >  src/gstreamer/gstlibcamera-utils.h   |  4 ++\n> >  src/gstreamer/gstlibcamerasrc.cpp    | 46 +++++++++++++++++-----\n> >  3 files changed, 86 insertions(+), 22 deletions(-)\n> >\n> > diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\n> > index a548b0c1..15069f98 100644\n> > --- a/src/gstreamer/gstlibcamera-utils.cpp\n> > +++ b/src/gstreamer/gstlibcamera-utils.cpp\n> > @@ -10,6 +10,9 @@\n> >\n> >  #include <libcamera/control_ids.h>\n> >  #include <libcamera/formats.h>\n> > +#include <libcamera/orientation.h>\n> > +\n> > +#include <gst/video/video.h>\n> >\n> >  using namespace libcamera;\n> >\n> > @@ -20,7 +23,7 @@ static struct {\n> >       /* Compressed */\n> >       { GST_VIDEO_FORMAT_ENCODED, formats::MJPEG },\n> >\n> > -     /* Bayer formats, gstreamer only supports 8-bit */\n> > +     /* Bayer formats */\n> >       { GST_VIDEO_FORMAT_ENCODED, formats::SBGGR8 },\n> >       { GST_VIDEO_FORMAT_ENCODED, formats::SGBRG8 },\n> >       { GST_VIDEO_FORMAT_ENCODED, formats::SGRBG8 },\n> > @@ -317,20 +320,15 @@ bare_structure_from_format(const PixelFormat &format)\n> >               return gst_structure_new(\"video/x-raw\", \"format\", G_TYPE_STRING,\n> >                                        gst_video_format_to_string(gst_format), nullptr);\n> >\n> > -     switch (format) {\n> > -     case formats::MJPEG:\n> > +     if (format == formats::MJPEG)\n> >               return gst_structure_new_empty(\"image/jpeg\");\n> >\n> > -     case formats::SBGGR8:\n> > -     case formats::SGBRG8:\n> > -     case formats::SGRBG8:\n> > -     case formats::SRGGB8:\n> > -             return gst_structure_new(\"video/x-bayer\", \"format\", G_TYPE_STRING,\n> > -                                      bayer_format_to_string(format), nullptr);\n> > -\n> > -     default:\n> > +     const gchar *s = bayer_format_to_string(format);\n> > +     if (s)\n> > +             return gst_structure_new(\"video/x-bayer\", \"format\",\n> > +                                      G_TYPE_STRING, s, nullptr);\n> > +     else\n> >               return nullptr;\n> > -     }\n> >  }\n> >\n> >  GstCaps *\n> > @@ -659,3 +657,39 @@ gst_libcamera_get_camera_manager(int &ret)\n> >\n> >       return cm;\n> >  }\n> > +\n> > +static const struct {\n> > +     Orientation orientation;\n> > +     GstVideoOrientationMethod method;\n> > +} orientation_map[]{\n> > +     { Orientation::Rotate0, GST_VIDEO_ORIENTATION_IDENTITY },\n> > +     { Orientation::Rotate90, GST_VIDEO_ORIENTATION_90R },\n> > +     { Orientation::Rotate180, GST_VIDEO_ORIENTATION_180 },\n> > +     { Orientation::Rotate270, GST_VIDEO_ORIENTATION_90L },\n> > +     { Orientation::Rotate0Mirror, GST_VIDEO_ORIENTATION_HORIZ },\n> > +     { Orientation::Rotate180Mirror, GST_VIDEO_ORIENTATION_VERT },\n> > +     { Orientation::Rotate90Mirror, GST_VIDEO_ORIENTATION_UL_LR },\n> > +     { Orientation::Rotate270Mirror, GST_VIDEO_ORIENTATION_UR_LL },\n> > +};\n> > +\n> > +Orientation\n> > +gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method)\n> > +{\n> > +     for (auto &b : orientation_map) {\n> > +             if (b.method == method)\n> > +                     return b.orientation;\n> > +     }\n> > +\n> > +     return Orientation::Rotate0;\n> > +}\n> > +\n> > +GstVideoOrientationMethod\n> > +libcamera_orientation_to_gst_video_orientation(Orientation orientation)\n> > +{\n> > +     for (auto &a : orientation_map) {\n> > +             if (a.orientation == orientation)\n> > +                     return a.method;\n> > +     }\n> > +\n> > +     return GST_VIDEO_ORIENTATION_IDENTITY;\n> > +}\n> > diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h\n> > index 5f4e8a0f..bbbd33db 100644\n> > --- a/src/gstreamer/gstlibcamera-utils.h\n> > +++ b/src/gstreamer/gstlibcamera-utils.h\n> > @@ -10,6 +10,7 @@\n> >\n> >  #include <libcamera/camera_manager.h>\n> >  #include <libcamera/controls.h>\n> > +#include <libcamera/orientation.h>\n> >  #include <libcamera/stream.h>\n> >\n> >  #include <gst/gst.h>\n> > @@ -92,3 +93,6 @@ public:\n> >  private:\n> >       GRecMutex *mutex_;\n> >  };\n> > +\n> > +libcamera::Orientation gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method);\n> > +GstVideoOrientationMethod libcamera_orientation_to_gst_video_orientation(libcamera::Orientation orientation);\n> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> > index 3aca4eed..85add936 100644\n> > --- a/src/gstreamer/gstlibcamerasrc.cpp\n> > +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> > @@ -29,6 +29,7 @@\n> >\n> >  #include <atomic>\n> >  #include <queue>\n> > +#include <sstream>\n> >  #include <tuple>\n> >  #include <utility>\n> >  #include <vector>\n> > @@ -38,6 +39,7 @@\n> >  #include <libcamera/control_ids.h>\n> >\n> >  #include <gst/base/base.h>\n> > +#include <gst/video/video.h>\n> >\n> >  #include \"gstlibcamera-controls.h\"\n> >  #include \"gstlibcamera-utils.h\"\n> > @@ -146,6 +148,7 @@ struct _GstLibcameraSrc {\n> >       GstTask *task;\n> >\n> >       gchar *camera_name;\n> > +     GstVideoOrientationMethod orientation;\n> >\n> >       std::atomic<GstEvent *> pending_eos;\n> >\n> > @@ -157,6 +160,7 @@ struct _GstLibcameraSrc {\n> >  enum {\n> >       PROP_0,\n> >       PROP_CAMERA_NAME,\n> > +     PROP_ORIENTATION,\n> >       PROP_LAST\n> >  };\n> >\n> > @@ -166,8 +170,8 @@ static void gst_libcamera_src_child_proxy_init(gpointer g_iface,\n> >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,\n> >                       G_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY,\n> >                                             gst_libcamera_src_child_proxy_init)\n> > -                     GST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> > -                                             \"libcamera Source\"))\n> > +                             GST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> > +                                                     \"libcamera Source\"))\n> >\n> >  #define TEMPLATE_CAPS GST_STATIC_CAPS(\"video/x-raw; image/jpeg; video/x-bayer\")\n> >\n> > @@ -225,8 +229,7 @@ int GstLibcameraSrcState::queueRequest()\n> >       return 0;\n> >  }\n> >\n> > -void\n> > -GstLibcameraSrcState::requestCompleted(Request *request)\n> > +void GstLibcameraSrcState::requestCompleted(Request *request)\n> >  {\n> >       GST_DEBUG_OBJECT(src_, \"buffers are ready\");\n> >\n> > @@ -616,9 +619,17 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> >               gst_libcamera_get_framerate_from_caps(caps, element_caps);\n> >       }\n> >\n> > +     /* Set orientation control. */\n> > +     state->config_->orientation = gst_video_orientation_to_libcamera_orientation(self->orientation);\n> > +\n> >       /* Validate the configuration. */\n> > -     if (state->config_->validate() == CameraConfiguration::Invalid)\n> > +     CameraConfiguration::Status status = state->config_->validate();\n> > +     if (status == CameraConfiguration::Invalid)\n> >               return false;\n> > +     else if (status == CameraConfiguration::Adjusted)\n> > +             GST_ELEMENT_INFO(self, RESOURCE, SETTINGS,\n> > +                              (\"Configuration was adjusted\"),\n> > +                              (\"CameraConfiguration::validate() returned CameraConfiguration::Adjusted\"));\n> >\n> >       int ret = state->cam_->configure(state->config_.get());\n> >       if (ret) {\n> > @@ -643,6 +654,10 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> >               g_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg, transfer[i]);\n> >               gst_libcamera_framerate_to_caps(caps, element_caps);\n> >\n> > +             if (status == CameraConfiguration::Adjusted &&\n> > +                 !gst_pad_peer_query_accept_caps(srcpad, caps))\n> > +                     return false;\n> > +\n> >               if (!gst_pad_push_event(srcpad, gst_event_new_caps(caps)))\n> >                       return false;\n> >       }\n> > @@ -730,7 +745,8 @@ gst_libcamera_src_task_run(gpointer user_data)\n> >               if (gst_pad_check_reconfigure(srcpad)) {\n> >                       /* Check if the caps even need changing. */\n> >                       g_autoptr(GstCaps) caps = gst_pad_get_current_caps(srcpad);\n> > -                     if (!gst_pad_peer_query_accept_caps(srcpad, caps)) {\n> > +                     g_autoptr(GstCaps) peercaps = gst_pad_peer_query_caps(srcpad, caps);\n> > +                     if (gst_caps_is_empty(peercaps)) {\n> >                               reconfigure = true;\n> >                               break;\n> >                       }\n> > @@ -926,6 +942,9 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id,\n> >               g_free(self->camera_name);\n> >               self->camera_name = g_value_dup_string(value);\n> >               break;\n> > +     case PROP_ORIENTATION:\n> > +             self->orientation = (GstVideoOrientationMethod)g_value_get_enum(value);\n> > +             break;\n> >       default:\n> >               if (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec))\n> >                       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> > @@ -945,6 +964,9 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,\n> >       case PROP_CAMERA_NAME:\n> >               g_value_set_string(value, self->camera_name);\n> >               break;\n> > +     case PROP_ORIENTATION:\n> > +             g_value_set_enum(value, (gint)self->orientation);\n> > +             break;\n> >       default:\n> >               if (!state->controls_.getProperty(prop_id - PROP_LAST, value, pspec))\n> >                       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> > @@ -1148,12 +1170,16 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >\n> >       GParamSpec *spec = g_param_spec_string(\"camera-name\", \"Camera Name\",\n> >                                              \"Select by name which camera to use.\", nullptr,\n> > -                                            (GParamFlags)(GST_PARAM_MUTABLE_READY\n> > -                                                          | G_PARAM_CONSTRUCT\n> > -                                                          | G_PARAM_READWRITE\n> > -                                                          | G_PARAM_STATIC_STRINGS));\n> > +                                            (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> >       g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);\n> >\n> > +     /* Register the orientation enum type. */\n> > +     spec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> > +                              \"Select the orientation of the camera.\",\n> > +                              GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,\n> > +                              (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> > +     g_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> > +\n> >       GstCameraControls::installProperties(object_class, PROP_LAST);\n> >  }\n> >\n> > --\n> > 2.43.0\n> >","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 70431C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Jul 2025 22:13:01 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D6721691C3;\n\tTue, 29 Jul 2025 00:12:59 +0200 (CEST)","from mail-il1-x12e.google.com (mail-il1-x12e.google.com\n\t[IPv6:2607:f8b0:4864:20::12e])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 754EB69080\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Jul 2025 00:12:55 +0200 (CEST)","by mail-il1-x12e.google.com with SMTP id\n\te9e14a558f8ab-3e3d238b3a7so31480405ab.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Jul 2025 15:12:55 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"AWbwWVMP\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=gmail.com; s=20230601; t=1753740774; x=1754345574;\n\tdarn=lists.libcamera.org; \n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:from:to:cc:subject:date:message-id:reply-to;\n\tbh=E0aOo2mOjeiIfyGghDwZe9T47eTjWRQKbMGzc8wdQSQ=;\n\tb=AWbwWVMPxLTaCsREIJfIPhdsWA43PeOWcXsNJgDFU3HICWwJe2yBGo/OWEOPaYUZqN\n\twwix1px+asnHSrddFI88KUFhZc5rElQqnLoQ6clCmb30F8W2gZPuj5otlcVK9C7EHIT9\n\t+mYmpg+61458WDEGYlfoU8L6Kk86Nc9jOca0nJDgqMH6ooKFHGiqKqTFEJdIpDuqZU0U\n\t68U0WjBhQiuudz5BmvsNBlHaXy9d+sGzrCGzEKmcHOoKPa2qkOgvgmfuETpIJCC+RExA\n\tQIjMsvQD4MUZjFsmp7ZOJ16t/tAjdYFX+ZKtHFDDG40BAguLMOHSe2SEyZPLPV/8edyn\n\tAZrQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1753740774; x=1754345574;\n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=E0aOo2mOjeiIfyGghDwZe9T47eTjWRQKbMGzc8wdQSQ=;\n\tb=gK6Kfqvm07/6j4WnAAhEz9UyFXlM92Zdj51eb2TigsDESNtyZ/onONWwegrNvl1uEl\n\tpaGSnir6LeGXPFBKeleWnwDkCWEVvM8cYhWqWPeNwBbAnlSVtatc3UbVHhB4+qCKEmgr\n\teITmNkYTqM6oeA04sLWvvf8EVCp5ZWqSKDwpUwCl6osUbBeZH9GAwcaDP2t9Tj3EessI\n\t+n9DykC3jvvRLBotMkCZtCxMQDIPjaAIF/ey9hMDSSCrnPxageM4grsFkevGjUAa2puC\n\tF6Gb5lfUJAGBMw8txHczf6xPcbaDgL31BS+PXifwdj6XTCv0TRVcgPMlrLN78wRjugjQ\n\tntxw==","X-Gm-Message-State":"AOJu0Yz62pzEM1pks/JX13LUk/pZKsdBuOuTsIGyQOwRktkeCfUBBgTf\n\tFeu7+tlWwNb/K7v3q5BRHXt3ao8OEzAEU2Ir+7QUlimPbn7DMQTySLmslXwQZvGV9jhOGLOvakb\n\t0LVtHWHRd3Q1sJ6cDbOz1tRYAkwJIP3DX3PKOk4I=","X-Gm-Gg":"ASbGncuO1o8Vc3OKKGTLAUi4jUPiOvTyppJRSGWVMhYXPwR4xHKhbBk6sbhWvBHUnd0\n\td1gyU2TG/BWlTX8ZWK+upZCZ1kFJl9HYO6zC4Er3mC7KmWPBFZXOeLpaamrUJmuAdtQFUeRrsE5\n\t0ezB144YVoBwVeOIw+xKCvfNokSXwKkdQ5kJPHUtp1Dr7vmEie2ouZ25xdJ9B6GL2gGcQ3nWaAU\n\twyNcaC3","X-Google-Smtp-Source":"AGHT+IFEYygatLsGtkqc48lhAeIvOy/EAnVsDEfayUlCLw9E5THSMgckmMQGFqDUMQLPehX5nEGxdBAN/6r0nKmWRUg=","X-Received":"by 2002:a05:6e02:300a:b0:3dd:be49:9278 with SMTP id\n\te9e14a558f8ab-3e3c5110919mr202943255ab.0.1753740773667;\n\tMon, 28 Jul 2025 15:12:53 -0700 (PDT)","MIME-Version":"1.0","References":"<20250725115602.1477743-1-giacomo.cappellini.87@gmail.com>\n\t<20250725115602.1477743-2-giacomo.cappellini.87@gmail.com>\n\t<zsdwyphnk2bvchbxxzy25y3p7quoatt6xb7sj375tde46wrq5i@wmeee4hxc2vg>","In-Reply-To":"<zsdwyphnk2bvchbxxzy25y3p7quoatt6xb7sj375tde46wrq5i@wmeee4hxc2vg>","From":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>","Date":"Tue, 29 Jul 2025 00:12:42 +0200","X-Gm-Features":"Ac12FXy_c1VyylA4E9nUmRia5WZsGWBxKnFced7hMpQviMV8ydhSyQp9I38ApwY","Message-ID":"<CABXJd1n7Jsuk+dbc3oeywzGtuo1M+sC=Ubx6RoN-iT8_YZsXMw@mail.gmail.com>","Subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","To":"Umang Jain <uajain@igalia.com>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"UTF-8\"","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35223,"web_url":"https://patchwork.libcamera.org/comment/35223/","msgid":"<CABXJd1keTqKWihs_v7u=6rObk-Oz3YKFg1tPyyiWVr1KhG59=Q@mail.gmail.com>","date":"2025-07-28T22:15:34","subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","submitter":{"id":231,"url":"https://patchwork.libcamera.org/api/people/231/","name":"Giacomo Cappellini","email":"giacomo.cappellini.87@gmail.com"},"content":"Hi Nicolas,\n\nas Umang Jain pointed out in previous mail I did the \"send your patch\non top of the other series\" wrong, so you're been commenting on code\nthat if for the most part of another patch (please check the cover\nletter). I'll comment only on the point relevant to my patch and send\nrenamed property with V5.\n\nIl giorno lun 28 lug 2025 alle ore 23:27 Nicolas Dufresne\n<nicolas@ndufresne.ca> ha scritto:\n>\n> Hi,\n>\n> Le vendredi 25 juillet 2025 à 13:30 +0200, Giacomo Cappellini a écrit :\n> > libcamera allows to control the images orientation through the\n> > CameraConfiguration::orientation field, expose a GST_PARAM_MUTABLE_READY\n> > parameter of type GstVideoOrientationMethod in GstLibcameraSrc to\n> > control it. Parameter is mapped internally to libcamera::Orientation via\n> > new gstlibcamera-utils functions:\n> > - gst_video_orientation_to_libcamera_orientation\n> > - libcamera_orientation_to_gst_video_orientation\n> >\n> > Signed-off-by: Giacomo Cappellini <giacomo.cappellini.87@gmail.com>\n> > ---\n> >  src/gstreamer/gstlibcamera-utils.cpp | 58 ++++++++++++++++++++++------\n> >  src/gstreamer/gstlibcamera-utils.h   |  4 ++\n> >  src/gstreamer/gstlibcamerasrc.cpp    | 46 +++++++++++++++++-----\n> >  3 files changed, 86 insertions(+), 22 deletions(-)\n> >\n> > diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\n> > index a548b0c1..15069f98 100644\n> > --- a/src/gstreamer/gstlibcamera-utils.cpp\n> > +++ b/src/gstreamer/gstlibcamera-utils.cpp\n> > @@ -10,6 +10,9 @@\n> >\n> >  #include <libcamera/control_ids.h>\n> >  #include <libcamera/formats.h>\n> > +#include <libcamera/orientation.h>\n> > +\n> > +#include <gst/video/video.h>\n> >\n> >  using namespace libcamera;\n> >\n> > @@ -20,7 +23,7 @@ static struct {\n> >       /* Compressed */\n> >       { GST_VIDEO_FORMAT_ENCODED, formats::MJPEG },\n> >\n> > -     /* Bayer formats, gstreamer only supports 8-bit */\n> > +     /* Bayer formats */\n>\n> Unrelated changes, but valid, what about giving it its own commit ?\n>\n> >       { GST_VIDEO_FORMAT_ENCODED, formats::SBGGR8 },\n> >       { GST_VIDEO_FORMAT_ENCODED, formats::SGBRG8 },\n> >       { GST_VIDEO_FORMAT_ENCODED, formats::SGRBG8 },\n> > @@ -317,20 +320,15 @@ bare_structure_from_format(const PixelFormat &format)\n> >               return gst_structure_new(\"video/x-raw\", \"format\", G_TYPE_STRING,\n> >                                        gst_video_format_to_string(gst_format), nullptr);\n> >\n> > -     switch (format) {\n> > -     case formats::MJPEG:\n> > +     if (format == formats::MJPEG)\n> >               return gst_structure_new_empty(\"image/jpeg\");\n> >\n> > -     case formats::SBGGR8:\n> > -     case formats::SGBRG8:\n> > -     case formats::SGRBG8:\n> > -     case formats::SRGGB8:\n> > -             return gst_structure_new(\"video/x-bayer\", \"format\", G_TYPE_STRING,\n> > -                                      bayer_format_to_string(format), nullptr);\n> > -\n> > -     default:\n> > +     const gchar *s = bayer_format_to_string(format);\n> > +     if (s)\n> > +             return gst_structure_new(\"video/x-bayer\", \"format\",\n> > +                                      G_TYPE_STRING, s, nullptr);\n> > +     else\n> >               return nullptr;\n>\n> Same, please dedicate a patch for that.\n>\n> > -     }\n> >  }\n> >\n> >  GstCaps *\n> > @@ -659,3 +657,39 @@ gst_libcamera_get_camera_manager(int &ret)\n> >\n> >       return cm;\n> >  }\n> > +\n> > +static const struct {\n> > +     Orientation orientation;\n> > +     GstVideoOrientationMethod method;\n> > +} orientation_map[]{\n> > +     { Orientation::Rotate0, GST_VIDEO_ORIENTATION_IDENTITY },\n> > +     { Orientation::Rotate90, GST_VIDEO_ORIENTATION_90R },\n> > +     { Orientation::Rotate180, GST_VIDEO_ORIENTATION_180 },\n> > +     { Orientation::Rotate270, GST_VIDEO_ORIENTATION_90L },\n> > +     { Orientation::Rotate0Mirror, GST_VIDEO_ORIENTATION_HORIZ },\n> > +     { Orientation::Rotate180Mirror, GST_VIDEO_ORIENTATION_VERT },\n> > +     { Orientation::Rotate90Mirror, GST_VIDEO_ORIENTATION_UL_LR },\n> > +     { Orientation::Rotate270Mirror, GST_VIDEO_ORIENTATION_UR_LL },\n> > +};\n> > +\n> > +Orientation\n> > +gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method)\n> > +{\n> > +     for (auto &b : orientation_map) {\n> > +             if (b.method == method)\n> > +                     return b.orientation;\n> > +     }\n> > +\n> > +     return Orientation::Rotate0;\n> > +}\n> > +\n> > +GstVideoOrientationMethod\n> > +libcamera_orientation_to_gst_video_orientation(Orientation orientation)\n> > +{\n> > +     for (auto &a : orientation_map) {\n> > +             if (a.orientation == orientation)\n> > +                     return a.method;\n> > +     }\n> > +\n> > +     return GST_VIDEO_ORIENTATION_IDENTITY;\n> > +}\n> > diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h\n> > index 5f4e8a0f..bbbd33db 100644\n> > --- a/src/gstreamer/gstlibcamera-utils.h\n> > +++ b/src/gstreamer/gstlibcamera-utils.h\n> > @@ -10,6 +10,7 @@\n> >\n> >  #include <libcamera/camera_manager.h>\n> >  #include <libcamera/controls.h>\n> > +#include <libcamera/orientation.h>\n> >  #include <libcamera/stream.h>\n> >\n> >  #include <gst/gst.h>\n> > @@ -92,3 +93,6 @@ public:\n> >  private:\n> >       GRecMutex *mutex_;\n> >  };\n> > +\n> > +libcamera::Orientation gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method);\n> > +GstVideoOrientationMethod libcamera_orientation_to_gst_video_orientation(libcamera::Orientation orientation);\n> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> > index 3aca4eed..85add936 100644\n> > --- a/src/gstreamer/gstlibcamerasrc.cpp\n> > +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> > @@ -29,6 +29,7 @@\n> >\n> >  #include <atomic>\n> >  #include <queue>\n> > +#include <sstream>\n> >  #include <tuple>\n> >  #include <utility>\n> >  #include <vector>\n> > @@ -38,6 +39,7 @@\n> >  #include <libcamera/control_ids.h>\n> >\n> >  #include <gst/base/base.h>\n> > +#include <gst/video/video.h>\n> >\n> >  #include \"gstlibcamera-controls.h\"\n> >  #include \"gstlibcamera-utils.h\"\n> > @@ -146,6 +148,7 @@ struct _GstLibcameraSrc {\n> >       GstTask *task;\n> >\n> >       gchar *camera_name;\n> > +     GstVideoOrientationMethod orientation;\n> >\n> >       std::atomic<GstEvent *> pending_eos;\n> >\n> > @@ -157,6 +160,7 @@ struct _GstLibcameraSrc {\n> >  enum {\n> >       PROP_0,\n> >       PROP_CAMERA_NAME,\n> > +     PROP_ORIENTATION,\n> >       PROP_LAST\n> >  };\n> >\n> > @@ -166,8 +170,8 @@ static void gst_libcamera_src_child_proxy_init(gpointer g_iface,\n> >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,\n> >                       G_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY,\n> >                                             gst_libcamera_src_child_proxy_init)\n> > -                     GST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> > -                                             \"libcamera Source\"))\n> > +                             GST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> > +                                                     \"libcamera Source\"))\n>\n> Not sure why this change, it looked better before.\n>\n> >\n> >  #define TEMPLATE_CAPS GST_STATIC_CAPS(\"video/x-raw; image/jpeg; video/x-bayer\")\n> >\n> > @@ -225,8 +229,7 @@ int GstLibcameraSrcState::queueRequest()\n> >       return 0;\n> >  }\n> >\n> > -void\n> > -GstLibcameraSrcState::requestCompleted(Request *request)\n> > +void GstLibcameraSrcState::requestCompleted(Request *request)\n>\n> Was GStreamer style, but at the same time, don't do style changes mixed with\n> your functional changes.\n>\n> >  {\n> >       GST_DEBUG_OBJECT(src_, \"buffers are ready\");\n> >\n> > @@ -616,9 +619,17 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> >               gst_libcamera_get_framerate_from_caps(caps, element_caps);\n> >       }\n> >\n> > +     /* Set orientation control. */\n> > +     state->config_->orientation = gst_video_orientation_to_libcamera_orientation(self->orientation);\n> > +\n> >       /* Validate the configuration. */\n> > -     if (state->config_->validate() == CameraConfiguration::Invalid)\n> > +     CameraConfiguration::Status status = state->config_->validate();\n> > +     if (status == CameraConfiguration::Invalid)\n> >               return false;\n> > +     else if (status == CameraConfiguration::Adjusted)\n> > +             GST_ELEMENT_INFO(self, RESOURCE, SETTINGS,\n> > +                              (\"Configuration was adjusted\"),\n> > +                              (\"CameraConfiguration::validate() returned CameraConfiguration::Adjusted\"));\n>\n> Not sure this is worth a message to the application using the bus.\n>\n> >\n> >       int ret = state->cam_->configure(state->config_.get());\n> >       if (ret) {\n> > @@ -643,6 +654,10 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> >               g_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg, transfer[i]);\n> >               gst_libcamera_framerate_to_caps(caps, element_caps);\n> >\n> > +             if (status == CameraConfiguration::Adjusted &&\n> > +                 !gst_pad_peer_query_accept_caps(srcpad, caps))\n> > +                     return false;\n>\n> Fair enough, this could though be done as its own patch, since it is valid\n> without the orientation. In fact, orientation is not part of the caps.\n>\n> > +\n> >               if (!gst_pad_push_event(srcpad, gst_event_new_caps(caps)))\n> >                       return false;\n> >       }\n> > @@ -730,7 +745,8 @@ gst_libcamera_src_task_run(gpointer user_data)\n> >               if (gst_pad_check_reconfigure(srcpad)) {\n> >                       /* Check if the caps even need changing. */\n> >                       g_autoptr(GstCaps) caps = gst_pad_get_current_caps(srcpad);\n> > -                     if (!gst_pad_peer_query_accept_caps(srcpad, caps)) {\n> > +                     g_autoptr(GstCaps) peercaps = gst_pad_peer_query_caps(srcpad, caps);\n> > +                     if (gst_caps_is_empty(peercaps)) {\n>\n> This patch I've seen as its own in some other submission, please drop.\n>\n> >                               reconfigure = true;\n> >                               break;\n> >                       }\n> > @@ -926,6 +942,9 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id,\n> >               g_free(self->camera_name);\n> >               self->camera_name = g_value_dup_string(value);\n> >               break;\n> > +     case PROP_ORIENTATION:\n> > +             self->orientation = (GstVideoOrientationMethod)g_value_get_enum(value);\n> > +             break;\n> >       default:\n> >               if (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec))\n> >                       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> > @@ -945,6 +964,9 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,\n> >       case PROP_CAMERA_NAME:\n> >               g_value_set_string(value, self->camera_name);\n> >               break;\n> > +     case PROP_ORIENTATION:\n> > +             g_value_set_enum(value, (gint)self->orientation);\n> > +             break;\n> >       default:\n> >               if (!state->controls_.getProperty(prop_id - PROP_LAST, value, pspec))\n> >                       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> > @@ -1148,12 +1170,16 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >\n> >       GParamSpec *spec = g_param_spec_string(\"camera-name\", \"Camera Name\",\n> >                                              \"Select by name which camera to use.\", nullptr,\n> > -                                            (GParamFlags)(GST_PARAM_MUTABLE_READY\n> > -                                                          | G_PARAM_CONSTRUCT\n> > -                                                          | G_PARAM_READWRITE\n> > -                                                          | G_PARAM_STATIC_STRINGS));\n> > +                                            (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n>\n> Looked fine before, and was accepted as such.\n>\n> >       g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);\n> >\n> > +     /* Register the orientation enum type. */\n> > +     spec = g_param_spec_enum(\"orientation\", \"Orientation\",\n>\n> Is the name \"orientation\" proper ? In the wilderness of GStremer, I see rotate-\n> method (glimagesink), video-direction (videoflip), I'd pick one of these.\n>\n> > +                              \"Select the orientation of the camera.\",\n> > +                              GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,\n> > +                              (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> > +     g_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> > +\n> >       GstCameraControls::installProperties(object_class, PROP_LAST);\n> >  }\n> >\n\nI've been naming it orientation to discriminate it from rotation in\nlibcamera terms, as GStreamer (as you said) has no clear property name\nfor that.\nIf you agree on following one of the existing GStreamer property names\nI'd vote for video-direction one of the videoflip element? Would you\nagree?\n\n> cheers,\n> Nicolas\n\nBest Regards,\nG.C.","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id DEC9DBDCC1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Jul 2025 22:15:55 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 160A269080;\n\tTue, 29 Jul 2025 00:15:55 +0200 (CEST)","from mail-io1-xd29.google.com (mail-io1-xd29.google.com\n\t[IPv6:2607:f8b0:4864:20::d29])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4D3F769080\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Jul 2025 00:15:48 +0200 (CEST)","by mail-io1-xd29.google.com with SMTP id\n\tca18e2360f4ac-87c32f46253so153440239f.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Jul 2025 15:15:48 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"SRtVzZp/\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=gmail.com; s=20230601; t=1753740947; x=1754345747;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=dn2bp23G+QdF47qVFuGIfpJn2mZoK5CNBtYtHgCQj2A=;\n\tb=SRtVzZp/p4e+ARtTnltP5AteJ0uqfUTmsNTGtC840uAEiul4C/OzjRJUmU3vWBjUXe\n\tU1COsbyTwIf5JgBlzTt6KTb96qOxYuFeWA1Tyao2HFfuHsSzTkenengChNFtE1Eb2J+I\n\tjnFa8sSuE3h/KOplBH3mXlhtsSOQoMcLt3Q6l2JwKPGK6yOtX6KFrFGznHp+i55sZQ8f\n\tkxb6QdrlchbGVSaWviTTojbzO0F3rnEdSSjfMuH4QkX6K348u0157gVcZJ5I/ikzv34w\n\tJrWS5z8a0hpYilN3pOFl9j5WZOqCzYa6uiw3DjyfUrt6X5BWLAAJ2lAzJe1VRLdtwQzk\n\tZiTw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1753740947; x=1754345747;\n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=dn2bp23G+QdF47qVFuGIfpJn2mZoK5CNBtYtHgCQj2A=;\n\tb=r/D13xgc/MdPbkLqUb8Or1lzEcQy8PsYjtuVxbzlIvShJXQ8TVjfUSpnb+zd3+nwva\n\t9LYVRS8t4y/2sWvAVig97zUvwB+uTx3oHJq7y6Oj0EU2jy8oWXUePt6RXgtTn6NK6hKs\n\tSqW3GDnzfC/a891lGEOQIAkXLEQ3JYv/yiFarTr72RKNMEUsTiz6N7/m0AqDLV5fxgfu\n\txJo5xUs03Y+Hu0MvUc2M23HHIcFW7DMN/WdRGLZtW3Vo4jP7V+nBCP7dvfVRQfjkDzV7\n\t7R/f/uWuBu8EOUOKysr1yF7PxhOFOSFKOmJP9uf1MfVa817W8JdMt3JKBGwimkk3pd/u\n\tl8Eg==","X-Gm-Message-State":"AOJu0Yx5voqVeuZeaxYGFdBmUfl7/TPGAuJqMXJtoOv9/Mb1dIJGz8cA\n\tPifh+OGnNL/MRm5UAevYoLviFdcRXxDWHpd7wvnUUnf0N2WzXoOdowzV6jOqtc+RAnjmbDqkKp1\n\tXboT9P/H85HE8+6ZN24GfrNgyiB6JxJA=","X-Gm-Gg":"ASbGncvRG8Uu/MmPy4RYXw03R3LX6RdzZf5+nWtSWCZ0Zd5xyrAbIS8L41uA+PmFu0C\n\t+RdDEPC0+YIqDt54/F2eEy/QDuMpptv9nvp0Fedd76scOnG+BPi1jpgXf7ZlnxfI2Z/XmntNfSx\n\t8OEdsyrdy/86U/MGjQX8v69ZLThI02jox7eIQpdAakYCVrFQTfPu/keIfj9b/6ueDvW50qvVQh7\n\tGX8VHtH","X-Google-Smtp-Source":"AGHT+IFJM1GXhkZpieD+26Ad4yfMmqyyses/NBRYOysH3SM4fbWE6vdBfwPNX7HM1ih6eRKFBUrD3Mr8W1y1a6d6w1c=","X-Received":"by 2002:a05:6e02:2510:b0:3e2:91bb:c075 with SMTP id\n\te9e14a558f8ab-3e3c535624dmr242486505ab.22.1753740946846;\n\tMon, 28 Jul 2025 15:15:46 -0700 (PDT)","MIME-Version":"1.0","References":"<20250725115602.1477743-1-giacomo.cappellini.87@gmail.com>\n\t<20250725115602.1477743-2-giacomo.cappellini.87@gmail.com>\n\t<f87475ab9bafe0e57abad2d3f857b3df623c7316.camel@ndufresne.ca>","In-Reply-To":"<f87475ab9bafe0e57abad2d3f857b3df623c7316.camel@ndufresne.ca>","From":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>","Date":"Tue, 29 Jul 2025 00:15:34 +0200","X-Gm-Features":"Ac12FXwNK_vL8fYE_r1DY9H7ezKXbQQ2fWFIaJorwEXz7Y2PZiTyJOgBi45zXPM","Message-ID":"<CABXJd1keTqKWihs_v7u=6rObk-Oz3YKFg1tPyyiWVr1KhG59=Q@mail.gmail.com>","Subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","To":"Nicolas Dufresne <nicolas@ndufresne.ca>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35594,"web_url":"https://patchwork.libcamera.org/comment/35594/","msgid":"<2d3fbk3xfz6xizcftc3vsf3uelkpxo53n5en3ejrsy5j7iscv5@o7iqkvkiobel>","date":"2025-08-27T15:48:11","subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","submitter":{"id":232,"url":"https://patchwork.libcamera.org/api/people/232/","name":"Umang Jain","email":"uajain@igalia.com"},"content":"Hi Giaco,\n\nOn Tue, Jul 29, 2025 at 12:15:34AM +0200, Giacomo Cappellini wrote:\n> Hi Nicolas,\n> \n> as Umang Jain pointed out in previous mail I did the \"send your patch\n> on top of the other series\" wrong, so you're been commenting on code\n> that if for the most part of another patch (please check the cover\n> letter). I'll comment only on the point relevant to my patch and send\n> renamed property with V5.\n\nDo you plan to send v5? Hopefully rebased over the latest master.\n\n> \n> Il giorno lun 28 lug 2025 alle ore 23:27 Nicolas Dufresne\n> <nicolas@ndufresne.ca> ha scritto:\n> >\n> > Hi,\n> >\n> > Le vendredi 25 juillet 2025 à 13:30 +0200, Giacomo Cappellini a écrit :\n> > > libcamera allows to control the images orientation through the\n> > > CameraConfiguration::orientation field, expose a GST_PARAM_MUTABLE_READY\n> > > parameter of type GstVideoOrientationMethod in GstLibcameraSrc to\n> > > control it. Parameter is mapped internally to libcamera::Orientation via\n> > > new gstlibcamera-utils functions:\n> > > - gst_video_orientation_to_libcamera_orientation\n> > > - libcamera_orientation_to_gst_video_orientation\n> > >\n> > > Signed-off-by: Giacomo Cappellini <giacomo.cappellini.87@gmail.com>\n> > > ---\n> > >  src/gstreamer/gstlibcamera-utils.cpp | 58 ++++++++++++++++++++++------\n> > >  src/gstreamer/gstlibcamera-utils.h   |  4 ++\n> > >  src/gstreamer/gstlibcamerasrc.cpp    | 46 +++++++++++++++++-----\n> > >  3 files changed, 86 insertions(+), 22 deletions(-)\n> > >\n> > > diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\n> > > index a548b0c1..15069f98 100644\n> > > --- a/src/gstreamer/gstlibcamera-utils.cpp\n> > > +++ b/src/gstreamer/gstlibcamera-utils.cpp\n> > > @@ -10,6 +10,9 @@\n> > >\n> > >  #include <libcamera/control_ids.h>\n> > >  #include <libcamera/formats.h>\n> > > +#include <libcamera/orientation.h>\n> > > +\n> > > +#include <gst/video/video.h>\n> > >\n> > >  using namespace libcamera;\n> > >\n> > > @@ -20,7 +23,7 @@ static struct {\n> > >       /* Compressed */\n> > >       { GST_VIDEO_FORMAT_ENCODED, formats::MJPEG },\n> > >\n> > > -     /* Bayer formats, gstreamer only supports 8-bit */\n> > > +     /* Bayer formats */\n> >\n> > Unrelated changes, but valid, what about giving it its own commit ?\n> >\n> > >       { GST_VIDEO_FORMAT_ENCODED, formats::SBGGR8 },\n> > >       { GST_VIDEO_FORMAT_ENCODED, formats::SGBRG8 },\n> > >       { GST_VIDEO_FORMAT_ENCODED, formats::SGRBG8 },\n> > > @@ -317,20 +320,15 @@ bare_structure_from_format(const PixelFormat &format)\n> > >               return gst_structure_new(\"video/x-raw\", \"format\", G_TYPE_STRING,\n> > >                                        gst_video_format_to_string(gst_format), nullptr);\n> > >\n> > > -     switch (format) {\n> > > -     case formats::MJPEG:\n> > > +     if (format == formats::MJPEG)\n> > >               return gst_structure_new_empty(\"image/jpeg\");\n> > >\n> > > -     case formats::SBGGR8:\n> > > -     case formats::SGBRG8:\n> > > -     case formats::SGRBG8:\n> > > -     case formats::SRGGB8:\n> > > -             return gst_structure_new(\"video/x-bayer\", \"format\", G_TYPE_STRING,\n> > > -                                      bayer_format_to_string(format), nullptr);\n> > > -\n> > > -     default:\n> > > +     const gchar *s = bayer_format_to_string(format);\n> > > +     if (s)\n> > > +             return gst_structure_new(\"video/x-bayer\", \"format\",\n> > > +                                      G_TYPE_STRING, s, nullptr);\n> > > +     else\n> > >               return nullptr;\n> >\n> > Same, please dedicate a patch for that.\n> >\n> > > -     }\n> > >  }\n> > >\n> > >  GstCaps *\n> > > @@ -659,3 +657,39 @@ gst_libcamera_get_camera_manager(int &ret)\n> > >\n> > >       return cm;\n> > >  }\n> > > +\n> > > +static const struct {\n> > > +     Orientation orientation;\n> > > +     GstVideoOrientationMethod method;\n> > > +} orientation_map[]{\n> > > +     { Orientation::Rotate0, GST_VIDEO_ORIENTATION_IDENTITY },\n> > > +     { Orientation::Rotate90, GST_VIDEO_ORIENTATION_90R },\n> > > +     { Orientation::Rotate180, GST_VIDEO_ORIENTATION_180 },\n> > > +     { Orientation::Rotate270, GST_VIDEO_ORIENTATION_90L },\n> > > +     { Orientation::Rotate0Mirror, GST_VIDEO_ORIENTATION_HORIZ },\n> > > +     { Orientation::Rotate180Mirror, GST_VIDEO_ORIENTATION_VERT },\n> > > +     { Orientation::Rotate90Mirror, GST_VIDEO_ORIENTATION_UL_LR },\n> > > +     { Orientation::Rotate270Mirror, GST_VIDEO_ORIENTATION_UR_LL },\n> > > +};\n> > > +\n> > > +Orientation\n> > > +gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method)\n> > > +{\n> > > +     for (auto &b : orientation_map) {\n> > > +             if (b.method == method)\n> > > +                     return b.orientation;\n> > > +     }\n> > > +\n> > > +     return Orientation::Rotate0;\n> > > +}\n> > > +\n> > > +GstVideoOrientationMethod\n> > > +libcamera_orientation_to_gst_video_orientation(Orientation orientation)\n> > > +{\n> > > +     for (auto &a : orientation_map) {\n> > > +             if (a.orientation == orientation)\n> > > +                     return a.method;\n> > > +     }\n> > > +\n> > > +     return GST_VIDEO_ORIENTATION_IDENTITY;\n> > > +}\n> > > diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h\n> > > index 5f4e8a0f..bbbd33db 100644\n> > > --- a/src/gstreamer/gstlibcamera-utils.h\n> > > +++ b/src/gstreamer/gstlibcamera-utils.h\n> > > @@ -10,6 +10,7 @@\n> > >\n> > >  #include <libcamera/camera_manager.h>\n> > >  #include <libcamera/controls.h>\n> > > +#include <libcamera/orientation.h>\n> > >  #include <libcamera/stream.h>\n> > >\n> > >  #include <gst/gst.h>\n> > > @@ -92,3 +93,6 @@ public:\n> > >  private:\n> > >       GRecMutex *mutex_;\n> > >  };\n> > > +\n> > > +libcamera::Orientation gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method);\n> > > +GstVideoOrientationMethod libcamera_orientation_to_gst_video_orientation(libcamera::Orientation orientation);\n> > > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> > > index 3aca4eed..85add936 100644\n> > > --- a/src/gstreamer/gstlibcamerasrc.cpp\n> > > +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> > > @@ -29,6 +29,7 @@\n> > >\n> > >  #include <atomic>\n> > >  #include <queue>\n> > > +#include <sstream>\n> > >  #include <tuple>\n> > >  #include <utility>\n> > >  #include <vector>\n> > > @@ -38,6 +39,7 @@\n> > >  #include <libcamera/control_ids.h>\n> > >\n> > >  #include <gst/base/base.h>\n> > > +#include <gst/video/video.h>\n> > >\n> > >  #include \"gstlibcamera-controls.h\"\n> > >  #include \"gstlibcamera-utils.h\"\n> > > @@ -146,6 +148,7 @@ struct _GstLibcameraSrc {\n> > >       GstTask *task;\n> > >\n> > >       gchar *camera_name;\n> > > +     GstVideoOrientationMethod orientation;\n> > >\n> > >       std::atomic<GstEvent *> pending_eos;\n> > >\n> > > @@ -157,6 +160,7 @@ struct _GstLibcameraSrc {\n> > >  enum {\n> > >       PROP_0,\n> > >       PROP_CAMERA_NAME,\n> > > +     PROP_ORIENTATION,\n> > >       PROP_LAST\n> > >  };\n> > >\n> > > @@ -166,8 +170,8 @@ static void gst_libcamera_src_child_proxy_init(gpointer g_iface,\n> > >  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,\n> > >                       G_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY,\n> > >                                             gst_libcamera_src_child_proxy_init)\n> > > -                     GST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> > > -                                             \"libcamera Source\"))\n> > > +                             GST_DEBUG_CATEGORY_INIT(source_debug, \"libcamerasrc\", 0,\n> > > +                                                     \"libcamera Source\"))\n> >\n> > Not sure why this change, it looked better before.\n> >\n> > >\n> > >  #define TEMPLATE_CAPS GST_STATIC_CAPS(\"video/x-raw; image/jpeg; video/x-bayer\")\n> > >\n> > > @@ -225,8 +229,7 @@ int GstLibcameraSrcState::queueRequest()\n> > >       return 0;\n> > >  }\n> > >\n> > > -void\n> > > -GstLibcameraSrcState::requestCompleted(Request *request)\n> > > +void GstLibcameraSrcState::requestCompleted(Request *request)\n> >\n> > Was GStreamer style, but at the same time, don't do style changes mixed with\n> > your functional changes.\n> >\n> > >  {\n> > >       GST_DEBUG_OBJECT(src_, \"buffers are ready\");\n> > >\n> > > @@ -616,9 +619,17 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> > >               gst_libcamera_get_framerate_from_caps(caps, element_caps);\n> > >       }\n> > >\n> > > +     /* Set orientation control. */\n> > > +     state->config_->orientation = gst_video_orientation_to_libcamera_orientation(self->orientation);\n> > > +\n> > >       /* Validate the configuration. */\n> > > -     if (state->config_->validate() == CameraConfiguration::Invalid)\n> > > +     CameraConfiguration::Status status = state->config_->validate();\n> > > +     if (status == CameraConfiguration::Invalid)\n> > >               return false;\n> > > +     else if (status == CameraConfiguration::Adjusted)\n> > > +             GST_ELEMENT_INFO(self, RESOURCE, SETTINGS,\n> > > +                              (\"Configuration was adjusted\"),\n> > > +                              (\"CameraConfiguration::validate() returned CameraConfiguration::Adjusted\"));\n> >\n> > Not sure this is worth a message to the application using the bus.\n> >\n> > >\n> > >       int ret = state->cam_->configure(state->config_.get());\n> > >       if (ret) {\n> > > @@ -643,6 +654,10 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> > >               g_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg, transfer[i]);\n> > >               gst_libcamera_framerate_to_caps(caps, element_caps);\n> > >\n> > > +             if (status == CameraConfiguration::Adjusted &&\n> > > +                 !gst_pad_peer_query_accept_caps(srcpad, caps))\n> > > +                     return false;\n> >\n> > Fair enough, this could though be done as its own patch, since it is valid\n> > without the orientation. In fact, orientation is not part of the caps.\n> >\n> > > +\n> > >               if (!gst_pad_push_event(srcpad, gst_event_new_caps(caps)))\n> > >                       return false;\n> > >       }\n> > > @@ -730,7 +745,8 @@ gst_libcamera_src_task_run(gpointer user_data)\n> > >               if (gst_pad_check_reconfigure(srcpad)) {\n> > >                       /* Check if the caps even need changing. */\n> > >                       g_autoptr(GstCaps) caps = gst_pad_get_current_caps(srcpad);\n> > > -                     if (!gst_pad_peer_query_accept_caps(srcpad, caps)) {\n> > > +                     g_autoptr(GstCaps) peercaps = gst_pad_peer_query_caps(srcpad, caps);\n> > > +                     if (gst_caps_is_empty(peercaps)) {\n> >\n> > This patch I've seen as its own in some other submission, please drop.\n> >\n> > >                               reconfigure = true;\n> > >                               break;\n> > >                       }\n> > > @@ -926,6 +942,9 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id,\n> > >               g_free(self->camera_name);\n> > >               self->camera_name = g_value_dup_string(value);\n> > >               break;\n> > > +     case PROP_ORIENTATION:\n> > > +             self->orientation = (GstVideoOrientationMethod)g_value_get_enum(value);\n> > > +             break;\n> > >       default:\n> > >               if (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec))\n> > >                       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> > > @@ -945,6 +964,9 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,\n> > >       case PROP_CAMERA_NAME:\n> > >               g_value_set_string(value, self->camera_name);\n> > >               break;\n> > > +     case PROP_ORIENTATION:\n> > > +             g_value_set_enum(value, (gint)self->orientation);\n> > > +             break;\n> > >       default:\n> > >               if (!state->controls_.getProperty(prop_id - PROP_LAST, value, pspec))\n> > >                       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n> > > @@ -1148,12 +1170,16 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> > >\n> > >       GParamSpec *spec = g_param_spec_string(\"camera-name\", \"Camera Name\",\n> > >                                              \"Select by name which camera to use.\", nullptr,\n> > > -                                            (GParamFlags)(GST_PARAM_MUTABLE_READY\n> > > -                                                          | G_PARAM_CONSTRUCT\n> > > -                                                          | G_PARAM_READWRITE\n> > > -                                                          | G_PARAM_STATIC_STRINGS));\n> > > +                                            (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> >\n> > Looked fine before, and was accepted as such.\n> >\n> > >       g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec);\n> > >\n> > > +     /* Register the orientation enum type. */\n> > > +     spec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> >\n> > Is the name \"orientation\" proper ? In the wilderness of GStremer, I see rotate-\n> > method (glimagesink), video-direction (videoflip), I'd pick one of these.\n> >\n> > > +                              \"Select the orientation of the camera.\",\n> > > +                              GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,\n> > > +                              (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> > > +     g_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> > > +\n> > >       GstCameraControls::installProperties(object_class, PROP_LAST);\n> > >  }\n> > >\n> \n> I've been naming it orientation to discriminate it from rotation in\n> libcamera terms, as GStreamer (as you said) has no clear property name\n> for that.\n> If you agree on following one of the existing GStreamer property names\n> I'd vote for video-direction one of the videoflip element? Would you\n> agree?\n> \n> > cheers,\n> > Nicolas\n> \n> Best Regards,\n> G.C.","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id A7E2EBD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 Aug 2025 15:48:07 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 638A7613C0;\n\tWed, 27 Aug 2025 17:48:06 +0200 (CEST)","from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id AF30B613BA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Aug 2025 17:48:03 +0200 (CEST)","from [49.36.69.233] (helo=uajain)\n\tby fanzine2.igalia.com with esmtpsa \n\t(Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)\n\t(Exim) id 1urINT-002VVM-OO; Wed, 27 Aug 2025 17:48:00 +0200"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=igalia.com header.i=@igalia.com\n\theader.b=\"joeCfIkk\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n\ts=20170329;\n\th=In-Reply-To:Content-Transfer-Encoding:Content-Type:MIME-Version\n\t:References:Message-ID:Subject:Cc:To:From:Date:Sender:Reply-To:Content-ID:\n\tContent-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc\n\t:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe:\n\tList-Post:List-Owner:List-Archive;\n\tbh=5AK295K4nvYGhi/iQEBZZVp4n/ykWlSUVgGGlvgbXeI=;\n\tb=joeCfIkk4oe8gi5hDdseX3ML//\n\t6OtansXKXdyBnRtk847w65NHFlec1oVjLzjvE7Crkk1+12UBrB6zFvDfzpaXQ5fZQffS/YSY7Skss\n\tYKrel/0/bVnhPLJukk536IvtqUWq7XCjY5XQl4V70hW8fej/BMT8XfkfYY/2H1BWmkZKuZEfyG2kz\n\tDQTmRR5/O8EQcVQHTkYMRks2Wi+mHy3WEA+lKU92HlX+OTF0aMU+S7z6wn3Edh5sipu1fRkecghFb\n\t4Zw4BaQsM7Kj50yobYca3JNi91CXfUhB35gQcOsMBhn2OLZ93oEYDp5asWqUt4LUZqiR/KZwSp7VW\n\t09luhV0Q==;","Date":"Wed, 27 Aug 2025 21:18:11 +0530","From":"Umang Jain <uajain@igalia.com>","To":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>","Cc":"Nicolas Dufresne <nicolas@ndufresne.ca>, \n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v4 1/1] gstreamer: Add support for Orientation","Message-ID":"<2d3fbk3xfz6xizcftc3vsf3uelkpxo53n5en3ejrsy5j7iscv5@o7iqkvkiobel>","References":"<20250725115602.1477743-1-giacomo.cappellini.87@gmail.com>\n\t<20250725115602.1477743-2-giacomo.cappellini.87@gmail.com>\n\t<f87475ab9bafe0e57abad2d3f857b3df623c7316.camel@ndufresne.ca>\n\t<CABXJd1keTqKWihs_v7u=6rObk-Oz3YKFg1tPyyiWVr1KhG59=Q@mail.gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<CABXJd1keTqKWihs_v7u=6rObk-Oz3YKFg1tPyyiWVr1KhG59=Q@mail.gmail.com>","User-Agent":"NeoMutt/20250510-dirty","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]