@@ -20,6 +20,7 @@
namespace libcamera {
class Camera;
+class CameraDescriptor;
class CameraManager : public Object, public Extensible
{
@@ -31,6 +32,8 @@ public:
int start();
void stop();
+ std::vector<std::shared_ptr<CameraDescriptor>> enumerate();
+
std::vector<std::shared_ptr<Camera>> cameras() const;
std::shared_ptr<Camera> get(std::string_view id);
@@ -25,6 +25,7 @@
namespace libcamera {
class Camera;
+class CameraDescriptor;
class DeviceEnumerator;
class IPAManager;
class MediaDevice;
@@ -39,6 +40,7 @@ public:
Private();
int start();
+ std::vector<std::shared_ptr<CameraDescriptor>> enumerate();
void addCamera(std::shared_ptr<Camera> camera) LIBCAMERA_TSA_EXCLUDES(mutex_);
void removeCamera(std::shared_ptr<Camera> camera) LIBCAMERA_TSA_EXCLUDES(mutex_);
@@ -59,6 +61,11 @@ private:
void createPipelineHandlers();
void pipelineFactoryMatch(const PipelineHandlerFactoryBase *factory);
std::shared_ptr<PipelineHandler> findMatchingHandler(const MediaDevice *media);
+
+ std::vector<std::shared_ptr<CameraDescriptor>> surveyThread() LIBCAMERA_TSA_EXCLUDES(mutex_);
+ void surveyFactory(const PipelineHandlerFactoryBase *factory) LIBCAMERA_TSA_EXCLUDES(mutex_);
+ std::shared_ptr<Camera> initializeThread(std::shared_ptr<CameraDescriptor> descriptor);
+
void cleanup() LIBCAMERA_TSA_EXCLUDES(mutex_);
/*
@@ -75,6 +82,8 @@ private:
int status_ LIBCAMERA_TSA_GUARDED_BY(mutex_);
bool started_ LIBCAMERA_TSA_GUARDED_BY(mutex_) = false;
+ /* Known camera descriptors, accessed from the CameraManager thread only. */
+ std::vector<std::shared_ptr<CameraDescriptor>> descriptors_;
std::unique_ptr<DeviceEnumerator> enumerator_;
@@ -7,13 +7,17 @@
#include "libcamera/internal/camera_manager.h"
+#include <algorithm>
+
#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>
#include <libcamera/camera.h>
+#include <libcamera/camera_descriptor.h>
#include <libcamera/property_ids.h>
#include "libcamera/internal/camera.h"
+#include "libcamera/internal/camera_descriptor.h"
#include "libcamera/internal/device_enumerator.h"
#include "libcamera/internal/global_configuration.h"
#include "libcamera/internal/ipa_manager.h"
@@ -99,6 +103,19 @@ int CameraManager::Private::startThread()
return 0;
}
+/*
+ * Enumerate the cameras in the system without initialising them, starting the
+ * camera manager thread on first use. Called from the application thread.
+ */
+std::vector<std::shared_ptr<CameraDescriptor>> CameraManager::Private::enumerate()
+{
+ int ret = startThread();
+ if (ret)
+ return {};
+
+ return invokeMethod(&Private::surveyThread, ConnectionTypeBlocking);
+}
+
void CameraManager::Private::run()
{
LOG(Camera, Debug) << "Starting camera manager";
@@ -255,6 +272,62 @@ CameraManager::Private::findMatchingHandler(const MediaDevice *media)
return match;
}
+/*
+ * Survey all pipeline handler factories and return the known camera
+ * descriptors. Descriptors are cached because later surveys skip the media
+ * devices in use by live pipeline handler instances, and would otherwise drop
+ * the cameras already initialised. Called on the CM thread.
+ */
+std::vector<std::shared_ptr<CameraDescriptor>> CameraManager::Private::surveyThread()
+{
+ ASSERT(Thread::current() == this);
+
+ for (const PipelineHandlerFactoryBase *factory : pipelineFactories())
+ surveyFactory(factory);
+
+ return descriptors_;
+}
+
+/*
+ * Survey the cameras of a single pipeline handler factory and cache their
+ * descriptors. Called on the CM thread.
+ */
+void CameraManager::Private::surveyFactory(const PipelineHandlerFactoryBase *factory)
+{
+ ASSERT(Thread::current() == this);
+
+ CameraManager *const o = LIBCAMERA_O_PTR();
+
+ std::shared_ptr<PipelineHandler> pipe = factory->create(o);
+ std::vector<std::shared_ptr<CameraDescriptor>> descriptors;
+ int ret = pipe->survey(enumerator_.get(), &descriptors);
+ if (ret == -ENOTSUP) {
+ /* The pipeline handler does not support surveying. */
+ return;
+ } else if (ret < 0) {
+ LOG(Camera, Error)
+ << "Failed to survey cameras for pipeline handler "
+ << factory->name() << ": " << strerror(-ret);
+ return;
+ }
+
+ for (std::shared_ptr<CameraDescriptor> &descriptor : descriptors) {
+ /*
+ * Record the factory that produced the descriptor, so that
+ * initialize() can create a pipeline handler for it.
+ */
+ descriptor->_d()->factory_ = factory;
+
+ auto match = [&](const auto &d) {
+ return d->id() == descriptor->id();
+ };
+ if (std::any_of(descriptors_.begin(), descriptors_.end(), match))
+ continue;
+
+ descriptors_.push_back(std::move(descriptor));
+ }
+}
+
void CameraManager::Private::cleanup()
{
enumerator_->devicesAdded.disconnect(this);
@@ -264,6 +337,8 @@ void CameraManager::Private::cleanup()
started_ = false;
}
+ descriptors_.clear();
+
/*
* Release all references to cameras to ensure they all get destroyed
* before the device enumerator deletes the media devices. Cameras are
@@ -457,6 +532,29 @@ void CameraManager::stop()
d->wait();
}
+/**
+ * \brief Enumerate the cameras in the system without initialising them
+ *
+ * Enumerate the devices in the system and return a descriptor for every
+ * camera found, without initialising any camera.
+ *
+ * Only cameras of pipeline handlers that support surveying are reported.
+ * Cameras of other pipeline handlers are created by start() and reported by
+ * cameras() as before.
+ *
+ * Descriptors are reported in match order, grouped by pipeline handler.
+ * Descriptors of cameras removed from the system remain listed until the
+ * camera manager is stopped.
+ *
+ * This function starts the camera manager if it is not yet running.
+ *
+ * \return A list of descriptors for the cameras found in the system
+ */
+std::vector<std::shared_ptr<CameraDescriptor>> CameraManager::enumerate()
+{
+ return _d()->enumerate();
+}
+
/**
* \fn CameraManager::cameras()
* \brief Retrieve all available cameras
Add a CameraManager::enumerate() function that returns a descriptor for every camera that the pipeline handlers can report without actually creating it. The descriptors are cached as media devices in use are skipped by later surveys. At present, Cameras cannot be created from a descriptor yet, so enumerate() is informational only. Signed-off-by: Naushir Patuck <naush@raspberrypi.com> --- include/libcamera/camera_manager.h | 3 + include/libcamera/internal/camera_manager.h | 9 ++ src/libcamera/camera_manager.cpp | 98 +++++++++++++++++++++ 3 files changed, 110 insertions(+)