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 */