[libcamera-devel] [RFC 2/9] libcamera: Define and use MediaDeviceMatch
Jacopo Mondi
jacopo.mondi at ideasonboard.com
Tue Aug 8 14:52:21 CEST 2023
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 at 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(-)
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);
--
2.40.1
More information about the libcamera-devel
mailing list