From patchwork Fri Nov 14 15:43:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antoine Bouyer X-Patchwork-Id: 25074 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 8257FC3241 for ; Fri, 14 Nov 2025 15:41:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6126460AA3; Fri, 14 Nov 2025 16:41:56 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=nxp.com header.i=@nxp.com header.b="YSsQDyYk"; dkim-atps=neutral Received: from MRWPR03CU001.outbound.protection.outlook.com (mail-francesouthazlp170110003.outbound.protection.outlook.com [IPv6:2a01:111:f403:c207::3]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CAA77609D8 for ; Fri, 14 Nov 2025 16:41:52 +0100 (CET) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=OhA24JWRkj9hFXiayUsBiPT5Fg/aCOKKiUAyvENH4fDHJ6OlS10/NbLLdaGpqsGtNIm2gNGpcCdmYVa94YzfVZ7LCVig4gvHaOHAL7WsyYbBo+2xR6RCkaXRRYSLzGfeb0ZPERSi4YBh/kF/mhyUU/I2u5EsFbY792H2gdCUieXrY8zq+GYF08//w6P+3Dl8K2gms6vtTZeO0IiinMftK6zrvPHi8DOPnMN6LBZtaVc9MbmM+PvhuNRxzQd0To75SPQxw36pMA+u/Sk9v3V6pAZ8fGLVi1R2bHbomZT4wfrqXaSpWT5CddpmMh4NK/Mz1FpHGL9ty5yF82R6a9ARpA== 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=mWeRjE0FDMUjDrm5L6VdjtVWhvPNuoOSRkTUVnUNIsxnySYtZQceoan0HXIipz7534/CAByKn6r25r5Yr8mk6mya8yTq0QW9htCqL9k9QQUu3nrjvbZCxl6hVOLPM8X58Pu7EuvJ/Skv6Gsh9YOAAl1ki3eivaWtVxDCiybEbv4a7GgbGCT0/T0M7f5T8/NUHykg0V8mmzOSVs+xG3aJvs6cIrAaVH96ISXo9pdRug7eQSRWxRCk9X+ayto597fLjb74hMOOmtA9sZABaTU3Zo4uBtOj50n+mHsNoDvOo0dcQyk/UJJAnEL4ITwIV15SFVxcjUQTfbKKNk7L3d8i+Q== 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=YSsQDyYkd11wO8Os3L/63MBV1QvQjujW294vLVnrzDwQChHGS89OiF3mKLuMNoUHzFGnxVjbNpMc1zOwpsv0pZNCOfS0Sxyi9p/eqdLwAhcuTjulURes9sRiZu5Z+wTqHk9NUiutoTPy7brdwcvUrgzCBVFtDagVq0as7QLalT8pjMDQIjm9Xnt9qsLlUNrB5aDmeLgsKB9NoSRTK39fvdvXCwgPaKN3OyS+52NLgR4Cg5PwbMdejex+VaduMUK+6kzQzqlGyR9Y2hF3xlsbNNXql05JfSiulRvUmhCqScFBnvwgHo8zlQBEKT0LMu2zEvjDT/ZBRyeycKsLbe/nzg== 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 GV1PR04MB10108.eurprd04.prod.outlook.com (2603:10a6:150:1a2::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9320.16; Fri, 14 Nov 2025 15:41: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.018; Fri, 14 Nov 2025 15:41:51 +0000 From: Antoine Bouyer To: libcamera-devel@lists.libcamera.org Cc: julien.vuillaumier@nxp.com, jacopo.mondi@ideasonboard.com, barnabas.pocze@ideasonboard.com, Andrei Gansari , Antoine Bouyer Subject: [PATCH v2 2/2] pipeline: imx8-isi: Integrating MediaPipeline class Date: Fri, 14 Nov 2025 16:43:41 +0100 Message-Id: <20251114154341.654850-3-antoine.bouyer@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251114154341.654850-1-antoine.bouyer@nxp.com> References: <20251114154341.654850-1-antoine.bouyer@nxp.com> X-ClientProxiedBy: AS4P192CA0039.EURP192.PROD.OUTLOOK.COM (2603:10a6:20b:658::20) To GVXPR04MB9831.eurprd04.prod.outlook.com (2603:10a6:150:11c::8) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: GVXPR04MB9831:EE_|GV1PR04MB10108:EE_ X-MS-Office365-Filtering-Correlation-Id: e18d2fb9-574c-4edc-43f8-08de239454a9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|52116014|19092799006|376014|1800799024|366016|38350700014; X-Microsoft-Antispam-Message-Info: YT7VLeyT5N7qUJK4LQw64+o01GVlT7WEKg7M9N/p7mIX7Aoh0PEiRKKeqr81RFAVJwdK8latJmscImVck+sthxMHFY9fD4Otv/uY87DqY2+RrRPU1d5SgPL32CO0cMLE1gEhkIpR7urF+KgoDofhq8QyFxXFmJGjxHwT7McKDTfSO+cS11pT3HgBtK6Ry0VQ2wl1fuHNNaEShFJJ3dcqEmgZ0ofQvjj7SZ9q9WtusdZEqPNdcmf1/6ZUe8NxTIodEaXLg8aEUg0Y440dumv8qiWwv1ML8CyXni4Uij1qUhlqONo6wM0wK56u11Atb/tJF1PYb2QsF1YYmKXZlawhg1r5SV1mxA2Hhpp9KviH2F0ScqirND4t/aMajM2zgaY6AOMBy9n1Bsi5mw7b1XB7DlkvKG28ZuW0b5tTIjdYTUBH9FwhV4tvO13iDdGJD6jVIMx5eE61pbcWJ5HUeaTlETFV1rBJLi2gFuNsydj7vsmTEfKir1N4VZ/1TUFNLlFz6JizExx+RoLXJkjtXqphwpy+oOzRJXkJfdyxEdMQjDcFtGMnwGLPHCM62AsTv8OCaAYdRYMEmFm7nsFUdbXEcuDVhVRkIVLSdsHv6L11c+Sfj3Wn0zwGbhLnKWMZWSbSCLqD1ftn1+sBG+ApR7XV1R2AzNyd+o/+1ab/wfaKAIs6YwIF30fUX8Y07liBwntMX3SIz+VWAhqktbo0hJUJVwoTriqh9xRmbfIOYH2kEaL4DbEgDbM02zPfmt5TbAWNDl/2rsIeNeOuG92MMJxQ5008Z31ibiW2m7iW1zUXr2pKssqR82uGMuwJ0Le+pntsYFPyzicGIlW+6nrBwEJfVs1DwD5kB4KP2Cn4jaeY7M0DCeVXI+51nOqyv9LZsUhNREeX1mdDxMnv6t0328sc2NXs3eCPUhy/FKq9+AV3lRwcOZkwp8ESwRnsK8xRjC5gfJdZO3/n9OiYLmqgK77IseyTWj6mqvUoZ+ACfDYeJP56FQX0W6xPhSBuEDDS81GnHqAai9EL1e1DUjzgQwbs9/kyHNBDV3pBo8s9/cu4JNSWglgktTQ3z3LMfymyOJAVVnX0zoRM9ggogDU25kGHZr13rYfMfv7vFBe+Rqwusn+GBTxeUznnNPHlLqTAJptBPFY1weppZ7rJ1/jwMS1jKbHBwW1q280MaZLyXyzR6a4f1HyNHXHfxctVJ5ZXn4MZT+CpVwf5QXfHLkgeCyOwgocvbAxYXDSIVARrvsnE/qB0oPbX8q46+9qrAZBYYUG+X1YbBig08aISW7aIR2Ho3P9dXdbmBw47qClXIy8X85MwolGG718nyF4pS9PwA48hx0kuWsHmGpJWPFDYYk1ARB3o7AJ7FNHhK1jTYRr5zJeT/8OnYqxNB0cevwT1HHDF/ztmQVo23ZoPn6zhXZqyt+9+X+ruh/1acKzAE7SzuTl7EZBRCE4a2SIRB6p3xVoAUNa8uUowgSFSI1SZ41bZ69obZErBd2I++lZuvjIvrau0iBY8J9JxAFFTpccOVZwz 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)(52116014)(19092799006)(376014)(1800799024)(366016)(38350700014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: a+1Ot1M5qwJTHF7c+hak7SahZ77YbJgdIlB0RgqQCQJIul55qUvuTACF6MV0nIJqhH9D9lMgpNyTMf/6Hc2mgxF3+Ntc2ZEk06fJhdvamuQh2h080K6XsCyKq0TO4isjOHYqItzJ3/tMRFn7aASm3mLouozjQqr9WMXk0A+iSArrv6zheFL9zuKdNYZ7WDjWXmVZTr7kuc4sApv5/W8dF4//mZSXQeByVBRBKkKKg6nGHIQLGZwRF7yAtQbduDC0cKCRDEeCEaYlejFph4qS21ATFwC5/nYXS34ZEpBuhWlRh+09oyZoupcuKfTJUVgs11D90GzSxZM4W+KSb/bBy2cjEEwK9Yj6M0ysKMmH6tTnacDmio7isBgUnJsB8sI228+Ckw0axcjCFhGtDxEhjzeMVLz59Yhx5YnNZR15N8Em477V5tUVxeO+t4ECmclxa/sMNHQKPrW2LT1Xi66bY7TRea1A1LEB9g3vlycExouwskZGdZoFqDfxXXa+MoSwUjpfd4Ji3s1JGIACB2BqtxLMClMlKwtNz6Tu2D9wxIrBNRTZksrZDIsvZ8F9fpY4ttDLZq/4y7bgX1kGAU3MvSagjVTNhc6XggiGWxN8iNFgiunrftVn8lNq6fmc3tP4DwWoHYQTJA0EkW07LVkFycXPP91cfdxFaiiLhljtfcwr9lLLM5Ensd56zTDL93jdBa86NfuvmceLTyJxuf7N0ZBr7/y/bGkhf1S/jNexVSVX/p27mcq2vsAvmaiqTsryO9+z94i+jNJnrVM2n25RaZDj5kds4c+ZxNUzuEZzizmAX01S4GbKPmz7fuTzj9olMKLTz7wM6POBAyUN6Yd5VCLU/lO4QBVOsv3/yFSLhr20WssjLPRaERTVoMMLWIUEBjv40+eyjg9QphAmxfJaFQfK1l+hngs+XV+YXOHAYEQ/T/7XMQN4pAGrvd+XyoDOisSIcYNaj26la4WM1pGwV1OTjHUeNdXtKlgjArm8P8zT5OeaU97EncOmrS4+H0ovHO3JU6X5+qHU3DNrIn50rS5roFMy5q5ZWt31IyQY/TBeqPsLztYCMNa0t4wdTbe+kwSaiz8X+l576GIco525kT0+PnZtTxKlHVZjW2MajcsUp16JIecMVpCFn1+wGlqSkl/OFob9JKarleOjuBqTctM0UHNn/YJIu9n/KCFMJNJ5HYfsTMfhJjtgI1Hxfd687u8dLTEpSrhYctZZ5ZjVfGKpVa3hJoJ93RI9G2DmC3BqsWOTrsX/MB6cgpaiYbnDbUIq0fPw+fa6mkOKMqa2jW/ufb6nD7SUQlo4NUmA0iE/97+BIR1PXfwTl58MfwowUNttGtC/PJbQTZoyx6WZ6IqsWdHsifbmj/w29zUZYY8DWkRw2RHNPrDC5yDDqCkOg6oCUPPzbTmAGHDZSe30xknmHxytw+5+mwHJcaGMo6TQuExrIcKzYfopx4LhFJSLEc0lzrHBwypbR07tS3N8S2YwiU5quPy5UgMdeKN1agm1US4Qm7HIjX+K638mZ/NHOAm9d9khTCemYoxgmw22J2qkkxu3i+8GLUXwyNL3nO+P0fq3U/uRp8CxjOwJ6kles3h5ETJ+PEV0pbifDWaDxw== X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: e18d2fb9-574c-4edc-43f8-08de239454a9 X-MS-Exchange-CrossTenant-AuthSource: GVXPR04MB9831.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Nov 2025 15:41:51.7090 (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: Rg3qXaa1r/yn7D4mU4pY2CIhhHV2mo1HHcOl6fDMJLKb3RtImpy5sy3v6vuXhdnmY6yM4REB12GbzhXmAn3VMw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GV1PR04MB10108 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 */