[RFC,v1,17/20] pipeline: rpi: Implement survey() and createCamera()
diff mbox series

Message ID 20260918080734.1228227-18-naush@raspberrypi.com
State New
Headers show
Series
  • libcamera: New enumeration API
Related show

Commit Message

Naushir Patuck Sept. 18, 2026, 7:59 a.m. UTC
Implement survey() and createCamera() for the vc4 and pisp platforms.
survey() pairs each frontend with a backend in match order and reports a
descriptor for every sensor entity on the frontend. The camera ID comes
from sysfs and the model from the entity name, so no device is acquired
or opened.

createCamera() creates a single camera from a descriptor. It acquires
the media devices unless this pipeline handler instance already holds
them, so that cameras behind a shared frontend end up in the same
instance.

The vc4 and pisp match() implementations are no longer used and removed.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 .../pipeline/rpi/common/pipeline_base.cpp     | 99 +++++++++++++++++++
 .../pipeline/rpi/common/pipeline_base.h       |  4 +
 src/libcamera/pipeline/rpi/pisp/pisp.cpp      | 90 -----------------
 src/libcamera/pipeline/rpi/vc4/vc4.cpp        | 57 -----------
 4 files changed, 103 insertions(+), 147 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
index 71f3f26a4ffe..57188b8343e3 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
@@ -15,11 +15,15 @@ 
 #include <libcamera/base/file.h>
 #include <libcamera/base/utils.h>
 
+#include <libcamera/camera_descriptor.h>
 #include <libcamera/formats.h>
 #include <libcamera/logging.h>
 #include <libcamera/property_ids.h>
 
+#include "libcamera/internal/camera_descriptor.h"
 #include "libcamera/internal/camera_lens.h"
+#include "libcamera/internal/camera_sensor.h"
+#include "libcamera/internal/device_enumerator.h"
 #include "libcamera/internal/v4l2_subdevice.h"
 #include "libcamera/internal/yaml_parser.h"
 
@@ -793,6 +797,101 @@  int PipelineHandlerBase::queueRequestDevice(Camera *camera, Request *request)
 	return 0;
 }
 
+int PipelineHandlerBase::survey(const DeviceEnumerator *enumerator,
+				std::vector<std::shared_ptr<CameraDescriptor>> *descriptors)
+{
+	/*
+	 * Pair each available frontend instance with a backend instance, in
+	 * the same order as match() acquires them, and report a descriptor
+	 * for every sensor entity attached to the frontend. No device is
+	 * acquired or opened.
+	 */
+	std::vector<std::shared_ptr<MediaDevice>> frontends =
+		enumerator->searchAll(frontendMatch());
+	std::vector<std::shared_ptr<MediaDevice>> backends =
+		enumerator->searchAll(backendMatch());
+
+	for (unsigned int i = 0; i < frontends.size() && i < backends.size(); i++) {
+		MediaDevice *frontendDevice = frontends[i].get();
+		MediaDevice *backendDevice = backends[i].get();
+
+		if (!platformSupported(frontendDevice, backendDevice))
+			continue;
+
+		for (MediaEntity *entity : frontendDevice->entities()) {
+			if (entity->function() != MEDIA_ENT_F_CAM_SENSOR)
+				continue;
+
+			std::string id = CameraSensorFactoryBase::generateId(entity);
+			if (id.empty()) {
+				LOG(RPI, Warning)
+					<< "Failed to generate an ID for sensor "
+					<< entity->name();
+				continue;
+			}
+
+			std::string model =
+				V4L2Subdevice::modelFromEntityName(entity->name());
+
+			auto data = std::make_unique<CameraDescriptor::Private>();
+			data->id_ = std::move(id);
+			data->properties_.set(properties::Model,
+					      utils::toAscii(model));
+			data->mediaDevices_ = { frontends[i], backends[i] };
+			data->entityName_ = entity->name();
+
+			descriptors->push_back(CameraDescriptor::create(std::move(data)));
+		}
+	}
+
+	return 0;
+}
+
+int PipelineHandlerBase::createCamera(const CameraDescriptor *descriptor)
+{
+	const CameraDescriptor::Private *data = descriptor->_d();
+
+	if (data->mediaDevices_.size() != 2)
+		return -EINVAL;
+
+	const std::shared_ptr<MediaDevice> &frontendDevice = data->mediaDevices_[0];
+	const std::shared_ptr<MediaDevice> &backendDevice = data->mediaDevices_[1];
+
+	/*
+	 * Acquire the media devices, unless this pipeline handler instance
+	 * already holds them because a camera behind the same frontend has
+	 * been created before.
+	 */
+	if (!usesMediaDevice(frontendDevice.get())) {
+		if (!acquireMediaDevice(frontendDevice))
+			return -EBUSY;
+		if (!acquireMediaDevice(backendDevice))
+			return -EBUSY;
+	}
+
+	MediaEntity *sensorEntity = nullptr;
+	for (MediaEntity *entity : frontendDevice->entities()) {
+		if (entity->name() == data->entityName_) {
+			sensorEntity = entity;
+			break;
+		}
+	}
+
+	if (!sensorEntity) {
+		LOG(RPI, Error) << "Sensor entity '" << data->entityName_
+				<< "' not found";
+		return -ENODEV;
+	}
+
+	std::unique_ptr<RPi::CameraData> cameraData =
+		allocateCameraData(frontendDevice.get(), backendDevice.get());
+	if (!cameraData)
+		return -EINVAL;
+
+	return registerCamera(cameraData, frontendDevice, frontendLinkName(),
+			      backendDevice, sensorEntity);
+}
+
 int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &cameraData,
 					std::shared_ptr<MediaDevice> frontend,
 					const std::string &frontendName,
diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h
index 16c509d6a769..6cc1684c74b0 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.h
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h
@@ -223,6 +223,10 @@  public:
 						   const V4L2SubdeviceFormat &format,
 						   BayerFormat::Packing packingReq);
 
+	int survey(const DeviceEnumerator *enumerator,
+		   std::vector<std::shared_ptr<CameraDescriptor>> *descriptors) override;
+	int createCamera(const CameraDescriptor *descriptor) override;
+
 	std::unique_ptr<CameraConfiguration>
 	generateConfiguration(Camera *camera, std::span<const StreamRole> roles) override;
 	int configure(Camera *camera, CameraConfiguration *config) override;
diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp
index 34de291f4092..221e058222ea 100644
--- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp
+++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp
@@ -861,8 +861,6 @@  public:
 	{
 	}
 
-	bool match(DeviceEnumerator *enumerator) override;
-
 private:
 	PiSPCameraData *cameraData(Camera *camera)
 	{
@@ -944,94 +942,6 @@  PipelineHandlerPiSP::allocateCameraData(MediaDevice *frontend, MediaDevice *back
 	return cameraData;
 }
 
-bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)
-{
-	constexpr unsigned int numCfeDevices = 2;
-
-	/*
-	 * Loop over all CFE instances, but return out once a match is found.
-	 * This is to ensure we correctly enumerate the camera when an instance
-	 * of the CFE has registered with media controller, but has not registered
-	 * device nodes due to a sensor subdevice failure.
-	 */
-	for (unsigned int i = 0; i < numCfeDevices; i++) {
-		DeviceMatch cfe("rp1-cfe");
-		cfe.add("rp1-cfe-fe-image0");
-		cfe.add("rp1-cfe-fe-stats");
-		cfe.add("rp1-cfe-fe-config");
-		std::shared_ptr<MediaDevice> cfeDevice = acquireMediaDevice(enumerator, cfe);
-
-		if (!cfeDevice) {
-			LOG(RPI, Debug) << "Unable to acquire a CFE instance";
-			break;
-		}
-
-		DeviceMatch isp("pispbe");
-		isp.add("pispbe-input");
-		isp.add("pispbe-config");
-		isp.add("pispbe-output0");
-		isp.add("pispbe-output1");
-		isp.add("pispbe-tdn_output");
-		isp.add("pispbe-tdn_input");
-		isp.add("pispbe-stitch_output");
-		isp.add("pispbe-stitch_input");
-		std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);
-
-		if (!ispDevice) {
-			LOG(RPI, Debug) << "Unable to acquire ISP instance";
-			break;
-		}
-
-		/*
-		 * The loop below is used to register multiple cameras behind
-		 * one or more video mux devices that are attached to a
-		 * particular CFE instance. Obviously these cameras cannot be
-		 * used simultaneously.
-		 */
-		unsigned int numCameras = 0;
-		for (MediaEntity *entity : cfeDevice->entities()) {
-			if (entity->function() != MEDIA_ENT_F_CAM_SENSOR)
-				continue;
-
-			const libpisp::PiSPVariant &variant =
-				libpisp::get_variant(cfeDevice->hwRevision(),
-						     ispDevice->hwRevision());
-			if (!variant.NumFrontEnds() || !variant.NumBackEnds()) {
-				LOG(RPI, Error) << "Unsupported PiSP variant";
-				break;
-			}
-
-			std::unique_ptr<RPi::CameraData> cameraData =
-				std::make_unique<PiSPCameraData>(this, variant);
-			PiSPCameraData *pisp =
-				static_cast<PiSPCameraData *>(cameraData.get());
-
-			pisp->fe_ = SharedMemObject<FrontEnd>
-					("pisp_frontend", true, pisp->pispVariant_);
-			pisp->be_ = SharedMemObject<BackEnd>
-					("pisp_backend", BackEnd::Config({}), pisp->pispVariant_);
-
-			if (!pisp->fe_.fd().isValid() || !pisp->be_.fd().isValid()) {
-				LOG(RPI, Error) << "Failed to create ISP shared objects";
-				break;
-			}
-
-			int ret = registerCamera(cameraData, cfeDevice, "csi2",
-						 ispDevice, entity);
-			if (ret)
-				LOG(RPI, Error) << "Failed to register camera "
-						<< entity->name() << ": " << ret;
-			else
-				numCameras++;
-		}
-
-		if (numCameras)
-			return true;
-	}
-
-	return false;
-}
-
 int PipelineHandlerPiSP::allocateBuffers(Camera *camera)
 {
 	PiSPCameraData *data = cameraData(camera);
diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
index f6af31072eee..a638fe6de052 100644
--- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
@@ -150,8 +150,6 @@  public:
 	{
 	}
 
-	bool match(DeviceEnumerator *enumerator) override;
-
 private:
 	Vc4CameraData *cameraData(Camera *camera)
 	{
@@ -186,61 +184,6 @@  private:
 			     std::shared_ptr<MediaDevice> isp) override;
 };
 
-bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)
-{
-	constexpr unsigned int numUnicamDevices = 2;
-
-	/*
-	 * Loop over all Unicam instances, but return out once a match is found.
-	 * This is to ensure we correctly enumrate the camera when an instance
-	 * of Unicam has registered with media controller, but has not registered
-	 * device nodes due to a sensor subdevice failure.
-	 */
-	for (unsigned int i = 0; i < numUnicamDevices; i++) {
-		DeviceMatch unicam("unicam");
-		std::shared_ptr<MediaDevice> unicamDevice = acquireMediaDevice(enumerator, unicam);
-
-		if (!unicamDevice) {
-			LOG(RPI, Debug) << "Unable to acquire a Unicam instance";
-			continue;
-		}
-
-		DeviceMatch isp("bcm2835-isp");
-		std::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);
-
-		if (!ispDevice) {
-			LOG(RPI, Debug) << "Unable to acquire ISP instance";
-			continue;
-		}
-
-		/*
-		 * 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;
-
-			std::unique_ptr<RPi::CameraData> cameraData = std::make_unique<Vc4CameraData>(this);
-			int ret = RPi::PipelineHandlerBase::registerCamera(cameraData,
-									   unicamDevice, "unicam-image",
-									   ispDevice, entity);
-			if (ret)
-				LOG(RPI, Error) << "Failed to register camera "
-						<< entity->name() << ": " << ret;
-			else
-				numCameras++;
-		}
-
-		if (numCameras)
-			return true;
-	}
-
-	return false;
-}
-
 int PipelineHandlerVc4::allocateBuffers(Camera *camera)
 {
 	Vc4CameraData *data = cameraData(camera);