Show a patch.

GET /api/1.1/patches/23901/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 23901,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/23901/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/23901/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20250723093954.599102-1-giacomo.cappellini.87@gmail.com>",
    "date": "2025-07-23T09:39:37",
    "name": "[v2] gstreamer: Add support for Orientation",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "dd54938047ae84d570a9065b4d3530e37c8fd908",
    "submitter": {
        "id": 231,
        "url": "https://patchwork.libcamera.org/api/1.1/people/231/?format=api",
        "name": "Giacomo Cappellini",
        "email": "giacomo.cappellini.87@gmail.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/23901/mbox/",
    "series": [
        {
            "id": 5313,
            "url": "https://patchwork.libcamera.org/api/1.1/series/5313/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5313",
            "date": "2025-07-23T09:39:37",
            "name": "[v2] gstreamer: Add support for Orientation",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/5313/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/23901/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/23901/checks/",
    "tags": {},
    "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 054FBBDCC1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 23 Jul 2025 09:40:08 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 17C416904D;\n\tWed, 23 Jul 2025 11:40:07 +0200 (CEST)",
            "from mail-ej1-x62f.google.com (mail-ej1-x62f.google.com\n\t[IPv6:2a00:1450:4864:20::62f])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B18CC68FB6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 23 Jul 2025 11:40:05 +0200 (CEST)",
            "by mail-ej1-x62f.google.com with SMTP id\n\ta640c23a62f3a-ae0c571f137so1223657566b.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 23 Jul 2025 02:40:05 -0700 (PDT)",
            "from jasus.ad.servtec.it\n\t(host-95-251-230-143.retail.telecomitalia.it. [95.251.230.143])\n\tby smtp.gmail.com with ESMTPSA id\n\ta640c23a62f3a-aec6c7d7783sm1023304566b.63.2025.07.23.02.40.03\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 23 Jul 2025 02:40:03 -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=\"Jflei3E8\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=gmail.com; s=20230601; t=1753263605; x=1753868405;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:mime-version:message-id:date:subject:cc\n\t:to:from:from:to:cc:subject:date:message-id:reply-to;\n\tbh=frtNiTtbW4je1h3Op+wmlTSSukxlBLL4xo8u1I2THCc=;\n\tb=Jflei3E8upOMtcCqn+O0tb2yFb1VkAfM0zEBU9RG8jAWCWYpUAvrlK2Ue0ck2kqcAW\n\tJjmMFPUx/ugJPRhqDaYs3bASJkOaOKbcgeNGx53gJRCQhpGjrPd47FBIgEQdoIq7W/6j\n\t3T2f2CF0kawHz8IEadc/XUO91GZd2CK+ouMF6p+hyxH9EdPH2r5xM8RRZjm+4qI5nzhP\n\tdmM4UKBF8t5wiY88alzZefZmhQvnF14F9Rqc4H/EosQGng8Y41N5qpZpHIeMA+EgoMut\n\tYYA909HAzSsmxn71n0s4bosTSX4Vyj80KE6ATjBOVIZUvYrZNeZkXdDTvKFNgCwMpouL\n\tselA==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1753263605; x=1753868405;\n\th=content-transfer-encoding:mime-version:message-id:date:subject:cc\n\t:to:from:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=frtNiTtbW4je1h3Op+wmlTSSukxlBLL4xo8u1I2THCc=;\n\tb=fqDnQqdL2cwDCkeVPo/yZRPIq3sV3H5dZ2RyQoNg72uWYeA3zk7n58TOCt2X6aY79P\n\t2AxJLMR/mJ6cfvqalkLWB3yUGKMwbg2do2NRDN/LcK65Kz7fIZGq/q61N5e4tmqJPPOV\n\tPHabbzgZ3okBKnB3y46wXVVK+EdoJRpk/A4Spz7n6NfCwx6EEsRRjZ3BQoUgJ2Un5dqn\n\ta0vARpI9KaQDhwAcVhFkteGAk0Uy6RsyDeMMS/UW5jrD5vjEjuVkNgVtJjMQbzlfww9O\n\tPbfoCanqXFZ6O6EKo/gnHcyGRD6gCyTBsLnnmTRTsesaMWGa4Sof2KF7tyN4gQz9ROzG\n\t0EnA==",
        "X-Gm-Message-State": "AOJu0YxUu3gXAdh+PJXKX1GW+vNnboz6LWurfhXE0inLTHMO6A+FqWLy\n\tvmHDuOUMxClhyOKOfCQ2QUe4gnhbr3MoroqWPa9hxDqilcdwp1MvxNhFdQBfazE+4Lw=",
        "X-Gm-Gg": "ASbGncsMP/zgdn41hU5Ir/ZySwvVgE+PeRSwoMLsmsypq1zXaAsuWBniG0m27hICqrX\n\tDfupgt5fZEjaCNOe/hG9zR3f06UM29Qhzy0l7DvofzcsGTB7L8YEiIwTiHsbH3RE+3f/8i63/j/\n\tghvdGq50cIjan2sq4PV6A8tcYrj8Ay2Oy7GB/s4R0HA6IwsVStrV1RdR9tVCsbpTLuTLtrHz/6/\n\thCRI+FiuDnjeLwMoVNnZsbnjnAOt2YNtZqUnYAnEPidsT3cfWUuYfZzCq5friPT6XSd7an4m8Ox\n\tS3+eg+584EPsDE7LYxY4BYz3YlpwOYVQJMEyhvQKTnqGIQ+E/FMcfj15wET8bcWHWVJeisz+EeI\n\tX3L+9qJv1fnDt4xCKCo2NbI4U3uq0OMuKmvhdn0U7dVPz8TqM3BijGyJdrdel6KHdakqLc3tSgp\n\t0JpsAO1/NPm+CbGWqMx3kaKg==",
        "X-Google-Smtp-Source": "AGHT+IGtB3qzr13XzkXeHj6anXyc2sb2nk6l2O/HjrP5Df30iTPZt5TQ0TkfvVET+1Lq9rPuv0KMFw==",
        "X-Received": "by 2002:a17:907:d643:b0:ae3:d021:9b05 with SMTP id\n\ta640c23a62f3a-af2f6bfd8a8mr241351066b.15.1753263604648; \n\tWed, 23 Jul 2025 02:40:04 -0700 (PDT)",
        "From": "Giacomo Cappellini <giacomo.cappellini.87@gmail.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Giacomo Cappellini <giacomo.cappellini.87@gmail.com>",
        "Subject": "[PATCH v2] gstreamer: Add support for Orientation",
        "Date": "Wed, 23 Jul 2025 11:39:37 +0200",
        "Message-ID": "<20250723093954.599102-1-giacomo.cappellini.87@gmail.com>",
        "X-Mailer": "git-send-email 2.43.0",
        "MIME-Version": "1.0",
        "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>"
    },
    "content": "libcamera allows to control the images orientation through the\nCameraConfiguration::orientation field, expose a GST_PARAM_MUTABLE_READY\nparameter of type GstVideoOrientationMethod in GstLibcameraSrc to\ncontrol it. Parameter is mapped internally to libcamera::Orientation via\nnew gstlibcamera-utils functions:\n- gst_video_orientation_to_libcamera_orientation\n- libcamera_orientation_to_gst_video_orientation\n\nUpdate CameraConfiguration::Adjusted case in negotiation to warn about\nchanges in StreamConfiguration and SensorConfiguration, as well as\nthe new Orientation parameter.\n\nsigned-off-by: Giacomo Cappellini <giacomo.cappellini.87@gmail.com>\n---\n src/gstreamer/gstlibcamera-utils.cpp |  32 +++++++\n src/gstreamer/gstlibcamera-utils.h   |   4 +\n src/gstreamer/gstlibcamerasrc.cpp    | 124 ++++++++++++++++++++++++++-\n 3 files changed, 159 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\nindex a548b0c1..fc29d19d 100644\n--- a/src/gstreamer/gstlibcamera-utils.cpp\n+++ b/src/gstreamer/gstlibcamera-utils.cpp\n@@ -10,6 +10,8 @@\n \n #include <libcamera/control_ids.h>\n #include <libcamera/formats.h>\n+#include <libcamera/orientation.h>\n+#include <gst/video/video.h>\n \n using namespace libcamera;\n \n@@ -659,3 +661,33 @@ gst_libcamera_get_camera_manager(int &ret)\n \n \treturn cm;\n }\n+\n+Orientation gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method)\n+{\n+    switch (method) {\n+    case GST_VIDEO_ORIENTATION_IDENTITY:   return Orientation::Rotate0;\n+    case GST_VIDEO_ORIENTATION_90R:        return Orientation::Rotate90;\n+    case GST_VIDEO_ORIENTATION_180:        return Orientation::Rotate180;\n+    case GST_VIDEO_ORIENTATION_90L:        return Orientation::Rotate270;\n+    case GST_VIDEO_ORIENTATION_HORIZ:      return Orientation::Rotate0Mirror;\n+    case GST_VIDEO_ORIENTATION_VERT:       return Orientation::Rotate180Mirror;\n+    case GST_VIDEO_ORIENTATION_UL_LR:      return Orientation::Rotate90Mirror;\n+    case GST_VIDEO_ORIENTATION_UR_LL:      return Orientation::Rotate270Mirror;\n+    default:                               return Orientation::Rotate0;\n+    }\n+}\n+\n+GstVideoOrientationMethod libcamera_orientation_to_gst_video_orientation(Orientation orientation)\n+{\n+    switch (orientation) {\n+    case Orientation::Rotate0:           return GST_VIDEO_ORIENTATION_IDENTITY;\n+    case Orientation::Rotate90:          return GST_VIDEO_ORIENTATION_90R;\n+    case Orientation::Rotate180:         return GST_VIDEO_ORIENTATION_180;\n+    case Orientation::Rotate270:         return GST_VIDEO_ORIENTATION_90L;\n+    case Orientation::Rotate0Mirror:     return GST_VIDEO_ORIENTATION_HORIZ;\n+    case Orientation::Rotate180Mirror:   return GST_VIDEO_ORIENTATION_VERT;\n+    case Orientation::Rotate90Mirror:    return GST_VIDEO_ORIENTATION_UL_LR;\n+    case Orientation::Rotate270Mirror:   return GST_VIDEO_ORIENTATION_UR_LL;\n+    default:                             return GST_VIDEO_ORIENTATION_IDENTITY;\n+    }\n+}\n\\ No newline at end of file\ndiff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h\nindex 5f4e8a0f..3d4b049f 100644\n--- a/src/gstreamer/gstlibcamera-utils.h\n+++ b/src/gstreamer/gstlibcamera-utils.h\n@@ -11,6 +11,7 @@\n #include <libcamera/camera_manager.h>\n #include <libcamera/controls.h>\n #include <libcamera/stream.h>\n+#include <libcamera/orientation.h>\n \n #include <gst/gst.h>\n #include <gst/video/video.h>\n@@ -92,3 +93,6 @@ public:\n private:\n \tGRecMutex *mutex_;\n };\n+\n+libcamera::Orientation gst_video_orientation_to_libcamera_orientation(GstVideoOrientationMethod method);\n+GstVideoOrientationMethod libcamera_orientation_to_gst_video_orientation(libcamera::Orientation orientation);\ndiff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\nindex 3aca4eed..03d389aa 100644\n--- a/src/gstreamer/gstlibcamerasrc.cpp\n+++ b/src/gstreamer/gstlibcamerasrc.cpp\n@@ -32,12 +32,14 @@\n #include <tuple>\n #include <utility>\n #include <vector>\n+#include <sstream>\n \n #include <libcamera/camera.h>\n #include <libcamera/camera_manager.h>\n #include <libcamera/control_ids.h>\n \n #include <gst/base/base.h>\n+#include <gst/video/video.h>\n \n #include \"gstlibcamera-controls.h\"\n #include \"gstlibcamera-utils.h\"\n@@ -146,6 +148,7 @@ struct _GstLibcameraSrc {\n \tGstTask *task;\n \n \tgchar *camera_name;\n+\tGstVideoOrientationMethod orientation;\n \n \tstd::atomic<GstEvent *> pending_eos;\n \n@@ -157,6 +160,7 @@ struct _GstLibcameraSrc {\n enum {\n \tPROP_0,\n \tPROP_CAMERA_NAME,\n+\tPROP_ORIENTATION,\n \tPROP_LAST\n };\n \n@@ -616,9 +620,110 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n \t\tgst_libcamera_get_framerate_from_caps(caps, element_caps);\n \t}\n \n+\t/* Set orientation control. */\n+\tstate->config_->orientation = gst_video_orientation_to_libcamera_orientation(self->orientation);\n+\n+\t/* Save original configuration for comparison after validation */\n+\tstd::vector<StreamConfiguration> orig_stream_cfgs;\n+\tfor (gsize i = 0; i < state->config_->size(); i++)\n+\t\torig_stream_cfgs.push_back(state->config_->at(i));\n+\tstd::optional<SensorConfiguration> orig_sensor_cfg = state->config_->sensorConfig;\n+\tOrientation orig_orientation = state->config_->orientation;\n+\n \t/* Validate the configuration. */\n-\tif (state->config_->validate() == CameraConfiguration::Invalid)\n+\tswitch(state->config_->validate()) {\n+\tcase CameraConfiguration::Valid:\n+\t\tGST_DEBUG_OBJECT(self, \"Camera configuration is valid\");\n+\t\tbreak;\n+\tcase CameraConfiguration::Adjusted:\n+\t{\t\n+\t\tbool warned = false;\n+\t\t// Warn if number of StreamConfigurations changed\n+\t\tif (orig_stream_cfgs.size() != state->config_->size()) {\n+\t\t\tGST_WARNING_OBJECT(self, \"Number of StreamConfiguration elements changed: requested=%zu, actual=%zu\",\n+\t\t\t\torig_stream_cfgs.size(), state->config_->size());\n+\t\t\twarned = true;\n+\t\t}\n+\t\t// Warn about changes in each StreamConfiguration\n+\t\t// TODO implement diffing in StreamConfiguration \n+\t\tfor (gsize i = 0; i < std::min(orig_stream_cfgs.size(), state->config_->size()); i++) {\n+\t\t\tif (orig_stream_cfgs[i].toString() != state->config_->at(i).toString()) {\n+\t\t\t\tGST_WARNING_OBJECT(self, \"StreamConfiguration %zu changed: %s -> %s\",\n+\t\t\t\t\ti, orig_stream_cfgs[i].toString().c_str(),\n+\t\t\t\t\tstate->config_->at(i).toString().c_str());\n+\t\t\t\twarned = true;\n+\t\t\t}\n+\t\t}\n+\t\t// Warn about SensorConfiguration changes\n+\t\t// TODO implement diffing in SensorConfiguration\n+\t\tif (orig_sensor_cfg.has_value() || state->config_->sensorConfig.has_value()) {\n+\t\t\tconst SensorConfiguration *orig = orig_sensor_cfg.has_value() ? &orig_sensor_cfg.value() : nullptr;\n+\t\t\tconst SensorConfiguration *curr = state->config_->sensorConfig.has_value() ? &state->config_->sensorConfig.value() : nullptr;\n+\t\t\tbool sensor_changed = false;\n+\t\t\tstd::ostringstream diff;\n+\t\t\tif ((orig == nullptr) != (curr == nullptr)) {\n+\t\t\t\tdiff << \"SensorConfiguration presence changed: \"\n+\t\t\t\t     << (orig ? \"was present\" : \"was absent\")\n+\t\t\t\t     << \" -> \"\n+\t\t\t\t     << (curr ? \"present\" : \"absent\");\n+\t\t\t\tsensor_changed = true;\n+\t\t\t} else if (orig && curr) {\n+\t\t\t\tif (orig->bitDepth != curr->bitDepth) {\n+\t\t\t\t\tdiff << \"bitDepth: \" << orig->bitDepth << \" -> \" << curr->bitDepth << \"; \";\n+\t\t\t\t\tsensor_changed = true;\n+\t\t\t\t}\n+\t\t\t\tif (orig->analogCrop != curr->analogCrop) {\n+\t\t\t\t\tdiff << \"analogCrop: \" << orig->analogCrop.toString() << \" -> \" << curr->analogCrop.toString() << \"; \";\n+\t\t\t\t\tsensor_changed = true;\n+\t\t\t\t}\n+\t\t\t\tif (orig->binning.binX != curr->binning.binX ||\n+\t\t\t\t    orig->binning.binY != curr->binning.binY) {\n+\t\t\t\t\tdiff << \"binning: (\" << orig->binning.binX << \",\" << orig->binning.binY << \") -> (\"\n+\t\t\t\t\t     << curr->binning.binX << \",\" << curr->binning.binY << \"); \";\n+\t\t\t\t\tsensor_changed = true;\n+\t\t\t\t}\n+\t\t\t\tif (orig->skipping.xOddInc != curr->skipping.xOddInc ||\n+\t\t\t\t    orig->skipping.xEvenInc != curr->skipping.xEvenInc ||\n+\t\t\t\t    orig->skipping.yOddInc != curr->skipping.yOddInc ||\n+\t\t\t\t    orig->skipping.yEvenInc != curr->skipping.yEvenInc) {\n+\t\t\t\t\tdiff << \"skipping: (\"\n+\t\t\t\t\t     << orig->skipping.xOddInc << \",\" << orig->skipping.xEvenInc << \",\"\n+\t\t\t\t\t     << orig->skipping.yOddInc << \",\" << orig->skipping.yEvenInc << \") -> (\"\n+\t\t\t\t\t     << curr->skipping.xOddInc << \",\" << curr->skipping.xEvenInc << \",\"\n+\t\t\t\t\t     << curr->skipping.yOddInc << \",\" << curr->skipping.yEvenInc << \"); \";\n+\t\t\t\t\tsensor_changed = true;\n+\t\t\t\t}\n+\t\t\t\tif (orig->outputSize != curr->outputSize) {\n+\t\t\t\t\tdiff << \"outputSize: \" << orig->outputSize.toString() << \" -> \" << curr->outputSize.toString() << \"; \";\n+\t\t\t\t\tsensor_changed = true;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (sensor_changed) {\n+\t\t\t\tGST_WARNING_OBJECT(self, \"SensorConfiguration changed: %s\", diff.str().c_str());\n+\t\t\t\twarned = true;\n+\t\t\t}\n+\t\t}\n+\t\t// Warn about orientation change\n+\t\tif (orig_orientation != state->config_->orientation) {\n+\t\t\tGEnumClass *enum_class = (GEnumClass *)g_type_class_ref(GST_TYPE_VIDEO_ORIENTATION_METHOD);\n+\t\t\tconst char *orig_orientation_str = g_enum_get_value(enum_class, libcamera_orientation_to_gst_video_orientation(orig_orientation))->value_nick;\n+\t\t\tconst char *new_orientation_str = g_enum_get_value(enum_class, libcamera_orientation_to_gst_video_orientation(state->config_->orientation))->value_nick;\n+\t\t\tGST_WARNING_OBJECT(self, \"Orientation changed: %s -> %s\", orig_orientation_str, new_orientation_str);\n+\t\t\twarned = true;\n+\t\t}\n+\t\tif (!warned) {\n+\t\t\tGST_DEBUG_OBJECT(self, \"Camera configuration adjusted, but no significant changes detected.\");\n+\t\t}\n+\t\t// Update Gst orientation property to match adjusted config\n+\t\tself->orientation = libcamera_orientation_to_gst_video_orientation(state->config_->orientation);\n+\t\tbreak;\n+\t}\n+\tcase CameraConfiguration::Invalid:\n+\t\tGST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,\n+\t\t\t\t  (\"Camera configuration is not supported\"),\n+\t\t\t\t  (\"CameraConfiguration::validate() returned Invalid\"));\n \t\treturn false;\n+\t}\n \n \tint ret = state->cam_->configure(state->config_.get());\n \tif (ret) {\n@@ -926,6 +1031,9 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id,\n \t\tg_free(self->camera_name);\n \t\tself->camera_name = g_value_dup_string(value);\n \t\tbreak;\n+\tcase PROP_ORIENTATION:\n+\t\tself->orientation = (GstVideoOrientationMethod)g_value_get_enum(value);\n+\t\tbreak;\n \tdefault:\n \t\tif (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec))\n \t\t\tG_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);\n@@ -945,6 +1053,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@@ -1154,6 +1265,17 @@ 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+\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       GST_TYPE_VIDEO_ORIENTATION_METHOD,\n+\t\t\t\t\t       GST_VIDEO_ORIENTATION_IDENTITY,\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 \n",
    "prefixes": [
        "v2"
    ]
}