summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacopo Mondi <jacopo@jmondi.org>2019-12-17 12:47:51 +0100
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2024-04-24 20:44:24 +0300
commitaa9a1eef2106383e965004c9ceeba9ed4746b78d (patch)
tree94cbbf1235e6fc3efa590a5ddedc1c2e209c6a69
parent0fd7d941955dee55be2104c8143b5fbe42178fd3 (diff)
libcamera: camera_sensor: Introduce CameraSensorFactory
Introduce a factory to create CameraSensor derived classes instances by inspecting the sensor media entity name and provide a convenience macro to register specialized sensor handlers. Signed-off-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> --- Changes since combined RFC: - Fix indentation in REGISTER_CAMERA_SENSOR() macro
-rw-r--r--include/libcamera/internal/camera_sensor.h48
-rw-r--r--src/libcamera/pipeline/imx8-isi/imx8-isi.cpp9
-rw-r--r--src/libcamera/pipeline/ipu3/cio2.cpp7
-rw-r--r--src/libcamera/pipeline/rkisp1/rkisp1.cpp7
-rw-r--r--src/libcamera/pipeline/rpi/common/pipeline_base.cpp5
-rw-r--r--src/libcamera/pipeline/simple/simple.cpp9
-rw-r--r--src/libcamera/pipeline/vimc/vimc.cpp7
-rw-r--r--src/libcamera/sensor/camera_sensor.cpp162
-rw-r--r--test/camera-sensor.cpp7
-rw-r--r--test/v4l2_videodevice/v4l2_videodevice_test.cpp5
-rw-r--r--test/v4l2_videodevice/v4l2_videodevice_test.h2
11 files changed, 231 insertions, 37 deletions
diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h
index d05f48eb..b9b23104 100644
--- a/include/libcamera/internal/camera_sensor.h
+++ b/include/libcamera/internal/camera_sensor.h
@@ -39,7 +39,6 @@ enum class Orientation;
class CameraSensor : protected Loggable
{
public:
- explicit CameraSensor(const MediaEntity *entity);
~CameraSensor();
int init();
@@ -82,6 +81,7 @@ public:
int setTestPatternMode(controls::draft::TestPatternModeEnum mode);
protected:
+ explicit CameraSensor(const MediaEntity *entity);
std::string logPrefix() const override;
private:
@@ -123,4 +123,50 @@ private:
std::unique_ptr<CameraLens> focusLens_;
};
+class CameraSensorFactoryBase
+{
+public:
+ CameraSensorFactoryBase();
+ virtual ~CameraSensorFactoryBase() = default;
+
+ static std::unique_ptr<CameraSensor> create(MediaEntity *entity);
+
+private:
+ LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorFactoryBase)
+
+ static std::vector<CameraSensorFactoryBase *> &factories();
+
+ static void registerFactory(CameraSensorFactoryBase *factory);
+
+ virtual bool match(const MediaEntity *entity) const = 0;
+
+ virtual std::unique_ptr<CameraSensor>
+ createInstance(MediaEntity *entity) const = 0;
+};
+
+template<typename _CameraSensor>
+class CameraSensorFactory final : public CameraSensorFactoryBase
+{
+public:
+ CameraSensorFactory()
+ : CameraSensorFactoryBase()
+ {
+ }
+
+private:
+ bool match(const MediaEntity *entity) const override
+ {
+ return _CameraSensor::match(entity);
+ }
+
+ std::unique_ptr<CameraSensor>
+ createInstance(MediaEntity *entity) const override
+ {
+ return _CameraSensor::create(entity);
+ }
+};
+
+#define REGISTER_CAMERA_SENSOR(sensor) \
+static CameraSensorFactory<sensor> global_##sensor##Factory{};
+
} /* namespace libcamera */
diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
index 63082cea..decf4179 100644
--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
@@ -157,11 +157,10 @@ PipelineHandlerISI *ISICameraData::pipe()
/* Open and initialize pipe components. */
int ISICameraData::init()
{
- int ret = sensor_->init();
- if (ret)
- return ret;
+ if (!sensor_)
+ return -ENODEV;
- ret = csis_->open();
+ int ret = csis_->open();
if (ret)
return ret;
@@ -1057,7 +1056,7 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)
std::unique_ptr<ISICameraData> data =
std::make_unique<ISICameraData>(this);
- data->sensor_ = std::make_unique<CameraSensor>(sensor);
+ data->sensor_ = CameraSensorFactoryBase::create(sensor);
data->csis_ = std::make_unique<V4L2Subdevice>(csi);
data->xbarSink_ = sink;
diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp
index 43c816ba..e09583ea 100644
--- a/src/libcamera/pipeline/ipu3/cio2.cpp
+++ b/src/libcamera/pipeline/ipu3/cio2.cpp
@@ -134,10 +134,9 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index)
MediaLink *link = links[0];
MediaEntity *sensorEntity = link->source()->entity();
- sensor_ = std::make_unique<CameraSensor>(sensorEntity);
- ret = sensor_->init();
- if (ret)
- return ret;
+ sensor_ = CameraSensorFactoryBase::create(sensorEntity);
+ if (!sensor_)
+ return -ENODEV;
ret = link->setEnabled(true);
if (ret)
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index abb21968..1a3e7938 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -1109,10 +1109,9 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)
std::make_unique<RkISP1CameraData>(this, &mainPath_,
hasSelfPath_ ? &selfPath_ : nullptr);
- data->sensor_ = std::make_unique<CameraSensor>(sensor);
- ret = data->sensor_->init();
- if (ret)
- return ret;
+ data->sensor_ = CameraSensorFactoryBase::create(sensor);
+ if (!data->sensor_)
+ return -ENODEV;
/* Initialize the camera properties. */
data->properties_ = data->sensor_->properties();
diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
index 7e420b3f..d662c8f1 100644
--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp
@@ -772,13 +772,10 @@ int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &camera
CameraData *data = cameraData.get();
int ret;
- data->sensor_ = std::make_unique<CameraSensor>(sensorEntity);
+ data->sensor_ = CameraSensorFactoryBase::create(sensorEntity);
if (!data->sensor_)
return -EINVAL;
- if (data->sensor_->init())
- return -EINVAL;
-
/* Populate the map of sensor supported formats and sizes. */
for (auto const mbusCode : data->sensor_->mbusCodes())
data->sensorFormats_.emplace(mbusCode,
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 61a59926..408e43c8 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -385,8 +385,6 @@ SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,
MediaEntity *sensor)
: Camera::Private(pipe), streams_(numStreams)
{
- int ret;
-
/*
* Find the shortest path from the camera sensor to a video capture
* device using the breadth-first search algorithm. This heuristic will
@@ -477,12 +475,9 @@ SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,
}
/* Finally also remember the sensor. */
- sensor_ = std::make_unique<CameraSensor>(sensor);
- ret = sensor_->init();
- if (ret) {
- sensor_.reset();
+ sensor_ = CameraSensorFactoryBase::create(sensor);
+ if (!sensor_)
return;
- }
LOG(SimplePipeline, Debug)
<< "Found pipeline: "
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index 5e66ee1d..ae0ca219 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -510,10 +510,9 @@ int VimcCameraData::init()
return ret;
/* Create and open the camera sensor, debayer, scaler and video device. */
- sensor_ = std::make_unique<CameraSensor>(media_->getEntityByName("Sensor B"));
- ret = sensor_->init();
- if (ret)
- return ret;
+ sensor_ = CameraSensorFactoryBase::create(media_->getEntityByName("Sensor B"));
+ if (!sensor_)
+ return -ENODEV;
debayer_ = V4L2Subdevice::fromEntityName(media_, "Debayer B");
if (debayer_->open())
diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp
index 5c4f3532..a35683eb 100644
--- a/src/libcamera/sensor/camera_sensor.cpp
+++ b/src/libcamera/sensor/camera_sensor.cpp
@@ -12,6 +12,7 @@
#include <float.h>
#include <iomanip>
#include <limits.h>
+#include <map>
#include <math.h>
#include <string.h>
@@ -1204,4 +1205,165 @@ std::string CameraSensor::logPrefix() const
return "'" + entity_->name() + "'";
}
+namespace {
+
+/* Transitory default camera sensor implementation */
+class CameraSensorDefault : public CameraSensor
+{
+public:
+ CameraSensorDefault(MediaEntity *entity)
+ : CameraSensor(entity)
+ {
+ }
+
+ static bool match([[maybe_unused]] const MediaEntity *entity)
+ {
+ return true;
+ }
+
+ static std::unique_ptr<CameraSensorDefault> create(MediaEntity *entity)
+ {
+ std::unique_ptr<CameraSensorDefault> sensor =
+ std::make_unique<CameraSensorDefault>(entity);
+
+ if (sensor->init())
+ return nullptr;
+
+ return sensor;
+ }
+};
+
+REGISTER_CAMERA_SENSOR(CameraSensorDefault)
+
+}; /* namespace */
+
+/**
+ * \class CameraSensorFactoryBase
+ * \brief Base class for camera sensor factories
+ *
+ * The CameraSensorFactoryBase class is the base of all specializations of
+ * the CameraSensorFactory class template. It implements the factory
+ * registration, maintains a registry of factories, and provides access to the
+ * registered factories.
+ */
+
+/**
+ * \brief Construct a camera sensor factory base
+ *
+ * Creating an instance of the factory base registers it with the global list of
+ * factories, accessible through the factories() function.
+ */
+CameraSensorFactoryBase::CameraSensorFactoryBase()
+{
+ registerFactory(this);
+}
+
+/**
+ * \brief Create an instance of the CameraSensor corresponding to a media entity
+ * \param[in] entity The media entity on the source end of the sensor
+ *
+ * \return A unique pointer to a new instance of the CameraSensor subclass
+ * matching the entity, or a null pointer if no such factory exists
+ */
+std::unique_ptr<CameraSensor> CameraSensorFactoryBase::create(MediaEntity *entity)
+{
+ const std::vector<CameraSensorFactoryBase *> &factories =
+ CameraSensorFactoryBase::factories();
+
+ for (const CameraSensorFactoryBase *factory : factories) {
+ if (!factory->match(entity))
+ continue;
+
+ std::unique_ptr<CameraSensor> sensor = factory->createInstance(entity);
+ if (!sensor) {
+ LOG(CameraSensor, Error)
+ << "Failed to create sensor for '"
+ << entity->name();
+ return nullptr;
+ }
+
+ return sensor;
+ }
+
+ return nullptr;
+}
+
+/**
+ * \brief Retrieve the list of all camera sensor factories
+ * \return The list of camera sensor factories
+ */
+std::vector<CameraSensorFactoryBase *> &CameraSensorFactoryBase::factories()
+{
+ /*
+ * The static factories map is defined inside the function to ensure
+ * it gets initialized on first use, without any dependency on link
+ * order.
+ */
+ static std::vector<CameraSensorFactoryBase *> factories;
+ return factories;
+}
+
+/**
+ * \brief Add a camera sensor class to the registry
+ * \param[in] factory Factory to use to construct the camera sensor
+ */
+void CameraSensorFactoryBase::registerFactory(CameraSensorFactoryBase *factory)
+{
+ std::vector<CameraSensorFactoryBase *> &factories =
+ CameraSensorFactoryBase::factories();
+
+ factories.push_back(factory);
+}
+
+/**
+ * \class CameraSensorFactory
+ * \brief Registration of CameraSensorFactory classes and creation of instances
+ * \tparam _CameraSensor The camera sensor class type for this factory
+ *
+ * To facilitate discovery and instantiation of CameraSensor classes, the
+ * CameraSensorFactory class implements auto-registration of camera sensors.
+ * Each CameraSensor subclass shall register itself using the
+ * REGISTER_CAMERA_SENSOR() macro, which will create a corresponding instance
+ * of a CameraSensorFactory subclass and register it with the static list of
+ * factories.
+ */
+
+/**
+ * \fn CameraSensorFactory::CameraSensorFactory()
+ * \brief Construct a camera sensor factory
+ *
+ * Creating an instance of the factory registers it with the global list of
+ * factories, accessible through the CameraSensorFactoryBase::factories()
+ * function.
+ */
+
+/**
+ * \fn CameraSensorFactory::createInstance() const
+ * \brief Create an instance of the CameraSensor corresponding to the factory
+ *
+ * \return A unique pointer to a newly constructed instance of the CameraSensor
+ * subclass corresponding to the factory
+ */
+
+/**
+ * \def REGISTER_CAMERA_SENSOR(sensor)
+ * \brief Register a camera sensor type to the sensor factory
+ * \param[in] sensor Class name of the CameraSensor derived class to register
+ *
+ * Register a CameraSensor subclass with the factory and make it available to
+ * try and match sensors. The subclass needs to implement two static functions:
+ *
+ * \code{.cpp}
+ * static bool match(const MediaEntity *entity);
+ * static std::unique_ptr<sensor> create(MediaEntity *entity);
+ * \endcode
+ *
+ * The match() function tests if the sensor class supports the camera sensor
+ * identified by a MediaEntity.
+ *
+ * The create() function creates a new instance of the sensor class. It may
+ * return a null pointer if initialization of the instance fails. It will only
+ * be called if the match() function has returned true for the given entity.
+ */
+
} /* namespace libcamera */
diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp
index 9503d775..acd3a124 100644
--- a/test/camera-sensor.cpp
+++ b/test/camera-sensor.cpp
@@ -52,8 +52,8 @@ protected:
return TestFail;
}
- sensor_ = new CameraSensor(entity);
- if (sensor_->init() < 0) {
+ sensor_ = CameraSensorFactoryBase::create(entity);
+ if (!sensor_) {
cerr << "Unable to initialise camera sensor" << endl;
return TestFail;
}
@@ -118,13 +118,12 @@ protected:
void cleanup()
{
- delete sensor_;
}
private:
std::unique_ptr<DeviceEnumerator> enumerator_;
std::shared_ptr<MediaDevice> media_;
- CameraSensor *sensor_;
+ std::unique_ptr<CameraSensor> sensor_;
CameraLens *lens_;
};
diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.cpp b/test/v4l2_videodevice/v4l2_videodevice_test.cpp
index 1113cf5b..9fbd24cc 100644
--- a/test/v4l2_videodevice/v4l2_videodevice_test.cpp
+++ b/test/v4l2_videodevice/v4l2_videodevice_test.cpp
@@ -64,8 +64,8 @@ int V4L2VideoDeviceTest::init()
format.size.height = 480;
if (driver_ == "vimc") {
- sensor_ = new CameraSensor(media_->getEntityByName("Sensor A"));
- if (sensor_->init())
+ sensor_ = CameraSensorFactoryBase::create(media_->getEntityByName("Sensor A"));
+ if (!sensor_)
return TestFail;
debayer_ = new V4L2Subdevice(media_->getEntityByName("Debayer A"));
@@ -98,6 +98,5 @@ void V4L2VideoDeviceTest::cleanup()
capture_->close();
delete debayer_;
- delete sensor_;
delete capture_;
}
diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.h b/test/v4l2_videodevice/v4l2_videodevice_test.h
index d2de1a6d..f06db72a 100644
--- a/test/v4l2_videodevice/v4l2_videodevice_test.h
+++ b/test/v4l2_videodevice/v4l2_videodevice_test.h
@@ -36,7 +36,7 @@ protected:
std::string entity_;
std::unique_ptr<libcamera::DeviceEnumerator> enumerator_;
std::shared_ptr<libcamera::MediaDevice> media_;
- libcamera::CameraSensor *sensor_;
+ std::unique_ptr<libcamera::CameraSensor> sensor_;
libcamera::V4L2Subdevice *debayer_;
libcamera::V4L2VideoDevice *capture_;
std::vector<std::unique_ptr<libcamera::FrameBuffer>> buffers_;