[{"id":22081,"web_url":"https://patchwork.libcamera.org/comment/22081/","msgid":"<164367494634.115113.8020732286602399927@Monstersaurus>","date":"2022-02-01T00:22:26","subject":"Re: [libcamera-devel] [RFC v1 2/2] pipeline: raspberrypi: Use\n\tMediaDevice::enumerateMediaWalks()","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Naushir Patuck (2022-01-13 10:25:29)\n> Use the new MediaDevice::enumerateMediaWalks() helper to enumerate the Unicam\n> MediaDevice, replacing the existing enumerateVideoDevices() function.\n> \n> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> ---\n>  .../pipeline/raspberrypi/raspberrypi.cpp      | 142 ++++--------------\n>  1 file changed, 32 insertions(+), 110 deletions(-)\n> \n> diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n> index 5ee713fe66a6..36f3acf1393a 100644\n> --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n> +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n> @@ -194,8 +194,6 @@ public:\n>         int loadIPA(ipa::RPi::SensorConfig *sensorConfig);\n>         int configureIPA(const CameraConfiguration *config);\n>  \n> -       void enumerateVideoDevices(MediaLink *link);\n> -\n>         void statsMetadataComplete(uint32_t bufferId, const ControlList &controls);\n>         void runIsp(uint32_t bufferId);\n>         void embeddedComplete(uint32_t bufferId);\n> @@ -326,7 +324,7 @@ private:\n>                 return static_cast<RPiCameraData *>(camera->_d());\n>         }\n>  \n> -       int registerCamera(MediaDevice *unicam, MediaDevice *isp, MediaEntity *sensorEntity);\n> +       int registerCamera(MediaDevice *unicam, MediaDevice *isp, const MediaDevice::MediaWalk &walk);\n>         int queueAllBuffers(Camera *camera);\n>         int prepareBuffers(Camera *camera);\n>         void freeBuffers(Camera *camera);\n> @@ -1111,30 +1109,34 @@ bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator)\n>                 return false;\n>         }\n>  \n> +       std::vector<MediaDevice::MediaWalk> walks = unicamDevice->enumerateMediaWalks();\n> +\n>         /*\n>          * The loop below is used to register multiple cameras behind one or more\n>          * video mux devices that are attached to a particular Unicam instance.\n>          * Obviously these cameras cannot be used simultaneously.\n>          */\n>         unsigned int numCameras = 0;\n> -       for (MediaEntity *entity : unicamDevice->entities()) {\n> -               if (entity->function() != MEDIA_ENT_F_CAM_SENSOR)\n> -                       continue;\n> +       for (const MediaDevice::MediaWalk &walk : walks) {\n> +               MediaEntity *sensorEntity = walk.front().entity;\n>  \n> -               int ret = registerCamera(unicamDevice, ispDevice, entity);\n> -               if (ret)\n> +               int ret = registerCamera(unicamDevice, ispDevice, walk);\n> +               if (ret) {\n>                         LOG(RPI, Error) << \"Failed to register camera \"\n> -                                       << entity->name() << \": \" << ret;\n> -               else\n> -                       numCameras++;\n> +                                       << sensorEntity->name() << \": \" << ret;\n> +                       continue;\n> +               }\n> +\n> +               numCameras++;\n>         }\n>  \n>         return !!numCameras;\n>  }\n>  \n> -int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, MediaEntity *sensorEntity)\n> +int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, const MediaDevice::MediaWalk &walk)\n>  {\n>         std::unique_ptr<RPiCameraData> data = std::make_unique<RPiCameraData>(this);\n> +       MediaEntity *sensorEntity = walk.front().entity;\n>  \n>         if (!data->dmaHeap_.isValid())\n>                 return -ENOMEM;\n> @@ -1180,12 +1182,24 @@ int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, Me\n>         if (data->sensor_->init())\n>                 return -EINVAL;\n>  \n> -       /*\n> -        * Enumerate all the Video Mux/Bridge devices across the sensor -> unicam\n> -        * chain. There may be a cascade of devices in this chain!\n> -        */\n> -       MediaLink *link = sensorEntity->getPadByIndex(0)->links()[0];\n> -       data->enumerateVideoDevices(link);\n> +       /* See if we can auto configure this MC graph. */\n> +       for (auto it = walk.begin() + 1; it < walk.end() - 1; ++it) {\n> +               MediaEntity *entity = it->entity;\n> +               MediaLink *sinkLink = it->sinkLink;\n> +\n> +               /* We only deal with Video Mux and Bridge devices in cascade. */\n> +               if (entity->function() != MEDIA_ENT_F_VID_MUX &&\n> +                   entity->function() != MEDIA_ENT_F_VID_IF_BRIDGE) {\n> +                       data->bridgeDevices_.clear();\n> +                       break;\n> +               }\n> +\n> +               LOG(RPI, Info) << \"Found video mux/bridge device \" << entity->name()\n> +                              << \" linked to sink pad \" << sinkLink->sink()->index();\n\nI hope that's not too verbose, so it sounds ok for Info for now.\n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> +\n> +               data->bridgeDevices_.emplace_back(std::make_unique<V4L2Subdevice>(entity), sinkLink);\n> +               data->bridgeDevices_.back().first->open();\n> +       }\n>  \n>         data->sensorFormats_ = populateSensorFormats(data->sensor_);\n>  \n> @@ -1545,98 +1559,6 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n>         return 0;\n>  }\n>  \n> -/*\n> - * enumerateVideoDevices() iterates over the Media Controller topology, starting\n> - * at the sensor and finishing at Unicam. For each sensor, RPiCameraData stores\n> - * a unique list of any intermediate video mux or bridge devices connected in a\n> - * cascade, together with the entity to entity link.\n> - *\n> - * Entity pad configuration and link enabling happens at the end of configure().\n> - * We first disable all pad links on each entity device in the chain, and then\n> - * selectively enabling the specific links to link sensor to Unicam across all\n> - * intermediate muxes and bridges.\n> - *\n> - * In the cascaded topology below, if Sensor1 is used, the Mux2 -> Mux1 link\n> - * will be disabled, and Sensor1 -> Mux1 -> Unicam links enabled. Alternatively,\n> - * if Sensor3 is used, the Sensor2 -> Mux2 and Sensor1 -> Mux1 links are disabled,\n> - * and Sensor3 -> Mux2 -> Mux1 -> Unicam links are enabled. All other links will\n> - * remain unchanged.\n> - *\n> - *  +----------+\n> - *  |  Unicam  |\n> - *  +-----^----+\n> - *        |\n> - *    +---+---+\n> - *    |  Mux1 <-------+\n> - *    +--^----+       |\n> - *       |            |\n> - * +-----+---+    +---+---+\n> - * | Sensor1 |    |  Mux2 |<--+\n> - * +---------+    +-^-----+   |\n> - *                  |         |\n> - *          +-------+-+   +---+-----+\n> - *          | Sensor2 |   | Sensor3 |\n> - *          +---------+   +---------+\n> - */\n> -void RPiCameraData::enumerateVideoDevices(MediaLink *link)\n> -{\n> -       const MediaPad *sinkPad = link->sink();\n> -       const MediaEntity *entity = sinkPad->entity();\n> -       bool unicamFound = false;\n> -\n> -       /* We only deal with Video Mux and Bridge devices in cascade. */\n> -       if (entity->function() != MEDIA_ENT_F_VID_MUX &&\n> -           entity->function() != MEDIA_ENT_F_VID_IF_BRIDGE)\n> -               return;\n> -\n> -       /* Find the source pad for this Video Mux or Bridge device. */\n> -       const MediaPad *sourcePad = nullptr;\n> -       for (const MediaPad *pad : entity->pads()) {\n> -               if (pad->flags() & MEDIA_PAD_FL_SOURCE) {\n> -                       /*\n> -                        * We can only deal with devices that have a single source\n> -                        * pad. If this device has multiple source pads, ignore it\n> -                        * and this branch in the cascade.\n> -                        */\n> -                       if (sourcePad)\n> -                               return;\n> -\n> -                       sourcePad = pad;\n> -               }\n> -       }\n> -\n> -       LOG(RPI, Debug) << \"Found video mux device \" << entity->name()\n> -                       << \" linked to sink pad \" << sinkPad->index();\n> -\n> -       bridgeDevices_.emplace_back(std::make_unique<V4L2Subdevice>(entity), link);\n> -       bridgeDevices_.back().first->open();\n> -\n> -       /*\n> -        * Iterate through all the sink pad links down the cascade to find any\n> -        * other Video Mux and Bridge devices.\n> -        */\n> -       for (MediaLink *l : sourcePad->links()) {\n> -               enumerateVideoDevices(l);\n> -               /* Once we reach the Unicam entity, we are done. */\n> -               if (l->sink()->entity()->name() == \"unicam-image\") {\n> -                       unicamFound = true;\n> -                       break;\n> -               }\n> -       }\n> -\n> -       /* This identifies the end of our entity enumeration recursion. */\n> -       if (link->source()->entity()->function() == MEDIA_ENT_F_CAM_SENSOR) {\n> -               /*\n> -               * If Unicam is not at the end of this cascade, we cannot configure\n> -               * this topology automatically, so remove all entity references.\n> -               */\n> -               if (!unicamFound) {\n> -                       LOG(RPI, Warning) << \"Cannot automatically configure this MC topology!\";\n> -                       bridgeDevices_.clear();\n> -               }\n> -       }\n> -}\n> -\n>  void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &controls)\n>  {\n>         if (state_ == State::Stopped)\n> -- \n> 2.25.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 46FE3BDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  1 Feb 2022 00:22:31 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AD55C609C6;\n\tTue,  1 Feb 2022 01:22:30 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3CC8E604F1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  1 Feb 2022 01:22:29 +0100 (CET)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D33679DE;\n\tTue,  1 Feb 2022 01:22:28 +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=\"L3OktY9T\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1643674948;\n\tbh=qf/cRfNLoPgE/0ABCL6ueSQ7O+LzIIHhbU8i88X+GY8=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=L3OktY9Tgr085dx7SZ1vX8G7BvKesCVrYRajW42bQGqR5vXCHckJbXBp0T+4ZzUAP\n\tJ/Ej+QWagpbJIhMwt29F+uoUuFIhM+0aKFwvp3PIL9dZVJn90d4OA6LtgN9+QsdMgg\n\tGxCNtIFQ/Y+PNIE/xplK+9OHgw8w5EUew36I9Ecs=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20220113102529.3163441-3-naush@raspberrypi.com>","References":"<20220113102529.3163441-1-naush@raspberrypi.com>\n\t<20220113102529.3163441-3-naush@raspberrypi.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"Naushir Patuck <naush@raspberrypi.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Tue, 01 Feb 2022 00:22:26 +0000","Message-ID":"<164367494634.115113.8020732286602399927@Monstersaurus>","User-Agent":"alot/0.10","Subject":"Re: [libcamera-devel] [RFC v1 2/2] pipeline: raspberrypi: Use\n\tMediaDevice::enumerateMediaWalks()","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>"}}]