[libcamera-devel,RFC,v1,2/2] pipeline: raspberrypi: Use MediaDevice::enumerateMediaWalks()
diff mbox series

Message ID 20220113102529.3163441-3-naush@raspberrypi.com
State New
Headers show
Series
  • MediaDevice enumeration helper
Related show

Commit Message

Naushir Patuck Jan. 13, 2022, 10:25 a.m. UTC
Use the new MediaDevice::enumerateMediaWalks() helper to enumerate the Unicam
MediaDevice, replacing the existing enumerateVideoDevices() function.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 .../pipeline/raspberrypi/raspberrypi.cpp      | 142 ++++--------------
 1 file changed, 32 insertions(+), 110 deletions(-)

Comments

Kieran Bingham Feb. 1, 2022, 12:22 a.m. UTC | #1
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@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@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
>

Patch
diff mbox series

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();
+
+		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)