summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacopo Mondi <jacopo.mondi@ideasonboard.com>2023-08-08 13:39:59 +0200
committerJacopo Mondi <jacopo.mondi@ideasonboard.com>2023-08-08 14:34:28 +0200
commit4d1ddf954159cd0b251c81d5b92c5fdfd33cf061 (patch)
tree3c8637b470f3abe93fec9bebad687d0d2f12e2fd
parent7e1ff7441363c59c659023a3b1e66ea01aca236d (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.h9
-rw-r--r--src/libcamera/pipeline_handler.cpp69
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) &&