[RFC,v1,14/20] libcamera: camera_manager: Create cameras through enumeration
diff mbox series

Message ID 20260918080734.1228227-15-naush@raspberrypi.com
State New
Headers show
Series
  • libcamera: New enumeration API
Related show

Commit Message

Naushir Patuck Sept. 18, 2026, 7:59 a.m. UTC
Implement start() as the enumeration of the cameras followed by the
initialisation of those not yet created. Pipeline handlers that do not
support surveying continue creating their cameras through match(), and
their cameras are not reported by enumerate().

Cameras are enumerated and initialised one pipeline handler at a time,
so that they are created in the same order as repeated match() calls
would create them. This keeps the order of cameras() unchanged for
applications that do not use enumerate().

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 include/libcamera/internal/camera_manager.h |  4 +-
 src/libcamera/camera_manager.cpp            | 64 +++++++++++++++------
 2 files changed, 49 insertions(+), 19 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h
index d727d4859c0d..b5c55bea6e5e 100644
--- a/include/libcamera/internal/camera_manager.h
+++ b/include/libcamera/internal/camera_manager.h
@@ -59,12 +59,12 @@  private:
 	int init();
 	std::vector<const PipelineHandlerFactoryBase *> pipelineFactories() const;
 	int startThread() LIBCAMERA_TSA_EXCLUDES(mutex_);
-	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_);
+	int surveyFactory(const PipelineHandlerFactoryBase *factory);
+	void createCameras() LIBCAMERA_TSA_EXCLUDES(mutex_);
 	std::shared_ptr<Camera> initializeThread(std::shared_ptr<CameraDescriptor> descriptor);
 
 	void cleanup() LIBCAMERA_TSA_EXCLUDES(mutex_);
diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp
index 5ca578bd0614..33ca28f76ba1 100644
--- a/src/libcamera/camera_manager.cpp
+++ b/src/libcamera/camera_manager.cpp
@@ -55,7 +55,18 @@  CameraManager::Private::Private()
 
 int CameraManager::Private::start()
 {
-	return startThread();
+	int ret = startThread();
+	if (ret)
+		return ret;
+
+	/*
+	 * Create every camera in the system by enumerating followed by
+	 * initialisation. Cameras already initialised from a descriptor are
+	 * left untouched.
+	 */
+	invokeMethod(&Private::createCameras, ConnectionTypeBlocking);
+
+	return 0;
 }
 
 /*
@@ -183,8 +194,7 @@  int CameraManager::Private::init()
 	if (!enumerator_ || enumerator_->enumerate())
 		return -ENODEV;
 
-	createPipelineHandlers();
-	enumerator_->devicesAdded.connect(this, &Private::createPipelineHandlers);
+	enumerator_->devicesAdded.connect(this, &Private::createCameras);
 
 	return 0;
 }
@@ -237,16 +247,6 @@  std::vector<const PipelineHandlerFactoryBase *> CameraManager::Private::pipeline
 	return selected;
 }
 
-void CameraManager::Private::createPipelineHandlers()
-{
-	/*
-	 * Try each pipeline handler until it exhausts
-	 * all pipelines it can provide.
-	 */
-	for (const PipelineHandlerFactoryBase *factory : pipelineFactories())
-		pipelineFactoryMatch(factory);
-}
-
 void CameraManager::Private::pipelineFactoryMatch(const PipelineHandlerFactoryBase *factory)
 {
 	CameraManager *const o = LIBCAMERA_O_PTR();
@@ -311,9 +311,10 @@  std::vector<std::shared_ptr<CameraDescriptor>> CameraManager::Private::surveyThr
 
 /*
  * Survey the cameras of a single pipeline handler factory and cache their
- * descriptors. Called on the CM thread.
+ * descriptors. Returns the result of the survey, -ENOTSUP if the pipeline
+ * handler does not support surveying. Called on the CM thread.
  */
-void CameraManager::Private::surveyFactory(const PipelineHandlerFactoryBase *factory)
+int CameraManager::Private::surveyFactory(const PipelineHandlerFactoryBase *factory)
 {
 	ASSERT(Thread::current() == this);
 
@@ -324,12 +325,12 @@  void CameraManager::Private::surveyFactory(const PipelineHandlerFactoryBase *fac
 	int ret = pipe->survey(enumerator_.get(), &descriptors);
 	if (ret == -ENOTSUP) {
 		/* The pipeline handler does not support surveying. */
-		return;
+		return ret;
 	} else if (ret < 0) {
 		LOG(Camera, Error)
 			<< "Failed to survey cameras for pipeline handler "
 			<< factory->name() << ": " << strerror(-ret);
-		return;
+		return ret;
 	}
 
 	for (std::shared_ptr<CameraDescriptor> &descriptor : descriptors) {
@@ -347,6 +348,35 @@  void CameraManager::Private::surveyFactory(const PipelineHandlerFactoryBase *fac
 
 		descriptors_.push_back(std::move(descriptor));
 	}
+
+	return 0;
+}
+
+/*
+ * Create every camera in the system. For each pipeline handler, enumerate its
+ * cameras and initialise them, or match it when it does not support surveying.
+ * Looping through one pipeline handler at a time keeps the cameras in the same
+ * order as repeated match() calls would create them. Cameras that already exist
+ * are left untouched. Called on the CM thread.
+ */
+void CameraManager::Private::createCameras()
+{
+	ASSERT(Thread::current() == this);
+
+	for (const PipelineHandlerFactoryBase *factory : pipelineFactories()) {
+		int ret = surveyFactory(factory);
+		if (ret == -ENOTSUP) {
+			pipelineFactoryMatch(factory);
+			continue;
+		} else if (ret < 0) {
+			continue;
+		}
+
+		for (const std::shared_ptr<CameraDescriptor> &descriptor : descriptors_) {
+			if (descriptor->_d()->factory_ == factory)
+				initializeThread(descriptor);
+		}
+	}
 }
 
 /*