From 2f3565efb5377768e3c2e1ef85eec99668f485de Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 7 Aug 2023 10:13:16 +0200 Subject: libcamera: Define and use MediaDeviceMatch 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 --- Documentation/guides/pipeline-handler.rst | 10 ++++---- include/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 +- test/v4l2_videodevice/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 10b9c75c..c3b21a88 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 `_: +- `MediaDeviceMatch `_: 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 259a9e46..2afb9fa0 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 search(const DeviceMatch &dm); + std::shared_ptr search(const MediaDeviceMatch &dm); Signal<> devicesAdded; diff --git a/include/libcamera/internal/device_match.h b/include/libcamera/internal/device_match.h index 9f190f0c..6df7dece 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 c96944f4..02b2f337 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 49afd783..3dda0838 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 DeviceEnumerator::search(const DeviceMatch &dm) +std::shared_ptr DeviceEnumerator::search(const MediaDeviceMatch &dm) { for (std::shared_ptr &media : devices_) { if (media->busy()) diff --git a/src/libcamera/device_match.cpp b/src/libcamera/device_match.cpp index a51b9081..17937d43 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 9bdfff0b..b7670a3c 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 a81c817a..5eca9eb0 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 6efa79f2..5855c9d3 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 018cf488..78fd3922 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 05ba76bc..88159a0c 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 38f48a5d..2114d48a 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 00e6f4c6..f97209ba 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 9c74c6cf..ca177cad 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 media = enumerator->search(dm); if (!media) diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp index 2a17cc79..e35126ca 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 a8ce9828..9063ef3e 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 dde11f36..8cb6f635 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 1397d123..8189e068 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 d8fbfd9f..56e5cc83 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 c45f581a..0effbf19 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 125aafd6..addc47d2 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); -- cgit v1.2.1