[libcamera-devel] [RFC v1 1/2] libcamera: media_device: Add enumerateMediaWalks() helper
Naushir Patuck
naush at raspberrypi.com
Thu Jan 13 11:25:28 CET 2022
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 <naush at raspberrypi.com>
---
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<EntityParams>;
+
MediaDevice(const std::string &deviceNode);
~MediaDevice();
@@ -47,6 +54,8 @@ public:
const std::vector<MediaEntity *> &entities() const { return entities_; }
MediaEntity *getEntityByName(const std::string &name) const;
+ std::vector<MediaWalk> 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<MediaWalk> *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::MediaWalk> MediaDevice::enumerateMediaWalks() const
+{
+ std::vector<MediaWalk> 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<MediaWalk> *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 */
--
2.25.1
More information about the libcamera-devel
mailing list