@@ -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,
@@ -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;
@@ -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);
@@ -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);
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(-)