[libcamera-devel] [RFC v1 2/2] pipeline: raspberrypi: Use MediaDevice::enumerateMediaWalks()
Kieran Bingham
kieran.bingham at ideasonboard.com
Tue Feb 1 01:22:26 CET 2022
Quoting Naushir Patuck (2022-01-13 10:25:29)
> Use the new MediaDevice::enumerateMediaWalks() helper to enumerate the Unicam
> MediaDevice, replacing the existing enumerateVideoDevices() function.
>
> Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
> ---
> .../pipeline/raspberrypi/raspberrypi.cpp | 142 ++++--------------
> 1 file changed, 32 insertions(+), 110 deletions(-)
>
> diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> index 5ee713fe66a6..36f3acf1393a 100644
> --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> @@ -194,8 +194,6 @@ public:
> int loadIPA(ipa::RPi::SensorConfig *sensorConfig);
> int configureIPA(const CameraConfiguration *config);
>
> - void enumerateVideoDevices(MediaLink *link);
> -
> void statsMetadataComplete(uint32_t bufferId, const ControlList &controls);
> void runIsp(uint32_t bufferId);
> void embeddedComplete(uint32_t bufferId);
> @@ -326,7 +324,7 @@ private:
> return static_cast<RPiCameraData *>(camera->_d());
> }
>
> - int registerCamera(MediaDevice *unicam, MediaDevice *isp, MediaEntity *sensorEntity);
> + int registerCamera(MediaDevice *unicam, MediaDevice *isp, const MediaDevice::MediaWalk &walk);
> int queueAllBuffers(Camera *camera);
> int prepareBuffers(Camera *camera);
> void freeBuffers(Camera *camera);
> @@ -1111,30 +1109,34 @@ bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator)
> return false;
> }
>
> + std::vector<MediaDevice::MediaWalk> walks = unicamDevice->enumerateMediaWalks();
> +
> /*
> * The loop below is used to register multiple cameras behind one or more
> * video mux devices that are attached to a particular Unicam instance.
> * Obviously these cameras cannot be used simultaneously.
> */
> unsigned int numCameras = 0;
> - for (MediaEntity *entity : unicamDevice->entities()) {
> - if (entity->function() != MEDIA_ENT_F_CAM_SENSOR)
> - continue;
> + for (const MediaDevice::MediaWalk &walk : walks) {
> + MediaEntity *sensorEntity = walk.front().entity;
>
> - int ret = registerCamera(unicamDevice, ispDevice, entity);
> - if (ret)
> + int ret = registerCamera(unicamDevice, ispDevice, walk);
> + if (ret) {
> LOG(RPI, Error) << "Failed to register camera "
> - << entity->name() << ": " << ret;
> - else
> - numCameras++;
> + << sensorEntity->name() << ": " << ret;
> + continue;
> + }
> +
> + numCameras++;
> }
>
> return !!numCameras;
> }
>
> -int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, MediaEntity *sensorEntity)
> +int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, const MediaDevice::MediaWalk &walk)
> {
> std::unique_ptr<RPiCameraData> data = std::make_unique<RPiCameraData>(this);
> + MediaEntity *sensorEntity = walk.front().entity;
>
> if (!data->dmaHeap_.isValid())
> return -ENOMEM;
> @@ -1180,12 +1182,24 @@ 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
> - * chain. There may be a cascade of devices in this chain!
> - */
> - MediaLink *link = sensorEntity->getPadByIndex(0)->links()[0];
> - data->enumerateVideoDevices(link);
> + /* See if we can auto configure this MC graph. */
> + for (auto it = walk.begin() + 1; it < walk.end() - 1; ++it) {
> + MediaEntity *entity = it->entity;
> + MediaLink *sinkLink = it->sinkLink;
> +
> + /* 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) {
> + data->bridgeDevices_.clear();
> + break;
> + }
> +
> + LOG(RPI, Info) << "Found video mux/bridge device " << entity->name()
> + << " linked to sink pad " << sinkLink->sink()->index();
I hope that's not too verbose, so it sounds ok for Info for now.
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> +
> + data->bridgeDevices_.emplace_back(std::make_unique<V4L2Subdevice>(entity), sinkLink);
> + data->bridgeDevices_.back().first->open();
> + }
>
> data->sensorFormats_ = populateSensorFormats(data->sensor_);
>
> @@ -1545,98 +1559,6 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)
> 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 disable 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 RPiCameraData::enumerateVideoDevices(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;
> -
> - /* Find the source pad for this Video Mux or Bridge device. */
> - const MediaPad *sourcePad = nullptr;
> - for (const MediaPad *pad : entity->pads()) {
> - if (pad->flags() & MEDIA_PAD_FL_SOURCE) {
> - /*
> - * We can only deal with devices that have a single source
> - * pad. If this device has multiple source pads, ignore it
> - * and this branch in the cascade.
> - */
> - if (sourcePad)
> - return;
> -
> - sourcePad = pad;
> - }
> - }
> -
> - LOG(RPI, Debug) << "Found video mux device " << entity->name()
> - << " linked to sink pad " << sinkPad->index();
> -
> - bridgeDevices_.emplace_back(std::make_unique<V4L2Subdevice>(entity), link);
> - bridgeDevices_.back().first->open();
> -
> - /*
> - * Iterate through all the sink pad links down the cascade to find any
> - * other Video Mux and Bridge devices.
> - */
> - for (MediaLink *l : sourcePad->links()) {
> - enumerateVideoDevices(l);
> - /* Once we reach the Unicam entity, we are done. */
> - if (l->sink()->entity()->name() == "unicam-image") {
> - unicamFound = true;
> - break;
> - }
> - }
> -
> - /* 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!";
> - bridgeDevices_.clear();
> - }
> - }
> -}
> -
> void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &controls)
> {
> if (state_ == State::Stopped)
> --
> 2.25.1
>
More information about the libcamera-devel
mailing list