From patchwork Wed Dec 10 16:15:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 25466 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 4B211C3257 for ; Wed, 10 Dec 2025 16:41:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D296E614B3; Wed, 10 Dec 2025 17:41:02 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="sjRZjNZU"; dkim-atps=neutral Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2AA556149B for ; Wed, 10 Dec 2025 17:41:00 +0100 (CET) Received: by mail-wm1-x332.google.com with SMTP id 5b1f17b1804b1-477563e28a3so77485e9.1 for ; Wed, 10 Dec 2025 08:41:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1765384859; x=1765989659; 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; bh=Wtgl8b6OKI9BVILRPi19ZaWqlmqtJLVOkWTLBjKeLR0=; b=sjRZjNZU2oOh6HeNGCCIYqgu1URx9YQdn7XZX+TDndYNZrdkd6Ro2vgvBPZPhz3nYs oAEYH7V/OfWnzqKHXbMP7krLoLSRr18ScJPX7SXB01VEATN0/Fc/v721X68soSfrl2pJ 28ZiHVEMHxvtRbq2nJpC1QNxKkAT767U8zsC8bjc5XA/Q6IxUwr6UYzw++Mzg94Lp7EK MjIDbbvxLZXp2Ypz2zvtd8stTaJiZlIpWUFcz1aldeOnVPUffQTeNFQoeqa90Tm8DQM6 GyjQxM70kaRgB7lvFQAAxUyK0YfCWkCNFZd9PQ/RmUMI8ysC+ux8bzsTq9ifO6wGMeXS wTOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765384859; x=1765989659; 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; bh=Wtgl8b6OKI9BVILRPi19ZaWqlmqtJLVOkWTLBjKeLR0=; b=hdDNOFuY3XbE4HU+BnjnXcg8PDPYxenzcJisR/NCafP9LOnvH4aNtD8K9yDgt0Yb2M uYtyj9GsqcPYcqOCWMVpylyZWT9P3v51eLZ1a7uT4wP7XCY7Uj938aZHKVAV+WAvOImm 71HXY7Ccb/vjsNlGo/ReF/NhRxec4dgK9Ud4qWLsgDcAlPj1tc5Pop72ZGQl2Et5jyzg ZGtAjhNep/Pqx1cMUySSjGGgRuVaPf5sMx9b1VuEQYYWs15cKeKmBkUwJCPbg4G2Szjy 3Vd0jSVdgIaatMBm/XLDXV1DXIDxiTJA2g2Yw5Pej2NcSV/KKH2kVhXBETLQh2JXA5Vz dwBw== X-Gm-Message-State: AOJu0Yyfs6JsP6mNRQlagpP2O6IRgySHZQKPK7c8LuwNue98SbpAJdqV LXq8QKp3z9sGV4J5o7l8sZlrIFUpERsfvcJTflUNNChTh3EIXzQQAbNJ3yqzU/Cr2zYO+Girpnq +AGxh X-Gm-Gg: ASbGncvFn8Xk+LKrGkQQF41Yw0lkx93jDe0DCTEbImvKySQhpK9o0VU02XhAfZe2uMU bnHRz1qi5m5rumC6CvBR3iC4+G8JHemK721hSXFv2iJK5Y/wbO0Gv9iojbmtugK5xR2fMQ4X7Pd Uew29gK3JWKMgIaFJ0k+Zj+OR4JxrbhDzmIFORFhrpQJV33XAJEIgaMPlbTctJfXqvoN1dOgGAY P1jTN6PhEkM15IKAN+uzsw1S7ePDy1VUZkWmYKjo2GPc0cIsl6qXFo/fKmn1jYAAeLgRlddHh83 V6Pa8TOk/RvrtD60qBjWov+EosBuAsygWO6RFNfBvcqSxJTpE6ZNSWmN+OtbbMqHoxPY3BBqDbf fsfJUNL0VgmxQC8V+lE1pncYVaQ9ZBD1fTbmT3vuZQ8JMML+ICqJ+763/y73s7CFOav++7bTFTi 5s5fLOnKXzQdV6XXF0AsWCCx/IA56LCGO8a4GmLUAvdXoLDjpSa1rKxEeN0cpGcxKoeosF7sPAw eeRIrhN2M4VmxLCivgW0eAn3ftpSg== X-Google-Smtp-Source: AGHT+IHPLrzKdRqu5yH4i1clWtwiIPDmVcjFEO46jOyHRWquJrJB76KskKEf2j/PqMGQtQ18yQtToQ== X-Received: by 2002:a05:600c:4818:b0:479:3a8e:c85c with SMTP id 5b1f17b1804b1-47a888ea47amr48775e9.18.1765384859249; Wed, 10 Dec 2025 08:40:59 -0800 (PST) Received: from davidp-pi5.pitowers.org ([2a00:1098:3142:1f:88ea:c658:5b20:5e46]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-47a88371e13sm1270415e9.11.2025.12.10.08.40.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Dec 2025 08:40:58 -0800 (PST) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [PATCH 01/11] libcamera: Infrastructure to ask for "memory" cameras Date: Wed, 10 Dec 2025 16:15:16 +0000 Message-ID: <20251210164055.17856-2-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20251210164055.17856-1-david.plowman@raspberrypi.com> References: <20251210164055.17856-1-david.plowman@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" "Memory" cameras are used to make it easier to process raw camera images that are stored in memory buffers. There may be no actual camera attached to the system at all. Memory cameras are not created when the system starts. Depending on the pipeline handler, it may be possible to open many memory cameras simultaneously, or none at all. So any time an application requests a memory camera, we check with the pipeline handler whether it can provide one. Signed-off-by: David Plowman --- include/libcamera/camera_manager.h | 4 ++ include/libcamera/internal/camera_manager.h | 5 ++ include/libcamera/internal/pipeline_handler.h | 8 +++ src/libcamera/camera_manager.cpp | 64 +++++++++++++++++++ src/libcamera/pipeline_handler.cpp | 23 +++++++ 5 files changed, 104 insertions(+) diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h index 27835500..436db409 100644 --- a/include/libcamera/camera_manager.h +++ b/include/libcamera/camera_manager.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include @@ -20,6 +21,7 @@ namespace libcamera { class Camera; +class PipelineHandler; class CameraManager : public Object, public Extensible { @@ -33,6 +35,8 @@ public: std::vector> cameras() const; std::shared_ptr get(std::string_view id); + std::vector memoryCameras() const; + std::shared_ptr getMemoryCamera(std::string_view id, std::string_view settings); static const std::string &version() { return version_; } diff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h index 755928ce..4dbc1dc8 100644 --- a/include/libcamera/internal/camera_manager.h +++ b/include/libcamera/internal/camera_manager.h @@ -55,6 +55,9 @@ private: void pipelineFactoryMatch(const PipelineHandlerFactoryBase *factory); void cleanup() LIBCAMERA_TSA_EXCLUDES(mutex_); + std::shared_ptr getMemoryCamera(const PipelineHandlerFactoryBase *factory, + std::string_view settings); + /* * This mutex protects * @@ -70,6 +73,8 @@ private: std::unique_ptr enumerator_; + std::vector memoryCameras_; + std::unique_ptr ipaManager_; const GlobalConfiguration configuration_; diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index b4f97477..cb631529 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -70,6 +70,14 @@ public: CameraManager *cameraManager() const { return manager_; } + virtual bool supportsMemoryCamera() { return false; } + + virtual std::shared_ptr createMemoryCamera([[maybe_unused]] DeviceEnumerator *enumerator, + [[maybe_unused]] std::string_view settings) + { + return nullptr; + } + protected: void registerCamera(std::shared_ptr camera); void hotplugMediaDevice(std::shared_ptr media); diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 83510e06..734f5836 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -155,6 +155,13 @@ void CameraManager::Private::pipelineFactoryMatch(const PipelineHandlerFactoryBa { CameraManager *const o = LIBCAMERA_O_PTR(); + /* First check for any memory-to-memory camera pipelines. */ + { + std::shared_ptr pipe = factory->create(o); + if (pipe->supportsMemoryCamera()) + memoryCameras_.push_back(std::string(pipe->name())); + } + /* Provide as many matching pipelines as possible. */ while (1) { std::shared_ptr pipe = factory->create(o); @@ -167,6 +174,19 @@ void CameraManager::Private::pipelineFactoryMatch(const PipelineHandlerFactoryBa } } +std::shared_ptr CameraManager::Private::getMemoryCamera(const PipelineHandlerFactoryBase *factory, + std::string_view settings) +{ + CameraManager *const o = LIBCAMERA_O_PTR(); + + std::shared_ptr pipe = factory->create(o); + + pipe->moveToThread(this); + + return pipe->invokeMethod(&PipelineHandler::createMemoryCamera, + ConnectionTypeBlocking, enumerator_.get(), settings); +} + void CameraManager::Private::cleanup() { enumerator_->devicesAdded.disconnect(this); @@ -371,6 +391,9 @@ void CameraManager::stop() * Before calling this function the caller is responsible for ensuring that * the camera manager is running. * + * This function does not list any memory cameras (for processing raw images + * held in memory buffers) that may be available. + * * \context This function is \threadsafe. * * \return List of all available cameras @@ -409,6 +432,47 @@ std::shared_ptr CameraManager::get(std::string_view id) return nullptr; } +/** + * \brief List the pipeline handlers that support memory cameras + * + * Lists the pipeline handlers in the system that have indicated they + * support memory cameras. Memory cameras are used for processing raw + * camera images stored in memory buffers, where no corresponding + * camera is available. + * + * \return Vector of pipeline handler ids (strings) + */ +std::vector CameraManager::memoryCameras() const +{ + return _d()->memoryCameras_; +} + +/** + * \brief Get a memory camera from the named pipeline handler + * \param[in] id ID of the pipeline handler that should create the memory camera + * + * This function causes the named pipeline handler to create and return a + * memory camera to the application. Pipeline handlers may support multiple + * simultaneous memory cameras, or none at all. + * + * \return Shared pointer to Camera object or nullptr if no memory camera + * could be provided + */ +std::shared_ptr CameraManager::getMemoryCamera(std::string_view id, + std::string_view settings) +{ + for (const auto &name : _d()->memoryCameras_) { + if (name == id) { + const PipelineHandlerFactoryBase *factory; + factory = PipelineHandlerFactoryBase::getFactoryByName(name); + + return _d()->getMemoryCamera(factory, settings); + } + } + + return nullptr; +} + /** * \var CameraManager::cameraAdded * \brief Notify of a new camera added to the system diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 5c469e5b..c0f3c84e 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -835,6 +835,29 @@ void PipelineHandler::disconnect() * \return The CameraManager for this pipeline handler */ +/** + * \fn PipelineHandler::supportsMemoryCamera() + * \brief Indicate whether this pipeline handler supports memory cameras. + * \return True if the pipeline handler supports memory cameras, otherwise false. + */ + +/** + * \fn PipelineHandler::createMemoryCamera() + * \brief Create a memory camera to process raw camera images from a memory buffer + * \param[in] enumerator The enumerator providing all media devices found in the + * system + * \param[in] settings A string of settings that the pipeline handler should use + * + * The pipeline handler should create a memory camera, which an application can + * use to process raw camera images that are stored in memory buffers (rather + * than being delivered from a live camera). + * + * The settings should indicate exactly what processing the application requires + * to be performed on the raw image. + * + * \return Shared pointer to a camera, or a nullptr if none could be created + */ + /** * \class PipelineHandlerFactoryBase * \brief Base class for pipeline handler factories