From patchwork Thu Apr 9 14:06:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabien Danieau X-Patchwork-Id: 26515 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 8F8F3BEFBE for ; Thu, 9 Apr 2026 14:07:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5B79662E4A; Thu, 9 Apr 2026 16:07:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=pollen-robotics-com.20251104.gappssmtp.com header.i=@pollen-robotics-com.20251104.gappssmtp.com header.b="otGeFR98"; dkim-atps=neutral Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6AF7362010 for ; Thu, 9 Apr 2026 16:07:38 +0200 (CEST) Received: by mail-wr1-x431.google.com with SMTP id ffacd0b85a97d-43cfce3a195so590923f8f.2 for ; Thu, 09 Apr 2026 07:07:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pollen-robotics-com.20251104.gappssmtp.com; s=20251104; t=1775743658; x=1776348458; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=slgFSKl1EsDPeq7rNxCxPtTEMdw7NZylBDykwXdV3VQ=; b=otGeFR98CrnH1Gg5GTR2wUw3fXusrxDx36xxJwJnsAEgZZmdgYN8ctCTpti4Bs+CE3 eLXW5dXAns5A+faXJY9w1qdUsA3eZY2465GVi3u1GoaThmPXk0T49581JGMfaJxcYbFa Z78x0Ugq9jsQOifsXuU8k4+PbsZBPOCimMlukxfMiugF7058QOBvaLfYEt2ybHXRJI9o vv0ff6lGd2o8Uj9UAQHe3p/D2ihNluS35YZycZxhrXBFqxUVqnLl2HVRr8Tua/t2eJVe GAaz8DJieZIEqHc0XzHV8fRg3zh/klCqBVBSsvlIsK2dcijq9CRSvVvoVvvM5OCaBrCF FKKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775743658; x=1776348458; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=slgFSKl1EsDPeq7rNxCxPtTEMdw7NZylBDykwXdV3VQ=; b=M3C3deHWI7uk/FGw6yE8lCK3Vb8dhycr/P0IaD9BJByg9ruMb1aodeqRJohC/oHzv1 Y6L4pwzOcI2xSA/0i35+MGlEH1/i/k7953pdiGE5n9k1HtEKfNxwfog31KB8QBBKCM3z 24O1h6tuZlpGI2PiEWAYTB/zSKn4edxGo4s96nJLrarvIn8nLuF7/CcO/gNLDTbtxGw1 6O3PFIYNxXXRcvoJ70vYL5CMipuY8AeImcI5bDQKPnPIUFS2xLBaS6Tj/DhWRK98hFUZ QEuYRKhlZ90sHbH5w3yGlmCKgbj9CRIfbsc0IITGAH2LsdTa0gQhQGiFkrD7vdYTQ6L4 AjEQ== X-Gm-Message-State: AOJu0Yx9xOBAA0deLC7Pm+4J+YQ+WQOoqk698eEcQcLg9PZrMOf08r3z BKvax65PC64DhQ6M9lqJdu8NhhhOdrotkwTHOgXmh1TxWJeq6t5Z8Xxgbxn9wJ0DIC5GE8CfLia iIuokv2Y= X-Gm-Gg: AeBDievl+GMiS4v8SHB2WiwtGwep7cSTd0RqQbEYQODdMJ9HU40M6Fl5I2LAM5hL8Ta mPO5ymoUut23yOt4fTLSBrNj4uSyp8FHpBM/hTKfATOxopihYNO2QU/g7Q1WMPhHBUdXxd49lzF 6vMnUTmOq5dwgVxNKzstl0es7q45uA1CtzMIB2B+jLDSEXVPd7pJJkSnG7BM63pbL7DM7riKHlb /tM1u32aB4eWRcg/7PvttPKQGNzeK7qUp7ELeOvFetTIECwyGnI11IrBXxoEASumqsLLGdLxyeI s7U9XHse7F8Fs9rikE+WesryAXONf3eMKxq3oBnhWctHJ6wRfNpuL+c3PkYcvZBHq8H2CYXVeTR +gs5Pyr7Ie2fn8fsBtmHXd+nsPW0bxMYxgsdoR7+LVSh98oS+AAsDck9Vkv0AXgN3GwEFXecu9U CFkten6+H/FBFYuNIsuqe+ip00e3xMd4CzNn9vtakspujI80M9Jo72khcxiNnLIGojrEqLb2fI6 5wyev9SzdfP0ERxPhASGFy511lwFW9CT7yZs5caarLzWMmgyy4= X-Received: by 2002:a05:6000:40cb:b0:43b:3cdc:941f with SMTP id ffacd0b85a97d-43d5a13db02mr4890971f8f.17.1775743657753; Thu, 09 Apr 2026 07:07:37 -0700 (PDT) Received: from lotus.home (dynamic-2a00-1028-8388-1986-846d-8679-d49f-e84f.ipv6.o2.cz. [2a00:1028:8388:1986:846d:8679:d49f:e84f]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43d1e4f5016sm72258177f8f.33.2026.04.09.07.07.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Apr 2026 07:07:37 -0700 (PDT) From: Fabien Danieau To: libcamera-devel@lists.libcamera.org Cc: Fabien Danieau Subject: [PATCH] gstreamer: Add sensor-mode property to libcamerasrc Date: Thu, 9 Apr 2026 16:06:56 +0200 Message-ID: <20260409140656.648249-1-fabien.danieau@pollen-robotics.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a sensor-mode property that allows users to force a specific sensor mode regardless of the stream output resolution. The property accepts a string in the format 'width:height:bit-depth' (e.g. '2304:1296:10'). This is useful when the desired output resolution is smaller than the sensor's native resolution but the full field of view must be preserved. Without this property, the pipeline handler auto-selects a sensor mode based on the output resolution, which may result in a cropped field of view. Signed-off-by: Fabien Danieau --- src/gstreamer/gstlibcamerasrc.cpp | 53 +++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index a7241e9b..00080ac4 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -141,6 +142,7 @@ struct _GstLibcameraSrc { GstTask *task; gchar *camera_name; + gchar *sensor_mode; std::atomic pending_eos; @@ -152,6 +154,7 @@ struct _GstLibcameraSrc { enum { PROP_0, PROP_CAMERA_NAME, + PROP_SENSOR_MODE, PROP_LAST }; @@ -810,6 +813,22 @@ gst_libcamera_src_task_run(gpointer user_data) gst_task_resume(self->task); } +static bool +gst_libcamera_src_parse_sensor_mode(const gchar *mode_str, + SensorConfiguration &sensorConfig) +{ + unsigned int width, height, bitDepth; + + if (sscanf(mode_str, "%u:%u:%u", &width, &height, &bitDepth) != 3) { + return false; + } + + sensorConfig.outputSize = Size(width, height); + sensorConfig.bitDepth = bitDepth; + + return sensorConfig.isValid(); +} + static void gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread, gpointer user_data) @@ -846,6 +865,24 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread, } g_assert(state->config_->size() == state->srcpads_.size()); + /* Apply the sensor mode if specified. */ + { + GLibLocker objLock(GST_OBJECT(self)); + if (self->sensor_mode) { + SensorConfiguration sensorConfig; + if (gst_libcamera_src_parse_sensor_mode(self->sensor_mode, + sensorConfig)) { + state->config_->sensorConfig = sensorConfig; + } else { + GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS, + ("Invalid sensor mode '%s'", self->sensor_mode), + ("Expected format: 'width:height:bit-depth'")); + gst_task_stop(task); + return; + } + } + } + if (!gst_libcamera_src_negotiate(self)) { state->initControls_.clear(); GST_ELEMENT_FLOW_ERROR(self, GST_FLOW_NOT_NEGOTIATED); @@ -934,6 +971,10 @@ gst_libcamera_src_set_property(GObject *object, guint prop_id, g_free(self->camera_name); self->camera_name = g_value_dup_string(value); break; + case PROP_SENSOR_MODE: + g_free(self->sensor_mode); + self->sensor_mode = g_value_dup_string(value); + break; default: if (!state->controls_.setProperty(prop_id - PROP_LAST, value, pspec)) G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -953,6 +994,9 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value, case PROP_CAMERA_NAME: g_value_set_string(value, self->camera_name); break; + case PROP_SENSOR_MODE: + g_value_set_string(value, self->sensor_mode); + break; default: if (!state->controls_.getProperty(prop_id - PROP_LAST, value, pspec)) G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -1040,6 +1084,7 @@ gst_libcamera_src_finalize(GObject *object) g_clear_object(&self->task); g_mutex_clear(&self->state->lock_); g_free(self->camera_name); + g_free(self->sensor_mode); delete self->state; return klass->finalize(object); @@ -1162,6 +1207,14 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass) | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, PROP_CAMERA_NAME, spec); + spec = g_param_spec_string("sensor-mode", "Sensor Mode", + "Sensor mode as 'width:height:bit-depth'. " + "This selects a specific sensor mode " + "regardless of the stream output resolution.", + nullptr, + (GParamFlags)(GST_PARAM_MUTABLE_READY | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(object_class, PROP_SENSOR_MODE, spec); + GstCameraControls::installProperties(object_class, PROP_LAST); }