[{"id":34628,"web_url":"https://patchwork.libcamera.org/comment/34628/","msgid":"<c17a0339-d323-4f7b-b618-e63f784cb2a7@ideasonboard.com>","date":"2025-06-24T21:28:45","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":156,"url":"https://patchwork.libcamera.org/api/people/156/","name":"Dan Scally","email":"dan.scally@ideasonboard.com"},"content":"Hi Giacomo - thanks for the patch. The functionality looks good to me, but I have a couple of \ncode-style nitpicks:\n\nOn 23/06/2025 17:35, Giacomo Cappellini wrote:\n> \"orientation\" parameter added to the libcamerasrc\n> element to control the orientation of the camera feed.\n>\n> GST_PARAM_MUTABLE_READY allows the parameter to be changed\n> only when pipeline is in the READY state\nI would drop this sentence from the commit message and add it as a comment above the line of code.\n>\n> The parameter is fed into the existing\n> CameraConfiguration orientation property\n>\n> This allows users to specify the rotation of the video stream,\n> enhancing flexibility in camera applications.\n> ---\n\n\nThe commit message also needs a \"Signed-off-by\" tag; see the linux kernel docs [1] for an \nexplanation of the meaning. You can add the tag automatically to a commit message using \"git commit -s\"\n\n\n[1] \nhttps://www.kernel.org/doc/html/v4.17/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin\n\n>   src/gstreamer/gstlibcamerasrc.cpp | 72 +++++++++++++++++++++++++++++++\n>   1 file changed, 72 insertions(+)\n>\n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index 51ba8b67..b07156af 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {\n>   \tGstTask *task;\n>   \n>   \tgchar *camera_name;\n> +\tOrientation orientation;\nIf you're using a type from a header, ideally include it explicitly (so include \n#<libcamera/orientation.h> in this case).\n>   \n>   \tstd::atomic<GstEvent *> pending_eos;\n>   \n> @@ -157,6 +158,7 @@ struct _GstLibcameraSrc {\n>   enum {\n>   \tPROP_0,\n>   \tPROP_CAMERA_NAME,\n> +\tPROP_ORIENTATION,\n>   \tPROP_LAST\n>   };\n>   \n> @@ -616,6 +618,11 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n>   \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n>   \t}\n>   \n> +\t// print state->orientation for debugging purposes\nYou can drop this comment - the line below is clear enough that it's unnecessary.\n> +\tGST_DEBUG_OBJECT(self, \"Orientation: %d\", (int)self->orientation);\nEmpty line here please.\n> +\t/* Set the orientation control. */\n> +\tstate->config_->orientation = self->orientation;\n> +\n>   \t/* Validate the configuration. */\n>   \tif (state->config_->validate() == CameraConfiguration::Invalid)\n>   \t\treturn false;\n> @@ -926,6 +933,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 = (libcamera::Orientation)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 +955,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> @@ -1120,6 +1133,53 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n>   \tgst_element_remove_pad(element, pad);\n>   }\n>   \n> +static GType\n> +gst_libcamera_orientation_get_type()\n> +{\n> +\tstatic GType type = 0;\n> +\tstatic const GEnumValue values[] = {\n> +\t\t{\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0),\n> +\t\t\t\"libcamera::Orientation::Rotate0\",\n> +\t\t\t\"rotate-0\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate0Mirror\",\n> +\t\t\t\"rotate-0-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180),\n> +\t\t\t\"libcamera::Orientation::Rotate180\",\n> +\t\t\t\"rotate-180\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate180Mirror\",\n> +\t\t\t\"rotate-180-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate90Mirror\",\n> +\t\t\t\"rotate-90-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270),\n> +\t\t\t\"libcamera::Orientation::Rotate270\",\n> +\t\t\t\"rotate-270\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate270Mirror\",\n> +\t\t\t\"rotate-270-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90),\n> +\t\t\t\"libcamera::Orientation::Rotate90\",\n> +\t\t\t\"rotate-90\",\n> +\t\t},\n> +\t\t{ 0, nullptr, nullptr }\n> +\t};\n> +\n> +\tif (!type)\n> +\t\ttype = g_enum_register_static(\"GstLibcameraOrientation\", values);\n> +\n> +\treturn type;\n> +}\nI think I prefer a global array of GEnumValues personally, but I'll let others weigh in on that one.\n> +\n>   static void\n>   gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>   {\n> @@ -1154,6 +1214,18 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>   \t\t\t\t\t\t\t     | 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> +\tGType orientation_type = gst_libcamera_orientation_get_type();\n> +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> +\t\t\t\t\t       \"Select the orientation of the camera.\",\n> +\t\t\t\t\t       orientation_type,\n> +\t\t\t\t\t       static_cast<gint>(libcamera::Orientation::Rotate0),\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));\nCould you align the parameters to the opening parenthesis please?\n> +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> +\n>   \tGstCameraControls::installProperties(object_class, PROP_LAST);\n>   }\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 4F620BDE6B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 24 Jun 2025 21:28:50 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3E0ED61536;\n\tTue, 24 Jun 2025 23:28:49 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 95A0C61534\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 24 Jun 2025 23:28:47 +0200 (CEST)","from [192.168.0.43]\n\t(cpc141996-chfd3-2-0-cust928.12-3.cable.virginm.net [86.13.91.161])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E6055EFF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 24 Jun 2025 23:28:29 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"v6bpm07g\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750800510;\n\tbh=pEKqUOvS56XRP3MO9VZB7GqakRIzdyLnZ7JSoaejJME=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=v6bpm07gfJoxVceCctgYTstufYMpSBL8TCHQazbdjAHnZjfrQ/UJXXw4FPAVHvfzM\n\t0YDNufiPDa71e3OiIOrVBczSjdD6VWHmfzf39lqDrHTC2SPUs1nN9o/duLrAetUlmI\n\tyybAfOjwRglek066AekxcUtVRb0Aeirx0oXiaOg0=","Message-ID":"<c17a0339-d323-4f7b-b618-e63f784cb2a7@ideasonboard.com>","Date":"Tue, 24 Jun 2025 22:28:45 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","To":"libcamera-devel@lists.libcamera.org","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>","Content-Language":"en-US","From":"Dan Scally <dan.scally@ideasonboard.com>","Autocrypt":"addr=dan.scally@ideasonboard.com; keydata=\n\txsFNBGLydlEBEADa5O2s0AbUguprfvXOQun/0a8y2Vk6BqkQALgeD6KnXSWwaoCULp18etYW\n\tB31bfgrdphXQ5kUQibB0ADK8DERB4wrzrUb5CMxLBFE7mQty+v5NsP0OFNK9XTaAOcmD+Ove\n\teIjYvqurAaro91jrRVrS1gBRxIFqyPgNvwwL+alMZhn3/2jU2uvBmuRrgnc/e9cHKiuT3Dtq\n\tMHGPKL2m+plk+7tjMoQFfexoQ1JKugHAjxAhJfrkXh6uS6rc01bYCyo7ybzg53m1HLFJdNGX\n\tsUKR+dQpBs3SY4s66tc1sREJqdYyTsSZf80HjIeJjU/hRunRo4NjRIJwhvnK1GyjOvvuCKVU\n\tRWpY8dNjNu5OeAfdrlvFJOxIE9M8JuYCQTMULqd1NuzbpFMjc9524U3Cngs589T7qUMPb1H1\n\tNTA81LmtJ6Y+IV5/kiTUANflpzBwhu18Ok7kGyCq2a2jsOcVmk8gZNs04gyjuj8JziYwwLbf\n\tvzABwpFVcS8aR+nHIZV1HtOzyw8CsL8OySc3K9y+Y0NRpziMRvutrppzgyMb9V+N31mK9Mxl\n\t1YkgaTl4ciNWpdfUe0yxH03OCuHi3922qhPLF4XX5LN+NaVw5Xz2o3eeWklXdouxwV7QlN33\n\tu4+u2FWzKxDqO6WLQGjxPE0mVB4Gh5Pa1Vb0ct9Ctg0qElvtGQARAQABzShEYW4gU2NhbGx5\n\tIDxkYW4uc2NhbGx5QGlkZWFzb25ib2FyZC5jb20+wsGNBBMBCAA3FiEEsdtt8OWP7+8SNfQe\n\tkiQuh/L+GMQFAmLydlIFCQWjmoACGwMECwkIBwUVCAkKCwUWAgMBAAAKCRCSJC6H8v4YxDI2\n\tEAC2Gz0iyaXJkPInyshrREEWbo0CA6v5KKf3I/HlMPqkZ48bmGoYm4mEQGFWZJAT3K4ir8bg\n\tcEfs9V54gpbrZvdwS4abXbUK4WjKwEs8HK3XJv1WXUN2bsz5oEJWZUImh9gD3naiLLI9QMMm\n\tw/aZkT+NbN5/2KvChRWhdcha7+2Te4foOY66nIM+pw2FZM6zIkInLLUik2zXOhaZtqdeJZQi\n\tHSPU9xu7TRYN4cvdZAnSpG7gQqmLm5/uGZN1/sB3kHTustQtSXKMaIcD/DMNI3JN/t+RJVS7\n\tc0Jh/ThzTmhHyhxx3DRnDIy7kwMI4CFvmhkVC2uNs9kWsj1DuX5kt8513mvfw2OcX9UnNKmZ\n\tnhNCuF6DxVrL8wjOPuIpiEj3V+K7DFF1Cxw1/yrLs8dYdYh8T8vCY2CHBMsqpESROnTazboh\n\tAiQ2xMN1cyXtX11Qwqm5U3sykpLbx2BcmUUUEAKNsM//Zn81QXKG8vOx0ZdMfnzsCaCzt8f6\n\t9dcDBBI3tJ0BI9ByiocqUoL6759LM8qm18x3FYlxvuOs4wSGPfRVaA4yh0pgI+ModVC2Pu3y\n\tejE/IxeatGqJHh6Y+iJzskdi27uFkRixl7YJZvPJAbEn7kzSi98u/5ReEA8Qhc8KO/B7wprj\n\txjNMZNYd0Eth8+WkixHYj752NT5qshKJXcyUU87BTQRi8nZSARAAx0BJayh1Fhwbf4zoY56x\n\txHEpT6DwdTAYAetd3yiKClLVJadYxOpuqyWa1bdfQWPb+h4MeXbWw/53PBgn7gI2EA7ebIRC\n\tPJJhAIkeym7hHZoxqDQTGDJjxFEL11qF+U3rhWiL2Zt0Pl+zFq0eWYYVNiXjsIS4FI2+4m16\n\ttPbDWZFJnSZ828VGtRDQdhXfx3zyVX21lVx1bX4/OZvIET7sVUufkE4hrbqrrufre7wsjD1t\n\t8MQKSapVrr1RltpzPpScdoxknOSBRwOvpp57pJJe5A0L7+WxJ+vQoQXj0j+5tmIWOAV1qBQp\n\thyoyUk9JpPfntk2EKnZHWaApFp5TcL6c5LhUvV7F6XwOjGPuGlZQCWXee9dr7zym8iR3irWT\n\t+49bIh5PMlqSLXJDYbuyFQHFxoiNdVvvf7etvGfqFYVMPVjipqfEQ38ST2nkzx+KBICz7uwj\n\tJwLBdTXzGFKHQNckGMl7F5QdO/35An/QcxBnHVMXqaSd12tkJmoRVWduwuuoFfkTY5mUV3uX\n\txGj3iVCK4V+ezOYA7c2YolfRCNMTza6vcK/P4tDjjsyBBZrCCzhBvd4VVsnnlZhVaIxoky4K\n\taL+AP+zcQrUZmXmgZjXOLryGnsaeoVrIFyrU6ly90s1y3KLoPsDaTBMtnOdwxPmo1xisH8oL\n\ta/VRgpFBfojLPxMAEQEAAcLBfAQYAQgAJhYhBLHbbfDlj+/vEjX0HpIkLofy/hjEBQJi8nZT\n\tBQkFo5qAAhsMAAoJEJIkLofy/hjEXPcQAMIPNqiWiz/HKu9W4QIf1OMUpKn3YkVIj3p3gvfM\n\tRes4fGX94Ji599uLNrPoxKyaytC4R6BTxVriTJjWK8mbo9jZIRM4vkwkZZ2bu98EweSucxbp\n\tvjESsvMXGgxniqV/RQ/3T7LABYRoIUutARYq58p5HwSP0frF0fdFHYdTa2g7MYZl1ur2JzOC\n\tFHRpGadlNzKDE3fEdoMobxHB3Lm6FDml5GyBAA8+dQYVI0oDwJ3gpZPZ0J5Vx9RbqXe8RDuR\n\tdu90hvCJkq7/tzSQ0GeD3BwXb9/R/A4dVXhaDd91Q1qQXidI+2jwhx8iqiYxbT+DoAUkQRQy\n\txBtoCM1CxH7u45URUgD//fxYr3D4B1SlonA6vdaEdHZOGwECnDpTxecENMbz/Bx7qfrmd901\n\tD+N9SjIwrbVhhSyUXYnSUb8F+9g2RDY42Sk7GcYxIeON4VzKqWM7hpkXZ47pkK0YodO+dRKM\n\tyMcoUWrTK0Uz6UzUGKoJVbxmSW/EJLEGoI5p3NWxWtScEVv8mO49gqQdrRIOheZycDmHnItt\n\t9Qjv00uFhEwv2YfiyGk6iGF2W40s2pH2t6oeuGgmiZ7g6d0MEK8Ql/4zPItvr1c1rpwpXUC1\n\tu1kQWgtnNjFHX3KiYdqjcZeRBiry1X0zY+4Y24wUU0KsEewJwjhmCKAsju1RpdlPg2kC","In-Reply-To":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","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":34629,"web_url":"https://patchwork.libcamera.org/comment/34629/","msgid":"<20250624214103.GG20757@pendragon.ideasonboard.com>","date":"2025-06-24T21:41:03","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"CC'ing Nicolas.\n\nOn Tue, Jun 24, 2025 at 10:28:45PM +0100, Daniel Scally wrote:\n> Hi Giacomo - thanks for the patch. The functionality looks good to me,\n> but I have a couple of code-style nitpicks:\n\nThe commit message subject and body is typically written in the\nimperative mood, so the subject would be\n\ngstreamer: Add property to control orientation\n\n> On 23/06/2025 17:35, Giacomo Cappellini wrote:\n> > \"orientation\" parameter added to the libcamerasrc\n> > element to control the orientation of the camera feed.\n\nAnd this would be\n\nAdd a \"orientation\" parameter to the libcamerasrc element to control the\norientation of the camera feed.\n\n> > GST_PARAM_MUTABLE_READY allows the parameter to be changed\n> > only when pipeline is in the READY state\n>\n> I would drop this sentence from the commit message and add it as a\n> comment above the line of code.\n>\n> > The parameter is fed into the existing\n> > CameraConfiguration orientation property\n\nMissing period at the end of the sentence.\n\n> >\n> > This allows users to specify the rotation of the video stream,\n> > enhancing flexibility in camera applications.\n> > ---\n> \n> The commit message also needs a \"Signed-off-by\" tag; see the linux kernel docs [1] for an \n\nOr the libcamera doc :-)\n\nhttps://libcamera.org/contributing.html#submitting-patches\n\n> explanation of the meaning. You can add the tag automatically to a commit message using \"git commit -s\"\n> \n> [1] https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin\n> \n> >   src/gstreamer/gstlibcamerasrc.cpp | 72 +++++++++++++++++++++++++++++++\n> >   1 file changed, 72 insertions(+)\n> >\n> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> > index 51ba8b67..b07156af 100644\n> > --- a/src/gstreamer/gstlibcamerasrc.cpp\n> > +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {\n> >   \tGstTask *task;\n> >   \n> >   \tgchar *camera_name;\n> > +\tOrientation orientation;\n>\n> If you're using a type from a header, ideally include it explicitly (so include \n> #<libcamera/orientation.h> in this case).\n>\n> >   \n> >   \tstd::atomic<GstEvent *> pending_eos;\n> >   \n> > @@ -157,6 +158,7 @@ struct _GstLibcameraSrc {\n> >   enum {\n> >   \tPROP_0,\n> >   \tPROP_CAMERA_NAME,\n> > +\tPROP_ORIENTATION,\n> >   \tPROP_LAST\n> >   };\n> >   \n> > @@ -616,6 +618,11 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> >   \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n> >   \t}\n> >   \n> > +\t// print state->orientation for debugging purposes\n>\n> You can drop this comment - the line below is clear enough that it's unnecessary.\n\nAnd is the debug print useful, or was it only used during development ?\n\n> > +\tGST_DEBUG_OBJECT(self, \"Orientation: %d\", (int)self->orientation);\n>\n> Empty line here please.\n>\n> > +\t/* Set the orientation control. */\n\ns/ control// as it's not a control.\n\n> > +\tstate->config_->orientation = self->orientation;\n> > +\n> >   \t/* Validate the configuration. */\n> >   \tif (state->config_->validate() == CameraConfiguration::Invalid)\n> >   \t\treturn false;\n> > @@ -926,6 +933,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 = (libcamera::Orientation)g_value_get_enum(value);\n\n\t\tself->orientation = static_cast<libcamera::Orientation>(g_value_get_enum(value));\n\nas it's C++.\n\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 +955,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> > @@ -1120,6 +1133,53 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n> >   \tgst_element_remove_pad(element, pad);\n> >   }\n> >   \n> > +static GType\n> > +gst_libcamera_orientation_get_type()\n> > +{\n> > +\tstatic GType type = 0;\n> > +\tstatic const GEnumValue values[] = {\n> > +\t\t{\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0),\n> > +\t\t\t\"libcamera::Orientation::Rotate0\",\n> > +\t\t\t\"rotate-0\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate0Mirror\",\n> > +\t\t\t\"rotate-0-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180),\n> > +\t\t\t\"libcamera::Orientation::Rotate180\",\n> > +\t\t\t\"rotate-180\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate180Mirror\",\n> > +\t\t\t\"rotate-180-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate90Mirror\",\n> > +\t\t\t\"rotate-90-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270),\n> > +\t\t\t\"libcamera::Orientation::Rotate270\",\n> > +\t\t\t\"rotate-270\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate270Mirror\",\n> > +\t\t\t\"rotate-270-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90),\n> > +\t\t\t\"libcamera::Orientation::Rotate90\",\n> > +\t\t\t\"rotate-90\",\n> > +\t\t},\n> > +\t\t{ 0, nullptr, nullptr }\n> > +\t};\n> > +\n> > +\tif (!type)\n> > +\t\ttype = g_enum_register_static(\"GstLibcameraOrientation\", values);\n> > +\n> > +\treturn type;\n> > +}\n>\n> I think I prefer a global array of GEnumValues personally, but I'll\n> let others weigh in on that one.\n\nDo you mean outside of the function ? As it's tightly related to the\nregistration of the enum, I think I'd keep it here.\n\n> > +\n> >   static void\n> >   gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >   {\n> > @@ -1154,6 +1214,18 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >   \t\t\t\t\t\t\t     | 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> > +\tGType orientation_type = gst_libcamera_orientation_get_type();\n> > +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> > +\t\t\t\t\t       \"Select the orientation of the camera.\",\n> > +\t\t\t\t\t       orientation_type,\n> > +\t\t\t\t\t       static_cast<gint>(libcamera::Orientation::Rotate0),\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>\n> Could you align the parameters to the opening parenthesis please?\n\nThat would be\n\n\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n\t\t\t\t \"Select the orientation of the camera.\",\n\t\t\t\t orientation_type,\n\t\t\t\t static_cast<gint>(libcamera::Orientation::Rotate0),\n\t\t\t\t (GParamFlags)(GST_PARAM_MUTABLE_READY\n\t\t\t\t\t     | G_PARAM_CONSTRUCT\n\t\t\t\t\t     | G_PARAM_READWRITE\n\t\t\t\t\t     | G_PARAM_STATIC_STRINGS));\n\n>\n> > +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> > +\n> >   \tGstCameraControls::installProperties(object_class, PROP_LAST);\n> >   }\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 F3DD1C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 24 Jun 2025 21:41:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D33F968DDD;\n\tTue, 24 Jun 2025 23:41:25 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3A8F861534\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 24 Jun 2025 23:41:24 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 33DBA134A; \n\tTue, 24 Jun 2025 23:41:06 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"VWsuEa9J\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750801266;\n\tbh=ZdtLZVw7oJ9I/oEVSShsqcQLRkorSwtQFBxA0pCVPYM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=VWsuEa9J12g0lFeCNIL0aY6CFrR+yDDLqCiA4m385yT3yPKIutRCDsek0T1u7rQ/P\n\t5nEMoJk/w1S62LrVewt+zPsY4rzQSlaP+1zs4pmpN3n/0mKEC6p/2B71JYhH9H1i4c\n\tg93L89t0N0v4QO4kd0DmVIGC+85rykGdhNnkUKHo=","Date":"Wed, 25 Jun 2025 00:41:03 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Dan Scally <dan.scally@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tNicolas Dufresne <nicolas.dufresne@collabora.com>","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","Message-ID":"<20250624214103.GG20757@pendragon.ideasonboard.com>","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>\n\t<c17a0339-d323-4f7b-b618-e63f784cb2a7@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<c17a0339-d323-4f7b-b618-e63f784cb2a7@ideasonboard.com>","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":34630,"web_url":"https://patchwork.libcamera.org/comment/34630/","msgid":"<fd93f8a6-a1f6-4752-acd6-00dc11ce82eb@igalia.com>","date":"2025-06-25T08:44:01","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":232,"url":"https://patchwork.libcamera.org/api/people/232/","name":"Umang Jain","email":"uajain@igalia.com"},"content":"Hi Giacomo,\n\nThank you for the patch.\n\nOn 6/23/25 10:05 PM, Giacomo Cappellini wrote:\n> \"orientation\" parameter added to the libcamerasrc\n> element to control the orientation of the camera feed.\n>\n> GST_PARAM_MUTABLE_READY allows the parameter to be changed\n> only when pipeline is in the READY state\n>\n> The parameter is fed into the existing\n> CameraConfiguration orientation property\n>\n> This allows users to specify the rotation of the video stream,\n> enhancing flexibility in camera applications.\n> ---\n>   src/gstreamer/gstlibcamerasrc.cpp | 72 +++++++++++++++++++++++++++++++\n>   1 file changed, 72 insertions(+)\n\n\nI believe we need to implement the GstVideoDirection interface[1] for \nlibcamerasrc, and map GstVideoOrientationMethod [2] to \nlibcamera::Orientation values and pass it to the \nCameraConfiguration::orientation.\n\nHere is a quick snippet to implement the interface:\n\n\ndiff --git a/src/gstreamer/gstlibcamerasrc.cpp \nb/src/gstreamer/gstlibcamerasrc.cpp\nindex 51ba8b67..2577fb5f 100644\n--- a/src/gstreamer/gstlibcamerasrc.cpp\n+++ b/src/gstreamer/gstlibcamerasrc.cpp\n@@ -163,9 +163,15 @@ enum {\n  static void gst_libcamera_src_child_proxy_init(gpointer g_iface,\n                                                gpointer iface_data);\n\n+\n+static void\n+gst_libcamera_src_video_direction_init(GstVideoDirectionInterface *iface);\n+\n  G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, \nGST_TYPE_ELEMENT,\nG_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY,\n- gst_libcamera_src_child_proxy_init)\n+ gst_libcamera_src_child_proxy_init);\n+ G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_DIRECTION,\n+ gst_libcamera_src_video_direction_init);\n                         GST_DEBUG_CATEGORY_INIT(source_debug, \n\"libcamerasrc\", 0,\n                                                 \"libcamera Source\"))\n\n@@ -1186,3 +1192,10 @@ gst_libcamera_src_child_proxy_init(gpointer \ng_iface, [[maybe_unused]] gpointer i\n         iface->get_child_by_index = \ngst_libcamera_src_child_proxy_get_child_by_index;\n         iface->get_children_count = \ngst_libcamera_src_child_proxy_get_children_count;\n  }\n+\n+static void\n+gst_libcamera_src_video_direction_init([[maybe_unused]] \nGstVideoDirectionInterface *iface)\n+{\n+       /* We implement the video-direction property */\n+\n+}\n\n[1] : \nhttps://gstreamer.freedesktop.org/documentation/video/gstvideodirection.html?gi-language=c\n\n[2]: \nhttps://gstreamer.freedesktop.org/documentation/video/gstvideo.html?gi-language=c#GstVideoOrientationMethod\n\n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index 51ba8b67..b07156af 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {\n>   \tGstTask *task;\n>   \n>   \tgchar *camera_name;\n> +\tOrientation orientation;\n\n\nThis should be GstVideoOrientationMethod\n\n>   \n>   \tstd::atomic<GstEvent *> pending_eos;\n>   \n> @@ -157,6 +158,7 @@ struct _GstLibcameraSrc {\n>   enum {\n>   \tPROP_0,\n>   \tPROP_CAMERA_NAME,\n> +\tPROP_ORIENTATION,\n>   \tPROP_LAST\n>   };\n>   \n> @@ -616,6 +618,11 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n>   \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n>   \t}\n>   \n> +\t// print state->orientation for debugging purposes\n> +\tGST_DEBUG_OBJECT(self, \"Orientation: %d\", (int)self->orientation);\n> +\t/* Set the orientation control. */\n> +\tstate->config_->orientation = self->orientation;\n> +\n\n\nThis can be\n\n     state->config_->orientation = \ngst_libcamera_src_gst_orientation_method_to_orientation(self->orientation);\n\n\ngst_libcamera_src_gst_orientation_method_to_orientation() returns the \ncorresponding libcamera::Orientation from GstOrientationMethod value.  I \nhope you get the idea.\n\n\n>   \t/* Validate the configuration. */\n>   \tif (state->config_->validate() == CameraConfiguration::Invalid)\n>   \t\treturn false;\n> @@ -926,6 +933,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 = (libcamera::Orientation)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 +955,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> @@ -1120,6 +1133,53 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n>   \tgst_element_remove_pad(element, pad);\n>   }\n>   \n> +static GType\n> +gst_libcamera_orientation_get_type()\n> +{\n> +\tstatic GType type = 0;\n> +\tstatic const GEnumValue values[] = {\n> +\t\t{\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0),\n> +\t\t\t\"libcamera::Orientation::Rotate0\",\n> +\t\t\t\"rotate-0\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate0Mirror\",\n> +\t\t\t\"rotate-0-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180),\n> +\t\t\t\"libcamera::Orientation::Rotate180\",\n> +\t\t\t\"rotate-180\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate180Mirror\",\n> +\t\t\t\"rotate-180-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate90Mirror\",\n> +\t\t\t\"rotate-90-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270),\n> +\t\t\t\"libcamera::Orientation::Rotate270\",\n> +\t\t\t\"rotate-270\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate270Mirror\",\n> +\t\t\t\"rotate-270-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90),\n> +\t\t\t\"libcamera::Orientation::Rotate90\",\n> +\t\t\t\"rotate-90\",\n> +\t\t},\n> +\t\t{ 0, nullptr, nullptr }\n> +\t};\n> +\n> +\tif (!type)\n> +\t\ttype = g_enum_register_static(\"GstLibcameraOrientation\", values);\n> +\n> +\treturn type;\n> +}\n> +\n>   static void\n>   gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>   {\n> @@ -1154,6 +1214,18 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>   \t\t\t\t\t\t\t     | 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> +\tGType orientation_type = gst_libcamera_orientation_get_type();\n> +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> +\t\t\t\t\t       \"Select the orientation of the camera.\",\n> +\t\t\t\t\t       orientation_type,\n> +\t\t\t\t\t       static_cast<gint>(libcamera::Orientation::Rotate0),\nAnd use GST_VIDEO_ORIENTATION_IDENTITY here.\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> +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> +\n>   \tGstCameraControls::installProperties(object_class, PROP_LAST);\n>   }\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 5E6A0C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Jun 2025 08:44:37 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D643468DEB;\n\tWed, 25 Jun 2025 10:44:36 +0200 (CEST)","from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 754B868DCE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 10:44:35 +0200 (CEST)","from [49.36.69.141] (helo=[192.168.29.108])\n\tby fanzine2.igalia.com with esmtpsa \n\t(Cipher TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_128_GCM:128)\n\t(Exim) id 1uULkA-008Qbs-7F; Wed, 25 Jun 2025 10:44:34 +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=\"PTWy0t39\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n\ts=20170329;\n\th=Content-Transfer-Encoding:Content-Type:In-Reply-To:From:\n\tReferences:To:Subject:MIME-Version:Date:Message-ID:Sender:Reply-To:Cc:\n\tContent-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:\n\tResent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:\n\tList-Subscribe:List-Post:List-Owner:List-Archive;\n\tbh=fO9otXQMXhBHOX0arlWEMT4Rk020I+hyev5GpjARgqY=;\n\tb=PTWy0t39mwgBJXjpIjEdLkWVkd\n\tqWE7xlUFfPc6/55+yz49UK75q5Yo18FjgWJHxV5Lzf/yK0NmRB+QWWrA+gtk7M3KRotL+IxvlTnrK\n\t3RTjlWj00Kz9didR46yPoFClvmyhSXrFrhqsAxvN+8l9CKvRJBGXl4tMqyjbHZo9p/S2IGJ32MDOn\n\t4px0rHOem08kH9fUNxvg67ymYQHtXucBR7t3tt8QHON7DsgZdQuRdq8sKynSRv9AZIAmeDtaX9+nn\n\tFyDV6lnz2TzmAh3CWmJrTef0Qz4ZtCATgbsP128RG68FzUg5bEPOzAgbdv8Pd+x7jzGpZpmHWDezG\n\tOktPYuEw==;","Message-ID":"<fd93f8a6-a1f6-4752-acd6-00dc11ce82eb@igalia.com>","Date":"Wed, 25 Jun 2025 14:14:01 +0530","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","To":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>","Content-Language":"en-US","From":"Umang Jain <uajain@igalia.com>","In-Reply-To":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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":34632,"web_url":"https://patchwork.libcamera.org/comment/34632/","msgid":"<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>","date":"2025-06-25T13:02:24","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":30,"url":"https://patchwork.libcamera.org/api/people/30/","name":"Nicolas Dufresne","email":"nicolas@ndufresne.ca"},"content":"Hi,\n\nadding my own review on top of other's.\n\nLe lundi 23 juin 2025 à 18:35 +0200, Giacomo Cappellini a écrit :\n> \"orientation\" parameter added to the libcamerasrc\n> element to control the orientation of the camera feed.\n> \n> GST_PARAM_MUTABLE_READY allows the parameter to be changed\n> only when pipeline is in the READY state\n> \n> The parameter is fed into the existing\n> CameraConfiguration orientation property\n> \n> This allows users to specify the rotation of the video stream,\n> enhancing flexibility in camera applications.\n\nSince this is 90 degrees and flips only, it should be clarified, I saw\nsome comment about free form rotation already.\n\nSome clarification need in regard to this vs camera physical orientation,\ne.g. if a sensor has been mounted with such a 90 degree rotation from\nits reference for a specific device.\n\n> ---\n>  src/gstreamer/gstlibcamerasrc.cpp | 72 +++++++++++++++++++++++++++++++\n>  1 file changed, 72 insertions(+)\n> \n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index 51ba8b67..b07156af 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {\n>  \tGstTask *task;\n>  \n>  \tgchar *camera_name;\n> +\tOrientation orientation;\n>  \n>  \tstd::atomic<GstEvent *> pending_eos;\n>  \n> @@ -157,6 +158,7 @@ struct _GstLibcameraSrc {\n>  enum {\n>  \tPROP_0,\n>  \tPROP_CAMERA_NAME,\n> +\tPROP_ORIENTATION,\n>  \tPROP_LAST\n>  };\n>  \n> @@ -616,6 +618,11 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n>  \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n>  \t}\n>  \n> +\t// print state->orientation for debugging purposes\n> +\tGST_DEBUG_OBJECT(self, \"Orientation: %d\", (int)self->orientation);\n> +\t/* Set the orientation control. */\n> +\tstate->config_->orientation = self->orientation;\n> +\n>  \t/* Validate the configuration. */\n>  \tif (state->config_->validate() == CameraConfiguration::Invalid)\n>  \t\treturn false;\n> @@ -926,6 +933,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 = (libcamera::Orientation)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 +955,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> @@ -1120,6 +1133,53 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n>  \tgst_element_remove_pad(element, pad);\n>  }\n>  \n> +static GType\n> +gst_libcamera_orientation_get_type()\n> +{\n> +\tstatic GType type = 0;\n> +\tstatic const GEnumValue values[] = {\n> +\t\t{\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0),\n\nWhen you write a GStreamer application, you usually import and link GStreamer libraries,\nbut don't link or import libcamera. For this reason, it would be nicer to use the values\nfrom GST_VIDEO_ORIENTATION_*. This enum has been made global in GStreamer for that\npurpose, but it does not mean you have to support all of it, or forced to use its naming.\n\nThough, not using the name naming as videoflip, glvideoflip, glimagesink etc. it very\nconfusing. Here's my suggestion, change this to (C++iffy this):\n\nstatic const GEnumValue rotate_methods[] = {\n  {GST_VIDEO_ORIENTATION_IDENTITY, \"Identity (no rotation)\", \"none\"},\n  {GST_VIDEO_ORIENTATION_90R, \"Rotate clockwise 90 degrees\", \"clockwise\"},\n  {GST_VIDEO_ORIENTATION_180, \"Rotate 180 degrees\", \"rotate-180\"},\n  {GST_VIDEO_ORIENTATION_90L, \"Rotate counter-clockwise 90 degrees\",\n      \"counterclockwise\"},\n  {GST_VIDEO_ORIENTATION_HORIZ, \"Flip horizontally\", \"horizontal-flip\"},\n  {GST_VIDEO_ORIENTATION_VERT, \"Flip vertically\", \"vertical-flip\"},\n  {GST_VIDEO_ORIENTATION_UL_LR,\n      \"Flip across upper left/lower right diagonal\", \"upper-left-diagonal\"},\n  {GST_VIDEO_ORIENTATION_UR_LL,\n      \"Flip across upper right/lower left diagonal\", \"upper-right-diagonal\"},\n// This can be added later if we think its useful/usable even though usually only\n// flips are supported\n//  {GST_VIDEO_ORIENTATION_AUTO,\n//      \"Select rotate method based on image-orientation tag\", \"automatic\"},\n  {0, NULL, NULL},\n};\n\nstruct rotate_item {\n\tGstVideoOrientation gst;\n\tlibcamera::Orientation lc;\n};\n\nstatic const rotate_enum_map[] = {\n\t{ GST_VIDEO_ORIENTATION_IDENTITY, libcamera::Orientation::Rotate0},\n\t...\n};\n\nThe orientation will be bound checked already by the GOBject property machinery.\n\n\n> +\t\t\t\"libcamera::Orientation::Rotate0\",\n> +\t\t\t\"rotate-0\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate0Mirror\",\n> +\t\t\t\"rotate-0-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180),\n> +\t\t\t\"libcamera::Orientation::Rotate180\",\n> +\t\t\t\"rotate-180\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate180Mirror\",\n> +\t\t\t\"rotate-180-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate90Mirror\",\n> +\t\t\t\"rotate-90-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270),\n> +\t\t\t\"libcamera::Orientation::Rotate270\",\n> +\t\t\t\"rotate-270\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270Mirror),\n> +\t\t\t\"libcamera::Orientation::Rotate270Mirror\",\n> +\t\t\t\"rotate-270-mirror\",\n> +\t\t}, {\n> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90),\n> +\t\t\t\"libcamera::Orientation::Rotate90\",\n> +\t\t\t\"rotate-90\",\n> +\t\t},\n> +\t\t{ 0, nullptr, nullptr }\n> +\t};\n> +\n> +\tif (!type)\n> +\t\ttype = g_enum_register_static(\"GstLibcameraOrientation\", values);\n> +\n> +\treturn type;\n> +}\n> +\n>  static void\n>  gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>  {\n> @@ -1154,6 +1214,18 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>  \t\t\t\t\t\t\t     | 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> +\tGType orientation_type = gst_libcamera_orientation_get_type();\n> +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> +\t\t\t\t\t       \"Select the orientation of the camera.\",\n\nThis needs a better description, and a better name. For me, the orientation of a camera is\nbasically the fixed (physical) orientation against a device specific reference point, not\nomething you can select. Even PTZ cameras don't have that kind of control physically.\n\nWhile dedicated elements such as videoflip or glvideoflip just call this method, a good \nname to follow could be glimagesink which calls this rotate-methode.\n\nNicolas\n\n> +\t\t\t\t\t       orientation_type,\n> +\t\t\t\t\t       static_cast<gint>(libcamera::Orientation::Rotate0),\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> +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> +\n>  \tGstCameraControls::installProperties(object_class, PROP_LAST);\n>  }\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 4794CC3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Jun 2025 13:02:32 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AB22668DEC;\n\tWed, 25 Jun 2025 15:02:30 +0200 (CEST)","from mail-qv1-xf32.google.com (mail-qv1-xf32.google.com\n\t[IPv6:2607:f8b0:4864:20::f32])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F063561533\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 15:02:28 +0200 (CEST)","by mail-qv1-xf32.google.com with SMTP id\n\t6a1803df08f44-6faf66905adso39181456d6.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 06:02:28 -0700 (PDT)","from ?IPv6:2606:6d00:17:b699::5ac? ([2606:6d00:17:b699::5ac])\n\tby smtp.gmail.com with ESMTPSA id\n\t6a1803df08f44-6fd09576766sm67566056d6.81.2025.06.25.06.02.25\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 25 Jun 2025 06:02:26 -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=\"EH0V8RDB\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ndufresne-ca.20230601.gappssmtp.com; s=20230601; t=1750856548;\n\tx=1751461348; 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=QC1d3R2FdizUd9ixZKz4fOH+d3emzGGMbMAk8e/LYV4=;\n\tb=EH0V8RDB+efLYR+JgDu5dMulyUDFe5mw4zgsyI0aCW8YGNbFYpfeFo6y5lP9rFuvM6\n\tIg9yJBLBEPpuoyDxTuaNEs3xiKsuX1bWf36NFvVG68MNPdJ/Ifc6mdHdPHAAJH6euMsJ\n\tqd1NhIX0EeYWSQtyK16T9Dn2C+Mt/LXpr8AC+zUOPHN+0sJQCyqtEukMpAGx2XIAkM9Y\n\t7aZm4MQwCqFSujBwo3RrY4cremeWnH7Y2BftW7vYhH2wuei+lBd4VJixeJH/0JG95kd1\n\ts0rLwZtytVDW+f6jEUsyPslCEpiHgRzhOlM6BZ6C3OJ1G4Pq149b9NIzt00JmLjyiC6E\n\t7UHw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1750856548; x=1751461348;\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=QC1d3R2FdizUd9ixZKz4fOH+d3emzGGMbMAk8e/LYV4=;\n\tb=YMU++XDOJMrMr0yqPeAXq/eRDeEk3D8ojgIOiLgHUR3ZbdAWkyALsmBYUZwpFgmeOs\n\tBGfxSv3XxrYh18GuiAYxxiLmbIcDolvNbgzRCUcPViyJ4e046Km5F2Mi/WYxivxs13yD\n\txeWPClZVNy9wlKvAQyAOW1/GnLoOc1WSuQwWlKSoPbBjyK7XO0Vy+aRIAyycPwaudiKi\n\tlICabgyfmFYIYCy+TXa7NMmHNDrCKamHWIKMXeoGeUjyhaSCBE5XYrNlQNvDqkdua+dn\n\tx9NAXIAaua7xtElEAySoFVz6847kpuHgU2Qst/IoEKdDqpy8VdGzs+OgUFxSbgF8+kgI\n\tFXMw==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCVXeElmTLao2XSjCq6To6LiJQm/hpXzFhidtCN6PmWj9a1eNaP0n9R5bsCtBn0ywLN/pDNY81W6JIn38eKUKJk=@lists.libcamera.org","X-Gm-Message-State":"AOJu0YwUkCCvsMxgVMyE+NXkdqesGo/kfDKwqiHnAyzWmH0QvwKuXRo6\n\trABxqjCC7JisqbO4+k4+xR13xQbmZwR2hBrN/64a5tMNVReBFaNImLP16mMVHJA29oE=","X-Gm-Gg":"ASbGnct74p3KMo/xYmhcVYaK/wlqsaC4V0GZKA6Y2NOgWUOxxcUUDuZfSsZzn00noWH\n\tQJzG8TUa78hKP2OPDgdEFoWRD0RfeGkM2oQoRP1uzxxbfe1rUxkV5lGrG3VPTuyYYBFoCl3OP6i\n\tY5StKPalAw+/3FnvKXNuZWl7mkRIi/OEZlK/QVN0GsALhLt/FhFj9qYwzUTXd2OmmMTu/NdYPP1\n\tyANQt0Q73rhkYp4iZ/XgjJN9TnaieRFzbYFHmP/rmfP/z7J8nRTOYuJqIl7oPGmCCLwMZ1+P7rO\n\tuCZkVGRe3E66DgQDZzQeSHA3Yvg/fQ/Cs1Y6O+8nmyYz9NLnzzAYSCfF0W4oLzeUDao=","X-Google-Smtp-Source":"AGHT+IGCiRztkejOofmQ5YJ+YrKFxmhXuhLi3IL5lTGyLhbqWxJcgwMusBzhQ408oew68uE3FEKtfw==","X-Received":"by 2002:ad4:5d63:0:b0:6fa:cb9b:a793 with SMTP id\n\t6a1803df08f44-6fd5ef7ef61mr35414796d6.26.1750856547303; \n\tWed, 25 Jun 2025 06:02:27 -0700 (PDT)","Message-ID":"<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","From":"Nicolas Dufresne <nicolas@ndufresne.ca>","To":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>, \n\tlibcamera-devel@lists.libcamera.org","Date":"Wed, 25 Jun 2025 09:02:24 -0400","In-Reply-To":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>","References":"<20250623163540.1787972-1-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=\"=-TgXfGBLLbUjR1ouXoZwY\"","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":34633,"web_url":"https://patchwork.libcamera.org/comment/34633/","msgid":"<7c8fc6a8b5586a22b9489ee2cfd3a657a31ce89e.camel@ndufresne.ca>","date":"2025-06-25T13:05:02","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":30,"url":"https://patchwork.libcamera.org/api/people/30/","name":"Nicolas Dufresne","email":"nicolas@ndufresne.ca"},"content":"Hi Umang,\n\nLe mercredi 25 juin 2025 à 14:14 +0530, Umang Jain a écrit :\n> Hi Giacomo,\n> \n> Thank you for the patch.\n> \n> On 6/23/25 10:05 PM, Giacomo Cappellini wrote:\n> > \"orientation\" parameter added to the libcamerasrc\n> > element to control the orientation of the camera feed.\n> > \n> > GST_PARAM_MUTABLE_READY allows the parameter to be changed\n> > only when pipeline is in the READY state\n> > \n> > The parameter is fed into the existing\n> > CameraConfiguration orientation property\n> > \n> > This allows users to specify the rotation of the video stream,\n> > enhancing flexibility in camera applications.\n> > ---\n> >   src/gstreamer/gstlibcamerasrc.cpp | 72 +++++++++++++++++++++++++++++++\n> >   1 file changed, 72 insertions(+)\n> \n> \n> I believe we need to implement the GstVideoDirection interface[1] for \n> libcamerasrc, and map GstVideoOrientationMethod [2] to \n> libcamera::Orientation values and pass it to the \n> CameraConfiguration::orientation.\n\nI'm not entirely certain that implementing the interface is a good idea. We\ndon't have any software fallback, so we can't guaranty the effect. I don't\nknow a lot of users for this interface, and may have a hard time verifying\nthe existing application needs.\n\n> \n> Here is a quick snippet to implement the interface:\n> \n> \n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp \n> b/src/gstreamer/gstlibcamerasrc.cpp\n> index 51ba8b67..2577fb5f 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -163,9 +163,15 @@ enum {\n>   static void gst_libcamera_src_child_proxy_init(gpointer g_iface,\n>                                                 gpointer iface_data);\n> \n> +\n> +static void\n> +gst_libcamera_src_video_direction_init(GstVideoDirectionInterface *iface);\n> +\n>   G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, \n> GST_TYPE_ELEMENT,\n> G_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY,\n> - gst_libcamera_src_child_proxy_init)\n> + gst_libcamera_src_child_proxy_init);\n> + G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_DIRECTION,\n> + gst_libcamera_src_video_direction_init);\n>                          GST_DEBUG_CATEGORY_INIT(source_debug, \n> \"libcamerasrc\", 0,\n>                                                  \"libcamera Source\"))\n> \n> @@ -1186,3 +1192,10 @@ gst_libcamera_src_child_proxy_init(gpointer \n> g_iface, [[maybe_unused]] gpointer i\n>          iface->get_child_by_index = \n> gst_libcamera_src_child_proxy_get_child_by_index;\n>          iface->get_children_count = \n> gst_libcamera_src_child_proxy_get_children_count;\n>   }\n> +\n> +static void\n> +gst_libcamera_src_video_direction_init([[maybe_unused]] \n> GstVideoDirectionInterface *iface)\n> +{\n> +       /* We implement the video-direction property */\n> +\n> +}\n> \n> [1] : \n> https://gstreamer.freedesktop.org/documentation/video/gstvideodirection.html?gi-language=c\n> \n> [2]: \n> https://gstreamer.freedesktop.org/documentation/video/gstvideo.html?gi-language=c#GstVideoOrientationMethod\n> \n> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> > index 51ba8b67..b07156af 100644\n> > --- a/src/gstreamer/gstlibcamerasrc.cpp\n> > +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {\n> >   \tGstTask *task;\n> >   \n> >   \tgchar *camera_name;\n> > +\tOrientation orientation;\n> \n> \n> This should be GstVideoOrientationMethod\n> \n> >   \n> >   \tstd::atomic<GstEvent *> pending_eos;\n> >   \n> > @@ -157,6 +158,7 @@ struct _GstLibcameraSrc {\n> >   enum {\n> >   \tPROP_0,\n> >   \tPROP_CAMERA_NAME,\n> > +\tPROP_ORIENTATION,\n> >   \tPROP_LAST\n> >   };\n> >   \n> > @@ -616,6 +618,11 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> >   \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n> >   \t}\n> >   \n> > +\t// print state->orientation for debugging purposes\n> > +\tGST_DEBUG_OBJECT(self, \"Orientation: %d\", (int)self->orientation);\n> > +\t/* Set the orientation control. */\n> > +\tstate->config_->orientation = self->orientation;\n> > +\n> \n> \n> This can be\n> \n>      state->config_->orientation = \n> gst_libcamera_src_gst_orientation_method_to_orientation(self->orientation);\n> \n> \n> gst_libcamera_src_gst_orientation_method_to_orientation() returns the \n> corresponding libcamera::Orientation from GstOrientationMethod value.  I \n> hope you get the idea.\n> \n> \n> >   \t/* Validate the configuration. */\n> >   \tif (state->config_->validate() == CameraConfiguration::Invalid)\n> >   \t\treturn false;\n> > @@ -926,6 +933,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 = (libcamera::Orientation)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 +955,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> > @@ -1120,6 +1133,53 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n> >   \tgst_element_remove_pad(element, pad);\n> >   }\n> >   \n> > +static GType\n> > +gst_libcamera_orientation_get_type()\n> > +{\n> > +\tstatic GType type = 0;\n> > +\tstatic const GEnumValue values[] = {\n> > +\t\t{\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0),\n> > +\t\t\t\"libcamera::Orientation::Rotate0\",\n> > +\t\t\t\"rotate-0\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate0Mirror\",\n> > +\t\t\t\"rotate-0-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180),\n> > +\t\t\t\"libcamera::Orientation::Rotate180\",\n> > +\t\t\t\"rotate-180\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate180Mirror\",\n> > +\t\t\t\"rotate-180-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate90Mirror\",\n> > +\t\t\t\"rotate-90-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270),\n> > +\t\t\t\"libcamera::Orientation::Rotate270\",\n> > +\t\t\t\"rotate-270\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate270Mirror\",\n> > +\t\t\t\"rotate-270-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90),\n> > +\t\t\t\"libcamera::Orientation::Rotate90\",\n> > +\t\t\t\"rotate-90\",\n> > +\t\t},\n> > +\t\t{ 0, nullptr, nullptr }\n> > +\t};\n> > +\n> > +\tif (!type)\n> > +\t\ttype = g_enum_register_static(\"GstLibcameraOrientation\", values);\n> > +\n> > +\treturn type;\n> > +}\n> > +\n> >   static void\n> >   gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >   {\n> > @@ -1154,6 +1214,18 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >   \t\t\t\t\t\t\t     | 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> > +\tGType orientation_type = gst_libcamera_orientation_get_type();\n> > +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> > +\t\t\t\t\t       \"Select the orientation of the camera.\",\n> > +\t\t\t\t\t       orientation_type,\n> > +\t\t\t\t\t       static_cast<gint>(libcamera::Orientation::Rotate0),\n> And use GST_VIDEO_ORIENTATION_IDENTITY here.\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> > +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> > +\n> >   \tGstCameraControls::installProperties(object_class, PROP_LAST);\n> >   }\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 C657BBDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Jun 2025 13:05:08 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 933B368DEC;\n\tWed, 25 Jun 2025 15:05:07 +0200 (CEST)","from mail-qt1-x830.google.com (mail-qt1-x830.google.com\n\t[IPv6:2607:f8b0:4864:20::830])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EC2E361533\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 15:05:05 +0200 (CEST)","by mail-qt1-x830.google.com with SMTP id\n\td75a77b69052e-4a43e277198so41646811cf.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 06:05:05 -0700 (PDT)","from ?IPv6:2606:6d00:17:b699::5ac? ([2606:6d00:17:b699::5ac])\n\tby smtp.gmail.com with ESMTPSA id\n\td75a77b69052e-4a779e79bbcsm59229511cf.55.2025.06.25.06.05.02\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 25 Jun 2025 06:05:03 -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=\"BDxO1fyC\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ndufresne-ca.20230601.gappssmtp.com; s=20230601; t=1750856705;\n\tx=1751461505; 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=mqpi5n9O1AjlDxZ6Lbim2vKZqS+H8WZaDU5ummbK7Fs=;\n\tb=BDxO1fyCvTYFWR8SZuXOmpndt843FjJZ7+7VMO3iOYkUUlz15cTNgGTlGRjFeqvUAa\n\tgT0f4cs9hBAAvKJXpWONUypfmqohOfjzsBoSBshoivLT+TCKerjO6jkycAq7Mg5MftlO\n\tCqSI9Fo32jLVn2cl6bcQnY84BoW8RFOCNuyKz7leNauK4DNRRuBWjD5ecJFs3QCwUFBP\n\tITS48r375b/HfhCLelNleDphsmVmXtrrYsi//QiVhZyXhmD0mv7XX4eMYNHcrX/WWKRm\n\t1uifZV8hqDI+30REhdx3rfFO2j4gtIIwV00elZZ1Vx2tO3vgvQ25Y2/2cQcAZyaVorCW\n\tCH8w==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1750856705; x=1751461505;\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=mqpi5n9O1AjlDxZ6Lbim2vKZqS+H8WZaDU5ummbK7Fs=;\n\tb=mChfy4/ayeSAH+cykEHAWzBwragxxvrgb39YWX1v9fyCTjERvr2VIatrLZalv26g9U\n\tou+uANkrGtC14JKhI6E8cqXHfdQb2JBHl31tQ6zHZJpWedzdiIa1dCKPahm7F60sS4cq\n\to1mYzZ68HZFIVGhlaFmO/wf5nuDM63l8aaKGeLarVXBOyy0hPItrFT+uHW54+zPP7SUr\n\tAwzYvvgE/jgw9ZGJwqEcw/+Hl70F/DMngcHwf0mbjRFpRi9TEAjjAwSHwE9P55AJc0tZ\n\tjZfBAxEMnz/XBy657YdVyYJ/08SuTrxUGEFbrmPhq66uKwH0S8S4XG9qpgXAgFxbXbgy\n\t1jNg==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCVRSvpTLoMa4Mm5SwyCPEmFSoC8KwLQUQrdVRKyW7uOip+t9o+BTIS17lsNaBnTbO1VCxoSYzde4EiFvOKB3S8=@lists.libcamera.org","X-Gm-Message-State":"AOJu0YxRJNeCo+sgZ14GI8DRVs5fZQYxECnl9oTu5m9XaJ2FnwdlsHci\n\tuDJQBTBaqZLzyPSJuyseR18ggQijTv8rXde65kfEcfy+X0JRcQ/B9dCr1JWbEDeaNJs=","X-Gm-Gg":"ASbGncv0p8alPMspIjVN9KrFiFHIaK2gVyvox/o+lAZHZD7v8VI8I5jReRsj0lTI3vz\n\tIVYoOuIF0wUNn/UwwJ/znwamaX2B0ZnOPeHshd0CtKjrJWcmvJ9wMBDrcmmOkFjFYr7yzi2cKE/\n\t5tXJInlTZdYrfSbQbQVeB2WrOTAY+rxGJRwbShhKTLbqFQ6dE7mhCftXaWt3yGkW/LK/80BK8TM\n\ta/EuN/DbFduCFUcug/dboLObFhIgyuYwlp9/okbh+fdAU9OfMkgbtxfGcf2b8T6yuCgBk2Jdhd9\n\tFK4cA40L8DVQ6/sHMSsqUQPZuTWPWOh5hgVRV5O+cj3iP0jkxKGi8bLjcnsTS5KScIQr7tQSqo8\n\tESw==","X-Google-Smtp-Source":"AGHT+IHLf2h5s0dTGhp/vKo6TDJgT+4/9nzJpObhNvgCsYUB6R8qbuUdlRwO8DyJ6r3PR4JC1EsV1A==","X-Received":"by 2002:a05:622a:2609:b0:4a4:2f0b:d2dc with SMTP id\n\td75a77b69052e-4a7c06cb60fmr49107991cf.20.1750856704238; \n\tWed, 25 Jun 2025 06:05:04 -0700 (PDT)","Message-ID":"<7c8fc6a8b5586a22b9489ee2cfd3a657a31ce89e.camel@ndufresne.ca>","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","From":"Nicolas Dufresne <nicolas@ndufresne.ca>","To":"Umang Jain <uajain@igalia.com>, Giacomo Cappellini\n\t<giacomo.cappellini.87@gmail.com>, libcamera-devel@lists.libcamera.org","Date":"Wed, 25 Jun 2025 09:05:02 -0400","In-Reply-To":"<fd93f8a6-a1f6-4752-acd6-00dc11ce82eb@igalia.com>","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>\n\t<fd93f8a6-a1f6-4752-acd6-00dc11ce82eb@igalia.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=\"=-pxEB9cQIPr2qHwiOArOm\"","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":34634,"web_url":"https://patchwork.libcamera.org/comment/34634/","msgid":"<i2ykumlzpdxc3jtlm6y2q2lqdnxbpedtr2o2cukddz2tbkq2sb@z77kegghjfkq>","date":"2025-06-25T13:17:52","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Nicolas\n\nOn Wed, Jun 25, 2025 at 09:02:24AM -0400, Nicolas Dufresne wrote:\n> Hi,\n>\n> adding my own review on top of other's.\n>\n> Le lundi 23 juin 2025 à 18:35 +0200, Giacomo Cappellini a écrit :\n> > \"orientation\" parameter added to the libcamerasrc\n> > element to control the orientation of the camera feed.\n> >\n> > GST_PARAM_MUTABLE_READY allows the parameter to be changed\n> > only when pipeline is in the READY state\n> >\n> > The parameter is fed into the existing\n> > CameraConfiguration orientation property\n> >\n> > This allows users to specify the rotation of the video stream,\n> > enhancing flexibility in camera applications.\n>\n> Since this is 90 degrees and flips only, it should be clarified, I saw\n> some comment about free form rotation already.\n>\n> Some clarification need in regard to this vs camera physical orientation,\n> e.g. if a sensor has been mounted with such a 90 degree rotation from\n> its reference for a specific device.\n\nJust to clarify, from a libcamera point of view, the mounting rotation\nis a physical property of the camera reported through\nproperties::Rotation, while CameraConfiguration::orientation instead\nis only about the orientation of the images you get. If you ask for a\n0deg (or 180 for that matter) rotation you'll get non-rotated images\n(or 180 degrees rotated images), regardless of the mounting\norientation as libcamera corrects that for you (provided you've asked\na rotation that can be achieved on the system, usually only 0/180\nthrough sensor flips).\nhttps://git.libcamera.org/libcamera/libcamera.git/tree/src/libcamera/sensor/camera_sensor_legacy.cpp#n932\n\nTo summarize:\n\n- mounting rotation is a static camera properties reported through\n  Camera::properties(). I'm not sure how you want/should expose this\n  thtough the gstreamer API.\n\n- orientation: is a configurable parameters of the camera that only\n  concerns with the actual images rotation. If you ask X you'll get X,\n  provided the camera pipeline can do that.\n\nHope it clarifies things in this regard.\n\nThanks\n  j\n\n>\n> > ---\n> >  src/gstreamer/gstlibcamerasrc.cpp | 72 +++++++++++++++++++++++++++++++\n> >  1 file changed, 72 insertions(+)\n> >\n> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> > index 51ba8b67..b07156af 100644\n> > --- a/src/gstreamer/gstlibcamerasrc.cpp\n> > +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {\n> >  \tGstTask *task;\n> >  \n> >  \tgchar *camera_name;\n> > +\tOrientation orientation;\n> >  \n> >  \tstd::atomic<GstEvent *> pending_eos;\n> >  \n> > @@ -157,6 +158,7 @@ struct _GstLibcameraSrc {\n> >  enum {\n> >  \tPROP_0,\n> >  \tPROP_CAMERA_NAME,\n> > +\tPROP_ORIENTATION,\n> >  \tPROP_LAST\n> >  };\n> >  \n> > @@ -616,6 +618,11 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> >  \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n> >  \t}\n> >  \n> > +\t// print state->orientation for debugging purposes\n> > +\tGST_DEBUG_OBJECT(self, \"Orientation: %d\", (int)self->orientation);\n> > +\t/* Set the orientation control. */\n> > +\tstate->config_->orientation = self->orientation;\n> > +\n> >  \t/* Validate the configuration. */\n> >  \tif (state->config_->validate() == CameraConfiguration::Invalid)\n> >  \t\treturn false;\n> > @@ -926,6 +933,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 = (libcamera::Orientation)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 +955,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> > @@ -1120,6 +1133,53 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n> >  \tgst_element_remove_pad(element, pad);\n> >  }\n> >  \n> > +static GType\n> > +gst_libcamera_orientation_get_type()\n> > +{\n> > +\tstatic GType type = 0;\n> > +\tstatic const GEnumValue values[] = {\n> > +\t\t{\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0),\n>\n> When you write a GStreamer application, you usually import and link GStreamer libraries,\n> but don't link or import libcamera. For this reason, it would be nicer to use the values\n> from GST_VIDEO_ORIENTATION_*. This enum has been made global in GStreamer for that\n> purpose, but it does not mean you have to support all of it, or forced to use its naming.\n>\n> Though, not using the name naming as videoflip, glvideoflip, glimagesink etc. it very\n> confusing. Here's my suggestion, change this to (C++iffy this):\n>\n> static const GEnumValue rotate_methods[] = {\n>   {GST_VIDEO_ORIENTATION_IDENTITY, \"Identity (no rotation)\", \"none\"},\n>   {GST_VIDEO_ORIENTATION_90R, \"Rotate clockwise 90 degrees\", \"clockwise\"},\n>   {GST_VIDEO_ORIENTATION_180, \"Rotate 180 degrees\", \"rotate-180\"},\n>   {GST_VIDEO_ORIENTATION_90L, \"Rotate counter-clockwise 90 degrees\",\n>       \"counterclockwise\"},\n>   {GST_VIDEO_ORIENTATION_HORIZ, \"Flip horizontally\", \"horizontal-flip\"},\n>   {GST_VIDEO_ORIENTATION_VERT, \"Flip vertically\", \"vertical-flip\"},\n>   {GST_VIDEO_ORIENTATION_UL_LR,\n>       \"Flip across upper left/lower right diagonal\", \"upper-left-diagonal\"},\n>   {GST_VIDEO_ORIENTATION_UR_LL,\n>       \"Flip across upper right/lower left diagonal\", \"upper-right-diagonal\"},\n> // This can be added later if we think its useful/usable even though usually only\n> // flips are supported\n> //  {GST_VIDEO_ORIENTATION_AUTO,\n> //      \"Select rotate method based on image-orientation tag\", \"automatic\"},\n>   {0, NULL, NULL},\n> };\n>\n> struct rotate_item {\n> \tGstVideoOrientation gst;\n> \tlibcamera::Orientation lc;\n> };\n>\n> static const rotate_enum_map[] = {\n> \t{ GST_VIDEO_ORIENTATION_IDENTITY, libcamera::Orientation::Rotate0},\n> \t...\n> };\n>\n> The orientation will be bound checked already by the GOBject property machinery.\n>\n>\n> > +\t\t\t\"libcamera::Orientation::Rotate0\",\n> > +\t\t\t\"rotate-0\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate0Mirror\",\n> > +\t\t\t\"rotate-0-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180),\n> > +\t\t\t\"libcamera::Orientation::Rotate180\",\n> > +\t\t\t\"rotate-180\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate180Mirror\",\n> > +\t\t\t\"rotate-180-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate90Mirror\",\n> > +\t\t\t\"rotate-90-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270),\n> > +\t\t\t\"libcamera::Orientation::Rotate270\",\n> > +\t\t\t\"rotate-270\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate270Mirror\",\n> > +\t\t\t\"rotate-270-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90),\n> > +\t\t\t\"libcamera::Orientation::Rotate90\",\n> > +\t\t\t\"rotate-90\",\n> > +\t\t},\n> > +\t\t{ 0, nullptr, nullptr }\n> > +\t};\n> > +\n> > +\tif (!type)\n> > +\t\ttype = g_enum_register_static(\"GstLibcameraOrientation\", values);\n> > +\n> > +\treturn type;\n> > +}\n> > +\n> >  static void\n> >  gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >  {\n> > @@ -1154,6 +1214,18 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >  \t\t\t\t\t\t\t     | 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> > +\tGType orientation_type = gst_libcamera_orientation_get_type();\n> > +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> > +\t\t\t\t\t       \"Select the orientation of the camera.\",\n>\n> This needs a better description, and a better name. For me, the orientation of a camera is\n> basically the fixed (physical) orientation against a device specific reference point, not\n> omething you can select. Even PTZ cameras don't have that kind of control physically.\n>\n> While dedicated elements such as videoflip or glvideoflip just call this method, a good\n> name to follow could be glimagesink which calls this rotate-methode.\n>\n> Nicolas\n>\n> > +\t\t\t\t\t       orientation_type,\n> > +\t\t\t\t\t       static_cast<gint>(libcamera::Orientation::Rotate0),\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> > +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> > +\n> >  \tGstCameraControls::installProperties(object_class, PROP_LAST);\n> >  }\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 63C42C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Jun 2025 13:17:58 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3F4E568DD0;\n\tWed, 25 Jun 2025 15:17:57 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C4CBC61533\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 15:17:55 +0200 (CEST)","from ideasonboard.com (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8CDA2C9;\n\tWed, 25 Jun 2025 15:17:37 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"UGWhWU0A\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750857457;\n\tbh=1BtB4ZbByuAvqAOgf81aa73IVYf7OnSPWBZ2weuFzoM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=UGWhWU0AO/C1X5/Dy7E6T/fz9JTjd9Tmqlo6iUC+TkKdMTTNhWASIOOjxRjZD4CQM\n\tWBrKIIgG7TBGZnGJzs94pGms6fWJ4eSPPpuFYt2FjtkDqrqFlZwepx8Ve6MggRNnb6\n\tzLqVyQJP1sQp6PXhngTZipJ2vV3IVr1gV/mdOndQ=","Date":"Wed, 25 Jun 2025 15:17:52 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Nicolas Dufresne <nicolas@ndufresne.ca>","Cc":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>, \n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","Message-ID":"<i2ykumlzpdxc3jtlm6y2q2lqdnxbpedtr2o2cukddz2tbkq2sb@z77kegghjfkq>","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>\n\t<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha512;\n\tprotocol=\"application/pgp-signature\"; boundary=\"74q5cgd2nasmr4uy\"","Content-Disposition":"inline","In-Reply-To":"<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>","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":34635,"web_url":"https://patchwork.libcamera.org/comment/34635/","msgid":"<nn2p6p2sv7r3u2hetn7sfppnw6v77ntr27ubyy76qqfrpzb7di@n474au6mrwbs>","date":"2025-06-25T13:24:10","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"On Wed, Jun 25, 2025 at 09:02:24AM -0400, Nicolas Dufresne wrote:\n> Hi,\n>\n> adding my own review on top of other's.\n>\n> Le lundi 23 juin 2025 à 18:35 +0200, Giacomo Cappellini a écrit :\n> > \"orientation\" parameter added to the libcamerasrc\n> > element to control the orientation of the camera feed.\n> >\n> > GST_PARAM_MUTABLE_READY allows the parameter to be changed\n> > only when pipeline is in the READY state\n> >\n> > The parameter is fed into the existing\n> > CameraConfiguration orientation property\n> >\n> > This allows users to specify the rotation of the video stream,\n> > enhancing flexibility in camera applications.\n>\n> Since this is 90 degrees and flips only, it should be clarified, I saw\n> some comment about free form rotation already.\n>\n> Some clarification need in regard to this vs camera physical orientation,\n> e.g. if a sensor has been mounted with such a 90 degree rotation from\n> its reference for a specific device.\n>\n> > ---\n> >  src/gstreamer/gstlibcamerasrc.cpp | 72 +++++++++++++++++++++++++++++++\n> >  1 file changed, 72 insertions(+)\n> >\n> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> > index 51ba8b67..b07156af 100644\n> > --- a/src/gstreamer/gstlibcamerasrc.cpp\n> > +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> > @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {\n> >  \tGstTask *task;\n> >  \n> >  \tgchar *camera_name;\n> > +\tOrientation orientation;\n> >  \n> >  \tstd::atomic<GstEvent *> pending_eos;\n> >  \n> > @@ -157,6 +158,7 @@ struct _GstLibcameraSrc {\n> >  enum {\n> >  \tPROP_0,\n> >  \tPROP_CAMERA_NAME,\n> > +\tPROP_ORIENTATION,\n> >  \tPROP_LAST\n> >  };\n> >  \n> > @@ -616,6 +618,11 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n> >  \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n> >  \t}\n> >  \n> > +\t// print state->orientation for debugging purposes\n> > +\tGST_DEBUG_OBJECT(self, \"Orientation: %d\", (int)self->orientation);\n> > +\t/* Set the orientation control. */\n> > +\tstate->config_->orientation = self->orientation;\n> > +\n> >  \t/* Validate the configuration. */\n> >  \tif (state->config_->validate() == CameraConfiguration::Invalid)\n> >  \t\treturn false;\n> > @@ -926,6 +933,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 = (libcamera::Orientation)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 +955,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> > @@ -1120,6 +1133,53 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n> >  \tgst_element_remove_pad(element, pad);\n> >  }\n> >  \n> > +static GType\n> > +gst_libcamera_orientation_get_type()\n> > +{\n> > +\tstatic GType type = 0;\n> > +\tstatic const GEnumValue values[] = {\n> > +\t\t{\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0),\n>\n> When you write a GStreamer application, you usually import and link GStreamer libraries,\n> but don't link or import libcamera. For this reason, it would be nicer to use the values\n> from GST_VIDEO_ORIENTATION_*. This enum has been made global in GStreamer for that\n> purpose, but it does not mean you have to support all of it, or forced to use its naming.\n>\n> Though, not using the name naming as videoflip, glvideoflip, glimagesink etc. it very\n> confusing. Here's my suggestion, change this to (C++iffy this):\n>\n> static const GEnumValue rotate_methods[] = {\n>   {GST_VIDEO_ORIENTATION_IDENTITY, \"Identity (no rotation)\", \"none\"},\n>   {GST_VIDEO_ORIENTATION_90R, \"Rotate clockwise 90 degrees\", \"clockwise\"},\n>   {GST_VIDEO_ORIENTATION_180, \"Rotate 180 degrees\", \"rotate-180\"},\n>   {GST_VIDEO_ORIENTATION_90L, \"Rotate counter-clockwise 90 degrees\",\n>       \"counterclockwise\"},\n>   {GST_VIDEO_ORIENTATION_HORIZ, \"Flip horizontally\", \"horizontal-flip\"},\n>   {GST_VIDEO_ORIENTATION_VERT, \"Flip vertically\", \"vertical-flip\"},\n>   {GST_VIDEO_ORIENTATION_UL_LR,\n>       \"Flip across upper left/lower right diagonal\", \"upper-left-diagonal\"},\n>   {GST_VIDEO_ORIENTATION_UR_LL,\n>       \"Flip across upper right/lower left diagonal\", \"upper-right-diagonal\"},\n> // This can be added later if we think its useful/usable even though usually only\n> // flips are supported\n> //  {GST_VIDEO_ORIENTATION_AUTO,\n> //      \"Select rotate method based on image-orientation tag\", \"automatic\"},\n>   {0, NULL, NULL},\n> };\n>\n> struct rotate_item {\n> \tGstVideoOrientation gst;\n> \tlibcamera::Orientation lc;\n> };\n>\n> static const rotate_enum_map[] = {\n> \t{ GST_VIDEO_ORIENTATION_IDENTITY, libcamera::Orientation::Rotate0},\n> \t...\n> };\n>\n> The orientation will be bound checked already by the GOBject property machinery.\n>\n>\n> > +\t\t\t\"libcamera::Orientation::Rotate0\",\n> > +\t\t\t\"rotate-0\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate0Mirror\",\n> > +\t\t\t\"rotate-0-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180),\n> > +\t\t\t\"libcamera::Orientation::Rotate180\",\n> > +\t\t\t\"rotate-180\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate180Mirror\",\n> > +\t\t\t\"rotate-180-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate90Mirror\",\n> > +\t\t\t\"rotate-90-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270),\n> > +\t\t\t\"libcamera::Orientation::Rotate270\",\n> > +\t\t\t\"rotate-270\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270Mirror),\n> > +\t\t\t\"libcamera::Orientation::Rotate270Mirror\",\n> > +\t\t\t\"rotate-270-mirror\",\n> > +\t\t}, {\n> > +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90),\n> > +\t\t\t\"libcamera::Orientation::Rotate90\",\n> > +\t\t\t\"rotate-90\",\n> > +\t\t},\n> > +\t\t{ 0, nullptr, nullptr }\n> > +\t};\n> > +\n> > +\tif (!type)\n> > +\t\ttype = g_enum_register_static(\"GstLibcameraOrientation\", values);\n> > +\n> > +\treturn type;\n> > +}\n> > +\n> >  static void\n> >  gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >  {\n> > @@ -1154,6 +1214,18 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >  \t\t\t\t\t\t\t     | 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> > +\tGType orientation_type = gst_libcamera_orientation_get_type();\n> > +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n> > +\t\t\t\t\t       \"Select the orientation of the camera.\",\n>\n> This needs a better description, and a better name. For me, the orientation of a camera is\n> basically the fixed (physical) orientation against a device specific reference point, not\n> omething you can select. Even PTZ cameras don't have that kind of control physically.\n\nIn facts, this is more precisely described as \"orientation of the\nimages\" for the reasons explained in my just-sent previous reply.\n\n>\n> While dedicated elements such as videoflip or glvideoflip just call this method, a good\n> name to follow could be glimagesink which calls this rotate-methode.\n>\n\nAlthough, if you have something more gstreamer-specific to use, that's\nfine. My main point here is that CameraConfiguration::orientation\ncontrols the orientation of the images you receive, libcamera takes\ninto account the sensor rotation for you when computing the transform\nto apply to get images oriented as you have asked.\n\nAs said, in the case the pipeline doesn't support the orientation\nyou've asked for, it will fall back to no-corrections (you'll get\nimages back that match the camera mounting rotation). You should\nprobably catch this validating that CameraConfiguration::orientation\nhas not been Adjusted by CameraConfiguration::validate() and act\naccordingly to inform other elements further down the pipeline, but\nthat's very gstreamer specific so I don't know if this is required or\nnot.\n\n\n> Nicolas\n>\n> > +\t\t\t\t\t       orientation_type,\n> > +\t\t\t\t\t       static_cast<gint>(libcamera::Orientation::Rotate0),\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> > +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n> > +\n> >  \tGstCameraControls::installProperties(object_class, PROP_LAST);\n> >  }\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 5614BBDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Jun 2025 13:24:16 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4F12668DD0;\n\tWed, 25 Jun 2025 15:24:15 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4179861533\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 15:24:13 +0200 (CEST)","from ideasonboard.com (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E4F4E6F3;\n\tWed, 25 Jun 2025 15:23:54 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"qPqmvT8E\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750857835;\n\tbh=hhz/bYxCBKAZLrNZV7KCoFGGVdltgSZTcq1P4wF5DcU=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=qPqmvT8EnqD6qTtK/vOK0MpTnO6ZOnKdOmmsBfE6WG+r1dPERKKYtgWWnETq5TNzh\n\txxo/ZG36rhwJ+i04iIPNyzK95RkeKW2+cybhPWDCVouSReq5ESo0c/IHIpB12aPi/H\n\t3f/0N/FU4gNU9wagxRM06FMM6yp49XQQNx4pUX3k=","Date":"Wed, 25 Jun 2025 15:24:10 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Nicolas Dufresne <nicolas@ndufresne.ca>","Cc":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>, \n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","Message-ID":"<nn2p6p2sv7r3u2hetn7sfppnw6v77ntr27ubyy76qqfrpzb7di@n474au6mrwbs>","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>\n\t<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha512;\n\tprotocol=\"application/pgp-signature\"; boundary=\"qko47bp2tv3ffekv\"","Content-Disposition":"inline","In-Reply-To":"<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>","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":34636,"web_url":"https://patchwork.libcamera.org/comment/34636/","msgid":"<641617cc-c4fa-4488-98ee-3e5beef4e0ea@igalia.com>","date":"2025-06-25T13:53:21","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":232,"url":"https://patchwork.libcamera.org/api/people/232/","name":"Umang Jain","email":"uajain@igalia.com"},"content":"Hi Nicolas,\n\nOn 6/25/25 6:35 PM, Nicolas Dufresne wrote:\n> Hi Umang,\n>\n> Le mercredi 25 juin 2025 à 14:14 +0530, Umang Jain a écrit :\n>> Hi Giacomo,\n>>\n>> Thank you for the patch.\n>>\n>> On 6/23/25 10:05 PM, Giacomo Cappellini wrote:\n>>> \"orientation\" parameter added to the libcamerasrc\n>>> element to control the orientation of the camera feed.\n>>>\n>>> GST_PARAM_MUTABLE_READY allows the parameter to be changed\n>>> only when pipeline is in the READY state\n>>>\n>>> The parameter is fed into the existing\n>>> CameraConfiguration orientation property\n>>>\n>>> This allows users to specify the rotation of the video stream,\n>>> enhancing flexibility in camera applications.\n>>> ---\n>>>    src/gstreamer/gstlibcamerasrc.cpp | 72 +++++++++++++++++++++++++++++++\n>>>    1 file changed, 72 insertions(+)\n>>\n>> I believe we need to implement the GstVideoDirection interface[1] for\n>> libcamerasrc, and map GstVideoOrientationMethod [2] to\n>> libcamera::Orientation values and pass it to the\n>> CameraConfiguration::orientation.\n> I'm not entirely certain that implementing the interface is a good idea. We\n> don't have any software fallback, so we can't guaranty the effect. I don't\n> know a lot of users for this interface, and may have a hard time verifying\n> the existing application needs.\n\n\nMy observations are same as ours when it comes to usage of the \nGstVideoDirection interface in other elements. Maybe that's the reason \nthat the interface is not very well used, is because elements probably \ndon't implement all the enum values or have a fallback.\n\nSo, indeed we can drop the interface part.\n\n\n>\n>> Here is a quick snippet to implement the interface:\n>>\n>>\n>> diff --git a/src/gstreamer/gstlibcamerasrc.cpp\n>> b/src/gstreamer/gstlibcamerasrc.cpp\n>> index 51ba8b67..2577fb5f 100644\n>> --- a/src/gstreamer/gstlibcamerasrc.cpp\n>> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n>> @@ -163,9 +163,15 @@ enum {\n>>    static void gst_libcamera_src_child_proxy_init(gpointer g_iface,\n>>                                                  gpointer iface_data);\n>>\n>> +\n>> +static void\n>> +gst_libcamera_src_video_direction_init(GstVideoDirectionInterface *iface);\n>> +\n>>    G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src,\n>> GST_TYPE_ELEMENT,\n>> G_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY,\n>> - gst_libcamera_src_child_proxy_init)\n>> + gst_libcamera_src_child_proxy_init);\n>> + G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_DIRECTION,\n>> + gst_libcamera_src_video_direction_init);\n>>                           GST_DEBUG_CATEGORY_INIT(source_debug,\n>> \"libcamerasrc\", 0,\n>>                                                   \"libcamera Source\"))\n>>\n>> @@ -1186,3 +1192,10 @@ gst_libcamera_src_child_proxy_init(gpointer\n>> g_iface, [[maybe_unused]] gpointer i\n>>           iface->get_child_by_index =\n>> gst_libcamera_src_child_proxy_get_child_by_index;\n>>           iface->get_children_count =\n>> gst_libcamera_src_child_proxy_get_children_count;\n>>    }\n>> +\n>> +static void\n>> +gst_libcamera_src_video_direction_init([[maybe_unused]]\n>> GstVideoDirectionInterface *iface)\n>> +{\n>> +       /* We implement the video-direction property */\n>> +\n>> +}\n>>\n>> [1] :\n>> https://gstreamer.freedesktop.org/documentation/video/gstvideodirection.html?gi-language=c\n>>\n>> [2]:\n>> https://gstreamer.freedesktop.org/documentation/video/gstvideo.html?gi-language=c#GstVideoOrientationMethod\n>>\n>>> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n>>> index 51ba8b67..b07156af 100644\n>>> --- a/src/gstreamer/gstlibcamerasrc.cpp\n>>> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n>>> @@ -146,6 +146,7 @@ struct _GstLibcameraSrc {\n>>>    \tGstTask *task;\n>>>    \n>>>    \tgchar *camera_name;\n>>> +\tOrientation orientation;\n>>\n>> This should be GstVideoOrientationMethod\n>>\n>>>    \n>>>    \tstd::atomic<GstEvent *> pending_eos;\n>>>    \n>>> @@ -157,6 +158,7 @@ struct _GstLibcameraSrc {\n>>>    enum {\n>>>    \tPROP_0,\n>>>    \tPROP_CAMERA_NAME,\n>>> +\tPROP_ORIENTATION,\n>>>    \tPROP_LAST\n>>>    };\n>>>    \n>>> @@ -616,6 +618,11 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n>>>    \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n>>>    \t}\n>>>    \n>>> +\t// print state->orientation for debugging purposes\n>>> +\tGST_DEBUG_OBJECT(self, \"Orientation: %d\", (int)self->orientation);\n>>> +\t/* Set the orientation control. */\n>>> +\tstate->config_->orientation = self->orientation;\n>>> +\n>>\n>> This can be\n>>\n>>       state->config_->orientation =\n>> gst_libcamera_src_gst_orientation_method_to_orientation(self->orientation);\n>>\n>>\n>> gst_libcamera_src_gst_orientation_method_to_orientation() returns the\n>> corresponding libcamera::Orientation from GstOrientationMethod value.  I\n>> hope you get the idea.\n>>\n>>\n>>>    \t/* Validate the configuration. */\n>>>    \tif (state->config_->validate() == CameraConfiguration::Invalid)\n>>>    \t\treturn false;\n>>> @@ -926,6 +933,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 = (libcamera::Orientation)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 +955,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>>> @@ -1120,6 +1133,53 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n>>>    \tgst_element_remove_pad(element, pad);\n>>>    }\n>>>    \n>>> +static GType\n>>> +gst_libcamera_orientation_get_type()\n>>> +{\n>>> +\tstatic GType type = 0;\n>>> +\tstatic const GEnumValue values[] = {\n>>> +\t\t{\n>>> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0),\n>>> +\t\t\t\"libcamera::Orientation::Rotate0\",\n>>> +\t\t\t\"rotate-0\",\n>>> +\t\t}, {\n>>> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate0Mirror),\n>>> +\t\t\t\"libcamera::Orientation::Rotate0Mirror\",\n>>> +\t\t\t\"rotate-0-mirror\",\n>>> +\t\t}, {\n>>> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180),\n>>> +\t\t\t\"libcamera::Orientation::Rotate180\",\n>>> +\t\t\t\"rotate-180\",\n>>> +\t\t}, {\n>>> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate180Mirror),\n>>> +\t\t\t\"libcamera::Orientation::Rotate180Mirror\",\n>>> +\t\t\t\"rotate-180-mirror\",\n>>> +\t\t}, {\n>>> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90Mirror),\n>>> +\t\t\t\"libcamera::Orientation::Rotate90Mirror\",\n>>> +\t\t\t\"rotate-90-mirror\",\n>>> +\t\t}, {\n>>> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270),\n>>> +\t\t\t\"libcamera::Orientation::Rotate270\",\n>>> +\t\t\t\"rotate-270\",\n>>> +\t\t}, {\n>>> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate270Mirror),\n>>> +\t\t\t\"libcamera::Orientation::Rotate270Mirror\",\n>>> +\t\t\t\"rotate-270-mirror\",\n>>> +\t\t}, {\n>>> +\t\t\tstatic_cast<gint>(libcamera::Orientation::Rotate90),\n>>> +\t\t\t\"libcamera::Orientation::Rotate90\",\n>>> +\t\t\t\"rotate-90\",\n>>> +\t\t},\n>>> +\t\t{ 0, nullptr, nullptr }\n>>> +\t};\n>>> +\n>>> +\tif (!type)\n>>> +\t\ttype = g_enum_register_static(\"GstLibcameraOrientation\", values);\n>>> +\n>>> +\treturn type;\n>>> +}\n>>> +\n>>>    static void\n>>>    gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>>>    {\n>>> @@ -1154,6 +1214,18 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n>>>    \t\t\t\t\t\t\t     | 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>>> +\tGType orientation_type = gst_libcamera_orientation_get_type();\n>>> +\tspec = g_param_spec_enum(\"orientation\", \"Orientation\",\n>>> +\t\t\t\t\t       \"Select the orientation of the camera.\",\n>>> +\t\t\t\t\t       orientation_type,\n>>> +\t\t\t\t\t       static_cast<gint>(libcamera::Orientation::Rotate0),\n>> And use GST_VIDEO_ORIENTATION_IDENTITY here.\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>>> +\tg_object_class_install_property(object_class, PROP_ORIENTATION, spec);\n>>> +\n>>>    \tGstCameraControls::installProperties(object_class, PROP_LAST);\n>>>    }\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 3DB65C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Jun 2025 13:53:25 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 054CB68DD0;\n\tWed, 25 Jun 2025 15:53:24 +0200 (CEST)","from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7F96261533\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 15:53:21 +0200 (CEST)","from [49.36.69.141] (helo=[192.168.29.4])\n\tby fanzine2.igalia.com with esmtpsa \n\t(Cipher TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_128_GCM:128)\n\t(Exim) id 1uUQYw-008XfA-EM; Wed, 25 Jun 2025 15:53:18 +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=\"nVAlMeyZ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n\ts=20170329;\n\th=Content-Transfer-Encoding:Content-Type:In-Reply-To:From:\n\tReferences:To:Subject:MIME-Version:Date:Message-ID:Sender:Reply-To:Cc:\n\tContent-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:\n\tResent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:\n\tList-Subscribe:List-Post:List-Owner:List-Archive;\n\tbh=mZ7wg9QZJ5oug2sw1tfGQSPXnjK8bY95ExB0A50fizk=;\n\tb=nVAlMeyZaELH//8rRc4VQOx80s\n\t9aEJBPVeiSkNL8/pJQ5qp4Ba4FjIu0fVAf/H1tQUdWcjDRP3gdiFTnYtQ5JwrQChCWlY6NXUkNkyx\n\tZb38zciTfkzwf5Zh/8M7t3w9eitkat8jyv1pbEtrWrIeSwZQ4MXD4NTSsOVcnENgHFwE60JmFy7DH\n\tagS2bQoHdhnuvBb3nsMxdepNRtWVPBsSbLAfkAPQ6aHN5IoEnTaWWHL9dTQkF6L4Tidi3tHZkfHJf\n\tvja5naFmqpr4mpKbAtZpx3Vyh7G4IRu3PORxwaaJMlnONaDxsswZVNZksfEmsLl0R0ybKUWyezFsP\n\t8SPc131Q==;","Message-ID":"<641617cc-c4fa-4488-98ee-3e5beef4e0ea@igalia.com>","Date":"Wed, 25 Jun 2025 19:23:21 +0530","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","To":"Nicolas Dufresne <nicolas@ndufresne.ca>,\n\tGiacomo Cappellini <giacomo.cappellini.87@gmail.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>\n\t<fd93f8a6-a1f6-4752-acd6-00dc11ce82eb@igalia.com>\n\t<7c8fc6a8b5586a22b9489ee2cfd3a657a31ce89e.camel@ndufresne.ca>","Content-Language":"en-US","From":"Umang Jain <uajain@igalia.com>","In-Reply-To":"<7c8fc6a8b5586a22b9489ee2cfd3a657a31ce89e.camel@ndufresne.ca>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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":34639,"web_url":"https://patchwork.libcamera.org/comment/34639/","msgid":"<35009f6a7e700959e7c5bb6f1b9083b52e2c34c8.camel@ndufresne.ca>","date":"2025-06-25T17:37:56","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":30,"url":"https://patchwork.libcamera.org/api/people/30/","name":"Nicolas Dufresne","email":"nicolas@ndufresne.ca"},"content":"Hi,\n\nLe mercredi 25 juin 2025 à 15:17 +0200, Jacopo Mondi a écrit :\n> Hi Nicolas\n\n[...]\n\n> To summarize:\n> \n> - mounting rotation is a static camera properties reported through\n>   Camera::properties(). I'm not sure how you want/should expose this\n>   thtough the gstreamer API.\n\n*If* you want to expose it, I would place that in the GstDevice in the\ndevice properties. Application will be able to get this through\ngst_device_get_properties() once the camera have beeen enumerated.\n\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 A402DBDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 25 Jun 2025 17:38:03 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4F67568DF3;\n\tWed, 25 Jun 2025 19:38:02 +0200 (CEST)","from mail-qk1-x72e.google.com (mail-qk1-x72e.google.com\n\t[IPv6:2607:f8b0:4864:20::72e])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1717061533\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 19:38:00 +0200 (CEST)","by mail-qk1-x72e.google.com with SMTP id\n\taf79cd13be357-7d0976776dcso12314785a.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 25 Jun 2025 10:38:00 -0700 (PDT)","from ?IPv6:2606:6d00:17:b699::bad? ([2606:6d00:17:b699::bad])\n\tby smtp.gmail.com with ESMTPSA id\n\taf79cd13be357-7d41d5ffcfcsm261833785a.68.2025.06.25.10.37.57\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 25 Jun 2025 10:37:58 -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=\"3CdipdZb\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ndufresne-ca.20230601.gappssmtp.com; s=20230601; t=1750873079;\n\tx=1751477879; darn=lists.libcamera.org; \n\th=mime-version:user-agent:autocrypt:references:in-reply-to:date:cc:to\n\t:from:subject:message-id:from:to:cc:subject:date:message-id:reply-to; \n\tbh=mFE7Zq7mBtjdrONKTtDGAS5EGdSrssLYRR9UPIQJ4As=;\n\tb=3CdipdZb3SaZ1sQ3z0A/rODGKYtzAYoXM6MCAdAZbXWjSY0ARTl2aKOhDsqYlaDr/W\n\tpcf5QcHMTrnuTo9M+ETn8uVW909bEX5bT9TXfh68GyvHPULWikZ6MOgoxVWpG6Jy49gK\n\tDeF9Yg51XDkppBjIpYqvdGJP3PxuSvE5EHIds6tH9IX6tFd6kv6o5y0i0mqxyrcaPJna\n\t3DGHdBlHV1ZI3PZ2tU9VGREX+WmijE/Os6yoqX7197eOPiZuRdvC1ODCJMb9JYk0UPhu\n\tbnMEuMpQxTLq27EGyzkcSaNEQTla0D+d81mO/xgSZfxR/xljsrnTIIsy6f6ob5tHZdLb\n\t46Xw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1750873079; x=1751477879;\n\th=mime-version:user-agent:autocrypt:references:in-reply-to:date:cc:to\n\t:from:subject:message-id:x-gm-message-state:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=mFE7Zq7mBtjdrONKTtDGAS5EGdSrssLYRR9UPIQJ4As=;\n\tb=mnQoE9WIBxXkm/8j36AF8o+DzP7JEkEH+GUDbNgiR4PqOnTDVCqJuKptbu1SF59qOz\n\tADh1K39aGN/Y6J5UijrGYJr5YPyl2kdZBZYSgZK19zRDAw0iu7wwR7I1zjDvYHiMCbsj\n\tRdzAkfwvmxQEuzb7pxX+uOO2iSh62PWz5IDYs6BZykRa/fWYDJtq2XyJ/YpqgSpeTqrL\n\tY8HUixr+BeZcABALje3l/c+Z61l7j/jdUOuncv82efXK9jqlhUDReuPkYxpYEd1ZRqx0\n\tmhjeWVdcQjrMa7XS6aEUMOSt5FYJX5lbAeuEPZsUxPaKC+ivxsx0RrKDyEO3Jngve0LN\n\tpNRg==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCXnt2Gx99dyowEe4BSJHsHV+kkIu6XpRsUIOEznaCE0xfwTwi3D3S6Zfn/ChzIac/n/eGueTqBxwOHtBNRex88=@lists.libcamera.org","X-Gm-Message-State":"AOJu0YyWUEdlgd6992XNhw9hO7j5fUqPM0O3fbKWjGaMQS+vHN9Kwvsv\n\tRc2e0onWUTEwsdWg9vLnPkwSYd+RxxOD9J1o+Ga6XFniuIo0gyE3S7QGUqDSYPztr9E=","X-Gm-Gg":"ASbGncv09ggOjVgZMEbXbxkEedKH/wp5p+CgxYDwumQmf/S60PH8zI02MitOQPKdqZk\n\t3+7m6SAWAx09K/PFbr5962suiitE9ow34OsKKIjIW+jzHdaur1w5P5UkvLVJOkDhCuOZOcjjFtO\n\tOkPpA6YHt1cwo0/yOq8YR3UiLZq+neGFMjFJZpqZtZ2DSz4N/ExeZYIGdjTaeIXBw013w3EqSis\n\t6Gmfw+nT2n/y9knCH2SeFN5+kviy+SnCd6tzYquttJY38rj8Z1Ka3NNvX256DtbejkuoViSLxdq\n\tGkGkKrQ8bQTp1kdjTbUmD6RibdFXJu8jXhde77OFZkvnVQ+8sHwi+ZbBTJr6kLWVC6Y=","X-Google-Smtp-Source":"AGHT+IHa4d6k03cLS6nXRIA598rQDiuHf221GHwcSkn+9bDIDSlLqd9HeKbeFMeVeDgOgLrypRnl2w==","X-Received":"by 2002:a05:620a:280e:b0:7d3:ed55:cc29 with SMTP id\n\taf79cd13be357-7d429715428mr528304185a.28.1750873078716; \n\tWed, 25 Jun 2025 10:37:58 -0700 (PDT)","Message-ID":"<35009f6a7e700959e7c5bb6f1b9083b52e2c34c8.camel@ndufresne.ca>","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","From":"Nicolas Dufresne <nicolas@ndufresne.ca>","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>, \n\tlibcamera-devel@lists.libcamera.org","Date":"Wed, 25 Jun 2025 13:37:56 -0400","In-Reply-To":"<i2ykumlzpdxc3jtlm6y2q2lqdnxbpedtr2o2cukddz2tbkq2sb@z77kegghjfkq>","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>\n\t<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>\n\t<i2ykumlzpdxc3jtlm6y2q2lqdnxbpedtr2o2cukddz2tbkq2sb@z77kegghjfkq>","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=\"=-YoOR5lZxI9b2DTgSZC24\"","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":34649,"web_url":"https://patchwork.libcamera.org/comment/34649/","msgid":"<20250626102450.GG8738@pendragon.ideasonboard.com>","date":"2025-06-26T10:24:50","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Wed, Jun 25, 2025 at 01:37:56PM -0400, Nicolas Dufresne wrote:\n> Le mercredi 25 juin 2025 à 15:17 +0200, Jacopo Mondi a écrit :\n> > Hi Nicolas\n> \n> [...]\n> \n> > To summarize:\n\nThanks Jacopo for that clear and accurate summary.\n\n> > - mounting rotation is a static camera properties reported through\n> >   Camera::properties(). I'm not sure how you want/should expose this\n> >   thtough the gstreamer API.\n> \n> *If* you want to expose it, I would place that in the GstDevice in the\n> device properties. Application will be able to get this through\n> gst_device_get_properties() once the camera have beeen enumerated.\n\nAck. I think it's useful to expose it, and making it a GstDevice\nproperty seems a good solution. It's a separate issue from controlling\nthe image orientation though, so it can be addresses separately.","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 9AA94BDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 26 Jun 2025 10:25:17 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8640668DF3;\n\tThu, 26 Jun 2025 12:25:16 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E4E0368DE8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 26 Jun 2025 12:25:14 +0200 (CEST)","from pendragon.ideasonboard.com (85-76-34-12-nat.elisa-mobile.fi\n\t[85.76.34.12])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 9F2E5743;\n\tThu, 26 Jun 2025 12:24:55 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"EJrsSNKL\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1750933496;\n\tbh=cl58W7wlXGrcTN61ZVYh4okEvF+Os+N8agsXRTfsJCQ=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=EJrsSNKLj+BqR8AGxm9p6wSwCPPhrMbmDy+JtIEZcOVokma/DpRDFuIz3xQz9zbFU\n\t8i+7Xi9QAbHBOEkVpcF4hXCm6Oy4MJeSKftoS8ln+IIosV/TpXUJhqprpMvv9QWnpb\n\tlaC2OUdeQLtUZSgISQepTUSFTa8BfR5lGfrt55Jc=","Date":"Thu, 26 Jun 2025 13:24:50 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Nicolas Dufresne <nicolas@ndufresne.ca>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tGiacomo Cappellini <giacomo.cappellini.87@gmail.com>,\n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","Message-ID":"<20250626102450.GG8738@pendragon.ideasonboard.com>","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>\n\t<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>\n\t<i2ykumlzpdxc3jtlm6y2q2lqdnxbpedtr2o2cukddz2tbkq2sb@z77kegghjfkq>\n\t<35009f6a7e700959e7c5bb6f1b9083b52e2c34c8.camel@ndufresne.ca>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<35009f6a7e700959e7c5bb6f1b9083b52e2c34c8.camel@ndufresne.ca>","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":34651,"web_url":"https://patchwork.libcamera.org/comment/34651/","msgid":"<CABXJd1mQUSSFyDYvPuoL2h+-jiNKmd1NajUMjbkhZXZOHo1JKg@mail.gmail.com>","date":"2025-06-26T10:28:26","subject":"Re: [PATCH] gstreamer: Adding property to control orientation","submitter":{"id":231,"url":"https://patchwork.libcamera.org/api/people/231/","name":"Giacomo Cappellini","email":"giacomo.cappellini.87@gmail.com"},"content":"Hi,\n\nI just sent [PATCH v2] gstreamer: Adding static rotation property to\nGstLibcameraDevice and mutable orientation property to GstLibcameraSrc\n\nAs discussed here,, I put rotation in GstDevice and orientation in\nGstLibcameraSrc. I make no use of GstVideoDirection.\n\nRegards,\nG.C.\n\nIl giorno gio 26 giu 2025 alle ore 12:25 Laurent Pinchart\n<laurent.pinchart@ideasonboard.com> ha scritto:\n>\n> On Wed, Jun 25, 2025 at 01:37:56PM -0400, Nicolas Dufresne wrote:\n> > Le mercredi 25 juin 2025 à 15:17 +0200, Jacopo Mondi a écrit :\n> > > Hi Nicolas\n> >\n> > [...]\n> >\n> > > To summarize:\n>\n> Thanks Jacopo for that clear and accurate summary.\n>\n> > > - mounting rotation is a static camera properties reported through\n> > >   Camera::properties(). I'm not sure how you want/should expose this\n> > >   thtough the gstreamer API.\n> >\n> > *If* you want to expose it, I would place that in the GstDevice in the\n> > device properties. Application will be able to get this through\n> > gst_device_get_properties() once the camera have beeen enumerated.\n>\n> Ack. I think it's useful to expose it, and making it a GstDevice\n> property seems a good solution. It's a separate issue from controlling\n> the image orientation though, so it can be addresses separately.\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","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 17AA8BDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 26 Jun 2025 10:28:42 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 61BDD68DF3;\n\tThu, 26 Jun 2025 12:28:41 +0200 (CEST)","from mail-il1-x12a.google.com (mail-il1-x12a.google.com\n\t[IPv6:2607:f8b0:4864:20::12a])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8CB9B68DE8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 26 Jun 2025 12:28:39 +0200 (CEST)","by mail-il1-x12a.google.com with SMTP id\n\te9e14a558f8ab-3df3891e28fso3174915ab.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 26 Jun 2025 03:28:39 -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=\"TGWEndy9\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=gmail.com; s=20230601; t=1750933718; x=1751538518;\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=RAcPgDpQIHV4BhhVfIjbmhJZX4G38x2LpvYfyPlDtPM=;\n\tb=TGWEndy9qy0DCkLD8yXukhBPGWACkJHsHZo+VVoSkzbzf6VNuNZLGhLiDxYd1a2kdT\n\tCnvr8NvgLa67CjyHXq3A4S4+LjM+D9BiyZT72BIHqvQ5GcPT+1u6s/aZNM9uwboiXOTq\n\t+ZhzBZKa63kWDBUkVOLkYYTlgN3gV4uQrzlkPKbmj/wy/OxqCZqCBtHC+5r3txjDg2Bh\n\twaF+reyZ8txQiLWKqwp+RDbDCwo77+eFFeuYFzbP7D5InSdMaVC4g6C0ztgjbuozf+cS\n\taxGQclBWLEe9Bf1QnZGsvQFd2vpdJAL44lgGV1AaEy6HmwH/d32ZgwgeK3pH6N1r71PP\n\tjn8w==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1750933718; x=1751538518;\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=RAcPgDpQIHV4BhhVfIjbmhJZX4G38x2LpvYfyPlDtPM=;\n\tb=An64alEgOwo4SQyxjk80YAY8qwpGJV+n/89w+JtIU01FeBlztO7LFsK3I7mXkQ7QN1\n\tz4MnPhFVdnl0sPgXm/CqlquHyYEGS0QRn8sMx2KIHEI4ETZqitLShrOYOrUHSn2SUuHQ\n\tez/T1/JzeZpV4WmZtlLVnEjCUaTen2/soISDHv3qJMEFoaqe/0aUoEldm6b21Uy2C29w\n\tAv7Ka2eDb0y5deK2ANC6uFzPXsY0jrU9pb9j6mm+l6bqM5hcZK6KJavJizTpZ/FNB16h\n\t8Xc6d4aNz58QHS3lwpYv1MMK+aWm5RWt7U//YUH4VJG+wJ/HXRQ+W0QciVh6ECzHyQOA\n\t/hHQ==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCX3elMTN7O9SmrXu506N1H+UjrzerM9qt16mdGS3lGLblnihnw8cUIbgMHmXYi49TnfzC0BYHBgWgzFZUtlxOM=@lists.libcamera.org","X-Gm-Message-State":"AOJu0YykuPagraGb6y76REnzlxlhqXu0X20PV4ypEHmgKm2/LUJLQPWr\n\t5vjYUkvzJ0VJ/UaGWDBw1XPBm8H0h4Mr1LiCyf6v3LETQ4gpMkCxJVTj9YYqhvazOSTDywa0mkR\n\tWZA9XjQLCWoNzb0BN67dEFPE29grTf9x1sNDyWsM=","X-Gm-Gg":"ASbGncuWkNpxTldChlcZmEqJ2PGyby3cPMCcTMTTkJ0z4KSr52/w6yUQb105eVJ/T6T\n\t6hstMvEGWbuZ4T6gZFIPugcOqurl057RtkE6T6CehpfJ0fW5uJK/Jmy2RxdoApakctr3tDMBMSA\n\tk4868Vb84AxKXug+Ys/+J6Dpe06Mo6plxN55yo3AvpO32Q","X-Google-Smtp-Source":"AGHT+IFvmhPX56/fWt/h5tLfg/b4aUJ2sPi3+EZBx7URgytQAYLJX8Y0xazWpdSnB2GxRaLs67TsBbadMoKOtq1bSec=","X-Received":"by 2002:a05:6e02:1789:b0:3dc:8b29:30b1 with SMTP id\n\te9e14a558f8ab-3df3299f953mr85676515ab.14.1750933718232;\n\tThu, 26 Jun 2025 03:28:38 -0700 (PDT)","MIME-Version":"1.0","References":"<20250623163540.1787972-1-giacomo.cappellini.87@gmail.com>\n\t<a0d058e095f40b53e5e1b77fa00920ce2556d5bc.camel@ndufresne.ca>\n\t<i2ykumlzpdxc3jtlm6y2q2lqdnxbpedtr2o2cukddz2tbkq2sb@z77kegghjfkq>\n\t<35009f6a7e700959e7c5bb6f1b9083b52e2c34c8.camel@ndufresne.ca>\n\t<20250626102450.GG8738@pendragon.ideasonboard.com>","In-Reply-To":"<20250626102450.GG8738@pendragon.ideasonboard.com>","From":"Giacomo Cappellini <giacomo.cappellini.87@gmail.com>","Date":"Thu, 26 Jun 2025 12:28:26 +0200","X-Gm-Features":"Ac12FXxe9_zpx19S7VDBNtsP1CmfXS5InKqwpEX5Mqc9RaYO5FrP2k9Y4C_SWug","Message-ID":"<CABXJd1mQUSSFyDYvPuoL2h+-jiNKmd1NajUMjbkhZXZOHo1JKg@mail.gmail.com>","Subject":"Re: [PATCH] gstreamer: Adding property to control orientation","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"Nicolas Dufresne <nicolas@ndufresne.ca>,\n\tJacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tlibcamera-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>"}}]