From patchwork Thu Feb 6 18:52:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 2796 Return-Path: Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C941960864 for ; Thu, 6 Feb 2020 19:50:19 +0100 (CET) X-Originating-IP: 93.34.114.233 Received: from uno.lan (93-34-114-233.ip49.fastwebnet.it [93.34.114.233]) (Authenticated sender: jacopo@jmondi.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 6F974FF804 for ; Thu, 6 Feb 2020 18:50:19 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Thu, 6 Feb 2020 19:52:43 +0100 Message-Id: <20200206185247.202233-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200206185247.202233-1-jacopo@jmondi.org> References: <20200206185247.202233-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 3/7] libcamera: camera_sensor: Introduce CameraSensorFactory X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 Feb 2020 18:50:20 -0000 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 --- src/libcamera/camera_sensor.cpp | 134 ++++++++++++++++++ src/libcamera/include/camera_sensor.h | 39 ++++- src/libcamera/pipeline/ipu3/ipu3.cpp | 2 +- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 2 +- src/libcamera/pipeline/vimc.cpp | 2 +- test/camera-sensor.cpp | 2 +- .../v4l2_videodevice_test.cpp | 2 +- 7 files changed, 177 insertions(+), 6 deletions(-) diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 2219a4307436..fc8452b607a0 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include #include @@ -42,6 +44,18 @@ LOG_DEFINE_CATEGORY(CameraSensor); * devices as the needs arise. */ +/** + * \fn CameraSensor::entityName() + * \brief Retrieve the name of the entity which identifies the supported sensor + * + * Camera sensor handlers have to report with this function the name of the + * media entity which represents the camera sensor they support. The here + * reported name is then matched against the name of the MediaEntity provided + * at createSensor() time to identify the correct CameraSensorFactory. + * + * \return The name of the media entity that identifies the sensor + */ + /** * \brief Construct a CameraSensor * \param[in] entity The media entity backing the camera sensor @@ -366,4 +380,124 @@ std::string CameraSensor::logPrefix() const return "'" + subdev_->entity()->name() + "'"; } +/** + * \class CameraSensorFactory + * \brief Factory of camera sensor handlers + * + * The class provides to camera sensor handlers the ability to register + * themselves to the factory to allow the creation of their instances by + * matching the name of the media entity which represents the sensor. + * + * Camera sensor handlers use the REGISTER_CAMERA_SENSOR() macro to + * add themselves to the camera sensor factory. Users of the factory + * creates camera sensor handler instances by using the static + * CameraSensorFactory::createInstance() method, which returns a pointer + * to the opportune CameraSensor sub-class if any, or a newly created instance + * of the generic CameraSensor class. + */ + +LOG_DEFINE_CATEGORY(CameraSensorFactory); + +/** + * \typedef CameraSensorFactory::factoriesMap + * \brief An std::map of sensor handler factories + * + * The registered sensor handler factories are associated in a map with the + * names of the media entity that represent the sensor + */ + +/** + * \brief Register a camera sensor handler factory + * \param[in] name The name of the media entity representing the sensor + * + * Register a new camera sensor factory which creates sensor handler instances + * that support camera sensors represented by the media entity with \a name. + */ +CameraSensorFactory::CameraSensorFactory(const char *name) +{ + CameraSensorFactory::registerSensorFactory(name, this); +} + +/** + * \brief Retrieve the list of registered camera sensor factories + * + * The static factories map is defined inside the function to ensures it gets + * initialized on first use, without any dependency on link order. + * + * \return The static list of registered camera sensor factories + */ +CameraSensorFactory::factoriesMap &CameraSensorFactory::factories() +{ + static factoriesMap factories; + return factories; +} + +/** + * \brief Register a camera sensor handler factory + * \param[in] name The name of the media entity that represents the sensor + * \param[in] factory The factory instance to register + * + * The newly registered sensor handler \a factory is associated with \a name, + * when a new sensor handler is instantiated with createSensor() the name of + * the media entity is matched against the \a name registered here to + * retrieve the correct factory. + */ +void CameraSensorFactory::registerSensorFactory(const char *name, + CameraSensorFactory *factory) +{ + factoriesMap &map = CameraSensorFactory::factories(); + map[name] = factory; +} + +/** + * \brief Create and return a CameraSensor + * \param[in] entity The media entity that represents the camera sensor + * + * Create a new instance of an handler for the sensor represented by \a + * entity using one of the registered factories. If no specific handler is + * available for the sensor, or creating the handler fails, a newly created + * instance of the generic CameraSensor base class is returned. + * + * Ownership of the created camera sensor instance is passed to the caller + * which is reponsible for deleting the instance. + * FIXME: is it worth using a smart pointer here ? + * + * \return A newly created camera sensor handler instance + */ +CameraSensor *CameraSensorFactory::createSensor(const MediaEntity *entity) +{ + /* + * The entity name contains both the sensor name and the I2C bus ID. + * + * Remove the i2c bus part and use the sensor name only as key to + * search for on the sensor handlers map. + */ + const char *entityName = entity->name().c_str(); + const char *delim = strchrnul(entityName, ' '); + std::string sensorName(entityName, delim); + + auto it = CameraSensorFactory::factories().find(sensorName); + if (it == CameraSensorFactory::factories().end()) { + LOG(CameraSensorFactory, Info) + << "Unsupported sensor '" << entity->name() + << "': using generic sensor handler"; + return new CameraSensor(entity); + } + + LOG(CameraSensorFactory, Info) << "Create handler for '" + << entity->name() << "' sensor"; + + CameraSensorFactory *factory = it->second; + return factory->create(entity); +} + +/** + * \def REGISTER_CAMERA_SENSOR(handler) + * \brief Register a camera sensor handler to the sensor factory + * \param[in] handler The name of the sensor handler + * + * Register a camera sensor handler to the sensor factory to make it available + * to the factory users. + */ + } /* namespace libcamera */ diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h index 99cff98128dc..2f4a0cc8ad3f 100644 --- a/src/libcamera/include/camera_sensor.h +++ b/src/libcamera/include/camera_sensor.h @@ -7,6 +7,7 @@ #ifndef __LIBCAMERA_CAMERA_SENSOR_H__ #define __LIBCAMERA_CAMERA_SENSOR_H__ +#include #include #include @@ -25,7 +26,8 @@ struct V4L2SubdeviceFormat; class CameraSensor : protected Loggable { public: - explicit CameraSensor(const MediaEntity *entity); + static const char *entityName(); + ~CameraSensor(); CameraSensor(const CameraSensor &) = delete; @@ -49,6 +51,8 @@ public: const ControlList &properties() const { return properties_; } protected: + friend class CameraSensorFactory; + explicit CameraSensor(const MediaEntity *entity); std::string logPrefix() const; private: @@ -61,6 +65,39 @@ private: ControlList properties_; }; +class CameraSensorFactory +{ +public: + using factoriesMap = std::map; + + CameraSensorFactory(const char *name); + virtual ~CameraSensorFactory() {} + + static CameraSensor *createSensor(const MediaEntity *entity = nullptr); + +private: + static factoriesMap &factories(); + static void registerSensorFactory(const char *name, + CameraSensorFactory *factory); + virtual CameraSensor *create(const MediaEntity *entity) = 0; + +}; + +#define REGISTER_CAMERA_SENSOR(handler) \ +class handler##CameraSensorFactory final : public CameraSensorFactory \ +{ \ +public: \ + handler##CameraSensorFactory() \ + : CameraSensorFactory(handler##CameraSensor::entityName()) {}\ + \ +private: \ + CameraSensor *create(const MediaEntity *entity) \ + { \ + return new handler##CameraSensor(entity); \ + } \ +}; \ +static handler##CameraSensorFactory global_##handler##CameraSensorFactory + } /* namespace libcamera */ #endif /* __LIBCAMERA_CAMERA_SENSOR_H__ */ diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 387bb070b505..21934e72eba7 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -1322,7 +1322,7 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) MediaLink *link = links[0]; MediaEntity *sensorEntity = link->source()->entity(); - sensor_ = new CameraSensor(sensorEntity); + sensor_ = CameraSensorFactory::createSensor(sensorEntity); ret = sensor_->init(); if (ret) return ret; diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 68f16f03a81e..f2f054596257 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -901,7 +901,7 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) data->controlInfo_ = std::move(ctrls); - data->sensor_ = new CameraSensor(sensor); + data->sensor_ = CameraSensorFactory::createSensor(sensor); ret = data->sensor_->init(); if (ret) return ret; diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index fd4df0b03c26..cfeec1aac751 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -403,7 +403,7 @@ int VimcCameraData::init(MediaDevice *media) return ret; /* Create and open the camera sensor, debayer, scaler and video device. */ - sensor_ = new CameraSensor(media->getEntityByName("Sensor B")); + sensor_ = CameraSensorFactory::createSensor(media->getEntityByName("Sensor B")); ret = sensor_->init(); if (ret) return ret; diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp index 27c190fe7ace..24b83a45b656 100644 --- a/test/camera-sensor.cpp +++ b/test/camera-sensor.cpp @@ -50,7 +50,7 @@ protected: return TestFail; } - sensor_ = new CameraSensor(entity); + sensor_ = CameraSensorFactory::createSensor(entity); if (sensor_->init() < 0) { cerr << "Unable to initialise camera sensor" << endl; return TestFail; diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.cpp b/test/v4l2_videodevice/v4l2_videodevice_test.cpp index 577da4cb601c..102a8b1b6c1c 100644 --- a/test/v4l2_videodevice/v4l2_videodevice_test.cpp +++ b/test/v4l2_videodevice/v4l2_videodevice_test.cpp @@ -61,7 +61,7 @@ int V4L2VideoDeviceTest::init() return TestFail; if (driver_ == "vimc") { - sensor_ = new CameraSensor(media_->getEntityByName("Sensor A")); + sensor_ = CameraSensorFactory::createSensor(media_->getEntityByName("Sensor A")); if (sensor_->init()) return TestFail;