summaryrefslogtreecommitdiff
path: root/src/libcamera/pipeline/simple
diff options
context:
space:
mode:
authorPhi-Bang Nguyen <pnguyen@baylibre.com>2021-04-02 17:00:49 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-08-03 17:44:34 +0300
commit3ee52c167f903b12563861797946937989c3c1ab (patch)
tree78fec8c850a4e68276efc0c9707f9745fc990063 /src/libcamera/pipeline/simple
parentbd25118dec87c2ad5a3463ec89df327255ab9422 (diff)
libcamera: pipeline: simple: Walk pipeline using subdev internal routing
When traversing the media graph to discover a pipeline from the camera sensor to a video node, all sink-to-source paths inside subdevs are considered. This can lead to invalid paths being followed, when a subdev has restrictions on its internal routing. The V4L2 API supports exposing subdev internal routing to userspace. Make use of this feature, when implemented by a subdev, to restrict the internal paths to the currently active routes. If a subdev doesn't implement the internal routing operations, all source pads are considered, as done today. This change is needed to properly support multiple sensors with devices such as the NXP i.MX8 ISI or the MediaTek i350 and i500 SENINF. Support for changing routes dynamically will be added later when required. Signed-off-by: Phi-Bang Nguyen <pnguyen@baylibre.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Tested-by: Jacopo Mondi <jacopo@jmondi.org>
Diffstat (limited to 'src/libcamera/pipeline/simple')
-rw-r--r--src/libcamera/pipeline/simple/simple.cpp73
1 files changed, 67 insertions, 6 deletions
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 3ca7fdff..069333c6 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -100,8 +100,14 @@ LOG_DEFINE_CATEGORY(SimplePipeline)
*
* During the breadth-first search, the pipeline is traversed from entity to
* entity, by following media graph links from source to sink, starting at the
- * camera sensor. When reaching an entity (on its sink side), all its source
- * pads are considered to continue the graph traversal.
+ * camera sensor.
+ *
+ * When reaching an entity (on its sink side), if the entity is a V4L2 subdev
+ * that supports the streams API, the subdev internal routes are followed to
+ * find the connected source pads. Otherwise all of the entity's source pads
+ * are considered to continue the graph traversal. The pipeline handler
+ * currently considers the default internal routes only and doesn't attempt to
+ * setup custom routes. This can be extended if needed.
*
* The shortest path between the camera sensor and a video node is stored in
* SimpleCameraData::entities_ as a list of SimpleCameraData::Entity structures,
@@ -261,6 +267,7 @@ public:
private:
void tryPipeline(unsigned int code, const Size &size);
+ static std::vector<const MediaPad *> routedSourcePads(MediaPad *sink);
void converterInputDone(FrameBuffer *buffer);
void converterOutputDone(FrameBuffer *buffer);
@@ -387,12 +394,29 @@ SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,
break;
}
- /* The actual breadth-first search algorithm. */
visited.insert(entity);
- for (MediaPad *pad : entity->pads()) {
- if (!(pad->flags() & MEDIA_PAD_FL_SOURCE))
- continue;
+ /*
+ * Add direct downstream entities to the search queue. If the
+ * current entity supports the subdev internal routing API,
+ * restrict the search to downstream entities reachable through
+ * active routes.
+ */
+
+ std::vector<const MediaPad *> pads;
+
+ if (sinkPad)
+ pads = routedSourcePads(sinkPad);
+
+ if (pads.empty()) {
+ for (const MediaPad *pad : entity->pads()) {
+ if (!(pad->flags() & MEDIA_PAD_FL_SOURCE))
+ continue;
+ pads.push_back(pad);
+ }
+ }
+
+ for (const MediaPad *pad : pads) {
for (MediaLink *link : pad->links()) {
MediaEntity *next = link->sink()->entity();
if (visited.find(next) == visited.end()) {
@@ -782,6 +806,43 @@ void SimpleCameraData::converterOutputDone(FrameBuffer *buffer)
pipe->completeRequest(request);
}
+/* Retrieve all source pads connected to a sink pad through active routes. */
+std::vector<const MediaPad *> SimpleCameraData::routedSourcePads(MediaPad *sink)
+{
+ MediaEntity *entity = sink->entity();
+ std::unique_ptr<V4L2Subdevice> subdev =
+ std::make_unique<V4L2Subdevice>(entity);
+
+ int ret = subdev->open();
+ if (ret < 0)
+ return {};
+
+ V4L2Subdevice::Routing routing = {};
+ ret = subdev->getRouting(&routing, V4L2Subdevice::ActiveFormat);
+ if (ret < 0)
+ return {};
+
+ std::vector<const MediaPad *> pads;
+
+ for (const struct v4l2_subdev_route &route : routing) {
+ if (sink->index() != route.sink_pad ||
+ !(route.flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
+ continue;
+
+ const MediaPad *pad = entity->getPadByIndex(route.source_pad);
+ if (!pad) {
+ LOG(SimplePipeline, Warning)
+ << "Entity " << entity->name()
+ << " has invalid route source pad "
+ << route.source_pad;
+ }
+
+ pads.push_back(pad);
+ }
+
+ return pads;
+}
+
/* -----------------------------------------------------------------------------
* Camera Configuration
*/