[{"id":37499,"web_url":"https://patchwork.libcamera.org/comment/37499/","msgid":"<176771495548.112111.12971944340047876740@isaac-ThinkPad-T16-Gen-2>","date":"2026-01-06T15:55:55","subject":"Re: [PATCH 01/11] libcamera: Infrastructure to ask for \"memory\"\n\tcameras","submitter":{"id":215,"url":"https://patchwork.libcamera.org/api/people/215/","name":"Isaac Scott","email":"isaac.scott@ideasonboard.com"},"content":"Hi David,\n\nThank you for the patch!\n\nQuoting David Plowman (2025-12-10 16:15:16)\n> \"Memory\" cameras are used to make it easier to process raw camera\n> images that are stored in memory buffers. There may be no actual\n> camera attached to the system at all.\n> \n> Memory cameras are not created when the system starts. Depending on\n> the pipeline handler, it may be possible to open many memory cameras\n> simultaneously, or none at all. So any time an application requests a\n> memory camera, we check with the pipeline handler whether it can\n> provide one.\n> \n> Signed-off-by: David Plowman <david.plowman@raspberrypi.com>\n> ---\n>  include/libcamera/camera_manager.h            |  4 ++\n>  include/libcamera/internal/camera_manager.h   |  5 ++\n>  include/libcamera/internal/pipeline_handler.h |  8 +++\n>  src/libcamera/camera_manager.cpp              | 64 +++++++++++++++++++\n>  src/libcamera/pipeline_handler.cpp            | 23 +++++++\n>  5 files changed, 104 insertions(+)\n> \n> diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h\n> index 27835500..436db409 100644\n> --- a/include/libcamera/camera_manager.h\n> +++ b/include/libcamera/camera_manager.h\n> @@ -7,6 +7,7 @@\n>  \n>  #pragma once\n>  \n> +#include <map>\n>  #include <memory>\n>  #include <string>\n>  #include <string_view>\n> @@ -20,6 +21,7 @@\n>  namespace libcamera {\n>  \n>  class Camera;\n> +class PipelineHandler;\n>  \n>  class CameraManager : public Object, public Extensible\n>  {\n> @@ -33,6 +35,8 @@ public:\n>  \n>         std::vector<std::shared_ptr<Camera>> cameras() const;\n>         std::shared_ptr<Camera> get(std::string_view id);\n> +       std::vector<std::string> memoryCameras() const;\n> +       std::shared_ptr<Camera> getMemoryCamera(std::string_view id, std::string_view settings);\n>  \n>         static const std::string &version() { return version_; }\n>  \n> diff --git a/include/libcamera/internal/camera_manager.h b/include/libcamera/internal/camera_manager.h\n> index 755928ce..4dbc1dc8 100644\n> --- a/include/libcamera/internal/camera_manager.h\n> +++ b/include/libcamera/internal/camera_manager.h\n> @@ -55,6 +55,9 @@ private:\n>         void pipelineFactoryMatch(const PipelineHandlerFactoryBase *factory);\n>         void cleanup() LIBCAMERA_TSA_EXCLUDES(mutex_);\n>  \n> +       std::shared_ptr<Camera> getMemoryCamera(const PipelineHandlerFactoryBase *factory,\n> +                                               std::string_view settings);\n> +\n>         /*\n>          * This mutex protects\n>          *\n> @@ -70,6 +73,8 @@ private:\n>  \n>         std::unique_ptr<DeviceEnumerator> enumerator_;\n>  \n> +       std::vector<std::string> memoryCameras_;\n> +\n>         std::unique_ptr<IPAManager> ipaManager_;\n>  \n>         const GlobalConfiguration configuration_;\n> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> index b4f97477..cb631529 100644\n> --- a/include/libcamera/internal/pipeline_handler.h\n> +++ b/include/libcamera/internal/pipeline_handler.h\n> @@ -70,6 +70,14 @@ public:\n>  \n>         CameraManager *cameraManager() const { return manager_; }\n>  \n> +       virtual bool supportsMemoryCamera() { return false; }\n> +\n> +       virtual std::shared_ptr<Camera> createMemoryCamera([[maybe_unused]] DeviceEnumerator *enumerator,\n> +                                                          [[maybe_unused]] std::string_view settings)\n> +       {\n> +               return nullptr;\n> +       }\n> +\n>  protected:\n>         void registerCamera(std::shared_ptr<Camera> camera);\n>         void hotplugMediaDevice(std::shared_ptr<MediaDevice> media);\n> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp\n> index 83510e06..734f5836 100644\n> --- a/src/libcamera/camera_manager.cpp\n> +++ b/src/libcamera/camera_manager.cpp\n> @@ -155,6 +155,13 @@ void CameraManager::Private::pipelineFactoryMatch(const PipelineHandlerFactoryBa\n>  {\n>         CameraManager *const o = LIBCAMERA_O_PTR();\n>  \n> +       /* First check for any memory-to-memory camera pipelines. */\n> +       {\n> +               std::shared_ptr<PipelineHandler> pipe = factory->create(o);\n> +               if (pipe->supportsMemoryCamera())\n\nAh, cool, the default is false! Looks good to me :-)\n\nReviewed-by: Isaac Scott <isaac.scott@ideasonboard.com>\n\n> +                       memoryCameras_.push_back(std::string(pipe->name()));\n> +       }\n> +\n>         /* Provide as many matching pipelines as possible. */\n>         while (1) {\n>                 std::shared_ptr<PipelineHandler> pipe = factory->create(o);\n> @@ -167,6 +174,19 @@ void CameraManager::Private::pipelineFactoryMatch(const PipelineHandlerFactoryBa\n>         }\n>  }\n>  \n> +std::shared_ptr<Camera> CameraManager::Private::getMemoryCamera(const PipelineHandlerFactoryBase *factory,\n> +                                                               std::string_view settings)\n> +{\n> +       CameraManager *const o = LIBCAMERA_O_PTR();\n> +\n> +       std::shared_ptr<PipelineHandler> pipe = factory->create(o);\n> +\n> +       pipe->moveToThread(this);\n> +\n> +       return pipe->invokeMethod(&PipelineHandler::createMemoryCamera,\n> +                                 ConnectionTypeBlocking, enumerator_.get(), settings);\n> +}\n> +\n>  void CameraManager::Private::cleanup()\n>  {\n>         enumerator_->devicesAdded.disconnect(this);\n> @@ -371,6 +391,9 @@ void CameraManager::stop()\n>   * Before calling this function the caller is responsible for ensuring that\n>   * the camera manager is running.\n>   *\n> + * This function does not list any memory cameras (for processing raw images\n> + * held in memory buffers) that may be available.\n> + *\n>   * \\context This function is \\threadsafe.\n>   *\n>   * \\return List of all available cameras\n> @@ -409,6 +432,47 @@ std::shared_ptr<Camera> CameraManager::get(std::string_view id)\n>         return nullptr;\n>  }\n>  \n> +/**\n> + * \\brief List the pipeline handlers that support memory cameras\n> + *\n> + * Lists the pipeline handlers in the system that have indicated they\n> + * support memory cameras. Memory cameras are used for processing raw\n> + * camera images stored in memory buffers, where no corresponding\n> + * camera is available.\n> + *\n> + * \\return Vector of pipeline handler ids (strings)\n> + */\n> +std::vector<std::string> CameraManager::memoryCameras() const\n> +{\n> +       return _d()->memoryCameras_;\n> +}\n> +\n> +/**\n> + * \\brief Get a memory camera from the named pipeline handler\n> + * \\param[in] id ID of the pipeline handler that should create the memory camera\n> + *\n> + * This function causes the named pipeline handler to create and return a\n> + * memory camera to the application. Pipeline handlers may support multiple\n> + * simultaneous memory cameras, or none at all.\n> + *\n> + * \\return Shared pointer to Camera object or nullptr if no memory camera\n> + * could be provided\n> + */\n> +std::shared_ptr<Camera> CameraManager::getMemoryCamera(std::string_view id,\n> +                                                      std::string_view settings)\n> +{\n> +       for (const auto &name : _d()->memoryCameras_) {\n> +               if (name == id) {\n> +                       const PipelineHandlerFactoryBase *factory;\n> +                       factory = PipelineHandlerFactoryBase::getFactoryByName(name);\n> +\n> +                       return _d()->getMemoryCamera(factory, settings);\n> +               }\n> +       }\n> +\n> +       return nullptr;\n> +}\n> +\n>  /**\n>   * \\var CameraManager::cameraAdded\n>   * \\brief Notify of a new camera added to the system\n> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> index 5c469e5b..c0f3c84e 100644\n> --- a/src/libcamera/pipeline_handler.cpp\n> +++ b/src/libcamera/pipeline_handler.cpp\n> @@ -835,6 +835,29 @@ void PipelineHandler::disconnect()\n>   * \\return The CameraManager for this pipeline handler\n>   */\n>  \n> +/**\n> + * \\fn PipelineHandler::supportsMemoryCamera()\n> + * \\brief Indicate whether this pipeline handler supports memory cameras.\n> + * \\return True if the pipeline handler supports memory cameras, otherwise false.\n> + */\n> +\n> +/**\n> + * \\fn PipelineHandler::createMemoryCamera()\n> + * \\brief Create a memory camera to process raw camera images from a memory buffer\n> + * \\param[in] enumerator The enumerator providing all media devices found in the\n> + * system\n> + * \\param[in] settings A string of settings that the pipeline handler should use\n> + *\n> + * The pipeline handler should create a memory camera, which an application can\n> + * use to process raw camera images that are stored in memory buffers (rather\n> + * than being delivered from a live camera).\n> + *\n> + * The settings should indicate exactly what processing the application requires\n> + * to be performed on the raw image.\n> + *\n> + * \\return Shared pointer to a camera, or a nullptr if none could be created\n> + */\n> +\n>  /**\n>   * \\class PipelineHandlerFactoryBase\n>   * \\brief Base class for pipeline handler factories\n> -- \n> 2.47.3\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 643EDBDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  6 Jan 2026 15:56:00 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A162461FA0;\n\tTue,  6 Jan 2026 16:55:59 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5FC5161F9F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  6 Jan 2026 16:55:58 +0100 (CET)","from thinkpad.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id F0D8F78E;\n\tTue,  6 Jan 2026 16:55:36 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"jLvsfHn0\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1767714937;\n\tbh=vk2ze0L3hCa6CaFU+g4rNrY6eIprxZTV64lYQaymW1M=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=jLvsfHn04JqS4vljLM6shdG5VPiVtTqRy4owYGqb8PVbGYmCqAcbl+Ko5yrnhA1A6\n\tDv2opm3VJJVG0w3hZnDV3Q9GDs45EHj9dM7tzP7uLO5owPFOiZi6Sxg17TlvPyfnl3\n\tv8G+wsvyd9qFLdqeQcFWIdBUJHgKB5rK0OobjjXk=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20251210164055.17856-2-david.plowman@raspberrypi.com>","References":"<20251210164055.17856-1-david.plowman@raspberrypi.com>\n\t<20251210164055.17856-2-david.plowman@raspberrypi.com>","Subject":"Re: [PATCH 01/11] libcamera: Infrastructure to ask for \"memory\"\n\tcameras","From":"Isaac Scott <isaac.scott@ideasonboard.com>","Cc":"David Plowman <david.plowman@raspberrypi.com>","To":"David Plowman <david.plowman@raspberrypi.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Tue, 06 Jan 2026 15:55:55 +0000","Message-ID":"<176771495548.112111.12971944340047876740@isaac-ThinkPad-T16-Gen-2>","User-Agent":"alot/0.10","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]