[libcamera-devel] [RFC v1 2/2] pipeline: raspberrypi: Use MediaDevice::enumerateMediaWalks()
Naushir Patuck
naush at raspberrypi.com
Thu Jan 13 11:25:29 CET 2022
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();
+
+ 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