diff options
author | Jacopo Mondi <jacopo.mondi@ideasonboard.com> | 2023-08-08 13:39:59 +0200 |
---|---|---|
committer | Jacopo Mondi <jacopo.mondi@ideasonboard.com> | 2023-08-08 14:34:28 +0200 |
commit | 4d1ddf954159cd0b251c81d5b92c5fdfd33cf061 (patch) | |
tree | 3c8637b470f3abe93fec9bebad687d0d2f12e2fd | |
parent | 7e1ff7441363c59c659023a3b1e66ea01aca236d (diff) |
libcamera: pipeline_handler: Add function to acquire a USB device
Add a function to the PipelineHandler base class to acquire a USB device
by providing a USBDeviceMatch class instance.
Support multiple CameraDevice derived classes by generalizing whenever
possible the device type in use.
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
-rw-r--r-- | include/libcamera/internal/pipeline_handler.h | 9 | ||||
-rw-r--r-- | src/libcamera/pipeline_handler.cpp | 69 |
2 files changed, 64 insertions, 14 deletions
diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index 02b2f337..b6b68aab 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -26,6 +26,7 @@ namespace libcamera { class Camera; class CameraConfiguration; +class CameraDevice; class CameraManager; class DeviceEnumerator; class MediaDeviceMatch; @@ -33,6 +34,8 @@ class FrameBuffer; class MediaDevice; class PipelineHandler; class Request; +class USBDevice; +class USBDeviceMatch; class PipelineHandler : public std::enable_shared_from_this<PipelineHandler>, public Object @@ -44,6 +47,8 @@ public: virtual bool match(DeviceEnumerator *enumerator) = 0; MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator, const MediaDeviceMatch &dm); + USBDevice *acquireUSBDevice(DeviceEnumerator *enumerator, + const USBDeviceMatch &dm); bool acquire(); void release(Camera *camera); @@ -82,7 +87,7 @@ protected: CameraManager *manager_; private: - void unlockMediaDevices(); + void unlockCameraDevices(); void mediaDeviceDisconnected(MediaDevice *media); virtual void disconnect(); @@ -90,7 +95,7 @@ private: void doQueueRequest(Request *request); void doQueueRequests(); - std::vector<std::shared_ptr<MediaDevice>> mediaDevices_; + std::vector<std::shared_ptr<CameraDevice>> cameraDevices_; std::vector<std::weak_ptr<Camera>> cameras_; std::queue<Request *> waitingRequests_; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index ca177cad..0b3e0fd8 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -27,6 +27,7 @@ #include "libcamera/internal/media_device.h" #include "libcamera/internal/request.h" #include "libcamera/internal/tracepoints.h" +#include "libcamera/internal/usb_device.h" /** * \file pipeline_handler.h @@ -76,8 +77,8 @@ PipelineHandler::PipelineHandler(CameraManager *manager) PipelineHandler::~PipelineHandler() { - for (std::shared_ptr<MediaDevice> media : mediaDevices_) - media->release(); + for (std::shared_ptr<CameraDevice> device : cameraDevices_) + device->release(); } /** @@ -139,12 +140,43 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator, if (!media->acquire()) return nullptr; - mediaDevices_.push_back(media); + cameraDevices_.push_back(media); return media.get(); } /** + * \brief Search and acquire a USBDevice matching a device pattern + * \param[in] enumerator Enumerator containing all media devices in the system + * \param[in] dm Device match pattern + * + * Search the device \a enumerator for an available USB device matching the + * device match pattern \a dm. Matching devices that have previously been + * acquired by MediaDevice::acquire() are not considered. If a match is found, + * the USB device is acquired and returned. The caller shall not release the + * device explicitly, it will be automatically released when the pipeline + * handler is destroyed. + * + * \context This function shall be called from the CameraManager thread. + * + * \return A pointer to the matching USBDevice, or nullptr if no match is found + */ +USBDevice *PipelineHandler::acquireUSBDevice(DeviceEnumerator *enumerator, + const USBDeviceMatch &dm) +{ + std::shared_ptr<USBDevice> usb = enumerator->search(dm); + if (!usb) + return nullptr; + + if (!usb->acquire()) + return nullptr; + + cameraDevices_.push_back(usb); + + return usb.get(); +} + +/** * \brief Acquire exclusive access to the pipeline handler for the process * * This function locks all the media devices used by the pipeline to ensure @@ -173,9 +205,9 @@ bool PipelineHandler::acquire() return true; } - for (std::shared_ptr<MediaDevice> &media : mediaDevices_) { - if (!media->lock()) { - unlockMediaDevices(); + for (std::shared_ptr<CameraDevice> &device : cameraDevices_) { + if (!device->lock()) { + unlockCameraDevices(); return false; } } @@ -206,7 +238,7 @@ void PipelineHandler::release(Camera *camera) ASSERT(useCount_); - unlockMediaDevices(); + unlockCameraDevices(); releaseDevice(camera); @@ -224,10 +256,10 @@ void PipelineHandler::releaseDevice([[maybe_unused]] Camera *camera) { } -void PipelineHandler::unlockMediaDevices() +void PipelineHandler::unlockCameraDevices() { - for (std::shared_ptr<MediaDevice> &media : mediaDevices_) - media->unlock(); + for (std::shared_ptr<CameraDevice> &device : cameraDevices_) + device->unlock(); } /** @@ -606,7 +638,7 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera) { cameras_.push_back(camera); - if (mediaDevices_.empty()) + if (cameraDevices_.empty()) LOG(Pipeline, Fatal) << "Registering camera with no media devices!"; @@ -615,7 +647,20 @@ void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera) * to the camera. */ std::vector<int64_t> devnums; - for (const std::shared_ptr<MediaDevice> &media : mediaDevices_) { + for (const std::shared_ptr<CameraDevice> &device : cameraDevices_) { + /* + * Only MediaDevice has entities and devnums. + * + * FIXME: This code path "abuses" RTTI. In general, conditional + * execution based on type information is discouraged and is + * a symptom of a fragile design. However this could be + * considered a temporary workaround, as USB-based devices + * should report devnums as well in future. + */ + MediaDevice *media = dynamic_cast<MediaDevice *>(device.get()); + if (!media) + continue; + for (const MediaEntity *entity : media->entities()) { if (entity->pads().size() == 1 && (entity->pads()[0]->flags() & MEDIA_PAD_FL_SINK) && |