<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 9 Dec 2021 at 13:32, Naushir Patuck <<a href="mailto:naush@raspberrypi.com">naush@raspberrypi.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This change will allow the pipeline handler to enumerate and control Video<br>
Mux or Bridge devices that may be attached between sensors and a particular<br>
Unicam instance. Cascaded mux or bridge devices are also handled.<br>
<br>
A new member function enumerateVideoDevices(), called from registerCamera(), is<br>
used to identify and open all mux and bridge subdevices present in the<br>
sensor -> Unicam link.<br>
<br>
Relevent links are enabled/disabled and pad formats correctly set in configure()<br>
before the camera is started.<br>
<br>
Signed-off-by: Naushir Patuck <<a href="mailto:naush@raspberrypi.com" target="_blank">naush@raspberrypi.com</a>><br>
Reviewed-by: Kieran Bingham <<a href="mailto:kieran.bingham@ideasonboard.com" target="_blank">kieran.bingham@ideasonboard.com</a>><br>
---<br>
 .../pipeline/raspberrypi/raspberrypi.cpp      | 119 ++++++++++++++++++<br>
 1 file changed, 119 insertions(+)<br>
<br>
diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp<br>
index 2a2fb5273eb8..49dbefd8637c 100644<br>
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp<br>
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp<br>
@@ -12,6 +12,7 @@<br>
 #include <mutex><br>
 #include <queue><br>
 #include <unordered_set><br>
+#include <utility><br>
<br>
 #include <libcamera/base/shared_fd.h><br>
 #include <libcamera/base/utils.h><br>
@@ -220,6 +221,11 @@ public:<br>
        std::vector<RPi::Stream *> streams_;<br>
        /* Stores the ids of the buffers mapped in the IPA. */<br>
        std::unordered_set<unsigned int> ipaBuffers_;<br>
+       /*<br>
+        * Stores a cascade of Video Mux or Bridge devices between the sensor and<br>
+        * Unicam together with media link across the entities.<br>
+        */<br>
+       std::vector<std::pair<std::unique_ptr<V4L2Subdevice>, MediaLink *>> bridgeDevices_;<br>
<br>
        /* DMAHEAP allocation helper. */<br>
        RPi::DmaHeap dmaHeap_;<br>
@@ -311,6 +317,7 @@ private:<br>
        }<br>
<br>
        int registerCamera(MediaDevice *unicam, MediaDevice *isp, MediaEntity *sensorEntity);<br>
+       void enumerateVideoDevices(RPiCameraData *data, MediaLink *link);<br>
        int queueAllBuffers(Camera *camera);<br>
        int prepareBuffers(Camera *camera);<br>
        void freeBuffers(Camera *camera);<br>
@@ -868,6 +875,33 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)<br>
         */<br>
        data->properties_.set(properties::ScalerCropMaximum, data->sensorInfo_.analogCrop);<br>
<br>
+       /* Setup the Video Mux/Bridge entities. */<br>
+       for (auto &[device, link] : data->bridgeDevices_) {<br>
+               /* Start by disabling all the sink pad links on the devices in the cascade. */<br>
+               for (const MediaPad *p : device->entity()->pads()) {<br>
+                       if (!(p->flags() & MEDIA_PAD_FL_SINK))<br>
+                               continue;<br>
+<br>
+                       for (MediaLink *l : p->links())<br>
+                               l->setEnabled(false);<br>
+               }<br>
+<br>
+               /* Next, enable the entity -> entity links, and setup the pad format. */<br>
+               link->setEnabled(true);<br>
+               const MediaPad *srcPad = link->sink();<br>
+               ret = device->setFormat(srcPad->index(), &sensorFormat);<br>
+               if (ret) {<br>
+                       LOG(RPI, Error) << "Failed to set format on " << device->entity()->name()<br>
+                                       << " pad " << srcPad->index()<br>
+                                       << " with format  " << format.toString()<br>
+                                       << ": " << ret;<br>
+                       return ret;<br>
+               }<br>
+<br>
+               LOG(RPI, Info) << "Configured media link on device " << device->entity()->name()<br>
+                              << " on pad " << srcPad->index();<br>
+       }<br>
+<br>
        return ret;<br>
 }<br>
<br>
@@ -1098,6 +1132,13 @@ int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, Me<br>
        if (data->sensor_->init())<br>
                return -EINVAL;<br>
<br>
+       /*<br>
+        * Enumerate all the Video Mux/Bridge devices across the sensor -> unicam<br>
+        * link. There may be a cascade of devices in this link!<br>
+        */<br>
+       MediaLink *link = sensorEntity->getPadByIndex(0)->links()[0];<br>
+       enumerateVideoDevices(data.get(), link);<br>
+<br>
        data->sensorFormats_ = populateSensorFormats(data->sensor_);<br>
<br>
        ipa::RPi::SensorConfig sensorConfig;<br>
@@ -1224,6 +1265,84 @@ int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, Me<br>
        return 0;<br>
 }<br>
<br>
+/*<br>
+ * enumerateVideoDevices() iterates over the Media Controller topology, starting<br>
+ * at the sensor and finishing at Unicam. For each sensor, RPiCameraData stores<br>
+ * a unique list of any intermediate video mux or bridge devices connected in a<br>
+ * cascade, together with the entity to entity link.<br>
+ *<br>
+ * Entity pad configuration and link enabling happens at the end of configure().<br>
+ * We first disables all pad links on each entity device in the chain, and then<br>
+ * selectively enabling the specific links to link sensor to Unicam across all<br>
+ * intermediate muxes and bridges.<br>
+ *<br>
+ * In the cascaded topology below, if Sensor1 is used, the Mux2 -> Mux1 link<br>
+ * will be disabled, and Sensor1 -> Mux1 -> Unicam links enabled. Alternatively,<br>
+ * if Sensor3 is used, the Sensor2 -> Mux2 and Sensor1 -> Mux1 links are disabled,<br>
+ * and Sensor3 -> Mux2 -> Mux1 -> Unicam links are enabled. All other links will<br>
+ * remain unchanged.<br>
+ *<br>
+ *  +----------+<br>
+ *  |  Unicam  |<br>
+ *  +-----^----+<br>
+ *        |<br>
+ *    +---+---+<br>
+ *    |  Mux1 <-------+<br>
+ *    +--^----+       |<br>
+ *       |            |<br>
+ * +-----+---+    +---+---+<br>
+ * | Sensor1 |    |  Mux2 |<--+<br>
+ * +---------+    +-^-----+   |<br>
+ *                  |         |<br>
+ *          +-------+-+   +---+-----+<br>
+ *          | Sensor2 |   | Sensor3 |<br>
+ *          +---------+   +---------+<br>
+ */<br>
+void PipelineHandlerRPi::enumerateVideoDevices(RPiCameraData *data, MediaLink *link)<br>
+{<br>
+       const MediaPad *sinkPad = link->sink();<br>
+       const MediaEntity *entity = sinkPad->entity();<br>
+       bool unicamFound = false;<br>
+<br>
+       /* We only deal with Video Mux and Bridge devices in cascade. */<br>
+       if (entity->function() != MEDIA_ENT_F_VID_MUX &&<br>
+           entity->function() != MEDIA_ENT_F_VID_IF_BRIDGE)<br>
+               return;<br></blockquote><div><br></div><div>I wonder if I should have a test here to ensure that the entity should only</div><div>ever have one source pad? If not, return without traversing down this</div><div>cascade.  Or are Video Mux and Bridge devices guaranteed to have</div><div>only one source pad?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+       LOG(RPI, Info) << "Found video mux device " << entity->name()<br>
+                      << " linked to sink pad " << sinkPad->index();<br>
+<br>
+       data->bridgeDevices_.emplace_back(std::make_unique<V4L2Subdevice>(entity), link);<br>
+       data->bridgeDevices_.back().first->open();<br>
+<br>
+       for (const MediaPad *pad : entity->pads()) {<br>
+               /*<br>
+                * Iterate through all the sink pads down the cascade to find any<br>
+                * other Video Mux and Bridge devices.<br>
+                */<br>
+               if (!(pad->flags() & MEDIA_PAD_FL_SOURCE))<br>
+                       continue;<br>
+<br>
+               for (MediaLink *l : pad->links()) {<br>
+                       enumerateVideoDevices(data, l);<br>
+                       if (l->sink()->entity()->name() == "unicam-image")<br>
+                               unicamFound = true;<br>
+               }<br>
+       }<br>
+<br>
+       /* This identifies the end of our entity enumeration recursion. */<br>
+       if (link->source()->entity()->function() == MEDIA_ENT_F_CAM_SENSOR) {<br>
+               /*<br>
+               * If Unicam is not at the end of this cascade, we cannot configure<br>
+               * this topology automatically, so remove all entity references.<br>
+               */<br>
+               if (!unicamFound) {<br>
+                       LOG(RPI, Warning) << "Cannot automatically configure this MC topology!";<br>
+                       data->bridgeDevices_.clear();<br>
+               }<br>
+       }<br>
+}<br>
+<br>
 int PipelineHandlerRPi::queueAllBuffers(Camera *camera)<br>
 {<br>
        RPiCameraData *data = cameraData(camera);<br>
-- <br>
2.25.1<br>
<br>
</blockquote></div></div>