From patchwork Thu Jan 13 10:25:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 15276 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 2FC36C325A for ; Thu, 13 Jan 2022 10:25:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C372A6093D; Thu, 13 Jan 2022 11:25:37 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="nf0c15no"; dkim-atps=neutral Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F2CB16017E for ; Thu, 13 Jan 2022 11:25:35 +0100 (CET) Received: by mail-wr1-x435.google.com with SMTP id q8so9135171wra.12 for ; Thu, 13 Jan 2022 02:25:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=5+boYhoE20g1aTmGiUb4iR1Pa8SbK9bEBGFwgPSNkLs=; b=nf0c15nobwcbHOFDywmBNY6ktZ1B7LuX266Yu/jewspDFtIJDvT+JqtRd0PqXS6VmI aLy5I70K1+XdM/8CKAIsg1k2sz2S10nR62XdMhXZQp2KK0f7xFs72pxLDoziG9l4JfSD rQ6DZPoQKoj6GkkxDzryRoivlPhMeIbS0WXrcQBvZbU0hSvtGSPqqAC5xgZcOvjJf6R0 16dMYg+rsiwB4BuTExS8ST8G4spAXk7YvlOt5UJ3wrXzr1AHHMfU2rIr7QrowbN8sxYG TQn9LfwxRm+y3pt62TDeL+YxZWotagorlb+VrnARljxMkrpKEKXIEDIKHMY5bMpTZIWl tKow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=5+boYhoE20g1aTmGiUb4iR1Pa8SbK9bEBGFwgPSNkLs=; b=CKWx6KiR0ofD8jwSha8FwV4nB8YkrVCcxOec6kK1LNd7m4kQE+Sdzew7HdUK7aJO7y GBD5DZRtLZEHbYyt8FLXmkeyL9VVItBxY+FaPbNr5uM0yeyhOtcLzevJRTvIkuHwg1BC oEYDTtXMsWe64gQTdOpLdF67hEgie6YwRsNo8iu/sFSHMh9DMF4d5keeVXl1ZkD+iTFA 8TEqxWr2zsWDHLqu0IfUar3lfqMz6jWxbXky2RpDIHWHG+KL1Fx2IJeZs6i+5K3Vwrqu Ycav5u71t9EYSisX/TUDl93EfUleDJqhRa7izj/CtklRxQLvO395TXT+MMeqqe/+7Wrb wlng== X-Gm-Message-State: AOAM530PjFn9Xam8Q1+qbyevuVewS8JFnEJFhvOwTA1X1/NHXUuhkI87 0MeRuXY2FQLO5ykbW30mYhtpLiMsKaIENjiF X-Google-Smtp-Source: ABdhPJwy8gF1gQ0HnWSTgBGXtrhcKD0Jgu+wlplraaA/TV6Gq952MANEt6fNxGfBbcTfe09VzPbmTQ== X-Received: by 2002:a5d:59ae:: with SMTP id p14mr3348845wrr.304.1642069535489; Thu, 13 Jan 2022 02:25:35 -0800 (PST) Received: from naush-laptop.pitowers.org ([2a00:1098:3142:14:194e:c2b:3339:eb51]) by smtp.gmail.com with ESMTPSA id s22sm6757855wmc.1.2022.01.13.02.25.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Jan 2022 02:25:35 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Thu, 13 Jan 2022 10:25:28 +0000 Message-Id: <20220113102529.3163441-2-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220113102529.3163441-1-naush@raspberrypi.com> References: <20220113102529.3163441-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC v1 1/2] libcamera: media_device: Add enumerateMediaWalks() helper 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" Add a new helper function to the MediaDevice class which returns a vector of all possible media device topologies starting at the sensor entity and walking to an endpoint for the media device. Each of these topologies is called a MediaWalk. For each entity in a MediaWalk, we store a MediaEntity pointer together with the source and sink MediaLink pointers. As an example, consider the media graph below: +----------+ | CSI2 | +-----^----+ | +---+---+ | Mux1 <-------+ +--^----+ | | | +-----+---+ +---+---+ | Sensor1 | | Mux2 |<--+ +---------+ +-^-----+ | | | +-------+-+ +---+-----+ | Sensor2 | | Sensor3 | +---------+ +---------+ This would return three MediaDevice::MediaWalk structures looking like: 1) +----------+ | CSI2 | +-----^----+ | +-----+----+ | Mux1 | +-----^----+ | +-----+----+ | Sensor1 | +----------+ 2) +----------+ | CSI2 | +-----^----+ | +-----+----+ | Mux1 | +-----^----+ | +-----+----+ | Mux2 | +-----^----+ | +-----+----+ | Sensor2 | +----------+ 3) +----------+ | CSI2 | +-----^----+ | +-----+----+ | Mux1 | +-----^----+ | +-----+----+ | Mux2 | +-----^----+ | +-----+----+ | Sensor3 | +----------+ Signed-off-by: Naushir Patuck Reviewed-by: Kieran Bingham --- include/libcamera/internal/media_device.h | 12 ++ src/libcamera/media_device.cpp | 135 ++++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/include/libcamera/internal/media_device.h b/include/libcamera/internal/media_device.h index 6e2a63f38229..63fcbe423eb9 100644 --- a/include/libcamera/internal/media_device.h +++ b/include/libcamera/internal/media_device.h @@ -25,6 +25,13 @@ namespace libcamera { class MediaDevice : protected Loggable { public: + struct EntityParams { + MediaEntity *entity; + MediaLink *sinkLink; + MediaLink *sourceLink; + }; + using MediaWalk = std::vector; + MediaDevice(const std::string &deviceNode); ~MediaDevice(); @@ -47,6 +54,8 @@ public: const std::vector &entities() const { return entities_; } MediaEntity *getEntityByName(const std::string &name) const; + std::vector enumerateMediaWalks() const; + MediaLink *link(const std::string &sourceName, unsigned int sourceIdx, const std::string &sinkName, unsigned int sinkIdx); MediaLink *link(const MediaEntity *source, unsigned int sourceIdx, @@ -77,6 +86,9 @@ private: friend int MediaLink::setEnabled(bool enable); int setupLink(const MediaLink *link, unsigned int flags); + void walkGraph(std::vector *mediaWalks, MediaWalk *walk, + MediaEntity *entity, MediaLink *sinkLink) const; + std::string driver_; std::string deviceNode_; std::string model_; diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp index 941f86c25f66..60b397e205a2 100644 --- a/src/libcamera/media_device.cpp +++ b/src/libcamera/media_device.cpp @@ -340,6 +340,105 @@ MediaEntity *MediaDevice::getEntityByName(const std::string &name) const return nullptr; } +/** + * \fn MediaDevice::enumerateMediaWalks() + * \brief Retrieve the list of all possible MediaWalks available to this device + * + * Enumerate the media graph and return all possible permutations of unique + * sub-graphs where the first entity is a sensor device. These sub-graphs are + * stored as a \a MediaDevice::MediaWalk structure, where each element gives the + * device entity and associated sink pad link. The first entity in this structure + * is asensor device, with the sink pad link set to a nullptr. + * + * As an example, consider the media graph below: + * + * +----------+ + * | CSI2 | + * +-----^----+ + * | + * +---+---+ + * | Mux1 <-------+ + * +--^----+ | + * | | + * +-----+---+ +---+---+ + * | Sensor1 | | Mux2 |<--+ + * +---------+ +-^-----+ | + * | | + * +-------+-+ +---+-----+ + * | Sensor2 | | Sensor3 | + * +---------+ +---------+ + * + * This would return three \a MediaDevice::MediaWalk structures looking like: + * + * 1) + * +----------+ + * | CSI2 | + * +-----^----+ + * | + * +-----+----+ + * | Mux1 | + * +-----^----+ + * | + * +-----+----+ + * | Sensor1 | + * +----------+ + * + * 2) + * +----------+ + * | CSI2 | + * +-----^----+ + * | + * +-----+----+ + * | Mux1 | + * +-----^----+ + * | + * +-----+----+ + * | Mux2 | + * +-----^----+ + * | + * +-----+----+ + * | Sensor2 | + * +----------+ + * + * 3) + * +----------+ + * | CSI2 | + * +-----^----+ + * | + * +-----+----+ + * | Mux1 | + * +-----^----+ + * | + * +-----+----+ + * | Mux2 | + * +-----^----+ + * | + * +-----+----+ + * | Sensor3 | + * +----------+ + * + * \return A vector of MediaWalk structures available + */ +std::vector MediaDevice::enumerateMediaWalks() const +{ + std::vector mediaWalks; + + for (MediaEntity *entity : entities_) { + /* Only perform enumeration starting with sensor entities */ + if (entity->function() != MEDIA_ENT_F_CAM_SENSOR) + continue; + /* + * Start with an empty MediaWalk structure, and walk the graph + * with the sensor entity at the top, and a nullptr as the sink + * pad link. + */ + mediaWalks.push_back({}); + walkGraph(&mediaWalks, &mediaWalks.back(), entity, nullptr); + } + + return mediaWalks; +} + /** * \brief Retrieve the MediaLink connecting two pads, identified by entity * names and pad indexes @@ -800,4 +899,40 @@ int MediaDevice::setupLink(const MediaLink *link, unsigned int flags) return 0; } +void MediaDevice::walkGraph(std::vector *mediaWalks, MediaWalk *walk, + MediaEntity *entity, MediaLink *sinkLink) const +{ + bool newWalk = false; + + walk->push_back({ entity, sinkLink, nullptr }); + + for (const MediaPad *pad : entity->pads()) { + /* We only walk down the graph, so ignore any sink pads */ + if (pad->flags() & MEDIA_PAD_FL_SINK) + continue; + + for (MediaLink *nextLink : pad->links()) { + MediaDevice::MediaWalk *nextWalk = walk; + /* + * If this is a new branch in the graph, create a new + * MediaWalk structure in our list, and populate it with + * a copy of the curret MediaWalk. Any subsequent recursion + * into this graph branch will cause it to diverge. + */ + if (newWalk) { + mediaWalks->push_back(*walk); + nextWalk = &mediaWalks->back(); + } + + /* Record the source pad link for the current entity */ + walk->back().sourceLink = nextLink; + + /* Recurse into the next entity for this source pad link */ + MediaEntity *nextEntity = nextLink->sink()->entity(); + walkGraph(mediaWalks, nextWalk, nextEntity, nextLink); + newWalk = true; + } + } +} + } /* namespace libcamera */ From patchwork Thu Jan 13 10:25:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 15277 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 BFD42BE086 for ; Thu, 13 Jan 2022 10:25:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7FABE6093F; Thu, 13 Jan 2022 11:25:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="T5crmhsK"; dkim-atps=neutral Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BF2D1604F4 for ; Thu, 13 Jan 2022 11:25:36 +0100 (CET) Received: by mail-wr1-x42a.google.com with SMTP id q8so9135224wra.12 for ; Thu, 13 Jan 2022 02:25:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=pybYtv+XgN2g1EUB39IWeK5ug3VPIt8Yt9FxyC7pas8=; b=T5crmhsKgvTkga31EM4WLDjN9o1uudC+urANVld8g5RUitzaP7aio6irAXxBansZZJ eHAIyXzULIYk3/6vAP9MtXTFkYCIk78bvLaml9Kmb0L1x93l7+SdpoX0bDCee9pELw0v TIrHhy5hAy1gYUn8LR7wy7XPbUJbPVAev8gKtq9VhjadIVV2G/JQPaUJnBtw5sqRZb3Y lEcu5fQqXW07g4uuLQULd9Nh/ElNBAf95Ma+pje8nkYH2njfbA4QABUYSGNb6F+xrdDT DztIjtgyGGJXLfyWhMJZWaiSiaaD4s5OsX8ho63PaY1EAbE6pKnmk2GFVyAvfwq6qhpO nPAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=pybYtv+XgN2g1EUB39IWeK5ug3VPIt8Yt9FxyC7pas8=; b=NhFmkx8uJyTxWU6azAIWpgtnILIJQRHXxJclO6g8+4zI8N0sxnTLLHTxSR0ee04XBm Apwt40zXiZ16yS3cE047kGlWLAsjTrM8ahRSmRuqqmifNlVoho5OvFqH6xrGXG49ZLtL SF7vvs7Ca/QdPIKwU7sC1JzT1toSGm1mPRnZdxGxvs6VBvctlb1eIPuP3DmjlqLm5WkK zl4oiRG84BLzCmAX2m1PckmxRy4MTtf2GUkhdvA093+42HGl/SOZ/vjd7q2dk/2X49RY zYYznC6Xgvf7cIWkOUB9CBPZK80ojO8SL9KuzmtZPg/K01XInb2WwAUk/a3YQ+P6nxoC Kn5g== X-Gm-Message-State: AOAM531zgrp+Zd1v6kt3kGbhWlsDcwAIp7GHFMpYRu55FrOEQzFnpbQS TMgdVOAbwBz4EQ5M3begqAbmfpyVI0W34dJY X-Google-Smtp-Source: ABdhPJzXWwhlWwbxmmG6LPNWEvjY+8o2ReUqFEWgQoK28xbewYYtgit/aleI8mc2CxxeegH+9RuR7Q== X-Received: by 2002:a5d:4609:: with SMTP id t9mr3506603wrq.551.1642069536159; Thu, 13 Jan 2022 02:25:36 -0800 (PST) Received: from naush-laptop.pitowers.org ([2a00:1098:3142:14:194e:c2b:3339:eb51]) by smtp.gmail.com with ESMTPSA id s22sm6757855wmc.1.2022.01.13.02.25.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Jan 2022 02:25:35 -0800 (PST) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Date: Thu, 13 Jan 2022 10:25:29 +0000 Message-Id: <20220113102529.3163441-3-naush@raspberrypi.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220113102529.3163441-1-naush@raspberrypi.com> References: <20220113102529.3163441-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC v1 2/2] pipeline: raspberrypi: Use MediaDevice::enumerateMediaWalks() 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" Use the new MediaDevice::enumerateMediaWalks() helper to enumerate the Unicam MediaDevice, replacing the existing enumerateVideoDevices() function. Signed-off-by: Naushir Patuck Reviewed-by: Kieran Bingham --- .../pipeline/raspberrypi/raspberrypi.cpp | 142 ++++-------------- 1 file changed, 32 insertions(+), 110 deletions(-) diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 5ee713fe66a6..36f3acf1393a 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -194,8 +194,6 @@ public: int loadIPA(ipa::RPi::SensorConfig *sensorConfig); int configureIPA(const CameraConfiguration *config); - void enumerateVideoDevices(MediaLink *link); - void statsMetadataComplete(uint32_t bufferId, const ControlList &controls); void runIsp(uint32_t bufferId); void embeddedComplete(uint32_t bufferId); @@ -326,7 +324,7 @@ private: return static_cast(camera->_d()); } - int registerCamera(MediaDevice *unicam, MediaDevice *isp, MediaEntity *sensorEntity); + int registerCamera(MediaDevice *unicam, MediaDevice *isp, const MediaDevice::MediaWalk &walk); int queueAllBuffers(Camera *camera); int prepareBuffers(Camera *camera); void freeBuffers(Camera *camera); @@ -1111,30 +1109,34 @@ bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator) return false; } + std::vector walks = unicamDevice->enumerateMediaWalks(); + /* * The loop below is used to register multiple cameras behind one or more * video mux devices that are attached to a particular Unicam instance. * Obviously these cameras cannot be used simultaneously. */ unsigned int numCameras = 0; - for (MediaEntity *entity : unicamDevice->entities()) { - if (entity->function() != MEDIA_ENT_F_CAM_SENSOR) - continue; + for (const MediaDevice::MediaWalk &walk : walks) { + MediaEntity *sensorEntity = walk.front().entity; - int ret = registerCamera(unicamDevice, ispDevice, entity); - if (ret) + int ret = registerCamera(unicamDevice, ispDevice, walk); + if (ret) { LOG(RPI, Error) << "Failed to register camera " - << entity->name() << ": " << ret; - else - numCameras++; + << sensorEntity->name() << ": " << ret; + continue; + } + + numCameras++; } return !!numCameras; } -int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, MediaEntity *sensorEntity) +int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, const MediaDevice::MediaWalk &walk) { std::unique_ptr data = std::make_unique(this); + MediaEntity *sensorEntity = walk.front().entity; if (!data->dmaHeap_.isValid()) return -ENOMEM; @@ -1180,12 +1182,24 @@ int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, Me if (data->sensor_->init()) return -EINVAL; - /* - * Enumerate all the Video Mux/Bridge devices across the sensor -> unicam - * chain. There may be a cascade of devices in this chain! - */ - MediaLink *link = sensorEntity->getPadByIndex(0)->links()[0]; - data->enumerateVideoDevices(link); + /* See if we can auto configure this MC graph. */ + for (auto it = walk.begin() + 1; it < walk.end() - 1; ++it) { + MediaEntity *entity = it->entity; + MediaLink *sinkLink = it->sinkLink; + + /* We only deal with Video Mux and Bridge devices in cascade. */ + if (entity->function() != MEDIA_ENT_F_VID_MUX && + entity->function() != MEDIA_ENT_F_VID_IF_BRIDGE) { + data->bridgeDevices_.clear(); + break; + } + + LOG(RPI, Info) << "Found video mux/bridge device " << entity->name() + << " linked to sink pad " << sinkLink->sink()->index(); + + data->bridgeDevices_.emplace_back(std::make_unique(entity), sinkLink); + data->bridgeDevices_.back().first->open(); + } data->sensorFormats_ = populateSensorFormats(data->sensor_); @@ -1545,98 +1559,6 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config) return 0; } -/* - * enumerateVideoDevices() iterates over the Media Controller topology, starting - * at the sensor and finishing at Unicam. For each sensor, RPiCameraData stores - * a unique list of any intermediate video mux or bridge devices connected in a - * cascade, together with the entity to entity link. - * - * Entity pad configuration and link enabling happens at the end of configure(). - * We first disable all pad links on each entity device in the chain, and then - * selectively enabling the specific links to link sensor to Unicam across all - * intermediate muxes and bridges. - * - * In the cascaded topology below, if Sensor1 is used, the Mux2 -> Mux1 link - * will be disabled, and Sensor1 -> Mux1 -> Unicam links enabled. Alternatively, - * if Sensor3 is used, the Sensor2 -> Mux2 and Sensor1 -> Mux1 links are disabled, - * and Sensor3 -> Mux2 -> Mux1 -> Unicam links are enabled. All other links will - * remain unchanged. - * - * +----------+ - * | Unicam | - * +-----^----+ - * | - * +---+---+ - * | Mux1 <-------+ - * +--^----+ | - * | | - * +-----+---+ +---+---+ - * | Sensor1 | | Mux2 |<--+ - * +---------+ +-^-----+ | - * | | - * +-------+-+ +---+-----+ - * | Sensor2 | | Sensor3 | - * +---------+ +---------+ - */ -void RPiCameraData::enumerateVideoDevices(MediaLink *link) -{ - const MediaPad *sinkPad = link->sink(); - const MediaEntity *entity = sinkPad->entity(); - bool unicamFound = false; - - /* We only deal with Video Mux and Bridge devices in cascade. */ - if (entity->function() != MEDIA_ENT_F_VID_MUX && - entity->function() != MEDIA_ENT_F_VID_IF_BRIDGE) - return; - - /* Find the source pad for this Video Mux or Bridge device. */ - const MediaPad *sourcePad = nullptr; - for (const MediaPad *pad : entity->pads()) { - if (pad->flags() & MEDIA_PAD_FL_SOURCE) { - /* - * We can only deal with devices that have a single source - * pad. If this device has multiple source pads, ignore it - * and this branch in the cascade. - */ - if (sourcePad) - return; - - sourcePad = pad; - } - } - - LOG(RPI, Debug) << "Found video mux device " << entity->name() - << " linked to sink pad " << sinkPad->index(); - - bridgeDevices_.emplace_back(std::make_unique(entity), link); - bridgeDevices_.back().first->open(); - - /* - * Iterate through all the sink pad links down the cascade to find any - * other Video Mux and Bridge devices. - */ - for (MediaLink *l : sourcePad->links()) { - enumerateVideoDevices(l); - /* Once we reach the Unicam entity, we are done. */ - if (l->sink()->entity()->name() == "unicam-image") { - unicamFound = true; - break; - } - } - - /* This identifies the end of our entity enumeration recursion. */ - if (link->source()->entity()->function() == MEDIA_ENT_F_CAM_SENSOR) { - /* - * If Unicam is not at the end of this cascade, we cannot configure - * this topology automatically, so remove all entity references. - */ - if (!unicamFound) { - LOG(RPI, Warning) << "Cannot automatically configure this MC topology!"; - bridgeDevices_.clear(); - } - } -} - void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &controls) { if (state_ == State::Stopped)