[{"id":36819,"web_url":"https://patchwork.libcamera.org/comment/36819/","msgid":"<fygaztb4csl7egddqdy5lskidmppb2gy2ph2x62contsnrngr5@qndemkelpz2n>","date":"2025-11-14T15:41:54","subject":"Re: [PATCH v1 2/2] pipeline: imx8-isi: Integrating MediaPipeline\n\tclass","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hello\n\nOn Thu, Nov 13, 2025 at 11:04:14AM +0100, Antoine Bouyer wrote:\n> From: Andrei Gansari <andrei.gansari@nxp.com>\n>\n> This change integrates the MediaPipeline class into the imx8-isi\n> pipeline handler. Purpose is to allow a dynamic discovery and\n> configuration of the actual subdevices graph between the sensor and\n> the ISI crossbar. This brings support for more complex topologies and\n> simplifies the implementation.\n>\n> Signed-off-by: Andrei Gansari <andrei.gansari@nxp.com>\n> Signed-off-by: Antoine Bouyer <antoine.bouyer@nxp.com>\n> ---\n>  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 159 ++++++++++++-------\n>  1 file changed, 98 insertions(+), 61 deletions(-)\n>\n> diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> index 9550f54600c4..aefc0ee60a11 100644\n> --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> @@ -25,6 +25,7 @@\n>  #include \"libcamera/internal/camera_sensor.h\"\n>  #include \"libcamera/internal/device_enumerator.h\"\n>  #include \"libcamera/internal/media_device.h\"\n> +#include \"libcamera/internal/media_pipeline.h\"\n>  #include \"libcamera/internal/pipeline_handler.h\"\n>  #include \"libcamera/internal/v4l2_subdevice.h\"\n>  #include \"libcamera/internal/v4l2_videodevice.h\"\n> @@ -62,14 +63,15 @@ public:\n>  \tunsigned int getYuvMediaBusFormat(const PixelFormat &pixelFormat) const;\n>  \tunsigned int getMediaBusFormat(PixelFormat *pixelFormat) const;\n>\n> +\t/* All entities, from the sensor to the ISI. */\n> +\tMediaPipeline mediaPipeline_;\n> +\n>  \tstd::unique_ptr<CameraSensor> sensor_;\n> -\tstd::unique_ptr<V4L2Subdevice> csis_;\n>\n>  \tstd::vector<Stream> streams_;\n>\n>  \tstd::vector<Stream *> enabledStreams_;\n>\n> -\tunsigned int xbarSink_ = 0;\n>  \tunsigned int xbarSourceOffset_ = 0;\n>  };\n>\n> @@ -141,6 +143,8 @@ private:\n>\n>  \tvoid bufferReady(FrameBuffer *buffer);\n>\n> +\tstd::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> +\n>  \tMediaDevice *isiDev_;\n>\n>  \tstd::unique_ptr<V4L2Subdevice> crossbar_;\n> @@ -164,10 +168,6 @@ int ISICameraData::init()\n>  \tif (!sensor_)\n>  \t\treturn -ENODEV;\n>\n> -\tint ret = csis_->open();\n> -\tif (ret)\n> -\t\treturn ret;\n> -\n>  \tproperties_ = sensor_->properties();\n>\n>  \treturn 0;\n> @@ -811,18 +811,29 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c)\n>  {\n>  \tISICameraConfiguration *camConfig = static_cast<ISICameraConfiguration *>(c);\n>  \tISICameraData *data = cameraData(camera);\n> +\tCameraSensor *sensor = data->sensor_.get();\n> +\tint ret;\n>\n> -\t/* Apply format to the sensor, CSIS receiver and crossbar sink pad. */\n> -\tV4L2SubdeviceFormat format = camConfig->sensorFormat_;\n> -\tint ret = data->sensor_->setFormat(&format);\n> -\tif (ret)\n> +\t/*\n> +\t * Enable the links all the way up to the ISI, through any connected CSI\n> +\t * receiver and optional formatter.\n> +\t */\n> +\tret = data->mediaPipeline_.initLinks();\n> +\tif (ret) {\n> +\t\tLOG(ISI, Error) << \"Failed to set up pipe links\";\n>  \t\treturn ret;\n> +\t}\n>\n> -\tret = data->csis_->setFormat(0, &format);\n> +\t/*\n> +\t * Configure the format on the sensor output and propagate it through\n> +\t * the pipeline.\n> +\t */\n> +\tV4L2SubdeviceFormat format = camConfig->sensorFormat_;\n> +\tret = sensor->setFormat(&format);\n>  \tif (ret)\n>  \t\treturn ret;\n>\n> -\tret = crossbar_->setFormat(data->xbarSink_, &format);\n> +\tret = data->mediaPipeline_.configure(sensor, &format);\n>  \tif (ret)\n>  \t\treturn ret;\n>\n> @@ -979,13 +990,8 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n>  \t\treturn false;\n>\n>  \t/* Count the number of sensors, to create one camera per sensor. */\n> -\tunsigned cameraCount = 0;\n> -\tfor (MediaEntity *entity : isiDev_->entities()) {\n> -\t\tif (entity->function() != MEDIA_ENT_F_CAM_SENSOR)\n> -\t\t\tcontinue;\n> -\n> -\t\tcameraCount++;\n> -\t}\n> +\tstd::vector<MediaEntity *> sensorEntities = locateSensors(isiDev_);\n> +\tunsigned cameraCount = sensorEntities.size();\n\nunsigned int\n\nbut maybe it's just me not being used to 'unsigned'\n\n>\n>  \tif (!cameraCount) {\n>  \t\tLOG(ISI, Error) << \"No camera sensor found\";\n> @@ -1048,60 +1054,28 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n>  \t * sensors to get at least one dedicated pipe.\n>  \t */\n>  \tunsigned int numCameras = 0;\n> -\tunsigned int numSinks = 0;\n>  \tconst unsigned int xbarFirstSource = crossbar_->entity()->pads().size() - pipes_.size();\n>  \tconst unsigned int maxStreams = pipes_.size() / cameraCount;\n>\n> -\tfor (MediaPad *pad : crossbar_->entity()->pads()) {\n> -\t\tunsigned int sink = numSinks;\n> -\n> -\t\tif (!(pad->flags() & MEDIA_PAD_FL_SINK))\n> -\t\t\tcontinue;\n> -\n> -\t\t/*\n> -\t\t * Count each crossbar sink pad to correctly configure\n> -\t\t * routing and format for this camera.\n> -\t\t */\n> -\t\tnumSinks++;\n> -\n> -\t\tif (pad->links().empty())\n> -\t\t\tcontinue;\n> -\n> -\t\tMediaEntity *csi = pad->links()[0]->source()->entity();\n> -\t\tif (csi->pads().size() != 2) {\n> -\t\t\tLOG(ISI, Debug) << \"Skip unsupported CSI-2 receiver \"\n> -\t\t\t\t\t<< csi->name();\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\tpad = csi->pads()[0];\n> -\t\tif (!(pad->flags() & MEDIA_PAD_FL_SINK) || pad->links().empty())\n> -\t\t\tcontinue;\n> -\n> -\t\tMediaEntity *sensor = pad->links()[0]->source()->entity();\n> -\t\tif (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) {\n> -\t\t\tLOG(ISI, Debug) << \"Skip unsupported subdevice \"\n> -\t\t\t\t\t<< sensor->name();\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\t/* All links are immutable except the sensor -> csis link. */\n> -\t\tconst MediaPad *sensorSrc = sensor->getPadByIndex(0);\n> -\t\tsensorSrc->links()[0]->setEnabled(true);\n> -\n> +\tfor (MediaEntity *sensor : sensorEntities) {\n>  \t\t/* Create the camera data. */\n>  \t\tstd::unique_ptr<ISICameraData> data =\n>  \t\t\tstd::make_unique<ISICameraData>(this, maxStreams);\n>\n> +\t\tret = data->mediaPipeline_.init(sensor, \"crossbar\");\n> +\t\tif (ret)\n> +\t\t\tcontinue;\n> +\n> +\t\tconst MediaPipeline::Entity *xbarEntity = &data->mediaPipeline_.entities().back();\n> +\t\tunsigned int xbarSinkIndex = xbarEntity->sink->index();\n> +\n>  \t\tdata->sensor_ = CameraSensorFactoryBase::create(sensor);\n> -\t\tdata->csis_ = std::make_unique<V4L2Subdevice>(csi);\n> -\t\tdata->xbarSink_ = sink;\n>  \t\tdata->xbarSourceOffset_ = numCameras * data->streams_.size();\n>\n>  \t\tLOG(ISI, Debug)\n>  \t\t\t<< \"cam\" << numCameras\n>  \t\t\t<< \" streams \" << data->streams_.size()\n> -\t\t\t<< \" sink \" << data->xbarSink_\n> +\t\t\t<< \" sink \" << xbarSinkIndex\n>  \t\t\t<< \" offset \" << data->xbarSourceOffset_;\n>\n>  \t\tret = data->init();\n> @@ -1120,7 +1094,7 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n>  \t\t/*  Add routes to the crossbar switch routing table. */\n>  \t\tfor (unsigned i = 0; i < data->streams_.size(); i++) {\n>  \t\t\tunsigned int sourcePad = xbarFirstSource + data->xbarSourceOffset_ + i;\n> -\t\t\trouting_.emplace_back(V4L2Subdevice::Stream{ data->xbarSink_, 0 },\n> +\t\t\trouting_.emplace_back(V4L2Subdevice::Stream{ xbarSinkIndex, 0 },\n>  \t\t\t\t\t     V4L2Subdevice::Stream{ sourcePad, 0 },\n>  \t\t\t\t\t     V4L2_SUBDEV_ROUTE_FL_ACTIVE);\n>  \t\t}\n> @@ -1163,6 +1137,69 @@ void PipelineHandlerISI::bufferReady(FrameBuffer *buffer)\n>  \tcompleteRequest(request);\n>  }\n>\n> +/* Original function taken from simple.cpp */\n> +std::vector<MediaEntity *>\n> +PipelineHandlerISI::locateSensors(MediaDevice *media)\n> +{\n> +\tstd::vector<MediaEntity *> entities;\n> +\n> +\t/*\n> +\t * Gather all the camera sensor entities based on the function they\n> +\t * expose.\n> +\t */\n> +\tfor (MediaEntity *entity : media->entities()) {\n> +\t\tif (entity->function() == MEDIA_ENT_F_CAM_SENSOR)\n> +\t\t\tentities.push_back(entity);\n> +\t}\n> +\n> +\tif (entities.empty())\n> +\t\treturn {};\n> +\n> +\t/*\n> +\t * Sensors can be made of multiple entities. For instance, a raw sensor\n> +\t * can be connected to an ISP, and the combination of both should be\n> +\t * treated as one sensor. To support this, as a crude heuristic, check\n> +\t * the downstream entity from the camera sensor, and if it is an ISP,\n> +\t * use it instead of the sensor.\n> +\t */\n> +\tstd::vector<MediaEntity *> sensors;\n> +\n> +\tfor (MediaEntity *entity : entities) {\n> +\t\t/*\n> +\t\t * Locate the downstream entity by following the first link\n> +\t\t * from a source pad.\n> +\t\t */\n> +\t\tconst MediaLink *link = nullptr;\n> +\n> +\t\tfor (const MediaPad *pad : entity->pads()) {\n> +\t\t\tif ((pad->flags() & MEDIA_PAD_FL_SOURCE) &&\n> +\t\t\t    !pad->links().empty()) {\n> +\t\t\t\tlink = pad->links()[0];\n> +\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t}\n> +\n> +\t\tif (!link)\n> +\t\t\tcontinue;\n> +\n> +\t\tMediaEntity *remote = link->sink()->entity();\n> +\t\tif (remote->function() == MEDIA_ENT_F_PROC_VIDEO_ISP)\n> +\t\t\tsensors.push_back(remote);\n> +\t\telse\n> +\t\t\tsensors.push_back(entity);\n> +\t}\n> +\n> +\t/*\n> +\t * Remove duplicates, in case multiple sensors are connected to the\n> +\t * same ISP.\n> +\t */\n> +\tstd::sort(sensors.begin(), sensors.end());\n> +\tauto last = std::unique(sensors.begin(), sensors.end());\n> +\tsensors.erase(last, sensors.end());\n> +\n> +\treturn sensors;\n> +}\n\nNothing to report here, apart that this code is copied from simple,\nand maybe it could be generalized. Not a requirement for this patch\nthough!\n\nReviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n\nThanks\n   j\n\n> +\n>  REGISTER_PIPELINE_HANDLER(PipelineHandlerISI, \"imx8-isi\")\n>\n>  } /* namespace libcamera */\n> --\n> 2.34.1\n>","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 8D390C32DB\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 14 Nov 2025 15:42:00 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 312E1609DE;\n\tFri, 14 Nov 2025 16:42:00 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id CFE94609DE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 14 Nov 2025 16:41:58 +0100 (CET)","from ideasonboard.com (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1787CC77;\n\tFri, 14 Nov 2025 16:39:57 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"rUozrqIc\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763134797;\n\tbh=HlXURiD6updjGN/T3ksn2kfZi5ZJhhtCPHXQUSU7dI8=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=rUozrqIcUtG7AfzscziMlozRwvOuhXHs9i16iocWmAILYK8VOxVBn/fyypoyaOrY3\n\tuByj6IdcYtJHfoCBubIghH9JxsL6PLAAiIKTwqWbzBZ39FnGsStDSnLRCY++EeDUO7\n\thUjttxVaQahkbebSCDCFFHGiX+CS6/uJTTun/vOQ=","Date":"Fri, 14 Nov 2025 16:41:54 +0100","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Antoine Bouyer <antoine.bouyer@nxp.com>","Cc":"libcamera-devel@lists.libcamera.org, julien.vuillaumier@nxp.com, \n\tAndrei Gansari <andrei.gansari@nxp.com>","Subject":"Re: [PATCH v1 2/2] pipeline: imx8-isi: Integrating MediaPipeline\n\tclass","Message-ID":"<fygaztb4csl7egddqdy5lskidmppb2gy2ph2x62contsnrngr5@qndemkelpz2n>","References":"<20251113100414.535550-1-antoine.bouyer@nxp.com>\n\t<20251113100414.535550-3-antoine.bouyer@nxp.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20251113100414.535550-3-antoine.bouyer@nxp.com>","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>"}},{"id":36820,"web_url":"https://patchwork.libcamera.org/comment/36820/","msgid":"<a0012d28-4429-4ece-ac02-4565adb94034@nxp.com>","date":"2025-11-14T15:52:38","subject":"Re: [EXT] Re: [PATCH v1 2/2] pipeline: imx8-isi: Integrating\n\tMediaPipeline class","submitter":{"id":218,"url":"https://patchwork.libcamera.org/api/people/218/","name":"Antoine Bouyer","email":"antoine.bouyer@nxp.com"},"content":"Hi Jacopo\n\nSorry I missed your 2/2 review while V2 was sent. Only applied comments \nfrom your 1/2 review.\n\nOn 11/14/25 4:41 PM, Jacopo Mondi wrote:\n> Caution: This is an external email. Please take care when clicking links or opening attachments. When in doubt, report the message using the 'Report this email' button\n> \n> \n> Hello\n> \n> On Thu, Nov 13, 2025 at 11:04:14AM +0100, Antoine Bouyer wrote:\n>> From: Andrei Gansari <andrei.gansari@nxp.com>\n>>\n>> This change integrates the MediaPipeline class into the imx8-isi\n>> pipeline handler. Purpose is to allow a dynamic discovery and\n>> configuration of the actual subdevices graph between the sensor and\n>> the ISI crossbar. This brings support for more complex topologies and\n>> simplifies the implementation.\n>>\n>> Signed-off-by: Andrei Gansari <andrei.gansari@nxp.com>\n>> Signed-off-by: Antoine Bouyer <antoine.bouyer@nxp.com>\n>> ---\n>>   src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 159 ++++++++++++-------\n>>   1 file changed, 98 insertions(+), 61 deletions(-)\n>>\n>> diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n>> index 9550f54600c4..aefc0ee60a11 100644\n>> --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n>> +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n>> @@ -25,6 +25,7 @@\n>>   #include \"libcamera/internal/camera_sensor.h\"\n>>   #include \"libcamera/internal/device_enumerator.h\"\n>>   #include \"libcamera/internal/media_device.h\"\n>> +#include \"libcamera/internal/media_pipeline.h\"\n>>   #include \"libcamera/internal/pipeline_handler.h\"\n>>   #include \"libcamera/internal/v4l2_subdevice.h\"\n>>   #include \"libcamera/internal/v4l2_videodevice.h\"\n>> @@ -62,14 +63,15 @@ public:\n>>        unsigned int getYuvMediaBusFormat(const PixelFormat &pixelFormat) const;\n>>        unsigned int getMediaBusFormat(PixelFormat *pixelFormat) const;\n>>\n>> +     /* All entities, from the sensor to the ISI. */\n>> +     MediaPipeline mediaPipeline_;\n>> +\n>>        std::unique_ptr<CameraSensor> sensor_;\n>> -     std::unique_ptr<V4L2Subdevice> csis_;\n>>\n>>        std::vector<Stream> streams_;\n>>\n>>        std::vector<Stream *> enabledStreams_;\n>>\n>> -     unsigned int xbarSink_ = 0;\n>>        unsigned int xbarSourceOffset_ = 0;\n>>   };\n>>\n>> @@ -141,6 +143,8 @@ private:\n>>\n>>        void bufferReady(FrameBuffer *buffer);\n>>\n>> +     std::vector<MediaEntity *> locateSensors(MediaDevice *media);\n>> +\n>>        MediaDevice *isiDev_;\n>>\n>>        std::unique_ptr<V4L2Subdevice> crossbar_;\n>> @@ -164,10 +168,6 @@ int ISICameraData::init()\n>>        if (!sensor_)\n>>                return -ENODEV;\n>>\n>> -     int ret = csis_->open();\n>> -     if (ret)\n>> -             return ret;\n>> -\n>>        properties_ = sensor_->properties();\n>>\n>>        return 0;\n>> @@ -811,18 +811,29 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c)\n>>   {\n>>        ISICameraConfiguration *camConfig = static_cast<ISICameraConfiguration *>(c);\n>>        ISICameraData *data = cameraData(camera);\n>> +     CameraSensor *sensor = data->sensor_.get();\n>> +     int ret;\n>>\n>> -     /* Apply format to the sensor, CSIS receiver and crossbar sink pad. */\n>> -     V4L2SubdeviceFormat format = camConfig->sensorFormat_;\n>> -     int ret = data->sensor_->setFormat(&format);\n>> -     if (ret)\n>> +     /*\n>> +      * Enable the links all the way up to the ISI, through any connected CSI\n>> +      * receiver and optional formatter.\n>> +      */\n>> +     ret = data->mediaPipeline_.initLinks();\n>> +     if (ret) {\n>> +             LOG(ISI, Error) << \"Failed to set up pipe links\";\n>>                return ret;\n>> +     }\n>>\n>> -     ret = data->csis_->setFormat(0, &format);\n>> +     /*\n>> +      * Configure the format on the sensor output and propagate it through\n>> +      * the pipeline.\n>> +      */\n>> +     V4L2SubdeviceFormat format = camConfig->sensorFormat_;\n>> +     ret = sensor->setFormat(&format);\n>>        if (ret)\n>>                return ret;\n>>\n>> -     ret = crossbar_->setFormat(data->xbarSink_, &format);\n>> +     ret = data->mediaPipeline_.configure(sensor, &format);\n>>        if (ret)\n>>                return ret;\n>>\n>> @@ -979,13 +990,8 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n>>                return false;\n>>\n>>        /* Count the number of sensors, to create one camera per sensor. */\n>> -     unsigned cameraCount = 0;\n>> -     for (MediaEntity *entity : isiDev_->entities()) {\n>> -             if (entity->function() != MEDIA_ENT_F_CAM_SENSOR)\n>> -                     continue;\n>> -\n>> -             cameraCount++;\n>> -     }\n>> +     std::vector<MediaEntity *> sensorEntities = locateSensors(isiDev_);\n>> +     unsigned cameraCount = sensorEntities.size();\n> \n> unsigned int\n> \n> but maybe it's just me not being used to 'unsigned'\n\nSure, let me apply it in V3 to avoid confusion. Will wait for more \nfeedback before sending it thought.\n\n> \n>>\n>>        if (!cameraCount) {\n>>                LOG(ISI, Error) << \"No camera sensor found\";\n>> @@ -1048,60 +1054,28 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n>>         * sensors to get at least one dedicated pipe.\n>>         */\n>>        unsigned int numCameras = 0;\n>> -     unsigned int numSinks = 0;\n>>        const unsigned int xbarFirstSource = crossbar_->entity()->pads().size() - pipes_.size();\n>>        const unsigned int maxStreams = pipes_.size() / cameraCount;\n>>\n>> -     for (MediaPad *pad : crossbar_->entity()->pads()) {\n>> -             unsigned int sink = numSinks;\n>> -\n>> -             if (!(pad->flags() & MEDIA_PAD_FL_SINK))\n>> -                     continue;\n>> -\n>> -             /*\n>> -              * Count each crossbar sink pad to correctly configure\n>> -              * routing and format for this camera.\n>> -              */\n>> -             numSinks++;\n>> -\n>> -             if (pad->links().empty())\n>> -                     continue;\n>> -\n>> -             MediaEntity *csi = pad->links()[0]->source()->entity();\n>> -             if (csi->pads().size() != 2) {\n>> -                     LOG(ISI, Debug) << \"Skip unsupported CSI-2 receiver \"\n>> -                                     << csi->name();\n>> -                     continue;\n>> -             }\n>> -\n>> -             pad = csi->pads()[0];\n>> -             if (!(pad->flags() & MEDIA_PAD_FL_SINK) || pad->links().empty())\n>> -                     continue;\n>> -\n>> -             MediaEntity *sensor = pad->links()[0]->source()->entity();\n>> -             if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) {\n>> -                     LOG(ISI, Debug) << \"Skip unsupported subdevice \"\n>> -                                     << sensor->name();\n>> -                     continue;\n>> -             }\n>> -\n>> -             /* All links are immutable except the sensor -> csis link. */\n>> -             const MediaPad *sensorSrc = sensor->getPadByIndex(0);\n>> -             sensorSrc->links()[0]->setEnabled(true);\n>> -\n>> +     for (MediaEntity *sensor : sensorEntities) {\n>>                /* Create the camera data. */\n>>                std::unique_ptr<ISICameraData> data =\n>>                        std::make_unique<ISICameraData>(this, maxStreams);\n>>\n>> +             ret = data->mediaPipeline_.init(sensor, \"crossbar\");\n>> +             if (ret)\n>> +                     continue;\n>> +\n>> +             const MediaPipeline::Entity *xbarEntity = &data->mediaPipeline_.entities().back();\n>> +             unsigned int xbarSinkIndex = xbarEntity->sink->index();\n>> +\n>>                data->sensor_ = CameraSensorFactoryBase::create(sensor);\n>> -             data->csis_ = std::make_unique<V4L2Subdevice>(csi);\n>> -             data->xbarSink_ = sink;\n>>                data->xbarSourceOffset_ = numCameras * data->streams_.size();\n>>\n>>                LOG(ISI, Debug)\n>>                        << \"cam\" << numCameras\n>>                        << \" streams \" << data->streams_.size()\n>> -                     << \" sink \" << data->xbarSink_\n>> +                     << \" sink \" << xbarSinkIndex\n>>                        << \" offset \" << data->xbarSourceOffset_;\n>>\n>>                ret = data->init();\n>> @@ -1120,7 +1094,7 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n>>                /*  Add routes to the crossbar switch routing table. */\n>>                for (unsigned i = 0; i < data->streams_.size(); i++) {\n>>                        unsigned int sourcePad = xbarFirstSource + data->xbarSourceOffset_ + i;\n>> -                     routing_.emplace_back(V4L2Subdevice::Stream{ data->xbarSink_, 0 },\n>> +                     routing_.emplace_back(V4L2Subdevice::Stream{ xbarSinkIndex, 0 },\n>>                                             V4L2Subdevice::Stream{ sourcePad, 0 },\n>>                                             V4L2_SUBDEV_ROUTE_FL_ACTIVE);\n>>                }\n>> @@ -1163,6 +1137,69 @@ void PipelineHandlerISI::bufferReady(FrameBuffer *buffer)\n>>        completeRequest(request);\n>>   }\n>>\n>> +/* Original function taken from simple.cpp */\n>> +std::vector<MediaEntity *>\n>> +PipelineHandlerISI::locateSensors(MediaDevice *media)\n>> +{\n>> +     std::vector<MediaEntity *> entities;\n>> +\n>> +     /*\n>> +      * Gather all the camera sensor entities based on the function they\n>> +      * expose.\n>> +      */\n>> +     for (MediaEntity *entity : media->entities()) {\n>> +             if (entity->function() == MEDIA_ENT_F_CAM_SENSOR)\n>> +                     entities.push_back(entity);\n>> +     }\n>> +\n>> +     if (entities.empty())\n>> +             return {};\n>> +\n>> +     /*\n>> +      * Sensors can be made of multiple entities. For instance, a raw sensor\n>> +      * can be connected to an ISP, and the combination of both should be\n>> +      * treated as one sensor. To support this, as a crude heuristic, check\n>> +      * the downstream entity from the camera sensor, and if it is an ISP,\n>> +      * use it instead of the sensor.\n>> +      */\n>> +     std::vector<MediaEntity *> sensors;\n>> +\n>> +     for (MediaEntity *entity : entities) {\n>> +             /*\n>> +              * Locate the downstream entity by following the first link\n>> +              * from a source pad.\n>> +              */\n>> +             const MediaLink *link = nullptr;\n>> +\n>> +             for (const MediaPad *pad : entity->pads()) {\n>> +                     if ((pad->flags() & MEDIA_PAD_FL_SOURCE) &&\n>> +                         !pad->links().empty()) {\n>> +                             link = pad->links()[0];\n>> +                             break;\n>> +                     }\n>> +             }\n>> +\n>> +             if (!link)\n>> +                     continue;\n>> +\n>> +             MediaEntity *remote = link->sink()->entity();\n>> +             if (remote->function() == MEDIA_ENT_F_PROC_VIDEO_ISP)\n>> +                     sensors.push_back(remote);\n>> +             else\n>> +                     sensors.push_back(entity);\n>> +     }\n>> +\n>> +     /*\n>> +      * Remove duplicates, in case multiple sensors are connected to the\n>> +      * same ISP.\n>> +      */\n>> +     std::sort(sensors.begin(), sensors.end());\n>> +     auto last = std::unique(sensors.begin(), sensors.end());\n>> +     sensors.erase(last, sensors.end());\n>> +\n>> +     return sensors;\n>> +}\n> \n> Nothing to report here, apart that this code is copied from simple,\n> and maybe it could be generalized. Not a requirement for this patch\n> though!\n> \n> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> \n> Thanks\n>     j\n> \n\nThanks\nAntoine\n\n>> +\n>>   REGISTER_PIPELINE_HANDLER(PipelineHandlerISI, \"imx8-isi\")\n>>\n>>   } /* namespace libcamera */\n>> --\n>> 2.34.1\n>>","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 3D449C3263\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 14 Nov 2025 15:52:45 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6FD5460A81;\n\tFri, 14 Nov 2025 16:52:44 +0100 (CET)","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 0F627606E6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 14 Nov 2025 16:52:43 +0100 (CET)","from GVXPR04MB9831.eurprd04.prod.outlook.com (2603:10a6:150:11c::8)\n\tby AM8PR04MB7844.eurprd04.prod.outlook.com (2603:10a6:20b:236::14)\n\twith Microsoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9320.17;\n\tFri, 14 Nov 2025 15:52:39 +0000","from GVXPR04MB9831.eurprd04.prod.outlook.com\n\t([fe80::4634:3d9c:c4a:641a]) by\n\tGVXPR04MB9831.eurprd04.prod.outlook.com\n\t([fe80::4634:3d9c:c4a:641a%6]) with mapi id 15.20.9320.018;\n\tFri, 14 Nov 2025 15:52:39 +0000"],"Authentication-Results":["lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxp.com header.i=@nxp.com header.b=\"W+xJrdw0\";\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=D32rmM6Dz57YiSf63cUe0utvmNY8udCMRTk1TqgKfVIDa6j26ab1GexhyiQNp1UnPsV/mkPdkLGHW04IWOh3f+f/TOVyjBX4jyouZEfewv6gZrIsQLFJTtAs8YyC1/2R+tSszUgwWPlL9uTKe0QXuzJVwCNckBklgnbmhRDq+WWOMFV8idWP1Nt+x6mf2Pmer8qo+gFrFKk+U302Fao0rxOhZI4j+/0gegUz5XKQnhfoodlHr4HrUiJXKQWqNfhTuaQ9crx71Dpl+QN4wc/4oKRjOWZa/8W9+cXIdSHloDSTuTdl32QKxjFhwHnBq0tJO+IHnGe8z54ZZNH6ShQmyw==","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=AnzbUB5rIA2KG4FpmwLBSVG1XLLEwqAuAD4KU3swu00=;\n\tb=HRjmXUWZA2iWL+XEADlC9SKfbipvRFft58yePUBv5re+utgzZUvZ0CQTgj+D5/T9dasbwaprbfGXp5LIQtdYxdNk/QWuNFKhOVGDt6SBVeKgfklULR2PAwEFFoo2eWLss/ShR6INnINWh5owcRLYtaqE3Z+Orw4il/ezx55xDbAYLuLQGpETfHkBcJdwhJC/JO/rScGiXmHVTsQz3o9JpG4qVkY8u9VdtZGyMwEnQWUras/VphCqEvJ1jY/Ww2S9/rGsbatCdw/S+WOnfS9KXS8wbgQYSovnl1bHw5CpQ4XT0Ye4l84z0ruSHNyBSzNu4o/8xTKwbcbBDvOD6YXW3A==","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=AnzbUB5rIA2KG4FpmwLBSVG1XLLEwqAuAD4KU3swu00=;\n\tb=W+xJrdw02wUZ2jVDzRlCSkWy5/Na6I65ge3LR7Y6lZhgGzU31N5bzNHqVLrzwvR8RqSW+IujaewXOW32HolVnAQf4KqhCPDcGVw2/ZYXnmicOCYndM+G4lxSKJsObGRWI38TPWTPw4cugaabe/2yzEJuMkLg04d1uIF3B5ygStffzVdOFOL8wp9P9IDMS1NaWorhMt3CNBwG7nAysonA+Xr5maC0m38wNbZmD9h71FrX5hfF2+ALJjegUJXzx5zbTyz05vj2HF0rgEp0q5OP1jOIEZrvMSIe39LM0wKNzMmsKDnKu8OiW4mjXkwfS5x6+oCT+As8UTRc2qvASghHEw==","Message-ID":"<a0012d28-4429-4ece-ac02-4565adb94034@nxp.com>","Date":"Fri, 14 Nov 2025 16:52:38 +0100","User-Agent":"Mozilla Thunderbird","Subject":"Re: [EXT] Re: [PATCH v1 2/2] pipeline: imx8-isi: Integrating\n\tMediaPipeline class","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, julien.vuillaumier@nxp.com,\n\tAndrei Gansari <andrei.gansari@nxp.com>","References":"<20251113100414.535550-1-antoine.bouyer@nxp.com>\n\t<20251113100414.535550-3-antoine.bouyer@nxp.com>\n\t<fygaztb4csl7egddqdy5lskidmppb2gy2ph2x62contsnrngr5@qndemkelpz2n>","Content-Language":"en-US","From":"Antoine Bouyer <antoine.bouyer@nxp.com>","In-Reply-To":"<fygaztb4csl7egddqdy5lskidmppb2gy2ph2x62contsnrngr5@qndemkelpz2n>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","X-ClientProxiedBy":"AM0PR04CA0052.eurprd04.prod.outlook.com\n\t(2603:10a6:208:1::29) To GVXPR04MB9831.eurprd04.prod.outlook.com\n\t(2603:10a6:150:11c::8)","MIME-Version":"1.0","X-MS-PublicTrafficType":"Email","X-MS-TrafficTypeDiagnostic":"GVXPR04MB9831:EE_|AM8PR04MB7844:EE_","X-MS-Office365-Filtering-Correlation-Id":"eb3e3f7f-658b-429d-05ac-08de2395d6ac","X-MS-Exchange-SenderADCheck":"1","X-MS-Exchange-AntiSpam-Relay":"0","X-Microsoft-Antispam":"BCL:0;\n\tARA:13230040|376014|1800799024|19092799006|366016; ","X-Microsoft-Antispam-Message-Info":"=?utf-8?q?d+BHsZ/lLUHXBI7plRt49umt4yPC?=\n\t=?utf-8?q?GxEhKp104HYneRGwwKiC6rrysIEUYiOevLzGKMTjrrJA1CaFEQZlZ0ff?=\n\t=?utf-8?q?bx023FxFUc7MTfvai7+EGH/GgL+4QENEneVVbCzJv0YyCwUoaq3WtHMp?=\n\t=?utf-8?q?rCUjjjxmKAedguFTSjQsxiXpfbkA3hgmckkI/5U4CRbzf31OkZKb0ogW?=\n\t=?utf-8?q?tO1OL3W+znYpOii6Mcpp4AKXNX+mtrgvZ97QAxBzsN+wrchpOOLsZxGB?=\n\t=?utf-8?q?HLUHNpx+amJwX3bq5CMPQO48KhMPMQ6uy0hveM5qGtcqZhAzRgjwmMEA?=\n\t=?utf-8?q?inN2xjfsF0Nq0zkVhoQ/6QW29Ji8qZHSUVrck4rFbqn4K0YtagLCx2fK?=\n\t=?utf-8?q?B2uRK8C5n+11ACyn/GYmHNN+VFIGmAipS9F9sHGvGMdQjXll6M3Jb/6E?=\n\t=?utf-8?q?pdP5Ey/hjMGGS+vLfmMircUrM1Dxnjb3klBdVOQCrFO8bX4v5/OiYl4c?=\n\t=?utf-8?q?9VgZJBFpeiI5HOXoXNKeUwi4xHqqD/DmU0Y9BUFDCngxcjdDnbBDi2vx?=\n\t=?utf-8?q?r/Pc0UVoEFEu2XYTMaIQVY3vnzRhVXKFKByIrZoNO5H510bM/MiF6QvS?=\n\t=?utf-8?q?1S2ltNZilPX1mbVxKWPuSkoCgjKqQu3xfrH8bEZnxyn1+bc2zP36sZLz?=\n\t=?utf-8?q?/5WTgcXZIhQnC4Q3aLD5GxYvlC1OutYj4Y+r96BHOAdrgbjxS3XoAPmq?=\n\t=?utf-8?q?aJOXnPNBkXjftGbkukCIUp2AA+gRWoQ9Am2k8RZs1ymwFdgL/z/nD6Be?=\n\t=?utf-8?q?jftNtlLApxgsiqojmJSB6UxQp+tr6NTx2c0+JLfaBEfF+nRhJhLPzPHs?=\n\t=?utf-8?q?bdYnWobpOHVF1HDJplxxzma1C9eWTfuSgnkMrreAh6MvWkpKLw+Hhxve?=\n\t=?utf-8?q?bCUJ9fiVqqvza92Jf3yVUfPNiAZxc8IZgU0/kWxApUXvsJDebhj/TNx/?=\n\t=?utf-8?q?rwcjGZNeViiG0470joVPCCkVePT5tnTfUfSHzUvV59Kpq5w7amzlSTLH?=\n\t=?utf-8?q?DFkI84s0T5+zkvrGCfNWZtMeA1ntZ3IAxWZvlSR8JMo6hIDNtkc15dGP?=\n\t=?utf-8?q?LJLof//7zo6KcRzLtzpTiqaiWiQtJws2MbCQJFWgTjlxVXBnH7ri9T0T?=\n\t=?utf-8?q?kHy24WJgbOrS7gu+EBIUsVJu1hdA/UMAycBHmnrQJjOXAjCmJnLc87OF?=\n\t=?utf-8?q?Sbgjy3foIvR6K9PkkqWfsS1Uvlbcf9T0+AbpgZKAAwCCvA3el4/B67Uq?=\n\t=?utf-8?q?U/+fsv9ARik3ULVEZDDno1/jzma1JwxYhPfgmkj6fxHblGDjCyvYLlq8?=\n\t=?utf-8?q?+SRS7PpyfiGUyigt5Fe06j4gaZcgpIywTakpcS7vJbcg0j0uELv7TGKv?=\n\t=?utf-8?q?Lnzjh5SChW3zNlImOzE2gB8uYQHvr99VcheWE975iAj1ZfqtGRiOFdJn?=\n\t=?utf-8?q?qKQv9I6ocP/lvZW8OYucbNosIDUUB/+zUB8/KfUbWSkV2xAveF1TdfCZ?=\n\t=?utf-8?q?0iNjJzTyi4kQMarmzqIqb9EKNokgig0mtlua9LyvSFfZ?=","X-Forefront-Antispam-Report":"CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n\tIPV:NLI; SFV:NSPM; H:GVXPR04MB9831.eurprd04.prod.outlook.com; PTR:;\n\tCAT:NONE; \n\tSFS:(13230040)(376014)(1800799024)(19092799006)(366016); DIR:OUT;\n\tSFP:1101; ","X-MS-Exchange-AntiSpam-MessageData-ChunkCount":"1","X-MS-Exchange-AntiSpam-MessageData-0":"=?utf-8?q?bHc89PH6/yofOqCdnTDBKCmcz?=\n\t=?utf-8?q?3su6nU8XGUri0Qrk4c40mxrm66huO0MEuatdhyhNEd+8tWKdf+baXIjR?=\n\t=?utf-8?q?6fUNSjGJrHN+aqOk5XlExiwIxigKj8b9N25OtAjxmQgPwawsGoTJIYm2?=\n\t=?utf-8?q?WHoFsvRR8ES6sL/2Vi1zuQNMCGW8BjmayGU23cCwSFgjkGSt3FQp+RtF?=\n\t=?utf-8?q?dzV8DM+W83HY1gQFEb9XEZscrTGz801iuUEPR5Ub+ZY3RK4roKd4yrAx?=\n\t=?utf-8?q?WZlqmfLOiE0VHwFu68ybO3fUJ93OQHG0tmHkeXTbdA7bW/DadsnTcWZD?=\n\t=?utf-8?q?vpd6FA9vDkuy64Hvsl750ktQRL9OJcgH0OZs2mLVLcuATAttIkrvqWdD?=\n\t=?utf-8?q?vv4MmABJ8h5+X69KdMFzJd6Ay7zBn/CiupDNT8fU19jTlfRRO9+W6PD4?=\n\t=?utf-8?q?JGigfxXC0frKgRw1CvqTVsKpYanIUBBQ48LK6YTKuh8cexGRwDluZvHS?=\n\t=?utf-8?q?JDbZTnlWu+SWvhBhrAVLCEcj0gX5oEkuhC5tCUMUdS5CSLJ+wC4GkZjd?=\n\t=?utf-8?q?FdScrNA+/btSpmFCK9MkW2d3c4B2l0N4LV+/ipIVxEwhHcWw0BqbmIoX?=\n\t=?utf-8?q?b5kaUVc/ATntFdh4W2QKhFe2C56AUqC9s3pumYwunKb34ujKn8JPzDg6?=\n\t=?utf-8?q?SMYVgpFqYrQlGOEXBEJ7XstGdcKlHfuQB4ie2+PbSicuntds3Pbo1zQQ?=\n\t=?utf-8?q?+jZAt1uQFaSVpyZA/bSFCXrw86by47hLE7JVXyvhQGHjIupnUMXcj5UO?=\n\t=?utf-8?q?iuO/hPcN4v/Z6mWTNdoX+SA8hPrOylHSQu1wB3JGx5HZSeqk2HXgyBny?=\n\t=?utf-8?q?/Eh2qI9OyXj1mVKxufgwWS+YVGJ+Bct779wj9exSBtO2g/AdAcO6tGwZ?=\n\t=?utf-8?q?BQ3/J4/2S1pBWArSoLtDeSOYlsTh7GtXE5441DJR267qABBUNMJKvc8f?=\n\t=?utf-8?q?WYHf2QeSEqu96Y16SexHPF3kgogY5WHMFW5x/oXB5kame3NjDiroYGMr?=\n\t=?utf-8?q?qouyKjq0hWBHlY1Gzu/ONsTxY/aWRF2bQSojLP2eojAu4m3+nrLBXx+p?=\n\t=?utf-8?q?VQX1CYRiTTkWL+EZVcAO/tjnJPTaRsuVTAj0lSYNPvvit6wHUrtNRvfK?=\n\t=?utf-8?q?5U4QdGzlZBkAdWFF7thXY14GxuR9/HT61yCMjMJWjsCu56UaTMqRXbn/?=\n\t=?utf-8?q?LjSzRcNi7FuG6QEU2RojBNukscP3Ji5cDh6smeWXG4DKlsEjIQXqn5VY?=\n\t=?utf-8?q?/UvtK5cniOPMG1cWWaGiQE1RC+I/yqGdfSkBeN38qhw+GU8cglxTByNb?=\n\t=?utf-8?q?L4G9sIhRh2jhoAk0bdm47Muav/ow22ATRDxPrcfCeHYTiIEEjXHqF/xj?=\n\t=?utf-8?q?NZPrDbCGRTpJ6k4SvfQuctwHKxkCWGRjQYf6aMiz0mfDhAS3B4flOA0r?=\n\t=?utf-8?q?F/6+8QfO+iykFHh4XB0jYvcIIl1xFJ2qCIPHXgFyXHsQ95IQWzbKOE/2?=\n\t=?utf-8?q?zEIziaFch9vn30Kfh62TdS5pVSM7niAYqQo/xJmHf4L5gU2KRWUr0/jA?=\n\t=?utf-8?q?846NyKH4pErrkRbxjaf6/5irUxjPjjHJ0MyYZOUEDK6z28PGrK63iPwG?=\n\t=?utf-8?q?uy+tnBRZ8T8u9mNIrHGf674YtU83xQaHauP2ym414ZRJio4682rVheSm?=\n\t=?utf-8?q?8JrQloc1p8wCAzfD8rZ7eJvJHg1rg=3D=3D?=","X-OriginatorOrg":"nxp.com","X-MS-Exchange-CrossTenant-Network-Message-Id":"eb3e3f7f-658b-429d-05ac-08de2395d6ac","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:52:39.3145\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":"/Uv5XXc+p6cfiyuj3ij7gWHdMj9DPTRb/kXOWEZdj2iFAgJALPAZYMYxxFZ1mcTW2+TxmHAzyap0P32nwoU7Lw==","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"AM8PR04MB7844","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>"}},{"id":36822,"web_url":"https://patchwork.libcamera.org/comment/36822/","msgid":"<w4nkvafbdgfpz3ibbhzjnkrquc6amej6freohh6oug73elkv7d@6ymdx5e6c52j>","date":"2025-11-14T16:27:10","subject":"Re: [EXT] Re: [PATCH v1 2/2] pipeline: imx8-isi: Integrating\n\tMediaPipeline class","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Antoine\n\nOn Fri, Nov 14, 2025 at 04:52:38PM +0100, Antoine Bouyer wrote:\n>\n> Hi Jacopo\n>\n> Sorry I missed your 2/2 review while V2 was sent. Only applied comments from\n> your 1/2 review.\n\nNo worries, let's wait for more feedback before sending v3.\n\nThanks\n  j\n\n\n>\n> On 11/14/25 4:41 PM, Jacopo Mondi wrote:\n> > Caution: This is an external email. Please take care when clicking links or opening attachments. When in doubt, report the message using the 'Report this email' button\n> >\n> >\n> > Hello\n> >\n> > On Thu, Nov 13, 2025 at 11:04:14AM +0100, Antoine Bouyer wrote:\n> > > From: Andrei Gansari <andrei.gansari@nxp.com>\n> > >\n> > > This change integrates the MediaPipeline class into the imx8-isi\n> > > pipeline handler. Purpose is to allow a dynamic discovery and\n> > > configuration of the actual subdevices graph between the sensor and\n> > > the ISI crossbar. This brings support for more complex topologies and\n> > > simplifies the implementation.\n> > >\n> > > Signed-off-by: Andrei Gansari <andrei.gansari@nxp.com>\n> > > Signed-off-by: Antoine Bouyer <antoine.bouyer@nxp.com>\n> > > ---\n> > >   src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 159 ++++++++++++-------\n> > >   1 file changed, 98 insertions(+), 61 deletions(-)\n> > >\n> > > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > index 9550f54600c4..aefc0ee60a11 100644\n> > > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp\n> > > @@ -25,6 +25,7 @@\n> > >   #include \"libcamera/internal/camera_sensor.h\"\n> > >   #include \"libcamera/internal/device_enumerator.h\"\n> > >   #include \"libcamera/internal/media_device.h\"\n> > > +#include \"libcamera/internal/media_pipeline.h\"\n> > >   #include \"libcamera/internal/pipeline_handler.h\"\n> > >   #include \"libcamera/internal/v4l2_subdevice.h\"\n> > >   #include \"libcamera/internal/v4l2_videodevice.h\"\n> > > @@ -62,14 +63,15 @@ public:\n> > >        unsigned int getYuvMediaBusFormat(const PixelFormat &pixelFormat) const;\n> > >        unsigned int getMediaBusFormat(PixelFormat *pixelFormat) const;\n> > >\n> > > +     /* All entities, from the sensor to the ISI. */\n> > > +     MediaPipeline mediaPipeline_;\n> > > +\n> > >        std::unique_ptr<CameraSensor> sensor_;\n> > > -     std::unique_ptr<V4L2Subdevice> csis_;\n> > >\n> > >        std::vector<Stream> streams_;\n> > >\n> > >        std::vector<Stream *> enabledStreams_;\n> > >\n> > > -     unsigned int xbarSink_ = 0;\n> > >        unsigned int xbarSourceOffset_ = 0;\n> > >   };\n> > >\n> > > @@ -141,6 +143,8 @@ private:\n> > >\n> > >        void bufferReady(FrameBuffer *buffer);\n> > >\n> > > +     std::vector<MediaEntity *> locateSensors(MediaDevice *media);\n> > > +\n> > >        MediaDevice *isiDev_;\n> > >\n> > >        std::unique_ptr<V4L2Subdevice> crossbar_;\n> > > @@ -164,10 +168,6 @@ int ISICameraData::init()\n> > >        if (!sensor_)\n> > >                return -ENODEV;\n> > >\n> > > -     int ret = csis_->open();\n> > > -     if (ret)\n> > > -             return ret;\n> > > -\n> > >        properties_ = sensor_->properties();\n> > >\n> > >        return 0;\n> > > @@ -811,18 +811,29 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c)\n> > >   {\n> > >        ISICameraConfiguration *camConfig = static_cast<ISICameraConfiguration *>(c);\n> > >        ISICameraData *data = cameraData(camera);\n> > > +     CameraSensor *sensor = data->sensor_.get();\n> > > +     int ret;\n> > >\n> > > -     /* Apply format to the sensor, CSIS receiver and crossbar sink pad. */\n> > > -     V4L2SubdeviceFormat format = camConfig->sensorFormat_;\n> > > -     int ret = data->sensor_->setFormat(&format);\n> > > -     if (ret)\n> > > +     /*\n> > > +      * Enable the links all the way up to the ISI, through any connected CSI\n> > > +      * receiver and optional formatter.\n> > > +      */\n> > > +     ret = data->mediaPipeline_.initLinks();\n> > > +     if (ret) {\n> > > +             LOG(ISI, Error) << \"Failed to set up pipe links\";\n> > >                return ret;\n> > > +     }\n> > >\n> > > -     ret = data->csis_->setFormat(0, &format);\n> > > +     /*\n> > > +      * Configure the format on the sensor output and propagate it through\n> > > +      * the pipeline.\n> > > +      */\n> > > +     V4L2SubdeviceFormat format = camConfig->sensorFormat_;\n> > > +     ret = sensor->setFormat(&format);\n> > >        if (ret)\n> > >                return ret;\n> > >\n> > > -     ret = crossbar_->setFormat(data->xbarSink_, &format);\n> > > +     ret = data->mediaPipeline_.configure(sensor, &format);\n> > >        if (ret)\n> > >                return ret;\n> > >\n> > > @@ -979,13 +990,8 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n> > >                return false;\n> > >\n> > >        /* Count the number of sensors, to create one camera per sensor. */\n> > > -     unsigned cameraCount = 0;\n> > > -     for (MediaEntity *entity : isiDev_->entities()) {\n> > > -             if (entity->function() != MEDIA_ENT_F_CAM_SENSOR)\n> > > -                     continue;\n> > > -\n> > > -             cameraCount++;\n> > > -     }\n> > > +     std::vector<MediaEntity *> sensorEntities = locateSensors(isiDev_);\n> > > +     unsigned cameraCount = sensorEntities.size();\n> >\n> > unsigned int\n> >\n> > but maybe it's just me not being used to 'unsigned'\n>\n> Sure, let me apply it in V3 to avoid confusion. Will wait for more feedback\n> before sending it thought.\n>\n> >\n> > >\n> > >        if (!cameraCount) {\n> > >                LOG(ISI, Error) << \"No camera sensor found\";\n> > > @@ -1048,60 +1054,28 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n> > >         * sensors to get at least one dedicated pipe.\n> > >         */\n> > >        unsigned int numCameras = 0;\n> > > -     unsigned int numSinks = 0;\n> > >        const unsigned int xbarFirstSource = crossbar_->entity()->pads().size() - pipes_.size();\n> > >        const unsigned int maxStreams = pipes_.size() / cameraCount;\n> > >\n> > > -     for (MediaPad *pad : crossbar_->entity()->pads()) {\n> > > -             unsigned int sink = numSinks;\n> > > -\n> > > -             if (!(pad->flags() & MEDIA_PAD_FL_SINK))\n> > > -                     continue;\n> > > -\n> > > -             /*\n> > > -              * Count each crossbar sink pad to correctly configure\n> > > -              * routing and format for this camera.\n> > > -              */\n> > > -             numSinks++;\n> > > -\n> > > -             if (pad->links().empty())\n> > > -                     continue;\n> > > -\n> > > -             MediaEntity *csi = pad->links()[0]->source()->entity();\n> > > -             if (csi->pads().size() != 2) {\n> > > -                     LOG(ISI, Debug) << \"Skip unsupported CSI-2 receiver \"\n> > > -                                     << csi->name();\n> > > -                     continue;\n> > > -             }\n> > > -\n> > > -             pad = csi->pads()[0];\n> > > -             if (!(pad->flags() & MEDIA_PAD_FL_SINK) || pad->links().empty())\n> > > -                     continue;\n> > > -\n> > > -             MediaEntity *sensor = pad->links()[0]->source()->entity();\n> > > -             if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) {\n> > > -                     LOG(ISI, Debug) << \"Skip unsupported subdevice \"\n> > > -                                     << sensor->name();\n> > > -                     continue;\n> > > -             }\n> > > -\n> > > -             /* All links are immutable except the sensor -> csis link. */\n> > > -             const MediaPad *sensorSrc = sensor->getPadByIndex(0);\n> > > -             sensorSrc->links()[0]->setEnabled(true);\n> > > -\n> > > +     for (MediaEntity *sensor : sensorEntities) {\n> > >                /* Create the camera data. */\n> > >                std::unique_ptr<ISICameraData> data =\n> > >                        std::make_unique<ISICameraData>(this, maxStreams);\n> > >\n> > > +             ret = data->mediaPipeline_.init(sensor, \"crossbar\");\n> > > +             if (ret)\n> > > +                     continue;\n> > > +\n> > > +             const MediaPipeline::Entity *xbarEntity = &data->mediaPipeline_.entities().back();\n> > > +             unsigned int xbarSinkIndex = xbarEntity->sink->index();\n> > > +\n> > >                data->sensor_ = CameraSensorFactoryBase::create(sensor);\n> > > -             data->csis_ = std::make_unique<V4L2Subdevice>(csi);\n> > > -             data->xbarSink_ = sink;\n> > >                data->xbarSourceOffset_ = numCameras * data->streams_.size();\n> > >\n> > >                LOG(ISI, Debug)\n> > >                        << \"cam\" << numCameras\n> > >                        << \" streams \" << data->streams_.size()\n> > > -                     << \" sink \" << data->xbarSink_\n> > > +                     << \" sink \" << xbarSinkIndex\n> > >                        << \" offset \" << data->xbarSourceOffset_;\n> > >\n> > >                ret = data->init();\n> > > @@ -1120,7 +1094,7 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)\n> > >                /*  Add routes to the crossbar switch routing table. */\n> > >                for (unsigned i = 0; i < data->streams_.size(); i++) {\n> > >                        unsigned int sourcePad = xbarFirstSource + data->xbarSourceOffset_ + i;\n> > > -                     routing_.emplace_back(V4L2Subdevice::Stream{ data->xbarSink_, 0 },\n> > > +                     routing_.emplace_back(V4L2Subdevice::Stream{ xbarSinkIndex, 0 },\n> > >                                             V4L2Subdevice::Stream{ sourcePad, 0 },\n> > >                                             V4L2_SUBDEV_ROUTE_FL_ACTIVE);\n> > >                }\n> > > @@ -1163,6 +1137,69 @@ void PipelineHandlerISI::bufferReady(FrameBuffer *buffer)\n> > >        completeRequest(request);\n> > >   }\n> > >\n> > > +/* Original function taken from simple.cpp */\n> > > +std::vector<MediaEntity *>\n> > > +PipelineHandlerISI::locateSensors(MediaDevice *media)\n> > > +{\n> > > +     std::vector<MediaEntity *> entities;\n> > > +\n> > > +     /*\n> > > +      * Gather all the camera sensor entities based on the function they\n> > > +      * expose.\n> > > +      */\n> > > +     for (MediaEntity *entity : media->entities()) {\n> > > +             if (entity->function() == MEDIA_ENT_F_CAM_SENSOR)\n> > > +                     entities.push_back(entity);\n> > > +     }\n> > > +\n> > > +     if (entities.empty())\n> > > +             return {};\n> > > +\n> > > +     /*\n> > > +      * Sensors can be made of multiple entities. For instance, a raw sensor\n> > > +      * can be connected to an ISP, and the combination of both should be\n> > > +      * treated as one sensor. To support this, as a crude heuristic, check\n> > > +      * the downstream entity from the camera sensor, and if it is an ISP,\n> > > +      * use it instead of the sensor.\n> > > +      */\n> > > +     std::vector<MediaEntity *> sensors;\n> > > +\n> > > +     for (MediaEntity *entity : entities) {\n> > > +             /*\n> > > +              * Locate the downstream entity by following the first link\n> > > +              * from a source pad.\n> > > +              */\n> > > +             const MediaLink *link = nullptr;\n> > > +\n> > > +             for (const MediaPad *pad : entity->pads()) {\n> > > +                     if ((pad->flags() & MEDIA_PAD_FL_SOURCE) &&\n> > > +                         !pad->links().empty()) {\n> > > +                             link = pad->links()[0];\n> > > +                             break;\n> > > +                     }\n> > > +             }\n> > > +\n> > > +             if (!link)\n> > > +                     continue;\n> > > +\n> > > +             MediaEntity *remote = link->sink()->entity();\n> > > +             if (remote->function() == MEDIA_ENT_F_PROC_VIDEO_ISP)\n> > > +                     sensors.push_back(remote);\n> > > +             else\n> > > +                     sensors.push_back(entity);\n> > > +     }\n> > > +\n> > > +     /*\n> > > +      * Remove duplicates, in case multiple sensors are connected to the\n> > > +      * same ISP.\n> > > +      */\n> > > +     std::sort(sensors.begin(), sensors.end());\n> > > +     auto last = std::unique(sensors.begin(), sensors.end());\n> > > +     sensors.erase(last, sensors.end());\n> > > +\n> > > +     return sensors;\n> > > +}\n> >\n> > Nothing to report here, apart that this code is copied from simple,\n> > and maybe it could be generalized. Not a requirement for this patch\n> > though!\n> >\n> > Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> >\n> > Thanks\n> >     j\n> >\n>\n> Thanks\n> Antoine\n>\n> > > +\n> > >   REGISTER_PIPELINE_HANDLER(PipelineHandlerISI, \"imx8-isi\")\n> > >\n> > >   } /* namespace libcamera */\n> > > --\n> > > 2.34.1\n> > >\n>","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 3C5DCC3241\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 14 Nov 2025 16:27:15 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0758360A86;\n\tFri, 14 Nov 2025 17:27:15 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7DFA8609D8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 14 Nov 2025 17:27:13 +0100 (CET)","from ideasonboard.com (93-61-96-190.ip145.fastwebnet.it\n\t[93.61.96.190])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7BB75664;\n\tFri, 14 Nov 2025 17:25:12 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"b/NdoD2W\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1763137512;\n\tbh=Be9wmovsOuIYapcZYaJDQgqZIXXQXXiqh1Zbekqtd2M=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=b/NdoD2WUsvv69pGO1ViJzfEYLQgBHLvy4Wt7xf6lEcjN3cbeYMJAvCn6btDmBb+1\n\t6ZFIdwK8Gf09tkUvuS6X6Ht4+YXSE21ysKJfL7v//gEjn0w5imxD3bUxt29UNqqUpM\n\tcWYI1DvelMlrZVb4c9IZU52/cFeN5v4+wxfiOxuY=","Date":"Fri, 14 Nov 2025 17:27:10 +0100","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Antoine Bouyer <antoine.bouyer@nxp.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tlibcamera-devel@lists.libcamera.org, julien.vuillaumier@nxp.com, \n\tAndrei Gansari <andrei.gansari@nxp.com>","Subject":"Re: [EXT] Re: [PATCH v1 2/2] pipeline: imx8-isi: Integrating\n\tMediaPipeline class","Message-ID":"<w4nkvafbdgfpz3ibbhzjnkrquc6amej6freohh6oug73elkv7d@6ymdx5e6c52j>","References":"<20251113100414.535550-1-antoine.bouyer@nxp.com>\n\t<20251113100414.535550-3-antoine.bouyer@nxp.com>\n\t<fygaztb4csl7egddqdy5lskidmppb2gy2ph2x62contsnrngr5@qndemkelpz2n>\n\t<a0012d28-4429-4ece-ac02-4565adb94034@nxp.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<a0012d28-4429-4ece-ac02-4565adb94034@nxp.com>","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>"}}]