From patchwork Thu Nov 13 10:04:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antoine Bouyer X-Patchwork-Id: 25011 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 106ABC3263 for ; Thu, 13 Nov 2025 10:03:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3DE1B60A81; Thu, 13 Nov 2025 11:02:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=nxp.com header.i=@nxp.com header.b="SIdlMSl3"; dkim-atps=neutral Received: from GVXPR05CU001.outbound.protection.outlook.com (mail-swedencentralazlp170130007.outbound.protection.outlook.com [IPv6:2a01:111:f403:c202::7]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6C00A60A7B for ; Thu, 13 Nov 2025 11:02:53 +0100 (CET) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=dzRkjIAmeIUEPsY1lfml6rkIvha+0Lh/zhWeNDgbkM++bvOzvsJjOPUatgMVt8cGa1vzDeuHlU6vSO0DX890lpFuCMLwqYdunNylm8yRaookkKlDYntBo7I6/R0+zM39CPY6T+nkJ5Ft6W7b0WkJ9XUA1I9GVD1rsXuy/mOZR0fjG9CQlTaZJwB+Snh3YgkrWSr153Z905h8mpV8P3vyOHRtex6qss6fjhPhjeFJIml+TFeo0SPsSKYflOXPOD1OJ3T43sqqVRj99T/31OPwSuWjC/e6QfsSrWm09+Ov05oZGrC9wSC6LJnUh3SC7C1ZSqBNfw4iJT4x3A+tB36KOQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=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; bh=SpUqncjHtUOgBWdmD8IwRZZJxhKUyakQtneBrT0pEwc=; b=d9/cU3n5x3J6QQWP+/tWNSIIywG1sPrE+c3ptvfZfW8G2B3BCmOQddML6jekPrmnYXFQnyM9IYdJKks1WvWHz+pcANGjv3pz17BKRxSD7p29qHsaliIqOj+lpkloeUIrvnz2RPM7IBim8ZNN+BAv8skhtUOmlmJK1lmCLZCatgj+KaBjZMQTlvxNUAHZGqXNb6ST7zX11sotdQJtgOHQFetXc8VA5SBH4HyyozSN3sj/Zf36ggGblIlVxJ6tMf5VbvEK0Ep/p4EsxA2LHYkOHWKm5PrHr0vuwBhAlGuJCnNFeqT1cPJNtqrCORiugwROR8ZrLn8bUSf5RnTG5960DA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=SpUqncjHtUOgBWdmD8IwRZZJxhKUyakQtneBrT0pEwc=; b=SIdlMSl3o08tGGtoc5TTA3zHTYuKWafRLUbG5S+RlCMIM0BIrAmb21CvttUcpSSx3is0IGsaLPT+fJixEXyFS2Cm2j4mcaajGitOC4QZvJQ4FTe0rBHvU8L6JZCAP0aJXuX58/xMRXS53UOSs3ijPhv1HX8WnbFOHM1viAonCNdu9ZJKOTn0eSz0CYlM2+xaLMmefclM5dmBSYvo3/p790yBkNDqor11wzG5RauTtsuvSUsr2ihrFwKw2cTsanAVBdL/7qtQLS8Aky2U4kSroPdqwJqROznrbWlC4M3v5aSrOfTWPPmHLBGy2WsUVzs+jJx1GbuyLqMeY8AXVSDM4g== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from GVXPR04MB9831.eurprd04.prod.outlook.com (2603:10a6:150:11c::8) by AM8PR04MB7235.eurprd04.prod.outlook.com (2603:10a6:20b:1d1::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9320.17; Thu, 13 Nov 2025 10:02:51 +0000 Received: from GVXPR04MB9831.eurprd04.prod.outlook.com ([fe80::4634:3d9c:c4a:641a]) by GVXPR04MB9831.eurprd04.prod.outlook.com ([fe80::4634:3d9c:c4a:641a%6]) with mapi id 15.20.9320.013; Thu, 13 Nov 2025 10:02:51 +0000 From: Antoine Bouyer To: libcamera-devel@lists.libcamera.org Cc: julien.vuillaumier@nxp.com, Andrei Gansari , Antoine Bouyer Subject: [PATCH v1 2/2] pipeline: imx8-isi: Integrating MediaPipeline class Date: Thu, 13 Nov 2025 11:04:14 +0100 Message-Id: <20251113100414.535550-3-antoine.bouyer@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251113100414.535550-1-antoine.bouyer@nxp.com> References: <20251113100414.535550-1-antoine.bouyer@nxp.com> X-ClientProxiedBy: AM0PR02CA0198.eurprd02.prod.outlook.com (2603:10a6:20b:28e::35) To GVXPR04MB9831.eurprd04.prod.outlook.com (2603:10a6:150:11c::8) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: GVXPR04MB9831:EE_|AM8PR04MB7235:EE_ X-MS-Office365-Filtering-Correlation-Id: 8ad38cf3-a84c-4ff4-9015-08de229bce5f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|366016|376014|19092799006|1800799024|52116014|38350700014; X-Microsoft-Antispam-Message-Info: +S+l1bTqoDCPwtPLJdITOV29RoV8eacXl1VbbXT9bITHWQvGosZJpx84pHuyQLKnGfRXjDivsxvsyxi1ThDoTMw9a/oLXN4lONaISsz0b47GFSGVsJ+aEWSmqLJAYEr+FVWr4Z2lSMexbhnAEzmTrst58mpe9kPxMJQrZZVPedBZWl2h9pFxLRXMH4iL0DFbVhLr4x3KHAb1mAar3JHIB2DBr7VMOvr00kQDN1KXDwFaYqcqBR0Ou8Jj8i6jVXeUTHU7+uUGWG4nfbQSRiU91yEFEapnoburTtC0CbEYSyi6CxG9QlepRf/put2U/KE2YsgtZdvJ8dTpuk2PLWxdibJmvj1UT08GXC+UajaP7yiCfoR8iXkex7RvEFx/zWdeGrYtBuRN5PcMR8ZZ97S2ijwvpE+Brv7USBQ00ymiZFDq7bk4INN00zSpIWfz4gKTprEod1NChtPfMshIR36mWq6wNiN7A8QIlPLdGJnArc/+5A4bntJVnLW8ZmcGNpH/pvvKgHBhHeMHQnjOf6xMN8HM24RqmNnB5JZ3wyljwc3N0sr+4l1rjtUp+jfMQ593+GWnmA84Pc4AxI/DHel8ISO7XK3dm244NyPw8RDOqKeEewgqXNsse5622lqXpFrFEYiQI8hN/AId/YtOHKc4Kpsh+keLvYt0xgqoWTEFC4/dlHkX2zQKwKpCWOTo0y5sTarjLg5FQcz1VzuHgYC0Gc2fbFC0FTypS/C6MTqf9Rbw7ohPZov6V+C1Ilcjk8/lap1L0/GAWVVAD6gMW+DFLAptkBfteueWBS3fwf3/Ka8CH+cr5t+SwicFTePqglRrBFAPqOlnKA2zsJU1CZ8NLRa2ArUsQthxNNgWOqfpRazakBaWE1gCo3Jv9rToldLGcaDZRo/KX+TWulLug38qCvYJ4OGxx8nld3iFCJVBghg5SmCdAY8UAhNbbmmqESMZDlaou5eEf+9gpz7Z22shfTk6H1EhBmQbkn3wwKSb+Uo6mVNxOK7Amg2HxKUWAmQarEzKJpXSalnr7XLlLhRyaWqzKz11ysnVMXHBW4AaBiCC+rntZV29cX3XGgY9Mo7dSvF92FGVxkKoxbN8iqGs/97VSkNkFlare6ZJLJtqvMR0kiIGXlgonye6nDQ1shpJkjbrBqFe/yfO4JbBjXzCT/fTk0EZRoORgFBjcwGW067pp8XUF5+JwRnuc4gQ86WrxfRHqkyt5mzR9yr7o4bSS/2GBxlOIc+l+vBPlig6cRKI6sGoDtny8oC6L4uxGYE91giv1+CvPgVeVewBeTq99WhaaV4OCfEO7eO4JTR6GKMNGkDYYCMbtVxcDRkA9C8gjl/NvH31DQi+1lKvGEmze7ZRPsXTc3BurmygB6vXHzohDO7cMTLD6Ea+/EDu005Qk8LRpN0arZGqfdxQBsT8HzJviadAvhPcBWg09NX07x7T/5NJjP6JwCWV7ZljsS3visq4emN3ZL5noYc8EyfoOfxh1bny/voTFEQNHpuI0f+QJdoieVTrIpg6C/yqvy+f X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:GVXPR04MB9831.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(376014)(19092799006)(1800799024)(52116014)(38350700014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 1RCT+NbVMpl91EaA2ioBlObEknRU7FZCYT3wU/8SRQr8pYJZO/uu+ugfp0wfe3bPK6AKFDLvaKk2FZqFaSixWGbTQB6oUkZckpkUkb13NfEvKH+MvVluFNJOqaFZjHks26IsGfKGqzcBplO5getRXEXQeQt1SLnAWpn9RGfgmL/CGeQf/UREyvKovARzVeIpxTdag+3SW+rogMtOPw7sdDYxSyv0/FLwOpgEUzn4Bc4R02ebQWJSwzfq7bO9/H6S35Z/k6PnfYp2u51QWOEqvKTKds4ziSilhv4NAyr5TQLdG0eJnRJmmhGxyOVCHCp4CKg1nSaI1D8QiEsNGCYnT9YEU6DYeTlW3BwrmO9hdg15k22LbCvKwCWQw0qYIiHFBLHW0ExHIiI6xMv5gfqwg7cCJ6WRK7aixNx/X877FZiNMsrfmotTtKhIoH2mLFvX3kstIM2q5SXckViCUIhyifH0WGbDumbyx+fWkNpzdc2GmaviAs8ObJ0j1o7gC+z3b9IaILEXTT4Ge+WU8ZjSAxCmFLval0jMVTSa419O+mkixgjUtOQqynlDlj6FOV0U44GDxUkS1YbLiwpEkAOXJNhc7c85oFoxJWSv0GlBMl8IzYHEfSpCGKZd5QuZf1xfns0Qa9JoKykp4kHz26mkv8F3LlDGqxSSO2141UlSbVCM3yKzZ6h4sNr5TH+g0JRQhogPdVk3nMKN2WExKsMPvm/RaabBaEnP1HyJjAhyuWdlavdtF8sBee0O3dWNHLN381Mndj6ATfk1/rHlSvcp28AYNfJrL62KL+mqxCBC/ReoEJ+lfhmTBGbd94iuvDXGhcB8oNUvw5n/zYM9skLu5sN1UjWxNDF5eMLXyb2gL6qUWzkc/MBDQ7TUFhWljX2anUomJJzZqNUmUkocbrDgzM5rEogBVVBku2EAf7tasCHaFc+g1+R3TR4l4xyO07AS6g18UAxXFhoz45J2PPvmbR70RJIQjpR1evndOMt0aQ27e+ZXVwHq04B1D20KJqlk2Eg34tT2MD30PCjnvXwIUeLzpxCLnX45M+zYGjYGbh5BuA0EQPFjTUS8khje4whx/R06cQelljMrsN4m4I7PPIZLmwOodJMSvUBu8L8Og2Bo+gsSGTA96mQ/aF8sBgZnZ77DyM72R/qilIrJfmqcLdawG0tPnO4kC+eGkYSRYrzYVBzTIMt1c/3DsgfEExqrZK6nBj2YV6OwAdyPz7YK2Y3H1CsjUPekjocmKZiixtcxGgQSzUWK7czMXER1oIhe1Sc3BBGXtpj0OfQbxUNfN+lSdPnacFwhN3aq8JPodBZ0ulGfGQVVOSfW1bD9/dovzXiknvBIujs7MXSK0TiHAo6rZcmP2VpItqvTuwjNVWgmzMD9/c434YFBFMA43K7BzsDrzXkGGRLDwkAfB5XUBJjg4Bx2ZByn/Ifyfp5Wmk1AShde7LOneb1jDCG6c30rYzycXV6A5V0MmkOLhpL94LqkYS6eLtWIOYUsEEzPsEnrhxiCXoSBMODjdTUz7l/WZalM5d7BvBbXAcEv+VfBlVXYIcSzi+iY14kxMXP4qUp5J41+ftHTmBMNa7mRuRXUuwe27KAiRQq/ZFMqTe00Bw== X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 8ad38cf3-a84c-4ff4-9015-08de229bce5f X-MS-Exchange-CrossTenant-AuthSource: GVXPR04MB9831.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 Nov 2025 10:02:51.2888 (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: vT1/IRQKFCNxTvBvaEvXih6JT8mjjneT83ERZwekO1xFip/Xet2i4yY3kY8G6nyJw0kwELRmf28jb4VFWi4BEA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM8PR04MB7235 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" From: Andrei Gansari This change integrates the MediaPipeline class into the imx8-isi pipeline handler. Purpose is to allow a dynamic discovery and configuration of the actual subdevices graph between the sensor and the ISI crossbar. This brings support for more complex topologies and simplifies the implementation. Signed-off-by: Andrei Gansari Signed-off-by: Antoine Bouyer --- src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 159 ++++++++++++------- 1 file changed, 98 insertions(+), 61 deletions(-) diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp index 9550f54600c4..aefc0ee60a11 100644 --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp @@ -25,6 +25,7 @@ #include "libcamera/internal/camera_sensor.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/media_device.h" +#include "libcamera/internal/media_pipeline.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/v4l2_subdevice.h" #include "libcamera/internal/v4l2_videodevice.h" @@ -62,14 +63,15 @@ public: unsigned int getYuvMediaBusFormat(const PixelFormat &pixelFormat) const; unsigned int getMediaBusFormat(PixelFormat *pixelFormat) const; + /* All entities, from the sensor to the ISI. */ + MediaPipeline mediaPipeline_; + std::unique_ptr sensor_; - std::unique_ptr csis_; std::vector streams_; std::vector enabledStreams_; - unsigned int xbarSink_ = 0; unsigned int xbarSourceOffset_ = 0; }; @@ -141,6 +143,8 @@ private: void bufferReady(FrameBuffer *buffer); + std::vector locateSensors(MediaDevice *media); + MediaDevice *isiDev_; std::unique_ptr crossbar_; @@ -164,10 +168,6 @@ int ISICameraData::init() if (!sensor_) return -ENODEV; - int ret = csis_->open(); - if (ret) - return ret; - properties_ = sensor_->properties(); return 0; @@ -811,18 +811,29 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c) { ISICameraConfiguration *camConfig = static_cast(c); ISICameraData *data = cameraData(camera); + CameraSensor *sensor = data->sensor_.get(); + int ret; - /* Apply format to the sensor, CSIS receiver and crossbar sink pad. */ - V4L2SubdeviceFormat format = camConfig->sensorFormat_; - int ret = data->sensor_->setFormat(&format); - if (ret) + /* + * Enable the links all the way up to the ISI, through any connected CSI + * receiver and optional formatter. + */ + ret = data->mediaPipeline_.initLinks(); + if (ret) { + LOG(ISI, Error) << "Failed to set up pipe links"; return ret; + } - ret = data->csis_->setFormat(0, &format); + /* + * Configure the format on the sensor output and propagate it through + * the pipeline. + */ + V4L2SubdeviceFormat format = camConfig->sensorFormat_; + ret = sensor->setFormat(&format); if (ret) return ret; - ret = crossbar_->setFormat(data->xbarSink_, &format); + ret = data->mediaPipeline_.configure(sensor, &format); if (ret) return ret; @@ -979,13 +990,8 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator) return false; /* Count the number of sensors, to create one camera per sensor. */ - unsigned cameraCount = 0; - for (MediaEntity *entity : isiDev_->entities()) { - if (entity->function() != MEDIA_ENT_F_CAM_SENSOR) - continue; - - cameraCount++; - } + std::vector sensorEntities = locateSensors(isiDev_); + unsigned cameraCount = sensorEntities.size(); if (!cameraCount) { LOG(ISI, Error) << "No camera sensor found"; @@ -1048,60 +1054,28 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator) * sensors to get at least one dedicated pipe. */ unsigned int numCameras = 0; - unsigned int numSinks = 0; const unsigned int xbarFirstSource = crossbar_->entity()->pads().size() - pipes_.size(); const unsigned int maxStreams = pipes_.size() / cameraCount; - for (MediaPad *pad : crossbar_->entity()->pads()) { - unsigned int sink = numSinks; - - if (!(pad->flags() & MEDIA_PAD_FL_SINK)) - continue; - - /* - * Count each crossbar sink pad to correctly configure - * routing and format for this camera. - */ - numSinks++; - - if (pad->links().empty()) - continue; - - MediaEntity *csi = pad->links()[0]->source()->entity(); - if (csi->pads().size() != 2) { - LOG(ISI, Debug) << "Skip unsupported CSI-2 receiver " - << csi->name(); - continue; - } - - pad = csi->pads()[0]; - if (!(pad->flags() & MEDIA_PAD_FL_SINK) || pad->links().empty()) - continue; - - MediaEntity *sensor = pad->links()[0]->source()->entity(); - if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) { - LOG(ISI, Debug) << "Skip unsupported subdevice " - << sensor->name(); - continue; - } - - /* All links are immutable except the sensor -> csis link. */ - const MediaPad *sensorSrc = sensor->getPadByIndex(0); - sensorSrc->links()[0]->setEnabled(true); - + for (MediaEntity *sensor : sensorEntities) { /* Create the camera data. */ std::unique_ptr data = std::make_unique(this, maxStreams); + ret = data->mediaPipeline_.init(sensor, "crossbar"); + if (ret) + continue; + + const MediaPipeline::Entity *xbarEntity = &data->mediaPipeline_.entities().back(); + unsigned int xbarSinkIndex = xbarEntity->sink->index(); + data->sensor_ = CameraSensorFactoryBase::create(sensor); - data->csis_ = std::make_unique(csi); - data->xbarSink_ = sink; data->xbarSourceOffset_ = numCameras * data->streams_.size(); LOG(ISI, Debug) << "cam" << numCameras << " streams " << data->streams_.size() - << " sink " << data->xbarSink_ + << " sink " << xbarSinkIndex << " offset " << data->xbarSourceOffset_; ret = data->init(); @@ -1120,7 +1094,7 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator) /* Add routes to the crossbar switch routing table. */ for (unsigned i = 0; i < data->streams_.size(); i++) { unsigned int sourcePad = xbarFirstSource + data->xbarSourceOffset_ + i; - routing_.emplace_back(V4L2Subdevice::Stream{ data->xbarSink_, 0 }, + routing_.emplace_back(V4L2Subdevice::Stream{ xbarSinkIndex, 0 }, V4L2Subdevice::Stream{ sourcePad, 0 }, V4L2_SUBDEV_ROUTE_FL_ACTIVE); } @@ -1163,6 +1137,69 @@ void PipelineHandlerISI::bufferReady(FrameBuffer *buffer) completeRequest(request); } +/* Original function taken from simple.cpp */ +std::vector +PipelineHandlerISI::locateSensors(MediaDevice *media) +{ + std::vector entities; + + /* + * Gather all the camera sensor entities based on the function they + * expose. + */ + for (MediaEntity *entity : media->entities()) { + if (entity->function() == MEDIA_ENT_F_CAM_SENSOR) + entities.push_back(entity); + } + + if (entities.empty()) + return {}; + + /* + * Sensors can be made of multiple entities. For instance, a raw sensor + * can be connected to an ISP, and the combination of both should be + * treated as one sensor. To support this, as a crude heuristic, check + * the downstream entity from the camera sensor, and if it is an ISP, + * use it instead of the sensor. + */ + std::vector sensors; + + for (MediaEntity *entity : entities) { + /* + * Locate the downstream entity by following the first link + * from a source pad. + */ + const MediaLink *link = nullptr; + + for (const MediaPad *pad : entity->pads()) { + if ((pad->flags() & MEDIA_PAD_FL_SOURCE) && + !pad->links().empty()) { + link = pad->links()[0]; + break; + } + } + + if (!link) + continue; + + MediaEntity *remote = link->sink()->entity(); + if (remote->function() == MEDIA_ENT_F_PROC_VIDEO_ISP) + sensors.push_back(remote); + else + sensors.push_back(entity); + } + + /* + * Remove duplicates, in case multiple sensors are connected to the + * same ISP. + */ + std::sort(sensors.begin(), sensors.end()); + auto last = std::unique(sensors.begin(), sensors.end()); + sensors.erase(last, sensors.end()); + + return sensors; +} + REGISTER_PIPELINE_HANDLER(PipelineHandlerISI, "imx8-isi") } /* namespace libcamera */