[{"id":38566,"web_url":"https://patchwork.libcamera.org/comment/38566/","msgid":"<20260409141322.GB2637588@killaraus.ideasonboard.com>","date":"2026-04-09T14:13:22","subject":"Re: [PATCH] gstreamer: Add sensor-mode property to libcamerasrc","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hello Fabien,\n\nThank you for the patch.\n\nOn Thu, Apr 09, 2026 at 04:06:56PM +0200, Fabien Danieau wrote:\n> Add a sensor-mode property that allows users to force a specific sensor\n> mode regardless of the stream output resolution. The property accepts a\n> string in the format 'width:height:bit-depth' (e.g. '2304:1296:10').\n> \n> This is useful when the desired output resolution is smaller than the\n> sensor's native resolution but the full field of view must be preserved.\n> Without this property, the pipeline handler auto-selects a sensor mode\n> based on the output resolution, which may result in a cropped field of\n> view.\n\nYou may have missed a similar patch that David Plowman has recently\nposted: https://patchwork.libcamera.org/patch/26384/\n\nCould you check that, and comment on which approach you think is best ?\n\n> Signed-off-by: Fabien Danieau <fabien.danieau@pollen-robotics.com>\n> ---\n>  src/gstreamer/gstlibcamerasrc.cpp | 53 +++++++++++++++++++++++++++++++\n>  1 file changed, 53 insertions(+)\n> \n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index a7241e9b..00080ac4 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -23,6 +23,7 @@\n>  \n>  #include <atomic>\n>  #include <queue>\n> +#include <stdio.h>\n>  #include <tuple>\n>  #include <utility>\n>  #include <vector>\n> @@ -141,6 +142,7 @@ struct _GstLibcameraSrc {\n>  \tGstTask *task;\n>  \n>  \tgchar *camera_name;\n> +\tgchar *sensor_mode;\n>  \n>  \tstd::atomic<GstEvent *> pending_eos;\n>  \n> @@ -152,6 +154,7 @@ struct _GstLibcameraSrc {\n>  enum {\n>  \tPROP_0,\n>  \tPROP_CAMERA_NAME,\n> +\tPROP_SENSOR_MODE,\n>  \tPROP_LAST\n>  };\n>  \n> @@ -810,6 +813,22 @@ gst_libcamera_src_task_run(gpointer user_data)\n>  \t\tgst_task_resume(self->task);\n>  }\n>  \n> +static bool\n> +gst_libcamera_src_parse_sensor_mode(const gchar *mode_str,\n> +\t\t\t\t    SensorConfiguration &sensorConfig)\n> +{\n> +\tunsigned int width, height, bitDepth;\n> +\n> +\tif (sscanf(mode_str, \"%u:%u:%u\", &width, &height, &bitDepth) != 3) {\n> +\t\treturn false;\n> +\t}\n> +\n> +\tsensorConfig.outputSize = Size(width, height);\n> +\tsensorConfig.bitDepth = bitDepth;\n> +\n> +\treturn sensorConfig.isValid();\n> +}\n> +\n>  static void\n>  gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\n>  \t\t\t     gpointer user_data)\n> @@ -846,6 +865,24 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\n>  \t}\n>  \tg_assert(state->config_->size() == state->srcpads_.size());\n>  \n> +\t/* Apply the sensor mode if specified. */\n> +\t{\n> +\t\tGLibLocker objLock(GST_OBJECT(self));\n> +\t\tif (self->sensor_mode) {\n> +\t\t\tSensorConfiguration sensorConfig;\n> +\t\t\tif (gst_libcamera_src_parse_sensor_mode(self->sensor_mode,\n> +\t\t\t\t\t\t\t\tsensorConfig)) {\n> +\t\t\t\tstate->config_->sensorConfig = sensorConfig;\n> +\t\t\t} else {\n> +\t\t\t\tGST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,\n> +\t\t\t\t\t\t  (\"Invalid sensor mode '%s'\", self->sensor_mode),\n> +\t\t\t\t\t\t  (\"Expected format: 'width:height:bit-depth'\"));\n> +\t\t\t\tgst_task_stop(task);\n> +\t\t\t\treturn;\n> +\t\t\t}\n> +\t\t}\n> +\t}\n> +\n>  \tif (!gst_libcamera_src_negotiate(self)) {\n>  \t\tstate->initControls_.clear();\n>  \t\tGST_ELEMENT_FLOW_ERROR(self, GST_FLOW_NOT_NEGOTIATED);\n> @@ -934,6 +971,10 @@ 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_SENSOR_MODE:\n> +\t\tg_free(self->sensor_mode);\n> +\t\tself->sensor_mode = g_value_dup_string(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> @@ -953,6 +994,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_SENSOR_MODE:\n> +\t\tg_value_set_string(value, self->sensor_mode);\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> @@ -1040,6 +1084,7 @@ gst_libcamera_src_finalize(GObject *object)\n>  \tg_clear_object(&self->task);\n>  \tg_mutex_clear(&self->state->lock_);\n>  \tg_free(self->camera_name);\n> +\tg_free(self->sensor_mode);\n>  \tdelete self->state;\n>  \n>  \treturn klass->finalize(object);\n> @@ -1162,6 +1207,14 @@ 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> +\tspec = g_param_spec_string(\"sensor-mode\", \"Sensor Mode\",\n> +\t\t\t\t   \"Sensor mode as 'width:height:bit-depth'. \"\n> +\t\t\t\t   \"This selects a specific sensor mode \"\n> +\t\t\t\t   \"regardless of the stream output resolution.\",\n> +\t\t\t\t   nullptr,\n> +\t\t\t\t   (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> +\tg_object_class_install_property(object_class, PROP_SENSOR_MODE, 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 8DC06BDCBD\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  9 Apr 2026 14:13:25 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A3A1162E4A;\n\tThu,  9 Apr 2026 16:13:24 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B459F62010\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  9 Apr 2026 16:13:23 +0200 (CEST)","from killaraus.ideasonboard.com\n\t(2001-14ba-703d-e500--2a1.rev.dnainternet.fi\n\t[IPv6:2001:14ba:703d:e500::2a1])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id A194B1C6;\n\tThu,  9 Apr 2026 16:11: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=\"qewTiKbs\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1775743914;\n\tbh=GLJe+wcW6wY+TpUF7KuzN1+BEv/CCEzblWlEDQg6FjY=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=qewTiKbsTE7FfqvQSroFQ6Uc35EH8B6lJ2Z6fAq4QqNbfNB4aKZxx5c7pt5Ad48OC\n\t0jPsCHKLbkrRLtt9QbmLUNLtQm98Tb0xxcynVx/QodzxcAP3BUJP+JU9zs6f603nPW\n\tecLwkm1gX9i0FcwRvaIDJh2xmpS7mCAW4R43lGms=","Date":"Thu, 9 Apr 2026 17:13:22 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Fabien Danieau <fabien.danieau@pollen-robotics.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] gstreamer: Add sensor-mode property to libcamerasrc","Message-ID":"<20260409141322.GB2637588@killaraus.ideasonboard.com>","References":"<20260409140656.648249-1-fabien.danieau@pollen-robotics.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20260409140656.648249-1-fabien.danieau@pollen-robotics.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":38567,"web_url":"https://patchwork.libcamera.org/comment/38567/","msgid":"<ade0P71A242Gujma@zed>","date":"2026-04-09T14:15:38","subject":"Re: [PATCH] gstreamer: Add sensor-mode property to libcamerasrc","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Fabien\n\nOn Thu, Apr 09, 2026 at 04:06:56PM +0200, Fabien Danieau wrote:\n> Add a sensor-mode property that allows users to force a specific sensor\n> mode regardless of the stream output resolution. The property accepts a\n> string in the format 'width:height:bit-depth' (e.g. '2304:1296:10').\n>\n> This is useful when the desired output resolution is smaller than the\n> sensor's native resolution but the full field of view must be preserved.\n> Without this property, the pipeline handler auto-selects a sensor mode\n> based on the output resolution, which may result in a cropped field of\n> view.\n\nHave a look at:\nhttps://patchwork.libcamera.org/patch/26384/\n\nIf that patch helps with your needs you can maybe send a Tested-by tag :)\n\n\n>\n> Signed-off-by: Fabien Danieau <fabien.danieau@pollen-robotics.com>\n> ---\n>  src/gstreamer/gstlibcamerasrc.cpp | 53 +++++++++++++++++++++++++++++++\n>  1 file changed, 53 insertions(+)\n>\n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index a7241e9b..00080ac4 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -23,6 +23,7 @@\n>\n>  #include <atomic>\n>  #include <queue>\n> +#include <stdio.h>\n>  #include <tuple>\n>  #include <utility>\n>  #include <vector>\n> @@ -141,6 +142,7 @@ struct _GstLibcameraSrc {\n>  \tGstTask *task;\n>\n>  \tgchar *camera_name;\n> +\tgchar *sensor_mode;\n>\n>  \tstd::atomic<GstEvent *> pending_eos;\n>\n> @@ -152,6 +154,7 @@ struct _GstLibcameraSrc {\n>  enum {\n>  \tPROP_0,\n>  \tPROP_CAMERA_NAME,\n> +\tPROP_SENSOR_MODE,\n>  \tPROP_LAST\n>  };\n>\n> @@ -810,6 +813,22 @@ gst_libcamera_src_task_run(gpointer user_data)\n>  \t\tgst_task_resume(self->task);\n>  }\n>\n> +static bool\n> +gst_libcamera_src_parse_sensor_mode(const gchar *mode_str,\n> +\t\t\t\t    SensorConfiguration &sensorConfig)\n> +{\n> +\tunsigned int width, height, bitDepth;\n> +\n> +\tif (sscanf(mode_str, \"%u:%u:%u\", &width, &height, &bitDepth) != 3) {\n> +\t\treturn false;\n> +\t}\n> +\n> +\tsensorConfig.outputSize = Size(width, height);\n> +\tsensorConfig.bitDepth = bitDepth;\n> +\n> +\treturn sensorConfig.isValid();\n> +}\n> +\n>  static void\n>  gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\n>  \t\t\t     gpointer user_data)\n> @@ -846,6 +865,24 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,\n>  \t}\n>  \tg_assert(state->config_->size() == state->srcpads_.size());\n>\n> +\t/* Apply the sensor mode if specified. */\n> +\t{\n> +\t\tGLibLocker objLock(GST_OBJECT(self));\n> +\t\tif (self->sensor_mode) {\n> +\t\t\tSensorConfiguration sensorConfig;\n> +\t\t\tif (gst_libcamera_src_parse_sensor_mode(self->sensor_mode,\n> +\t\t\t\t\t\t\t\tsensorConfig)) {\n> +\t\t\t\tstate->config_->sensorConfig = sensorConfig;\n> +\t\t\t} else {\n> +\t\t\t\tGST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,\n> +\t\t\t\t\t\t  (\"Invalid sensor mode '%s'\", self->sensor_mode),\n> +\t\t\t\t\t\t  (\"Expected format: 'width:height:bit-depth'\"));\n> +\t\t\t\tgst_task_stop(task);\n> +\t\t\t\treturn;\n> +\t\t\t}\n> +\t\t}\n> +\t}\n> +\n>  \tif (!gst_libcamera_src_negotiate(self)) {\n>  \t\tstate->initControls_.clear();\n>  \t\tGST_ELEMENT_FLOW_ERROR(self, GST_FLOW_NOT_NEGOTIATED);\n> @@ -934,6 +971,10 @@ 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_SENSOR_MODE:\n> +\t\tg_free(self->sensor_mode);\n> +\t\tself->sensor_mode = g_value_dup_string(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> @@ -953,6 +994,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_SENSOR_MODE:\n> +\t\tg_value_set_string(value, self->sensor_mode);\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> @@ -1040,6 +1084,7 @@ gst_libcamera_src_finalize(GObject *object)\n>  \tg_clear_object(&self->task);\n>  \tg_mutex_clear(&self->state->lock_);\n>  \tg_free(self->camera_name);\n> +\tg_free(self->sensor_mode);\n>  \tdelete self->state;\n>\n>  \treturn klass->finalize(object);\n> @@ -1162,6 +1207,14 @@ 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> +\tspec = g_param_spec_string(\"sensor-mode\", \"Sensor Mode\",\n> +\t\t\t\t   \"Sensor mode as 'width:height:bit-depth'. \"\n> +\t\t\t\t   \"This selects a specific sensor mode \"\n> +\t\t\t\t   \"regardless of the stream output resolution.\",\n> +\t\t\t\t   nullptr,\n> +\t\t\t\t   (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> +\tg_object_class_install_property(object_class, PROP_SENSOR_MODE, spec);\n> +\n>  \tGstCameraControls::installProperties(object_class, PROP_LAST);\n>  }\n>\n> --\n> 2.47.3\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 C3EC7BEFBE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  9 Apr 2026 14:15:44 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D3F1362E4A;\n\tThu,  9 Apr 2026 16:15:43 +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 2313162010\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  9 Apr 2026 16:15:42 +0200 (CEST)","from ideasonboard.com (93-46-82-201.ip106.fastwebnet.it\n\t[93.46.82.201])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 0FE871C6;\n\tThu,  9 Apr 2026 16:14:13 +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=\"NlzechYJ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1775744053;\n\tbh=S1S1b5i/nUVP39ghd4N/KkaBVEFRgMf/xnxmFQnhWNE=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=NlzechYJ6++5qusGmu1Ao7vVMb3QZtePACmsP+bpcjhlCidmwsk1wBvjMM1x2QAn3\n\t8FQX/MNq4wwNvBfBiAwSpHvM/yLiXejJG+FNNfzzlaHn9nGlaMWz9AAOShAkJwVITK\n\tZ7OHuh6tt9ZwWE0WWMIZ8nWoBdcvMJxTyIqAnRvg=","Date":"Thu, 9 Apr 2026 16:15:38 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Fabien Danieau <fabien.danieau@pollen-robotics.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] gstreamer: Add sensor-mode property to libcamerasrc","Message-ID":"<ade0P71A242Gujma@zed>","References":"<20260409140656.648249-1-fabien.danieau@pollen-robotics.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20260409140656.648249-1-fabien.danieau@pollen-robotics.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":38570,"web_url":"https://patchwork.libcamera.org/comment/38570/","msgid":"<e4d9e23bef9f5ac3526f21152e92d8ac4edb0a9d.camel@pollen-robotics.com>","date":"2026-04-09T15:39:01","subject":"Re: [PATCH] gstreamer: Add sensor-mode property to libcamerasrc","submitter":{"id":265,"url":"https://patchwork.libcamera.org/api/people/265/","name":"Fabien Danieau","email":"fabien.danieau@pollen-robotics.com"},"content":"Hello,\n\nOk done! The existing patch works well for me. Thanks for pointing this\nout.\n\nBest,\n\nFabien\n\nOn Thu, 2026-04-09 at 16:15 +0200, Jacopo Mondi wrote:\n> Hi Fabien\n> \n> On Thu, Apr 09, 2026 at 04:06:56PM +0200, Fabien Danieau wrote:\n> > Add a sensor-mode property that allows users to force a specific\n> > sensor\n> > mode regardless of the stream output resolution. The property\n> > accepts a\n> > string in the format 'width:height:bit-depth' (e.g.\n> > '2304:1296:10').\n> > \n> > This is useful when the desired output resolution is smaller than\n> > the\n> > sensor's native resolution but the full field of view must be\n> > preserved.\n> > Without this property, the pipeline handler auto-selects a sensor\n> > mode\n> > based on the output resolution, which may result in a cropped field\n> > of\n> > view.\n> \n> Have a look at:\n> https://patchwork.libcamera.org/patch/26384/\n> \n> If that patch helps with your needs you can maybe send a Tested-by\n> tag :)\n> \n> \n> > \n> > Signed-off-by: Fabien Danieau <fabien.danieau@pollen-robotics.com>\n> > ---\n> >  src/gstreamer/gstlibcamerasrc.cpp | 53\n> > +++++++++++++++++++++++++++++++\n> >  1 file changed, 53 insertions(+)\n> > \n> > diff --git a/src/gstreamer/gstlibcamerasrc.cpp\n> > b/src/gstreamer/gstlibcamerasrc.cpp\n> > index a7241e9b..00080ac4 100644\n> > --- a/src/gstreamer/gstlibcamerasrc.cpp\n> > +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> > @@ -23,6 +23,7 @@\n> > \n> >  #include <atomic>\n> >  #include <queue>\n> > +#include <stdio.h>\n> >  #include <tuple>\n> >  #include <utility>\n> >  #include <vector>\n> > @@ -141,6 +142,7 @@ struct _GstLibcameraSrc {\n> >   GstTask *task;\n> > \n> >   gchar *camera_name;\n> > + gchar *sensor_mode;\n> > \n> >   std::atomic<GstEvent *> pending_eos;\n> > \n> > @@ -152,6 +154,7 @@ struct _GstLibcameraSrc {\n> >  enum {\n> >   PROP_0,\n> >   PROP_CAMERA_NAME,\n> > + PROP_SENSOR_MODE,\n> >   PROP_LAST\n> >  };\n> > \n> > @@ -810,6 +813,22 @@ gst_libcamera_src_task_run(gpointer user_data)\n> >   gst_task_resume(self->task);\n> >  }\n> > \n> > +static bool\n> > +gst_libcamera_src_parse_sensor_mode(const gchar *mode_str,\n> > +     SensorConfiguration\n> > &sensorConfig)\n> > +{\n> > + unsigned int width, height, bitDepth;\n> > +\n> > + if (sscanf(mode_str, \"%u:%u:%u\", &width, &height,\n> > &bitDepth) != 3) {\n> > + return false;\n> > + }\n> > +\n> > + sensorConfig.outputSize = Size(width, height);\n> > + sensorConfig.bitDepth = bitDepth;\n> > +\n> > + return sensorConfig.isValid();\n> > +}\n> > +\n> >  static void\n> >  gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]]\n> > GThread *thread,\n> >        gpointer user_data)\n> > @@ -846,6 +865,24 @@ gst_libcamera_src_task_enter(GstTask *task,\n> > [[maybe_unused]] GThread *thread,\n> >   }\n> >   g_assert(state->config_->size() == state->srcpads_.size());\n> > \n> > + /* Apply the sensor mode if specified. */\n> > + {\n> > + GLibLocker objLock(GST_OBJECT(self));\n> > + if (self->sensor_mode) {\n> > + SensorConfiguration sensorConfig;\n> > + if\n> > (gst_libcamera_src_parse_sensor_mode(self->sensor_mode,\n> > +\n> > sensorConfig)) {\n> > + state->config_->sensorConfig =\n> > sensorConfig;\n> > + } else {\n> > + GST_ELEMENT_ERROR(self, RESOURCE,\n> > SETTINGS,\n> > +   (\"Invalid sensor\n> > mode '%s'\", self->sensor_mode),\n> > +   (\"Expected\n> > format: 'width:height:bit-depth'\"));\n> > + gst_task_stop(task);\n> > + return;\n> > + }\n> > + }\n> > + }\n> > +\n> >   if (!gst_libcamera_src_negotiate(self)) {\n> >   state->initControls_.clear();\n> >   GST_ELEMENT_FLOW_ERROR(self,\n> > GST_FLOW_NOT_NEGOTIATED);\n> > @@ -934,6 +971,10 @@ gst_libcamera_src_set_property(GObject\n> > *object, guint prop_id,\n> >   g_free(self->camera_name);\n> >   self->camera_name = g_value_dup_string(value);\n> >   break;\n> > + case PROP_SENSOR_MODE:\n> > + g_free(self->sensor_mode);\n> > + self->sensor_mode = g_value_dup_string(value);\n> > + break;\n> >   default:\n> >   if (!state->controls_.setProperty(prop_id -\n> > PROP_LAST, value, pspec))\n> >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object,\n> > prop_id, pspec);\n> > @@ -953,6 +994,9 @@ gst_libcamera_src_get_property(GObject *object,\n> > guint prop_id, GValue *value,\n> >   case PROP_CAMERA_NAME:\n> >   g_value_set_string(value, self->camera_name);\n> >   break;\n> > + case PROP_SENSOR_MODE:\n> > + g_value_set_string(value, self->sensor_mode);\n> > + break;\n> >   default:\n> >   if (!state->controls_.getProperty(prop_id -\n> > PROP_LAST, value, pspec))\n> >   G_OBJECT_WARN_INVALID_PROPERTY_ID(object,\n> > prop_id, pspec);\n> > @@ -1040,6 +1084,7 @@ gst_libcamera_src_finalize(GObject *object)\n> >   g_clear_object(&self->task);\n> >   g_mutex_clear(&self->state->lock_);\n> >   g_free(self->camera_name);\n> > + g_free(self->sensor_mode);\n> >   delete self->state;\n> > \n> >   return klass->finalize(object);\n> > @@ -1162,6 +1207,14 @@\n> > gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)\n> >        |\n> > G_PARAM_STATIC_STRINGS));\n> >   g_object_class_install_property(object_class,\n> > PROP_CAMERA_NAME, spec);\n> > \n> > + spec = g_param_spec_string(\"sensor-mode\", \"Sensor Mode\",\n> > +    \"Sensor mode as\n> > 'width:height:bit-depth'. \"\n> > +    \"This selects a specific sensor\n> > mode \"\n> > +    \"regardless of the stream output\n> > resolution.\",\n> > +    nullptr,\n> > +   \n> > (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT |\n> > G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));\n> > + g_object_class_install_property(object_class,\n> > PROP_SENSOR_MODE, spec);\n> > +\n> >   GstCameraControls::installProperties(object_class,\n> > PROP_LAST);\n> >  }\n> > \n> > --\n> > 2.47.3\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 5D8A8C32BB\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  9 Apr 2026 15:39:04 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 076A562E54;\n\tThu,  9 Apr 2026 17:39:04 +0200 (CEST)","from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com\n\t[IPv6:2a00:1450:4864:20::42d])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D997F62E4A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  9 Apr 2026 17:39:02 +0200 (CEST)","by mail-wr1-x42d.google.com with SMTP id\n\tffacd0b85a97d-43d17bb1c65so682207f8f.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 09 Apr 2026 08:39:02 -0700 (PDT)","from lotus.home\n\t(dynamic-2a00-1028-8388-1986-846d-8679-d49f-e84f.ipv6.o2.cz.\n\t[2a00:1028:8388:1986:846d:8679:d49f:e84f])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-43d5e969be7sm5573136f8f.6.2026.04.09.08.39.01\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tThu, 09 Apr 2026 08:39:01 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=pollen-robotics-com.20251104.gappssmtp.com\n\theader.i=@pollen-robotics-com.20251104.gappssmtp.com\n\theader.b=\"Yc8IxhR0\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=pollen-robotics-com.20251104.gappssmtp.com; s=20251104; t=1775749142;\n\tx=1776353942; darn=lists.libcamera.org; \n\th=mime-version:user-agent:references:in-reply-to:date:cc:to:from\n\t:subject:message-id:from:to:cc:subject:date:message-id:reply-to;\n\tbh=UX7RTNO4NWiVe8wckN7tUECX0pFKymWxrAaK6kwoHlM=;\n\tb=Yc8IxhR0/9sw903j+XKC2Qz/+GTA4Q9KrRJZSbHSCz6HgO2EWFQd37YNglNgfKLsux\n\tSwKXKwBYNeFy5DkNa71ImhmH899Sk+kKlU77axqqh9TbkB3wiebGb6YGuhI7l3ve1UAF\n\tnc8BZ2xCDCmQbIQ5S+KXkigWs0wand+dFQl66ShymeUwgOkdPbHXTocMgdgAQAh+ZmV7\n\t28gLt0D7JKRUI8DMwPlsrqmHEBicMz/EVia9oogLOigxM844Zkf8P6UylyBklp/TOPm9\n\tab2oUpU5a51Z7lvesLETyB9JOC9TKXIwVaLSIfB7LSVm/A6hIZmUVu22lcT3A1S2HsoQ\n\tXDuw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1775749142; x=1776353942;\n\th=mime-version:user-agent:references:in-reply-to:date:cc:to:from\n\t:subject:message-id:x-gm-gg:x-gm-message-state:from:to:cc:subject\n\t:date:message-id:reply-to;\n\tbh=UX7RTNO4NWiVe8wckN7tUECX0pFKymWxrAaK6kwoHlM=;\n\tb=cO/e3i/hzE3YoVQuRe3+djQ3O0xHiSX9DxmyfgkmAOKbSap0+G/QZPCw9keQUZGmN/\n\t8ZxZLb3+lxuzavq4ZVufbfUIjr6um++bjwj/Ba49YtZ5m9RpDP34LtdTb1uA+jXloopT\n\t6TT5IiLvE43sUZNe332A6lrq+FMRalmwg8v6RtK3856NSuvItchiGJlIXf3sdKJJpPzH\n\teiwxUVbuHhbuxwT2eRlKzIFsXGIs66gQ0ZLqbm0h9dcg/953gHyqlLk1+5WhHGOO0scP\n\thoqIqMpzN+W/sG3IdZ5GznpJUNrMIWTwwayABGZWW6dP2Vj1GnJa2f1aahJNRE2V9VYt\n\tnidg==","X-Gm-Message-State":"AOJu0YziGCtlb2YJE1eB6sQUhlEnDL6NfMtP3dPeX5kgswtngJ3YBAke\n\t62LKkqxu/0yd3EIQSDrXKUZwlF6lUocNiZjyTdDYZlGcYcqeTbqx2ck70TOoDrvdi1ktn8br6Jm\n\tP+y5VPFk=","X-Gm-Gg":"AeBDietHkyW0hTlKx78vcxOGocG+xR6w4FWbWc1DkBeSHrdY4hS6ncZkfOyQxaPspqZ\n\t7W9N14CGMdj9VNG43vkWOoDa7R/67cShFe0+BwvXgtxQzB/Ww6XA/IjK8ZhLkrzwHLgQcXwaZAV\n\tm+2dO08OAvvwaZ8guUf5oDc16EUFWnb/3lagxFrEQWZPt4/RZydD5b6apyh+HVIJxtTj6EYHKG+\n\tEy8IDohjlPvK/T2vNtAl0RcVG/NbeDFx4PkgmKwfd4r8RJJ2ePJsOS8uZgV81HTgufO86GqfKd/\n\t316+S7P6GDwup2zzjfk/vRIJsztC3jvy28dwgw46FcSiti59UZAaKApt5ilmVI9tgNpAP1BLD2B\n\tGKk1vDKiGdqs2+WAyCeyFpZeGrpcYVdVIPxeiNh17NJS04nkrTrQGxK59vjnhYszZpOXgKRzIrG\n\tyBvbrMzugH70LVgpFtPzVskpJa3ALyVKEkm92EYI+llE55J/HSVXpDYoCeZKBZ3RHxegLttQD2V\n\tAGPxY6mTlzmCiuej1RDyTiVWf+tbf1MEgqM/DTc","X-Received":"by 2002:a05:6000:26c2:b0:43d:60e:6aff with SMTP id\n\tffacd0b85a97d-43d2928b819mr34988598f8f.15.1775749142215; \n\tThu, 09 Apr 2026 08:39:02 -0700 (PDT)","Message-ID":"<e4d9e23bef9f5ac3526f21152e92d8ac4edb0a9d.camel@pollen-robotics.com>","Subject":"Re: [PATCH] gstreamer: Add sensor-mode property to libcamerasrc","From":"Fabien Danieau <fabien.danieau@pollen-robotics.com>","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Date":"Thu, 09 Apr 2026 17:39:01 +0200","In-Reply-To":"<ade0P71A242Gujma@zed>","References":"<20260409140656.648249-1-fabien.danieau@pollen-robotics.com>\n\t<ade0P71A242Gujma@zed>","Content-Type":"multipart/alternative; boundary=\"=-PfiTtzu7Ij79HlsiEVDH\"","User-Agent":"Evolution 3.56.2-0+deb13u1 ","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>"}}]