[libcamera-devel,RFC,2/9] libcamera: Define and use MediaDeviceMatch
diff mbox series

Message ID 20230808125228.29043-3-jacopo.mondi@ideasonboard.com
State New
Headers show
Series
  • libcamera: Generalize device match and support USB devices
Related show

Commit Message

Jacopo Mondi Aug. 8, 2023, 12:52 p.m. UTC
The xistingdevice search and match criteria implemented by libcamera
only supports 'media device' based cameras, which are supported in the
Linux kernel by the usage of the V4L2/MC API.

Define a MediaDeviceMatch class derived from DeviceMatch and use it
wherever DeviceMatch was used in order to later introduce new derived
classes to support searching and matching devices of a different type.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
 Documentation/guides/pipeline-handler.rst     | 10 +++---
 .../libcamera/internal/device_enumerator.h    |  2 +-
 include/libcamera/internal/device_match.h     |  9 ++++--
 include/libcamera/internal/pipeline_handler.h |  4 +--
 src/libcamera/device_enumerator.cpp           |  2 +-
 src/libcamera/device_match.cpp                | 31 ++++++++++++++-----
 src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |  2 +-
 src/libcamera/pipeline/ipu3/ipu3.cpp          |  4 +--
 src/libcamera/pipeline/rkisp1/rkisp1.cpp      |  2 +-
 src/libcamera/pipeline/rpi/vc4/vc4.cpp        |  4 +--
 src/libcamera/pipeline/simple/simple.cpp      |  4 +--
 src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |  2 +-
 src/libcamera/pipeline/vimc/vimc.cpp          |  2 +-
 src/libcamera/pipeline_handler.cpp            |  3 +-
 test/camera-sensor.cpp                        |  2 +-
 test/delayed_controls.cpp                     |  2 +-
 test/libtest/buffer_source.cpp                |  2 +-
 test/media_device/media_device_test.cpp       |  2 +-
 test/v4l2_subdevice/v4l2_subdevice_test.cpp   |  2 +-
 test/v4l2_videodevice/v4l2_m2mdevice.cpp      |  2 +-
 .../v4l2_videodevice_test.cpp                 |  2 +-
 21 files changed, 59 insertions(+), 36 deletions(-)

Patch
diff mbox series

diff --git a/Documentation/guides/pipeline-handler.rst b/Documentation/guides/pipeline-handler.rst
index 10b9c75c2a7f..c3b21a885e19 100644
--- a/Documentation/guides/pipeline-handler.rst
+++ b/Documentation/guides/pipeline-handler.rst
@@ -90,7 +90,7 @@  functionalities described above. Below is a brief overview of each of those:
    registered with it, by creating instances of the ``MediaDevice`` class and
    storing them.
 
--  `DeviceMatch <https://libcamera.org/api-html/classlibcamera_1_1DeviceMatch.html>`_:
+-  `MediaDeviceMatch <https://libcamera.org/api-html/classlibcamera_1_1MediaDeviceMatch.html>`_:
    Describes a media device search pattern using entity names, or other
    properties.
 
@@ -316,10 +316,10 @@  Matching devices
 ~~~~~~~~~~~~~~~~
 
 Each pipeline handler registered in libcamera gets tested against the current
-system configuration, by matching a ``DeviceMatch`` with the system
-``DeviceEnumerator``. A successful match makes sure all the requested components
-have been registered in the system and allows the pipeline handler to be
-initialized.
+system configuration, by matching an instance of a class derived from
+``DeviceMatch`` with the system ``DeviceEnumerator``. A successful match makes
+sure all the requested components have been registered in the system and allows
+the pipeline handler to be initialized.
 
 The main entry point of a pipeline handler is the `match()`_ class member
 function. When the ``CameraManager`` is started (using the `start()`_ function),
diff --git a/include/libcamera/internal/device_enumerator.h b/include/libcamera/internal/device_enumerator.h
index 259a9e4621ea..2afb9fa0dea8 100644
--- a/include/libcamera/internal/device_enumerator.h
+++ b/include/libcamera/internal/device_enumerator.h
@@ -29,7 +29,7 @@  public:
 	virtual int init() = 0;
 	virtual int enumerate() = 0;
 
-	std::shared_ptr<MediaDevice> search(const DeviceMatch &dm);
+	std::shared_ptr<MediaDevice> search(const MediaDeviceMatch &dm);
 
 	Signal<> devicesAdded;
 
diff --git a/include/libcamera/internal/device_match.h b/include/libcamera/internal/device_match.h
index 9f190f0c8a84..6df7dece1031 100644
--- a/include/libcamera/internal/device_match.h
+++ b/include/libcamera/internal/device_match.h
@@ -17,11 +17,16 @@  class MediaDevice;
 class DeviceMatch
 {
 public:
-	DeviceMatch(const std::string &driver);
+	virtual bool match(const MediaDevice *device) const = 0;
+};
 
+class MediaDeviceMatch : public DeviceMatch
+{
+public:
 	void add(const std::string &entity);
+	MediaDeviceMatch(const std::string &driver);
 
-	bool match(const MediaDevice *device) const;
+	bool match(const MediaDevice *device) const override;
 
 private:
 	std::string driver_;
diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index c96944f4ecc4..02b2f33727a3 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -28,7 +28,7 @@  class Camera;
 class CameraConfiguration;
 class CameraManager;
 class DeviceEnumerator;
-class DeviceMatch;
+class MediaDeviceMatch;
 class FrameBuffer;
 class MediaDevice;
 class PipelineHandler;
@@ -43,7 +43,7 @@  public:
 
 	virtual bool match(DeviceEnumerator *enumerator) = 0;
 	MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator,
-					const DeviceMatch &dm);
+					const MediaDeviceMatch &dm);
 
 	bool acquire();
 	void release(Camera *camera);
diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp
index 49afd7834db2..3dda08380e6e 100644
--- a/src/libcamera/device_enumerator.cpp
+++ b/src/libcamera/device_enumerator.cpp
@@ -229,7 +229,7 @@  void DeviceEnumerator::removeDevice(const std::string &deviceNode)
  *
  * \return pointer to the matching MediaDevice, or nullptr if no match is found
  */
-std::shared_ptr<MediaDevice> DeviceEnumerator::search(const DeviceMatch &dm)
+std::shared_ptr<MediaDevice> DeviceEnumerator::search(const MediaDeviceMatch &dm)
 {
 	for (std::shared_ptr<MediaDevice> &media : devices_) {
 		if (media->busy())
diff --git a/src/libcamera/device_match.cpp b/src/libcamera/device_match.cpp
index a51b9081d398..17937d435c88 100644
--- a/src/libcamera/device_match.cpp
+++ b/src/libcamera/device_match.cpp
@@ -18,21 +18,38 @@  namespace libcamera {
 
 /**
  * \class DeviceMatch
+ * \brief Pure virtual base class for device serch pattern
+ *
+ * The DeviceMatch class defines the interface to implement device search
+ * patterns to allow searching and matching different device typologies, such as
+ * media devices for V4L2/MC cameras, USB for cameras controlled through the USB
+ * protocol which do not implement the UVC specification and for virtual
+ * cameras.
+ *
+ * Pipeline handlers are expected to instantiate the correct derived class
+ * depending on the device type they support and populate it with their desired
+ * matching criteria. Derived classes of DeviceMatch override the pure virtual
+ * match() function to implement custom matching criteria based on the device
+ * type they represent.
+ */
+
+/**
+ * \class MediaDeviceMatch
  * \brief Description of a media device search pattern
  *
- * The DeviceMatch class describes a media device using properties from the
+ * The MediaDeviceMatch class describes a media device using properties from the
  * Media Controller struct media_device_info, entity names in the media graph
  * or other properties that can be used to identify a media device.
  *
  * The description is meant to be filled by pipeline managers and passed to a
  * device enumerator to find matching media devices.
  *
- * A DeviceMatch is created with a specific Linux device driver in mind,
+ * A MediaDeviceMatch is created with a specific Linux device driver in mind,
  * therefore the name of the driver is a required property. One or more Entity
  * names can be added as match criteria.
  *
- * Pipeline handlers are recommended to add entities to DeviceMatch as
- * appropriare to ensure that the media device they need can be uniquely
+ * Pipeline handlers are recommended to add entities to MediaDeviceMatch as
+ * appropriate to ensure that the media device they need can be uniquely
  * identified. This is useful when the corresponding kernel driver can produce
  * different graphs, for instance as a result of different driver versions or
  * hardware configurations, and not all those graphs are suitable for a pipeline
@@ -43,7 +60,7 @@  namespace libcamera {
  * \brief Construct a media device search pattern
  * \param[in] driver The Linux device driver name that created the media device
  */
-DeviceMatch::DeviceMatch(const std::string &driver)
+MediaDeviceMatch::MediaDeviceMatch(const std::string &driver)
 	: driver_(driver)
 {
 }
@@ -52,7 +69,7 @@  DeviceMatch::DeviceMatch(const std::string &driver)
  * \brief Add a media entity name to the search pattern
  * \param[in] entity The name of the entity in the media graph
  */
-void DeviceMatch::add(const std::string &entity)
+void MediaDeviceMatch::add(const std::string &entity)
 {
 	entities_.push_back(entity);
 }
@@ -67,7 +84,7 @@  void DeviceMatch::add(const std::string &entity)
  *
  * \return True if the media device matches the search pattern, false otherwise
  */
-bool DeviceMatch::match(const MediaDevice *device) const
+bool MediaDeviceMatch::match(const MediaDevice *device) const
 {
 	if (driver_ != device->driver())
 		return false;
diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
index 9bdfff0b155e..b7670a3cad8c 100644
--- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
+++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp
@@ -971,7 +971,7 @@  int PipelineHandlerISI::queueRequestDevice(Camera *camera, Request *request)
 
 bool PipelineHandlerISI::match(DeviceEnumerator *enumerator)
 {
-	DeviceMatch dm("mxc-isi");
+	MediaDeviceMatch dm("mxc-isi");
 	dm.add("crossbar");
 	dm.add("mxc_isi.0");
 	dm.add("mxc_isi.0.capture");
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index a81c817a1255..5eca9eb0b922 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -846,7 +846,7 @@  bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator)
 {
 	int ret;
 
-	DeviceMatch cio2_dm("ipu3-cio2");
+	MediaDeviceMatch cio2_dm("ipu3-cio2");
 	cio2_dm.add("ipu3-csi2 0");
 	cio2_dm.add("ipu3-cio2 0");
 	cio2_dm.add("ipu3-csi2 1");
@@ -856,7 +856,7 @@  bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator)
 	cio2_dm.add("ipu3-csi2 3");
 	cio2_dm.add("ipu3-cio2 3");
 
-	DeviceMatch imgu_dm("ipu3-imgu");
+	MediaDeviceMatch imgu_dm("ipu3-imgu");
 	imgu_dm.add("ipu3-imgu 0");
 	imgu_dm.add("ipu3-imgu 0 input");
 	imgu_dm.add("ipu3-imgu 0 parameters");
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 6efa79f29f66..5855c9d3cacc 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -1155,7 +1155,7 @@  bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)
 {
 	const MediaPad *pad;
 
-	DeviceMatch dm("rkisp1");
+	MediaDeviceMatch dm("rkisp1");
 	dm.add("rkisp1_isp");
 	dm.add("rkisp1_resizer_mainpath");
 	dm.add("rkisp1_mainpath");
diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
index 018cf4881d0e..78fd392256e1 100644
--- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
@@ -175,7 +175,7 @@  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)
 	 * device nodes due to a sensor subdevice failure.
 	 */
 	for (unsigned int i = 0; i < numUnicamDevices; i++) {
-		DeviceMatch unicam("unicam");
+		MediaDeviceMatch unicam("unicam");
 		MediaDevice *unicamDevice = acquireMediaDevice(enumerator, unicam);
 
 		if (!unicamDevice) {
@@ -183,7 +183,7 @@  bool PipelineHandlerVc4::match(DeviceEnumerator *enumerator)
 			continue;
 		}
 
-		DeviceMatch isp("bcm2835-isp");
+		MediaDeviceMatch isp("bcm2835-isp");
 		MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp);
 
 		if (!ispDevice) {
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 05ba76bce630..88159a0c4197 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -1398,7 +1398,7 @@  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)
 	unsigned int numStreams = 1;
 
 	for (const SimplePipelineInfo &inf : supportedDevices) {
-		DeviceMatch dm(inf.driver);
+		MediaDeviceMatch dm(inf.driver);
 		media_ = acquireMediaDevice(enumerator, dm);
 		if (media_) {
 			info = &inf;
@@ -1410,7 +1410,7 @@  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)
 		return false;
 
 	for (const auto &[name, streams] : info->converters) {
-		DeviceMatch converterMatch(name);
+		MediaDeviceMatch converterMatch(name);
 		converter_ = acquireMediaDevice(enumerator, converterMatch);
 		if (converter_) {
 			numStreams = streams;
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 38f48a5d9269..2114d48a2a66 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -387,7 +387,7 @@  int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)
 bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)
 {
 	MediaDevice *media;
-	DeviceMatch dm("uvcvideo");
+	MediaDeviceMatch dm("uvcvideo");
 
 	media = acquireMediaDevice(enumerator, dm);
 	if (!media)
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index 00e6f4c6a51f..f97209ba26b0 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -442,7 +442,7 @@  int PipelineHandlerVimc::queueRequestDevice(Camera *camera, Request *request)
 
 bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
 {
-	DeviceMatch dm("vimc");
+	MediaDeviceMatch dm("vimc");
 
 	dm.add("Raw Capture 0");
 	dm.add("Raw Capture 1");
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 9c74c6cfda70..ca177cad985c 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -22,6 +22,7 @@ 
 #include "libcamera/internal/camera.h"
 #include "libcamera/internal/camera_manager.h"
 #include "libcamera/internal/device_enumerator.h"
+#include "libcamera/internal/device_match.h"
 #include "libcamera/internal/framebuffer.h"
 #include "libcamera/internal/media_device.h"
 #include "libcamera/internal/request.h"
@@ -129,7 +130,7 @@  PipelineHandler::~PipelineHandler()
  * \return A pointer to the matching MediaDevice, or nullptr if no match is found
  */
 MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator,
-						 const DeviceMatch &dm)
+						 const MediaDeviceMatch &dm)
 {
 	std::shared_ptr<MediaDevice> media = enumerator->search(dm);
 	if (!media)
diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp
index 2a17cc79ea76..e35126ca1831 100644
--- a/test/camera-sensor.cpp
+++ b/test/camera-sensor.cpp
@@ -39,7 +39,7 @@  protected:
 			return TestFail;
 		}
 
-		DeviceMatch dm("vimc");
+		MediaDeviceMatch dm("vimc");
 		media_ = enumerator_->search(dm);
 		if (!media_) {
 			cerr << "Unable to find \'vimc\' media device node" << endl;
diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp
index a8ce9828d73d..9063ef3e7a20 100644
--- a/test/delayed_controls.cpp
+++ b/test/delayed_controls.cpp
@@ -38,7 +38,7 @@  protected:
 			return TestFail;
 		}
 
-		DeviceMatch dm("vivid");
+		MediaDeviceMatch dm("vivid");
 		dm.add("vivid-000-vid-cap");
 
 		media_ = enumerator_->search(dm);
diff --git a/test/libtest/buffer_source.cpp b/test/libtest/buffer_source.cpp
index dde11f365e43..8cb6f6353b99 100644
--- a/test/libtest/buffer_source.cpp
+++ b/test/libtest/buffer_source.cpp
@@ -43,7 +43,7 @@  int BufferSource::allocate(const StreamConfiguration &config)
 		return TestFail;
 	}
 
-	DeviceMatch dm("vivid");
+	MediaDeviceMatch dm("vivid");
 	dm.add(videoDeviceName);
 
 	media_ = enumerator->search(dm);
diff --git a/test/media_device/media_device_test.cpp b/test/media_device/media_device_test.cpp
index 1397d1236697..8189e068212c 100644
--- a/test/media_device/media_device_test.cpp
+++ b/test/media_device/media_device_test.cpp
@@ -25,7 +25,7 @@  int MediaDeviceTest::init()
 		return TestFail;
 	}
 
-	DeviceMatch dm("vimc");
+	MediaDeviceMatch dm("vimc");
 	media_ = enumerator_->search(dm);
 	if (!media_) {
 		cerr << "No VIMC media device found: skip test" << endl;
diff --git a/test/v4l2_subdevice/v4l2_subdevice_test.cpp b/test/v4l2_subdevice/v4l2_subdevice_test.cpp
index d8fbfd9f6b0f..56e5cc8377c4 100644
--- a/test/v4l2_subdevice/v4l2_subdevice_test.cpp
+++ b/test/v4l2_subdevice/v4l2_subdevice_test.cpp
@@ -39,7 +39,7 @@  int V4L2SubdeviceTest::init()
 		return TestFail;
 	}
 
-	DeviceMatch dm("vimc");
+	MediaDeviceMatch dm("vimc");
 	media_ = enumerator_->search(dm);
 	if (!media_) {
 		cerr << "Unable to find \'vimc\' media device node" << endl;
diff --git a/test/v4l2_videodevice/v4l2_m2mdevice.cpp b/test/v4l2_videodevice/v4l2_m2mdevice.cpp
index c45f581a8653..0effbf191966 100644
--- a/test/v4l2_videodevice/v4l2_m2mdevice.cpp
+++ b/test/v4l2_videodevice/v4l2_m2mdevice.cpp
@@ -65,7 +65,7 @@  protected:
 			return TestFail;
 		}
 
-		DeviceMatch dm("vim2m");
+		MediaDeviceMatch dm("vim2m");
 		dm.add("vim2m-source");
 		dm.add("vim2m-sink");
 
diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.cpp b/test/v4l2_videodevice/v4l2_videodevice_test.cpp
index 125aafd65041..addc47d2b62a 100644
--- a/test/v4l2_videodevice/v4l2_videodevice_test.cpp
+++ b/test/v4l2_videodevice/v4l2_videodevice_test.cpp
@@ -30,7 +30,7 @@  int V4L2VideoDeviceTest::init()
 		return TestFail;
 	}
 
-	DeviceMatch dm(driver_);
+	MediaDeviceMatch dm(driver_);
 	dm.add(entity_);
 
 	media_ = enumerator_->search(dm);