From patchwork Fri Sep 18 07:59:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 28325 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 5EC98C3356 for ; Fri, 18 Sep 2026 08:08:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EDB4C68734; Fri, 18 Sep 2026 10:08:02 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="NMfTrdLw"; dkim-atps=neutral Received: from mail-wr2-x10.google.com (mail-wr2-x10.google.com [IPv6:2a00:1450:4864:30::10]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9102268726 for ; Fri, 18 Sep 2026 10:07:53 +0200 (CEST) Received: by mail-wr2-x10.google.com with SMTP id ffacd0b85a97d-4843178b1c8so62460f8f.0 for ; Fri, 18 Sep 2026 01:07:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1789718873; x=1790323673; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=SxPK7aIO8MYNrG29Gy4vLkP6fLXJuag8dJw3roVdh9E=; b=NMfTrdLweNzDjvDqA5z6Kjvvda/Lu6KnkCfD3Pzo302I5VR2JgtFxRiWn7rB6DjF7B Gjj9WgcGVYW/RCfiALork/iYUnyQ8Tth/g/9JS1fdENCC4zduxAVoBREcJvT3vrasjTl Okl+EYaguQfkNv2iEmy/hHC/biDVcDZImMcPTZ5ExD7FKgU5tMGf6eK4L/sD51V56sJl rbTQWDEXdJ915bHCWRBHo8UL0ZcB2P2qFIHSg1rT/KcQcTMZZNXfB6b6i7UgKX9xe7yF SPasuYEYTAx6EJ7oFMFBNBZLzYCbCQO+Rm/gbYnTxkoM347iBoexYF/9qqo+E1O8ZuWC 4saw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789718873; x=1790323673; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=SxPK7aIO8MYNrG29Gy4vLkP6fLXJuag8dJw3roVdh9E=; b=rng2uuwva0BCX2KQ3XiYiRUb6yj0kZmagU97pPLtHe5eUY3v+4uMhjLYCQyUZEoep8 K1q+IBoMLmRB/fSzJQZb38yNf5t5VRwBwASf8B54/xApaOBvUrwKu1agrEs78012Qupd SfYzkms2MaFOphFxhxiZtZXAxVbDK0oATIhOpZV8UC99e+YeMJcP62NmoT6jYpiGG/cn DsvUgaSGQ2TddKwE3agRvxanB2/jTdtSSO8Ind8b3j9Lo7axwN/Dh0NPBMcFm5CFDMIn 1aSQOtG8JDKt+vlXsTiwrQnNuZCyyMJLcltL8e9qi7DNNSg0/lZ61FjqSMD4bSVNVkj/ xfPw== X-Gm-Message-State: AFuF++m6fPEA+DbQ3Bz7AU9xAfRGXHfMng6vRq42RWCIN5cYqwrfIadN tO3Brz89nFArNAEy/e5pQsbyOxDfMdgIMi+cQVUS4/sm4qHzPF06lFpb/19UaREFIj/syJHImBF 0b4gJAVw= X-Gm-Gg: AYBFou1KjHnhZe0ptySdBHOnSWRg0EgqYk4AAn1RWq+xnCa5A4D6gNJUIvgEPE05Nw/ mMmsyGUDQkQ8mwJOriiUNfL33JLT7EIuBXIreF4C7geINfyk/hXAN7oFU5vIFrZYO4SYojqAY10 6rgwZa7w751l1NhIraO2EMu1uLdyeXDZdXRy6nYHnUsRpAFRo0IMzdnJPsV3D8aXt3ZO5QwCiG4 iwtJnxzUa5uv2RTj3zv5mEfh/Fq+sWNsFyzOD24XCqttxk7WuSIKVdRVKuufVK1QOzzdbPwDCdJ xxliWvXoI3qHO53j4fL8iB4Mr35VPdkFQdEZ4+4DyQRYiUbrA2Ax/N/MijEeO3tyoSmQP35FiNT VaGsD/o/9LteUEI1r8zOnzsADUKkl7gSOwXWTNQIioL+LX6Pn+dxyJ/emNL3tfRWbtc1jirQFpy MMHRIEdejlNTD5sOMsHtqiVAuaMGKCBxbo7ypgMRLyl9g5rt/nq8f5IbhiuNK9E+vP1FFFPHNH2 gXe1wu1SPx0fU8wasZHjvd0PACZ/C8CTgvpY+iarTHEgHIqFWA8lbqoZEDXbadkNktHUEqGPxBN KMVqr2AuZzgksFMaSEacDb8F2CgarPyygX2EICwDIAd3fVXU5Vl1DA13zMlHfFVhKs45kAhUCuk F6grHOISlaK4klw0fU+ejliIkrPTEvseGDd0= X-Received: by 2002:a05:6000:230a:b0:487:342:d145 with SMTP id ffacd0b85a97d-4871f9fb207mr1191335f8f.2.1789718872881; Fri, 18 Sep 2026 01:07:52 -0700 (PDT) Received: from naush-dell.pitowers.org ([2a00:1098:3142:1f:45e3:df8b:2b18:6253]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-487203f077fsm1742230f8f.26.2026.09.18.01.07.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Sep 2026 01:07:52 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Naushir Patuck Subject: [RFC PATCH v1 14/20] libcamera: camera_manager: Create cameras through enumeration Date: Fri, 18 Sep 2026 08:59:52 +0100 Message-ID: <20260918080734.1228227-15-naush@raspberrypi.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260918080734.1228227-1-naush@raspberrypi.com> References: <20260918080734.1228227-1-naush@raspberrypi.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 --- include/libcamera/internal/camera_manager.h | 4 +- src/libcamera/camera_manager.cpp | 64 +++++++++++++++------ 2 files changed, 49 insertions(+), 19 deletions(-) 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 pipelineFactories() const; int startThread() LIBCAMERA_TSA_EXCLUDES(mutex_); - void createPipelineHandlers(); void pipelineFactoryMatch(const PipelineHandlerFactoryBase *factory); std::shared_ptr findMatchingHandler(const MediaDevice *media); std::vector> 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 initializeThread(std::shared_ptr 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 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> 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 &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 &descriptor : descriptors_) { + if (descriptor->_d()->factory_ == factory) + initializeThread(descriptor); + } + } } /*