From patchwork Thu Nov 27 15:45:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antoine Bouyer X-Patchwork-Id: 25264 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 0E714C3257 for ; Thu, 27 Nov 2025 15:43:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B81B460AA3; Thu, 27 Nov 2025 16:43:45 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=nxp.com header.i=@nxp.com header.b="hgKNr6TD"; 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 03355609DE for ; Thu, 27 Nov 2025 16:43:44 +0100 (CET) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=vGqJBLc64Adrsmous7IC9EWz3mZAhyh9cUsXNCCrC0dZ5OvHofNK44DB0lEaMfVoRjSzvwXQySNediuOqH5LNF8B+tY2raKUvuuMGeT3+yEXkdKkpsp6sb4sJXmywhKBvff5LNIuZVSMu8DYRDq7iRKZGUaKWk6NSh8vynL0M7zuRBW03R5xXH6TtY9pg2cut6fyMoMDenmDQzDRbDylYyjTClxXLDPrktWZFRpFHeGH7AdE2WFdG6Y/iFjv0uFSSbN+mRJhqfJtg4jhlm5A0AZtcUIMQ/q3PS/pQIl8GnJLCa+XuTzWtWBZH2/4va3l4aWRP6/D5u+pwPW+yMESGg== 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=qKhC5/1JewYOODVFTvuvey1lUC6npjBW4Rjf3olYO28=; b=qKJB5wPzq0KHRKkS++TUUie2Gc2Xvjf54swLySq6Eef7eFQ+mVeyTMzVNH0aTGddp6+ATIyTDunLlNc5m5X2Yn9lyvV6S0DKu6PkWcZKHWuIiymNYYSQcqJMjHxBpSBddQcjZ2ArRAnSgZH4+C/brOV9NqR2JcFcoTggCMq5Yej3XxUMKJ6TOzMfOKFwvpTu0c/lf8IJ9TEORFvqkVBxM/te0rzaYuzhC//2X8x+t4OAp/UFNniglPF/gWjMKaTNtMDkVvX7DdsOWa3EJe+hWhZgTb32078Bce6SSljkp3zajmVsTi7d3Xmi/MHWSg5JqKEkjsU3T/dxIgV0ECPtTQ== 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=qKhC5/1JewYOODVFTvuvey1lUC6npjBW4Rjf3olYO28=; b=hgKNr6TDtjWNt5QbpKqqoFvkKV7XyBjfTADYuVnEUVn8Cf8FPPBlxwxfGUjgjxBQX8ay4kg2cixZDehD7mzfObTSKcuUrLePNucCCI+m5ptHyYe5b0T+RmzwMX+gegg6wPy64Aaf89VhVm8k39V/WQyMt5f9G9gGhzZM28KUgxcb4Sh5b3mQVPbW4qqSuKE01ehjayfv3vmhJxLJRBAZAmPkzpezO4ItxGIhkNaxf4Rx6UaSU2R/A3YDM8qkdaCuNCcQOtwetWKv7DxjjmVIzZfs8FX6z0kflIbRd6wiPMQxY0wpD7WAciJ5rdiVEvZqEqj9hXy/mQJbfuhy8ek+7g== 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 PR3PR04MB7372.eurprd04.prod.outlook.com (2603:10a6:102:80::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9366.13; Thu, 27 Nov 2025 15:43:42 +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.9366.009; Thu, 27 Nov 2025 15:43:42 +0000 From: Antoine Bouyer To: libcamera-devel@lists.libcamera.org Cc: julien.vuillaumier@nxp.com, jacopo.mondi@ideasonboard.com, barnabas.pocze@ideasonboard.com, isaac.scott@ideasonboard.com, Andrei Gansari , Antoine Bouyer Subject: [PATCH v3 2/2] pipeline: imx8-isi: Integrating MediaPipeline class Date: Thu, 27 Nov 2025 16:45:18 +0100 Message-ID: <20251127154519.2038844-3-antoine.bouyer@nxp.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20251127154519.2038844-1-antoine.bouyer@nxp.com> References: <20251127154519.2038844-1-antoine.bouyer@nxp.com> X-ClientProxiedBy: SJ0PR05CA0173.namprd05.prod.outlook.com (2603:10b6:a03:339::28) To GVXPR04MB9831.eurprd04.prod.outlook.com (2603:10a6:150:11c::8) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: GVXPR04MB9831:EE_|PR3PR04MB7372:EE_ X-MS-Office365-Filtering-Correlation-Id: cb6e063b-6390-4b32-447f-08de2dcbbdec X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|1800799024|366016|19092799006|376014|52116014|38350700014; X-Microsoft-Antispam-Message-Info: kgKj4lPaXGZsaoHg/wPG2BnW8Zg/O+bNmQIfreoOFDS15BvGnL6e7uCETV0G/JXinEakYkOkm45G/5SXTvefUOq6tYtRoYsH/6sFFuCJuOWsTklNL7JDPD3PBLwZ3/J9EUQC7GyvjZbFLiSRd01dU8c4rBDr6p8x2aIkU++qRITMDBSwS9/YnjH7DYkn/uydo14oaspjMfkZ8SOUoWajNs/W4Mf6Lx6di4JGP7ODPlB76szDkeCQsR4u8lueIIHkNy7Vejt7C2bHw/zuNVhLQovEqqcBSwwPQOxgIWMdh/v7XEhM4j4Q52KeRLh6abm6qSlO/bol76hgiEoI2fUCLFIZXeNTn+CbNVAhapu8hHMZjsKEf6QELdj3cnlKKVPlWTMtzJscjlA9l1HKTdVYm13+y63DY6TArOfwhNJyJ7amk6WVQ2gRMVkxprR4n2dVETfQFYoIiZGLxqpcRZzXnM4/49iRlXjYnkrSwfCpYnyL4hrhhBqPVuanGsKHQDtO/SumEISOfPdcwOvFuRkkiZV1ms4MBVjVz8EhaFkLvmEjz0PSz4qwar0wntb1fWEgxiUjlV3iMSVnvkBMPAPHKN449BLEe71anib+5FN2aoBIraw59tjSv6p72KqFj7TmhTUaeU+1alTWDyEVkhP2R6TWVW9qkRFoM9JTMaDsE+5uqqbap1NCvqmudcficfhRiET8NLD0lz+ksu0hzKSBn8sv86THSmBvc3GrIDTZKaFso9ohoDXTa6+LXVKM3bAmyJwqEHh91Lx0AO9/iPrMNWDuMf199/nQ+whlCIm9YNC0qE6wDgCYjvVfXAH6JMDmYqNX9y9RfElMCkCubbBU2ybqCWm1AOx95B+hxiLc2SKUGLxCOiSYglSDlTkzCy7addPRjSoEquiOlc/ESOvDEbPhkZ26cvN0dY7GshajhMbRkkXgSNCrCD8I3B1w7JGdAmETbBqrxfPtKKtuH27lTHq1/NfYPT9aVpJqGSPGzJWN0LiplfexcZrjCzBN+qEiPZCY4mZSQtWutHJsvhtG+OiuYC8UMdnQE9PJjYzhwyrFy4iWUoIUDuqxfN5o9U4XpH7J6o7b1qzpkGH1Dpt2SE9qYrbbkURsqszduunrvMeiDX9ypznmpVUzTdg7/3MUYGIWiyzP+NrKEn5+DdRUm0Y50bZMFKoIdz5fyi6299mw8xl7fRuV7JOjgo+aXZt/71yzpiAAQU5yuBRHP8dmcqQ0RbLG8O5PvLixep6H4p/xpC3NWo7zh0A7pX1lV9IkkuntyWm6a8ZJXa7QLUH0I/Unib5GejSrtusPGee8W3aT/5MK/qlRb9eNTfmkqorAQiw+qEnqmvzAEql7fRPO7hj2De/yXFM20K2P5qAkyNTP9OS3IdEA3fGPszSFL2i6JxJRjJaGqVLp3ydvjztYbB2xUPcpVsjwrel89WL1rmFCGR9e/xjDJU6Xi4ny0FWplHjtdGWgvOBSbJLIIgC5dDyUJKBN6TJ1hI87nqgeBKBSYpOZtz46mqZHzIge6Boo 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)(1800799024)(366016)(19092799006)(376014)(52116014)(38350700014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: dkINNNF0l1QUkpCENoTgvoz9439qmbbOgn72BqJ0MFrmNklXOsmljQgiXAwK4k11GyVyzJcxioY7gyrWHn8pF1JFzYeZVsQ/fVcSac0yTo0PRijHdOgyoB+it4iL+Cjqfp1zhIfYtOxABBaRB7zM5ypeKGTo0PfdQtnA8TeAvw3FDuXgldHLxiIJz6dKAJtsmTOFJk/jzl7w3CKkMqdAvOTKqtgJMdN8yrc/hiKuuUNWYfKbdEsSuDnFEMqHtmaRYDXzBaF8uJCHY/JyETBjGFMHZfnNXnMhyQLZ6dAx5mkrU56x7XHu21uqHDczw5dTFs8R2TsPPAZZq34222mf0M+FGhEl0AZtrp+eEkh8+37K13s2p4gb31bQ1oFMln4vf4iHR023glraBwE2gPDq/0qRqXgyJuA2GZjShhHGxerixdgJXp9R5/9e6W1XQqMNORciwH1NIVO8TaVDI7Hm10k7kzb+e5D4y+1cDg4YP2eTsR6fFN4fJ2WoFXfGc9CZYR7iPlQ4GFnyT1QcOguGSBFK/Xy8Vvs5XSZtgshzpwuALo1sxThtUMbOf0DFtul8j8Aw0DUGG0sxla+6IyAiUaovwbC9Ri7anq7zC8ty0sIZbJnIkClh11300p+WVr+p/M1bEoQOnr/3lTbA5RyBf8TKEG5Dh6WQ2W/HyjHRNVoDUhSyqLPjOYu65vOVaJ3EWqa/pbAuRuH8edFCrrWjMb1yDx9nYdDvLZDBDQSI9wYK63yzSdoffoCGADwDlRsECNPhIBljEgA22Gh8ghQkeLgI46kPWdztgkK4Dk9w78MEcZ2U8krYOGI3k5cVESNzZRCStf09ePmf2BgljyFzJV7z7ipgbdWgcccjttkuabiGTLwzjIIKlc+R3jXvGALtJhIrJdkGGsGUlgdPswVbk+B2tagC5NnfJNCWZ1pjwcHU1Cc+bdis/aG7y53LF8W0ORNTs920u6R4aMmzDpSrFEE6m2HbQ/35MyN2W5iKNTjgX8jjqfFR5LjkAj3evyQ83TLIp19wEzlhOx3PDV5CeY8baIOM1EqoIx75hOr1KVIMciORyuPp00H9n4noxTotypXYRUnlOSWqQWYvTOJXKxGBfVFRXzcdY13REF9pEhPmUVP8CeoIyfdK7LzY8GUgBTGVEvGk6JKZyMv7EKOOnZBsdyZiRxt5GUO+U/P/PKdTP8o7r+Y7zAnOsT/ORDaDS09wewUYLm1q+7ZHSRtc9xsZk+Kc0frxl75nAy1vu2zvoTv5khWh5Rkvc/klO+KdqOI7DftfHL4TcMAPra2Pxfn9QrA7NpGFkskBe7VHgwFE/FA2EsntbO1O2TDhA/HuZ0lIXOquYxq/lKM9uUl85ItsJMSwQUM6C927lLljfOZy8viTTobV40k6TcjQLrgV5fc6BHnEH2PFA+4Lzz1gnQUb1ksDNJ4Ad983LC1281iXvAbe9bnmip77GHEgqij7Xo4Gll4h7X5QVOs91/pWRpxh2ntLdAVN6fZCVYyNDioTHH6yHvVxUv1Xt+knUhalfeP0+DGnJUQLyPMfTCpVmrALWb2it6SM0yii3Z+2rWR2gapj7TxGXW+ZpMH0hON0Ik55FmmRuyam+8VkMxhz2Q== X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: cb6e063b-6390-4b32-447f-08de2dcbbdec X-MS-Exchange-CrossTenant-AuthSource: GVXPR04MB9831.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 27 Nov 2025 15:43:42.4115 (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: WnwsJOhPduehpFrONDFkAA8qx4IY1yDhAk2fQAZn0DRKYv3fA7z4Wtn+R7s0nJYFGMyuDaSzrd6M+GtVnnLkBg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PR3PR04MB7372 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 Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- 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 049d9b1c44cb..008155ff21a7 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); + std::shared_ptr 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_.get()); + unsigned int 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 */