[libcamera-devel] [PATCH v3 2/2] pipeline: raspberrypi: Add support for Video Mux and Bridge devices

Kieran Bingham kieran.bingham at ideasonboard.com
Fri Dec 10 15:56:55 CET 2021


Quoting Naushir Patuck (2021-12-09 15:17:36)
> On Thu, 9 Dec 2021 at 13:32, Naushir Patuck <naush at raspberrypi.com> wrote:
> 
> > This change will allow the pipeline handler to enumerate and control Video
> > Mux or Bridge devices that may be attached between sensors and a particular
> > Unicam instance. Cascaded mux or bridge devices are also handled.
> >
> > A new member function enumerateVideoDevices(), called from
> > registerCamera(), is
> > used to identify and open all mux and bridge subdevices present in the
> > sensor -> Unicam link.
> >
> > Relevent links are enabled/disabled and pad formats correctly set in
> > configure()
> > before the camera is started.
> >
> > Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
> > Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> > ---
> >  .../pipeline/raspberrypi/raspberrypi.cpp      | 119 ++++++++++++++++++
> >  1 file changed, 119 insertions(+)
> >
> > diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > index 2a2fb5273eb8..49dbefd8637c 100644
> > --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > @@ -12,6 +12,7 @@
> >  #include <mutex>
> >  #include <queue>
> >  #include <unordered_set>
> > +#include <utility>
> >
> >  #include <libcamera/base/shared_fd.h>
> >  #include <libcamera/base/utils.h>
> > @@ -220,6 +221,11 @@ public:
> >         std::vector<RPi::Stream *> streams_;
> >         /* Stores the ids of the buffers mapped in the IPA. */
> >         std::unordered_set<unsigned int> ipaBuffers_;
> > +       /*
> > +        * Stores a cascade of Video Mux or Bridge devices between the
> > sensor and
> > +        * Unicam together with media link across the entities.
> > +        */
> > +       std::vector<std::pair<std::unique_ptr<V4L2Subdevice>, MediaLink
> > *>> bridgeDevices_;
> >
> >         /* DMAHEAP allocation helper. */
> >         RPi::DmaHeap dmaHeap_;
> > @@ -311,6 +317,7 @@ private:
> >         }
> >
> >         int registerCamera(MediaDevice *unicam, MediaDevice *isp,
> > MediaEntity *sensorEntity);
> > +       void enumerateVideoDevices(RPiCameraData *data, MediaLink *link);
> >         int queueAllBuffers(Camera *camera);
> >         int prepareBuffers(Camera *camera);
> >         void freeBuffers(Camera *camera);
> > @@ -868,6 +875,33 @@ int PipelineHandlerRPi::configure(Camera *camera,
> > CameraConfiguration *config)
> >          */
> >         data->properties_.set(properties::ScalerCropMaximum,
> > data->sensorInfo_.analogCrop);
> >
> > +       /* Setup the Video Mux/Bridge entities. */
> > +       for (auto &[device, link] : data->bridgeDevices_) {
> > +               /* Start by disabling all the sink pad links on the
> > devices in the cascade. */
> > +               for (const MediaPad *p : device->entity()->pads()) {
> > +                       if (!(p->flags() & MEDIA_PAD_FL_SINK))
> > +                               continue;
> > +
> > +                       for (MediaLink *l : p->links())
> > +                               l->setEnabled(false);
> > +               }
> > +
> > +               /* Next, enable the entity -> entity links, and setup the
> > pad format. */
> > +               link->setEnabled(true);
> > +               const MediaPad *srcPad = link->sink();
> > +               ret = device->setFormat(srcPad->index(), &sensorFormat);
> > +               if (ret) {
> > +                       LOG(RPI, Error) << "Failed to set format on " <<
> > device->entity()->name()
> > +                                       << " pad " << srcPad->index()
> > +                                       << " with format  " <<
> > format.toString()
> > +                                       << ": " << ret;
> > +                       return ret;
> > +               }
> > +
> > +               LOG(RPI, Info) << "Configured media link on device " <<
> > device->entity()->name()
> > +                              << " on pad " << srcPad->index();
> > +       }
> > +
> >         return ret;
> >  }
> >
> > @@ -1098,6 +1132,13 @@ 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
> > +        * link. There may be a cascade of devices in this link!
> > +        */
> > +       MediaLink *link = sensorEntity->getPadByIndex(0)->links()[0];
> > +       enumerateVideoDevices(data.get(), link);
> > +
> >         data->sensorFormats_ = populateSensorFormats(data->sensor_);
> >
> >         ipa::RPi::SensorConfig sensorConfig;
> > @@ -1224,6 +1265,84 @@ int PipelineHandlerRPi::registerCamera(MediaDevice
> > *unicam, MediaDevice *isp, Me
> >         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 disables 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 PipelineHandlerRPi::enumerateVideoDevices(RPiCameraData *data,
> > 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;
> >
> 
> I wonder if I should have a test here to ensure that the entity should only
> ever have one source pad? If not, return without traversing down this
> cascade.  Or are Video Mux and Bridge devices guaranteed to have
> only one source pad?

I don't think it's essential at this stage, as it's not particularly
supported but ... <looks down at diagram of hardware in front of him>
I could imagine a video mux that acts as a crossbar being defined
sometime...

I suspect as a sanity check to validate that it only parses devices it
can handle, a check with a warning print would help any future developer
that might decide to try to implement something a bit more complex...

--
Kieran

> > +
> > +       LOG(RPI, Info) << "Found video mux device " << entity->name()
> > +                      << " linked to sink pad " << sinkPad->index();
> > +
> > +
> >  data->bridgeDevices_.emplace_back(std::make_unique<V4L2Subdevice>(entity),
> > link);
> > +       data->bridgeDevices_.back().first->open();
> > +
> > +       for (const MediaPad *pad : entity->pads()) {
> > +               /*
> > +                * Iterate through all the sink pads down the cascade to
> > find any
> > +                * other Video Mux and Bridge devices.
> > +                */
> > +               if (!(pad->flags() & MEDIA_PAD_FL_SOURCE))
> > +                       continue;
> > +
> > +               for (MediaLink *l : pad->links()) {
> > +                       enumerateVideoDevices(data, l);
> > +                       if (l->sink()->entity()->name() == "unicam-image")
> > +                               unicamFound = true;
> > +               }
> > +       }
> > +
> > +       /* 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!";
> > +                       data->bridgeDevices_.clear();
> > +               }
> > +       }
> > +}
> > +
> >  int PipelineHandlerRPi::queueAllBuffers(Camera *camera)
> >  {
> >         RPiCameraData *data = cameraData(camera);
> > --
> > 2.25.1
> >
> >


More information about the libcamera-devel mailing list