{"id":24810,"url":"https://patchwork.libcamera.org/api/patches/24810/?format=json","web_url":"https://patchwork.libcamera.org/patch/24810/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20251024151058.1523308-3-julien.vuillaumier@nxp.com>","date":"2025-10-24T15:10:58","name":"[RFC,v1,2/2] libcamera: camera_sensor: Add support for auxiliary image","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"d249b8bd1df8b82db9e2078d8f6e4224fc3e0dd5","submitter":{"id":190,"url":"https://patchwork.libcamera.org/api/people/190/?format=json","name":"Julien Vuillaumier","email":"julien.vuillaumier@nxp.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/24810/mbox/","series":[{"id":5527,"url":"https://patchwork.libcamera.org/api/series/5527/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5527","date":"2025-10-24T15:10:56","name":"libcamera: camera_sensor: Add support for an additional image stream","version":1,"mbox":"https://patchwork.libcamera.org/series/5527/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/24810/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/24810/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 8B8B8BE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Oct 2025 15:12:00 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4CA53609B8;\n\tFri, 24 Oct 2025 17:12:00 +0200 (CEST)","from OSPPR02CU001.outbound.protection.outlook.com\n\t(mail-norwayeastazlp170130007.outbound.protection.outlook.com\n\t[IPv6:2a01:111:f403:c20f::7])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5B2A56097E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Oct 2025 17:11:59 +0200 (CEST)","from AM9PR04MB8147.eurprd04.prod.outlook.com\n\t(2603:10a6:20b:3e0::22)\n\tby VI0PR04MB11784.eurprd04.prod.outlook.com (2603:10a6:800:2ea::12)\n\twith Microsoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9253.13;\n\tFri, 24 Oct 2025 15:11:57 +0000","from AM9PR04MB8147.eurprd04.prod.outlook.com\n\t([fe80::b387:72c6:e33c:8656]) by\n\tAM9PR04MB8147.eurprd04.prod.outlook.com\n\t([fe80::b387:72c6:e33c:8656%7]) with mapi id 15.20.9253.011;\n\tFri, 24 Oct 2025 15:11:56 +0000"],"Authentication-Results":["lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxp.com header.i=@nxp.com header.b=\"VPFyg0HU\";\n\tdkim-atps=neutral","dkim=none (message not signed)\n\theader.d=none;dmarc=none action=none header.from=nxp.com;"],"ARC-Seal":"i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n\tb=Ug3xhWrsl1xzaTfrwZeRlP7brMjWsDJAAueUkKmKeeCZR13vcjYD8ZTYDFjrAkfTwvW5wPZd20uAYn/7MRyZnMuBjBIuHVISzSCXY7FD3ScA8oZqARrRpqcxIiPw4wACJK/MLOq7BtynmIrlAVLio5iBR6/YwUqScmlXji1kPZR6NqYsL2w1f6/TaRG/9CUx5RylNIUthlIgFdrESe/aqYlGD2Dh+qYAEtUBhKO4bfl+CEvqNBqL9TKvvhCO7W8r0M0JqEFkd/5j+v3pFZ5AzmXOWMVnegRLvG7soQCXc/Tqb4GEuRh61c79Rd+WLdaVjHOZnuncAIN0LN3uYnXeZA==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n\ts=arcselector10001;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n\tbh=Vb/YeCjVaYSAZ2P53BvQnfIoJItQtp6cAEBx3DjboCo=;\n\tb=vaMVYnF6ierocBwXA2VvC+fgPG92z5E2jlUcZevxHzZ1snDow17kV1OnHDVpsuws3MfP/ZhQozqCWFvXcE5LrwLGblb5u0GH5Prb8DXhDRSTYNnIT6ZxJh/zLWdVwvCh+eqe/yVuLE7TSW4QsrCz1beelJMI6PWnEhYzmB/h1gFE4mieHbfBvZ0rnAlTbSRLaIreagnI9Th7O+VQILbin/6s4EuAQvSsq7JTAUfIpw3FAO1M3/TPmRax7kPXMFrW5soVch7A7qNGhhf2zJKtLo0l5vxQJjk3KR+TlOnWe7MK1IYebKEtX1EpdanscTPefvJW981r8IBv7D3xGzVaWQ==","ARC-Authentication-Results":"i=1; mx.microsoft.com 1; spf=pass\n\tsmtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com;\n\tdkim=pass header.d=nxp.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n\tbh=Vb/YeCjVaYSAZ2P53BvQnfIoJItQtp6cAEBx3DjboCo=;\n\tb=VPFyg0HUZ8ZAf7s3zw0H2hG3GG/S+t0SZ4M56YlqecMPN4I9nKgdQNs5lkC8c3KHaIsR0bVIzLivZH+8YE0FlSKknCh/hpwdkT9IaOBOrIwKfSTO/aZiMM8T3ZuH25ReCrgrfdiUCaZ4ZEX2cUlxwf61QON6x08JDuKMTEk4lqr70pwemTddUb6bY8z6RJOJ6gFDAYE/3LYXtH7YxIpx4tg8HJMuiFXbWZQLTXFwFoVS1PnrY13T0f41ApD3H20N30JeTYT1rPGao6EZtWBU68PFR5QiFZNjcnGJGk6EQ8hD7MSKrdW7tdr0jLJjXcfv2Va9eSbCip1eakmzGW7DmA==","From":"Julien Vuillaumier <julien.vuillaumier@nxp.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Julien Vuillaumier <julien.vuillaumier@nxp.com>","Subject":"[RFC PATCH v1 2/2] libcamera: camera_sensor: Add support for\n\tauxiliary image","Date":"Fri, 24 Oct 2025 17:10:58 +0200","Message-Id":"<20251024151058.1523308-3-julien.vuillaumier@nxp.com>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20251024151058.1523308-1-julien.vuillaumier@nxp.com>","References":"<20251024151058.1523308-1-julien.vuillaumier@nxp.com>","Content-Transfer-Encoding":"8bit","Content-Type":"text/plain","X-ClientProxiedBy":"AM8P189CA0019.EURP189.PROD.OUTLOOK.COM\n\t(2603:10a6:20b:218::24) To AM9PR04MB8147.eurprd04.prod.outlook.com\n\t(2603:10a6:20b:3e0::22)","MIME-Version":"1.0","X-MS-PublicTrafficType":"Email","X-MS-TrafficTypeDiagnostic":"AM9PR04MB8147:EE_|VI0PR04MB11784:EE_","X-MS-Office365-Filtering-Correlation-Id":"69c9281d-7fd3-4661-c6b0-08de130fabb2","X-MS-Exchange-SenderADCheck":"1","X-MS-Exchange-AntiSpam-Relay":"0","X-Microsoft-Antispam":"BCL:0;\n\tARA:13230040|19092799006|52116014|376014|366016|1800799024|38350700014;","X-Microsoft-Antispam-Message-Info":"w0AIRPwnBZL4b85ACz3NTUDlnmvIouLrtpSVvwDY6GyRTFGhKwFuBdPbJljHtXIrKLmVKGJ8hCpm4nW/8Q3a7wuZu56Y3oZCVQQBQdxYSpMCEkAarMkJdITw9Q9ArnZaoy7y8WvlhXEzlwi9G5o4AS7FC19WMelMIujBHtZ/a4ddRA4VJkBKSiHnS1dUcBnaVxlggIthrfYytNCiAkmoEgSm6I548FaiVrzBkx+Av9D7deOQhJvtOTwtdoPHoGvWV+a4tCo971zSjPD9EXvGRZhExtE/iZoMiIYSDQtf9Y/9BnFx6SP8g2U5T8XKhHctT/iLxcqDAs6iz+Prf2ex1oexOfUqffGRpze87W39rLEyzOWLechAgTssfXRtTkX41bMojDOSYi2do+4VXxvUnKHCQ/rt7c0k8Tf7HyAyLM46vdtTyVtadcI978fw56c8xL6SK10YaAdZorf1iEHRFTZTd19LgVqrDEU1HkvYpIPeFEXcdQgjghVjHWwT5WrNyGu05OlKFaG6ynWqYRuMMQGYdVliF5gr3f6CPjmQ+qByAF8HuJbBrtBmUUk/a2BeTcp8zYJVgbV3dk8qV764xeKnRwKaj3h4LkWVGNkB1rFe0ZaigaoZk2hLez3uJRDrSY2xS8zQ+osOu8vEhw3bgDPoOXu3iA1qT/9GjZDMitZvWdfdi4DKvyN/N2ohxfB8T7EkrOZgXQ6mcWLbNrP2i8fSP2e9yOID319vVUOpS5CPO9uJrouCneNgTipMYAM6yhf7GiV5rYS1bZuKVZRovNlTHt2iZ1oscXDwb78F/FMT3tL+5yOm6ETutRHNOE0bpupDmj3NVgu3W6QX0vhKNvB368ybBEv3wWnCrCatuvQGFR/Njj07PMicc07XYGW6gYmFcdD+WK+myex9eMjy8SCfdCwaR10M5zZCWAYoIFoV/Ttw6r9LhJqGUuD5fnKyXKY4U0fV7Cai1LX/frCz//Lg/Ee4gTZpf2CT+d6mgQGDaJeXd+Dd8m6XPd8ydwa6t7L6vRDAfnzNmH2ojsrnCBAAA/HR0h1ASstAbUEgO+viJRD5+coTRX767p4tnYYS4+dDnpOGqoaMOhx4K1/ZLYY6GlXdciCUMO0rTdKdpP4Jzz9t5UgNbgqNsejAdDWyAuaeRe8k3hzIKv34AefIMWkYJ7HuqWGHnzUj0oUfM/FArZlVolKMgFARwnzQRYFYx56bHFZv0wq9QlZXHYXyMMqr6wDXEItjSfdXSs+E9ZMpRDq0KuEE7qlQcBIUKy1mH6pOfeVCG1IxTWCQSo+PpzhjR9+3jp61FhGaaAnyyYfXaMd8RhLpkfyCxcyNjifO8nQjdwFlQUQYCfqOuQa0EeeqxdOV/J6WbS/O9fhrActlZBHxUBAD2oOZjkmWMdK81CvYgN440RcNKv3tx2ZOr0pnfEgzoBi62+eJOZeB/6PWuAMudj5QM0cVd15i4WGTuwix4QlptouWejhBEjhEGXWVVmwisLTUbyWTfIGn/8luulW//KUAL6e0euak8sN4","X-Forefront-Antispam-Report":"CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n\tIPV:NLI; SFV:NSPM; H:AM9PR04MB8147.eurprd04.prod.outlook.com; PTR:;\n\tCAT:NONE; \n\tSFS:(13230040)(19092799006)(52116014)(376014)(366016)(1800799024)(38350700014);\n\tDIR:OUT; SFP:1101; ","X-MS-Exchange-AntiSpam-MessageData-ChunkCount":"1","X-MS-Exchange-AntiSpam-MessageData-0":"M6jbWtZPZFSvayV4KLoWWf2Npt3JA5a2F/cPk3KgatnRHjxmHh0M+Lt9+iN9UVjCB22ZbrwY+9cxHsP5xOPn0lGkhn9dddCAQ0A8oP3l0zEFUYP8tCqBc/doO5ZkRl3NSTXXuc1T/x9Ybc1t4u8BlmGtF7gw/EadmjGXeWKFuv40l564BtavHIBrDWxxF88LrBWDkfmRVI/drSZOMGgwpyJX9K7wKDePBZAdlFXXcTcz+RpmTEiBKa7A0z9XxMjwN5p9DEIDxdZ0r5X5k/a3XTd+Id8rXKZA6SZ8eEOu3oqlJcjRpfDZ29Eq5rMq8DbmEAy43/sqc3KzKR9gMB6SVV/aCy1SlciKhzhuUvXj+08Ftf+cHM+Hb8Z/RcdWZyoMunAuXgwjaghL2G5hqx5XBFXvRhwFOpliOKMMuubhjSslYU6HkeMGaK163bK2rInWB4kBhQfsrk52zPB/59S80mY4MePHdO7yw/iXb06wjkn6hvHsM1AS97P9KUhPMfTSzIo3VKxEoF3gYhi44W+unpC4S39JxU54wtmr/5TzsjWffcl9bHdhTVUH5uhRzqYCXG/T1upNqDMqrKgc8riXlHfuPfDgsDJ/KjFn8Cu+cK+k8x5xJbk46CcpeGyFqqCOiYHxL9tkEd6wuiul0OyAS7ryheLDl7p2QuQ5r/TgCoxHSbVXg28XlT9PPt4YEvGh14J4M4G6/F5qV0avwjFDB4xvWcgbaVH3GWqLB105YfzvaTNXeUMyvgrbUv0b2GR4Lzy2it/+ZJMOUDnDN+orWU+Ds9xcr8cw5Jm+8TL2eT3M3lHTz8YvxE9rbKGGzrpxf5Tt//BpPqP37rx/KtJJ2DEGle+303JRUQleyY+murtFUbVY+41wrlsqtKJvFmkIC3FpgbYPITchQAY3WtBkXJ6+rP1ie7J1vTArAfLGnJljD5vU2njlZ+4w2jpASu9DzNd7XahHr8PgqncOM8KKHAGEt8uSVKSm5Sc+xPotA+iao0leluKQiI/bxty22LKTAqeFsyzDjK9An6T4iftcxovXJcr54RscRAqathkbirDGVHDJYjo7vz7tWUEDme03pTw7GzCrHHVbGWxWmGLHJDcODllQ06AjjSC7hNxcmd7n4wp7CAI1sUL9V0m8jeeQLt5RTRPcTn+Gf8MPp9770R28b6Zpx+/m/ez7wTMGsXcCW6t62rWbnLdJ7Ed5JLeSnqqgX2B4lQ7vJEjIGEwuWi8a+V5R3og24c9Lx+hOGgmTDjlhSm6VQZG+Pjrvs5oNW7Xwyr+wolQE4Nax6G96xSvfPn0mvbkAC46HI1F971tVIOZncoQoLQuvK3g6Jhx8zTEBkk3lDUauNloLikLOoBtPVeybUg3b72pp8iSFNaiAQz9xhX5AyIkIKqIVIyrM0X3wOWrC2UYuS/ijZrC+JeLy9FPA+dwr9X0bOt5GT15V5kc3OZ0LiCeB79iKpyWa6UzA5mr/p+1DjZ0jkCSb2GUce0TDMv74hUv7MAh+S/I6PTu3RmjeKAxeyX3KctydFXoCGyuZ8Z3J82jeVj30Hkqu/YEGP0d4XAPOk1IjEvu5yOawFtMvtVhz/G2OtZUBK274lzUf58xMnNEeX6Z2tg==","X-OriginatorOrg":"nxp.com","X-MS-Exchange-CrossTenant-Network-Message-Id":"69c9281d-7fd3-4661-c6b0-08de130fabb2","X-MS-Exchange-CrossTenant-AuthSource":"AM9PR04MB8147.eurprd04.prod.outlook.com","X-MS-Exchange-CrossTenant-AuthAs":"Internal","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"24 Oct 2025 15:11:56.1147\n\t(UTC)","X-MS-Exchange-CrossTenant-FromEntityHeader":"Hosted","X-MS-Exchange-CrossTenant-Id":"686ea1d3-bc2b-4c6f-a92c-d99c5c301635","X-MS-Exchange-CrossTenant-MailboxType":"HOSTED","X-MS-Exchange-CrossTenant-UserPrincipalName":"M8aYyrwQ5TGdQsLEvUrS/3gFc3b6vV0T4/xAvudeb2VDNZ2NUHEeF2TeRrW3QVWPsRMSWjNOenw9zZHMmVw+FJEq8tkdkfzOPAwVnzISrQs=","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"VI0PR04MB11784","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":"Some sensors can produce and transmit an auxiliary image over a\ndedicated stream, separate from the image stream. Examples for such\nsensor are the ones supporting HDR or A/B mode captures.\n\nAdd support for that type of stream in the CameraSensor interface,\nand implement it for the CameraSensorRaw class.\nThe CameraSensorLegacy uses the default stub implementation, as\nthe corresponding kernel drivers don't support an auxiliary image.\n\nSigned-off-by: Julien Vuillaumier <julien.vuillaumier@nxp.com>\n---\n include/libcamera/internal/camera_sensor.h |   3 +\n src/libcamera/sensor/camera_sensor.cpp     |  52 ++++++++++\n src/libcamera/sensor/camera_sensor_raw.cpp | 112 ++++++++++++++++++---\n 3 files changed, 151 insertions(+), 16 deletions(-)","diff":"diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h\nindex f6ef4df1..6df928f5 100644\n--- a/include/libcamera/internal/camera_sensor.h\n+++ b/include/libcamera/internal/camera_sensor.h\n@@ -68,6 +68,9 @@ public:\n \tvirtual std::optional<V4L2Subdevice::Stream> embeddedDataStream() const;\n \tvirtual V4L2SubdeviceFormat embeddedDataFormat() const;\n \tvirtual int setEmbeddedDataEnabled(bool enable);\n+\tvirtual std::optional<V4L2Subdevice::Stream> auxiliaryStream() const;\n+\tvirtual V4L2SubdeviceFormat auxiliaryFormat() const;\n+\tvirtual int setAuxiliaryEnabled(bool enable);\n \n \tvirtual const ControlList &properties() const = 0;\n \tvirtual int sensorInfo(IPACameraSensorInfo *info) const = 0;\ndiff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp\nindex 4f2fd269..3bf05f11 100644\n--- a/src/libcamera/sensor/camera_sensor.cpp\n+++ b/src/libcamera/sensor/camera_sensor.cpp\n@@ -266,6 +266,58 @@ int CameraSensor::setEmbeddedDataEnabled(bool enable)\n \treturn enable ? -ENOSTR : 0;\n }\n \n+/**\n+ * \\brief Retrieve the auxiliary image source stream\n+ *\n+ * Some sensors produce an auxiliary image stream separate from the image\n+ * stream. This function indicates if the sensor supports this feature by\n+ * returning the auxialiary stream on the sensor's source pad if available,\n+ * or an std::optional<> without a value otheriwse.\n+ *\n+ * \\return The auxiliary source stream\n+ */\n+std::optional<V4L2Subdevice::Stream> CameraSensor::auxiliaryStream() const\n+{\n+\treturn {};\n+}\n+\n+/**\n+ * \\brief Retrieve the format on the auxiliary stream\n+ *\n+ * When an auxiliary image stream is available, this function returns the\n+ * corresponding format on the sensor's source pad. The format may vary with\n+ * the image stream format, and should therefore be retrieved after configuring\n+ * the image stream.\n+ *\n+ * If the sensor doesn't support auxiliary stream, this function returns a\n+ * default-constructed format.\n+ *\n+ * \\return The format on the embedded data stream\n+ */\n+V4L2SubdeviceFormat CameraSensor::auxiliaryFormat() const\n+{\n+\treturn {};\n+}\n+\n+/**\n+ * \\brief Enable or disable the auxiliary image stream\n+ * \\param[in] enable True to enable the auxiliary image stream, false to disable it\n+ *\n+ * For sensors that support it function enables or disables generation of\n+ * auxiliary image stream. Some of such sensors always produce an auxiliary\n+ * stream, in which case this function return -EISCONN if the caller attempts to\n+ * disable it.\n+ *\n+ * If the sensor doesn't support an auxiliary image stream, this function\n+ * returns 0 when \\a enable is false, and -ENOSTR otherwise.\n+ *\n+ * \\return 0 on success, or a negative error code otherwise\n+ */\n+int CameraSensor::setAuxiliaryEnabled(bool enable)\n+{\n+\treturn enable ? -ENOSTR : 0;\n+}\n+\n /**\n  * \\fn CameraSensor::properties()\n  * \\brief Retrieve the camera sensor properties\ndiff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/libcamera/sensor/camera_sensor_raw.cpp\nindex ad4a94ad..ecc64b44 100644\n--- a/src/libcamera/sensor/camera_sensor_raw.cpp\n+++ b/src/libcamera/sensor/camera_sensor_raw.cpp\n@@ -89,6 +89,9 @@ public:\n \tstd::optional<V4L2Subdevice::Stream> embeddedDataStream() const override;\n \tV4L2SubdeviceFormat embeddedDataFormat() const override;\n \tint setEmbeddedDataEnabled(bool enable) override;\n+\tvirtual std::optional<V4L2Subdevice::Stream> auxiliaryStream() const override;\n+\tvirtual V4L2SubdeviceFormat auxiliaryFormat() const override;\n+\tvirtual int setAuxiliaryEnabled(bool enable) override;\n \n \tconst ControlList &properties() const override { return properties_; }\n \tint sensorInfo(IPACameraSensorInfo *info) const override;\n@@ -127,6 +130,7 @@ private:\n \tstruct {\n \t\tStreams image;\n \t\tstd::optional<Streams> edata;\n+\t\tstd::optional<Streams> auxiliary;\n \t} streams_;\n \n \tconst CameraSensorProperties *staticProps_;\n@@ -206,7 +210,7 @@ CameraSensorRaw::match(MediaEntity *entity)\n \t\t}\n \t}\n \n-\tif (numSinks < 1 || numSinks > 2 || numSources != 1) {\n+\tif (numSinks < 1 || numSinks > 3 || numSources != 1) {\n \t\tlibcamera::LOG(CameraSensor, Debug)\n \t\t\t<< entity->name() << \": unsupported number of sinks (\"\n \t\t\t<< numSinks << \") or sources (\" << numSources << \")\";\n@@ -277,6 +281,7 @@ std::optional<int> CameraSensorRaw::init()\n \t}\n \n \tbool imageStreamFound = false;\n+\tbool auxiliaryStreamFound = false;\n \n \tfor (const V4L2Subdevice::Route &route : routing) {\n \t\tif (route.source.pad != sourcePad) {\n@@ -306,17 +311,21 @@ std::optional<int> CameraSensorRaw::init()\n \n \t\tswitch (*type) {\n \t\tcase MediaBusFormatInfo::Type::Image:\n-\t\t\tif (imageStreamFound) {\n+\t\t\t/* Assume that primary image is on the stream 0/0 */\n+\t\t\tif (!imageStreamFound &&\n+\t\t\t    route.source.pad == 0 && route.source.stream == 0) {\n+\t\t\t\timageStreamFound = true;\n+\t\t\t\tstreams_.image = { route.sink, route.source };\n+\t\t\t} else if (!auxiliaryStreamFound) {\n+\t\t\t\tauxiliaryStreamFound = true;\n+\t\t\t\tstreams_.auxiliary = { route.sink, route.source };\n+\t\t\t} else {\n \t\t\t\tLOG(CameraSensor, Error)\n \t\t\t\t\t<< \"Multiple internal image streams (\"\n \t\t\t\t\t<< streams_.image.sink << \" and \"\n \t\t\t\t\t<< route.sink << \")\";\n \t\t\t\treturn { -EINVAL };\n \t\t\t}\n-\n-\t\t\timageStreamFound = true;\n-\t\t\tstreams_.image.sink = route.sink;\n-\t\t\tstreams_.image.source = route.source;\n \t\t\tbreak;\n \n \t\tcase MediaBusFormatInfo::Type::Metadata:\n@@ -363,6 +372,11 @@ std::optional<int> CameraSensorRaw::init()\n \t\t\t<< \"Found embedded data stream \" << streams_.edata->sink\n \t\t\t<< \" -> \" << streams_.edata->source;\n \n+\tif (streams_.auxiliary)\n+\t\tLOG(CameraSensor, Debug)\n+\t\t\t<< \"Found auxiliary stream \" << streams_.auxiliary->sink\n+\t\t\t<< \" -> \" << streams_.auxiliary->source;\n+\n \t/* Restore the routes to their initial state */\n \tret = subdev_->setRouting(&routing);\n \tif (ret) {\n@@ -963,20 +977,22 @@ V4L2SubdeviceFormat CameraSensorRaw::embeddedDataFormat() const\n \n int CameraSensorRaw::setEmbeddedDataEnabled(bool enable)\n {\n+\tint ret;\n+\n \tif (!streams_.edata)\n \t\treturn enable ? -ENOSTR : 0;\n \n-\tV4L2Subdevice::Routing routing{ 2 };\n-\n-\trouting[0].sink = streams_.image.sink;\n-\trouting[0].source = streams_.image.source;\n-\trouting[0].flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE;\n-\n-\trouting[1].sink = streams_.edata->sink;\n-\trouting[1].source = streams_.edata->source;\n-\trouting[1].flags = enable ? V4L2_SUBDEV_ROUTE_FL_ACTIVE : 0;\n+\tV4L2Subdevice::Routing routing;\n+\tret = subdev_->getRouting(&routing);\n+\tif (ret)\n+\t\treturn ret;\n \n-\tint ret = subdev_->setRouting(&routing);\n+\tfor (V4L2Subdevice::Route &route : routing) {\n+\t\tif (route.source != streams_.edata->source)\n+\t\t\tcontinue;\n+\t\troute.flags = enable ? V4L2_SUBDEV_ROUTE_FL_ACTIVE : 0;\n+\t}\n+\tret = subdev_->setRouting(&routing);\n \tif (ret)\n \t\treturn ret;\n \n@@ -1002,6 +1018,70 @@ int CameraSensorRaw::setEmbeddedDataEnabled(bool enable)\n \treturn 0;\n }\n \n+std::optional<V4L2Subdevice::Stream> CameraSensorRaw::auxiliaryStream() const\n+{\n+\tif (!streams_.auxiliary)\n+\t\treturn {};\n+\n+\treturn { streams_.auxiliary->source };\n+}\n+\n+V4L2SubdeviceFormat CameraSensorRaw::auxiliaryFormat() const\n+{\n+\tif (!streams_.auxiliary)\n+\t\treturn {};\n+\n+\tV4L2SubdeviceFormat format;\n+\tint ret = subdev_->getFormat(streams_.auxiliary->source, &format);\n+\tif (ret)\n+\t\treturn {};\n+\n+\treturn format;\n+}\n+\n+int CameraSensorRaw::setAuxiliaryEnabled(bool enable)\n+{\n+\tint ret;\n+\n+\tif (!streams_.auxiliary)\n+\t\treturn enable ? -ENOSTR : 0;\n+\n+\tV4L2Subdevice::Routing routing;\n+\tret = subdev_->getRouting(&routing);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tfor (V4L2Subdevice::Route &route : routing) {\n+\t\tif (route.source != streams_.auxiliary->source)\n+\t\t\tcontinue;\n+\t\troute.flags = enable ? V4L2_SUBDEV_ROUTE_FL_ACTIVE : 0;\n+\t}\n+\tret = subdev_->setRouting(&routing);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/*\n+\t * Check if the auxiliary stream has been enabled or disabled\n+\t * correctly. Assume at least one route will match the auxiliary\n+\t * source stream, as there would be something seriously wrong\n+\t * otherwise.\n+\t */\n+\tbool enabled = false;\n+\n+\tfor (const V4L2Subdevice::Route &route : routing) {\n+\t\tif (route.source != streams_.auxiliary->source)\n+\t\t\tcontinue;\n+\n+\t\tenabled = route.flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE;\n+\t\tbreak;\n+\t}\n+\n+\tif (enabled != enable)\n+\t\treturn enabled ? -EISCONN : -ENOSTR;\n+\n+\treturn 0;\n+}\n+\n int CameraSensorRaw::sensorInfo(IPACameraSensorInfo *info) const\n {\n \tinfo->model = model();\n","prefixes":["RFC","v1","2/2"]}