Patch Detail
Show a patch.
GET /api/patches/25471/?format=api
{ "id": 25471, "url": "https://patchwork.libcamera.org/api/patches/25471/?format=api", "web_url": "https://patchwork.libcamera.org/patch/25471/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20251210164055.17856-7-david.plowman@raspberrypi.com>", "date": "2025-12-10T16:15:21", "name": "[06/11] libcamera: pipeline: rpi: Allow creation of the first \"memory\" camera", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "2c70d490d5d6a50c0248a0152bc617b01854b220", "submitter": { "id": 42, "url": "https://patchwork.libcamera.org/api/people/42/?format=api", "name": "David Plowman", "email": "david.plowman@raspberrypi.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/25471/mbox/", "series": [ { "id": 5650, "url": "https://patchwork.libcamera.org/api/series/5650/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5650", "date": "2025-12-10T16:15:15", "name": "Bayer re-processing", "version": 1, "mbox": "https://patchwork.libcamera.org/series/5650/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/25471/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/25471/checks/", "tags": {}, "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 9AEBEC326C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 10 Dec 2025 16:41:11 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 65EEF614BA;\n\tWed, 10 Dec 2025 17:41:10 +0100 (CET)", "from mail-wm1-x334.google.com (mail-wm1-x334.google.com\n\t[IPv6:2a00:1450:4864:20::334])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8CCB8614AB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 10 Dec 2025 17:41:04 +0100 (CET)", "by mail-wm1-x334.google.com with SMTP id\n\t5b1f17b1804b1-477632d9326so47941455e9.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 10 Dec 2025 08:41:04 -0800 (PST)", "from davidp-pi5.pitowers.org\n\t([2a00:1098:3142:1f:88ea:c658:5b20:5e46])\n\tby smtp.gmail.com with ESMTPSA id\n\t5b1f17b1804b1-47a88371e13sm1270415e9.11.2025.12.10.08.41.02\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 10 Dec 2025 08:41:03 -0800 (PST)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"d+RxSkA+\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1765384864; x=1765989664;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=xHq6lLERxDdLmM67XaICA48L1mdiYZYJFWVPoXLhIsw=;\n\tb=d+RxSkA+wLq68Uc2Rq3rqDU3u28gw+ehaGXVnjpTbmnYDBvCYqME96d8D4wHG2aC7F\n\tGu2MjbHblpYEi7HVzfdtqIlFUz+Xv7kyGT4VdxU9lOdV397DXvAH0cUwDSHKQCvLlUR/\n\tKtAZJ/DpiOHXZyyc3sf489ZWiGMXZT+asWL8hl78RjcsCFguRyD47sfy0tk9P4LZFA0w\n\tWy8T4fBoFUJKA4QGSOCnihpj+Q1kdIEPK3Y5CI0yN9yXObmo2+O2HKuCOwpWF32qljLQ\n\tz2I5SvXsxNRQTCbk/m3LqAEQXZJ3rrSfLPsyqqdf9wmb3uAlLNLDMdyrg4VE3DMCDLlj\n\trkog==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1765384864; x=1765989664;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n\t:to:cc:subject:date:message-id:reply-to;\n\tbh=xHq6lLERxDdLmM67XaICA48L1mdiYZYJFWVPoXLhIsw=;\n\tb=M08qjaDDg3ThUhmoehEoD6XXQLhnw58oknZ0491QtgdvE2ZkW8v9Cxb+GBeXI7OrX7\n\tg0N7QAEwo4NqiX1S5DLwugpne6LUjL6XU3YMzAxznZoI6xPiaxcugYLX/Rn4c1an7cbE\n\tq/kzn9StaL98Ztme8Zfs7Zc+H6b6BEsXerw5jRDXSznyXD4SSVNb4c4qjx6vSGhrMiQ7\n\tcgdlVziwSbJHw1NlFk1AT0TEhclnoRVXaWGVn3rnkyG2WjPnYANKFe1AOQI+VQ5aj+m7\n\tceuZ2Jea+tnhBOMXPjovhh5v5l7AksAgaifpaMmBkXtZLB3OgBQs6yeeoE50QnvWRQyD\n\t9ZUQ==", "X-Gm-Message-State": "AOJu0YzqbymgBslI06S6y9u/NRCksqZh3f7UtDW4kvEBS9EDHgKmHyQy\n\tZdRpXfA8Yz9v6BG/mkj64SBHgnDAUMdhsdi4Gw2tqnyeabNd0sC2GYFuDdLxINcB95uCLaepxMJ\n\tUTztp", "X-Gm-Gg": "ASbGncubbbXkzF4L5MojJ/+NQUtRFdJGbaj3D4sfSQQvX9YeJtI+2bkw9uUV3toy+iZ\n\tLfswFoyA4lLr6hq1e9HOfDSPjRLHuw9Wiq4tfwPTp8mBRIFw1pJ+s+Duw/9yzpBIi+JVrgYHEq4\n\t5kIByBL1j63N4m+v4042AvRL/xQJsNxa5Z8Jq6EdtHHQMbDU1pk3CDLafzte1MSDOZIPBO4Qiv0\n\tojT/O/FqS2TFjLWOTKp+ihpUnLkc+MClm8YYdMgj4NGJz6kVLhGjBKlpIEM2VrO4umL40yHDVgP\n\tBc2Z658U/CfQY7pFumKa6N2SuBEcRFCceqn/RfqgvATC1rRV3qQa9xUe0Vp/HmfZJEi0hZLq/pR\n\tP36gpnf6gaMkMyWlY1aKus9E+2DOpiIwSmmD2mjgMn+upHA+8jtiymhRtrrS4a2gVj15v2eJsxs\n\tV5vf3lUaVLa8COUMNiO7gfk5c6Fp+oRtX0amjFkCvNRz8AGNmAJeOBGeGRLKNRHuO3VB6neXi2t\n\tOvl+fYLgkwGwze2+4Mxg5FA6YRReQ==", "X-Google-Smtp-Source": "AGHT+IGWCUCABkuOVZ1Ydh+rnYbbB5LdkrfVDglFf9NQJ1dKY6iVjW18ECqHtnKtVWgR/E66qfLXhw==", "X-Received": "by 2002:a05:600c:820c:b0:477:a54a:acba with SMTP id\n\t5b1f17b1804b1-47a8384c38bmr34671815e9.17.1765384863555; \n\tWed, 10 Dec 2025 08:41:03 -0800 (PST)", "From": "David Plowman <david.plowman@raspberrypi.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "David Plowman <david.plowman@raspberrypi.com>", "Subject": "[PATCH 06/11] libcamera: pipeline: rpi: Allow creation of the first\n\t\"memory\" camera", "Date": "Wed, 10 Dec 2025 16:15:21 +0000", "Message-ID": "<20251210164055.17856-7-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", "Content-Transfer-Encoding": "8bit", "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>" }, "content": "The Raspberry Pi PiSP pipeline handler is updated to indicate that it\nsupports the creation of \"memory\" cameras, and extended actually to do\nso.\n\nMemory cameras are created on demand when applications request them.\n\nSubsequent commits will support the correct handling of camera\nconfigurations with \"input\" streams, that will require the use of\nthese memory cameras.\n\nSigned-off-by: David Plowman <david.plowman@raspberrypi.com>\n---\n .../pipeline/rpi/common/pipeline_base.cpp | 19 ++\n .../pipeline/rpi/common/pipeline_base.h | 1 +\n src/libcamera/pipeline/rpi/pisp/pisp.cpp | 220 +++++++++++++-----\n 3 files changed, 188 insertions(+), 52 deletions(-)", "diff": "diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\nindex 00b088fc..6878bdee 100644\n--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n@@ -1217,6 +1217,25 @@ int CameraData::loadIPA(ipa::RPi::InitResult *result)\n \treturn ipa_->init(settings, params, result);\n }\n \n+int CameraData::loadNamedIPA(std::string const &tuningFile, ipa::RPi::InitResult *result)\n+{\n+\tint ret;\n+\n+\tipa_ = IPAManager::createIPA<ipa::RPi::IPAProxyRPi>(pipe(), 1, 1);\n+\n+\tif (!ipa_)\n+\t\treturn -ENOENT;\n+\n+\tIPASettings settings(tuningFile, \"default\");\n+\tipa::RPi::InitParams params;\n+\n+\tret = platformInitIpa(params);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn ipa_->init(settings, params, result);\n+}\n+\n int CameraData::configureIPA(const CameraConfiguration *config, ipa::RPi::ConfigResult *result)\n {\n \tipa::RPi::ConfigParams params;\ndiff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\nindex 1f174473..9453ae7e 100644\n--- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n@@ -72,6 +72,7 @@ public:\n \n \tint loadPipelineConfiguration();\n \tint loadIPA(ipa::RPi::InitResult *result);\n+\tint loadNamedIPA(std::string const &settings, ipa::RPi::InitResult *result);\n \tint configureIPA(const CameraConfiguration *config, ipa::RPi::ConfigResult *result);\n \tvirtual int platformInitIpa(ipa::RPi::InitParams ¶ms) = 0;\n \tvirtual int platformConfigureIpa(ipa::RPi::ConfigParams ¶ms) = 0;\ndiff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\nindex c08210b4..726ab063 100644\n--- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n+++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n@@ -815,6 +815,11 @@ public:\n \n \tbool match(DeviceEnumerator *enumerator) override;\n \n+\tbool supportsMemoryCamera() override;\n+\n+\tstd::shared_ptr<Camera> createMemoryCamera(DeviceEnumerator *enumerator,\n+\t\t\t\t\t\t std::string_view settings) override;\n+\n private:\n \tPiSPCameraData *cameraData(Camera *camera)\n \t{\n@@ -822,6 +827,8 @@ private:\n \t}\n \n \tint prepareBuffers(Camera *camera) override;\n+\tstd::shared_ptr<Camera> platformCreateCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n+\t\t\t\t\t\t MediaDevice *cfe, MediaDevice *isp);\n \tint platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n \t\t\t std::shared_ptr<MediaDevice> cfe,\n \t\t\t std::shared_ptr<MediaDevice> isp) override;\n@@ -889,10 +896,8 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n \t\t\tPiSPCameraData *pisp =\n \t\t\t\tstatic_cast<PiSPCameraData *>(cameraData.get());\n \n-\t\t\tpisp->fe_ = SharedMemObject<FrontEnd>\n-\t\t\t\t\t(\"pisp_frontend\", true, pisp->pispVariant_);\n-\t\t\tpisp->be_ = SharedMemObject<BackEnd>\n-\t\t\t\t\t(\"pisp_backend\", BackEnd::Config({}), pisp->pispVariant_);\n+\t\t\tpisp->fe_ = SharedMemObject<FrontEnd>(\"pisp_frontend\", true, pisp->pispVariant_);\n+\t\t\tpisp->be_ = SharedMemObject<BackEnd>(\"pisp_backend\", BackEnd::Config({}), pisp->pispVariant_);\n \n \t\t\tif (!pisp->fe_.fd().isValid() || !pisp->be_.fd().isValid()) {\n \t\t\t\tLOG(RPI, Error) << \"Failed to create ISP shared objects\";\n@@ -915,6 +920,84 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator)\n \treturn false;\n }\n \n+bool PipelineHandlerPiSP::supportsMemoryCamera()\n+{\n+\treturn true;\n+}\n+\n+static bool get_variant(unsigned int be_version, const libpisp::PiSPVariant **variant)\n+{\n+\tfor (const auto &hw : libpisp::get_variants()) {\n+\t\tif (hw.BackEndVersion() == be_version) {\n+\t\t\t*variant = &hw;\n+\t\t\treturn true;\n+\t\t}\n+\t}\n+\n+\treturn false;\n+}\n+\n+std::shared_ptr<Camera>\n+PipelineHandlerPiSP::createMemoryCamera(DeviceEnumerator *enumerator,\n+\t\t\t\t\tstd::string_view settings)\n+{\n+\tDeviceMatch isp(\"pispbe\");\n+\tisp.add(\"pispbe-input\");\n+\tisp.add(\"pispbe-config\");\n+\tisp.add(\"pispbe-output0\");\n+\tisp.add(\"pispbe-output1\");\n+\tisp.add(\"pispbe-tdn_output\");\n+\tisp.add(\"pispbe-tdn_input\");\n+\tisp.add(\"pispbe-stitch_output\");\n+\tisp.add(\"pispbe-stitch_input\");\n+\tstd::shared_ptr<MediaDevice> ispDevice = acquireMediaDevice(enumerator, isp);\n+\n+\tif (!ispDevice) {\n+\t\tLOG(RPI, Warning) << \"Unable to acquire ISP instance\";\n+\t\treturn nullptr;\n+\t}\n+\n+\tconst libpisp::PiSPVariant *variant = nullptr;\n+\tif (!get_variant(ispDevice->hwRevision(), &variant)) {\n+\t\tLOG(RPI, Warning) << \"Failed to find variant\";\n+\t\treturn nullptr;\n+\t}\n+\n+\tstd::unique_ptr<RPi::CameraData> cameraData =\n+\t\tstd::make_unique<PiSPCameraData>(this, *variant);\n+\tPiSPCameraData *pisp =\n+\t\tstatic_cast<PiSPCameraData *>(cameraData.get());\n+\n+\t/* Only need the back end, but creating the front end makes things easier */\n+\tpisp->fe_ = SharedMemObject<FrontEnd>(\"pisp_frontend\", true, pisp->pispVariant_);\n+\tpisp->be_ = SharedMemObject<BackEnd>(\"pisp_backend\", BackEnd::Config({}), pisp->pispVariant_);\n+\n+\tif (!pisp->fe_.fd().isValid() || !pisp->be_.fd().isValid()) {\n+\t\tLOG(RPI, Error) << \"Failed to create ISP shared objects\";\n+\t\treturn nullptr;\n+\t}\n+\n+\t/*\n+\t * Next, we want to do PipelineHandlerBase::registerCamera, including:\n+\t * loadIPA\n+\t * platformReigster\n+\t * loadPipelineConfiguration\n+\t */\n+\n+\t/* loadIPA is a bit different for us as we have a filename */\n+\tipa::RPi::InitResult result;\n+\tstd::string configFile = std::string(settings);\n+\tif (pisp->loadNamedIPA(configFile, &result)) {\n+\t\tLOG(RPI, Error) << \"Failed to load a suitable IPA library\";\n+\t\treturn nullptr;\n+\t}\n+\tLOG(RPI, Info) << \"Loaded IPA library \" << configFile << \" for memory camera\";\n+\n+\tstd::shared_ptr<Camera> camera = platformCreateCamera(cameraData, nullptr, ispDevice.get());\n+\n+\treturn camera;\n+}\n+\n int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n {\n \tPiSPCameraData *data = cameraData(camera);\n@@ -1022,17 +1105,51 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n \treturn 0;\n }\n \n-int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n-\t\t\t\t\t std::shared_ptr<MediaDevice> cfe,\n-\t\t\t\t\t std::shared_ptr<MediaDevice> isp)\n+static int createCameraCfe(PiSPCameraData *data, MediaDevice *cfe, std::set<Stream *> &streams)\n {\n-\tPiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n-\tint ret;\n-\n \tMediaEntity *cfeImage = cfe->getEntityByName(\"rp1-cfe-fe_image0\");\n \tMediaEntity *cfeEmbedded = cfe->getEntityByName(\"rp1-cfe-embedded\");\n \tMediaEntity *cfeStats = cfe->getEntityByName(\"rp1-cfe-fe_stats\");\n \tMediaEntity *cfeConfig = cfe->getEntityByName(\"rp1-cfe-fe_config\");\n+\n+\t/* Locate and open the cfe video streams. */\n+\tdata->cfe_[Cfe::Output0] = RPi::Stream(\"CFE Image\", cfeImage, StreamFlag::RequiresMmap);\n+\tdata->cfe_[Cfe::Embedded] = RPi::Stream(\"CFE Embedded\", cfeEmbedded);\n+\tdata->cfe_[Cfe::Stats] = RPi::Stream(\"CFE Stats\", cfeStats);\n+\tdata->cfe_[Cfe::Config] = RPi::Stream(\"CFE Config\", cfeConfig,\n+\t\t\t\t\t StreamFlag::Recurrent | StreamFlag::RequiresMmap);\n+\n+\t/* Wire up all the buffer connections. */\n+\tdata->cfe_[Cfe::Output0].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue);\n+\tdata->cfe_[Cfe::Stats].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue);\n+\tdata->cfe_[Cfe::Config].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue);\n+\tdata->cfe_[Cfe::Embedded].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue);\n+\n+\tdata->csi2Subdev_ = std::make_unique<V4L2Subdevice>(cfe->getEntityByName(\"csi2\"));\n+\tdata->feSubdev_ = std::make_unique<V4L2Subdevice>(cfe->getEntityByName(\"pisp-fe\"));\n+\tdata->csi2Subdev_->open();\n+\tdata->feSubdev_->open();\n+\n+\t/*\n+\t * The below grouping is just for convenience so that we can easily\n+\t * iterate over all streams in one go.\n+\t */\n+\tdata->streams_.push_back(&data->cfe_[Cfe::Output0]);\n+\tdata->streams_.push_back(&data->cfe_[Cfe::Config]);\n+\tdata->streams_.push_back(&data->cfe_[Cfe::Stats]);\n+\tif (data->sensorMetadata_)\n+\t\tdata->streams_.push_back(&data->cfe_[Cfe::Embedded]);\n+\n+\tdata->ipa_->setCameraTimeout.connect(data, &PiSPCameraData::setCameraTimeout);\n+\n+\t/* Applications may ask for this stream. */\n+\tstreams.insert(&data->cfe_[Cfe::Output0]);\n+\n+\treturn 0;\n+}\n+\n+static int createCameraBe(PiSPCameraData *data, MediaDevice *isp, std::set<Stream *> &streams)\n+{\n \tMediaEntity *ispInput = isp->getEntityByName(\"pispbe-input\");\n \tMediaEntity *IpaPrepare = isp->getEntityByName(\"pispbe-config\");\n \tMediaEntity *ispOutput0 = isp->getEntityByName(\"pispbe-output0\");\n@@ -1042,13 +1159,6 @@ int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &came\n \tMediaEntity *ispStitchOutput = isp->getEntityByName(\"pispbe-stitch_output\");\n \tMediaEntity *ispStitchInput = isp->getEntityByName(\"pispbe-stitch_input\");\n \n-\t/* Locate and open the cfe video streams. */\n-\tdata->cfe_[Cfe::Output0] = RPi::Stream(\"CFE Image\", cfeImage, StreamFlag::RequiresMmap);\n-\tdata->cfe_[Cfe::Embedded] = RPi::Stream(\"CFE Embedded\", cfeEmbedded);\n-\tdata->cfe_[Cfe::Stats] = RPi::Stream(\"CFE Stats\", cfeStats);\n-\tdata->cfe_[Cfe::Config] = RPi::Stream(\"CFE Config\", cfeConfig,\n-\t\t\t\t\t StreamFlag::Recurrent | StreamFlag::RequiresMmap);\n-\n \t/* Tag the ISP input stream as an import stream. */\n \tdata->isp_[Isp::Input] =\n \t\tRPi::Stream(\"ISP Input\", ispInput, StreamFlag::ImportOnly);\n@@ -1071,34 +1181,15 @@ int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &came\n \t\t\t\t\t\t\t\tStreamFlag::Recurrent);\n \n \t/* Wire up all the buffer connections. */\n-\tdata->cfe_[Cfe::Output0].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue);\n-\tdata->cfe_[Cfe::Stats].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue);\n-\tdata->cfe_[Cfe::Config].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue);\n \tdata->isp_[Isp::Input].dev()->bufferReady.connect(data, &PiSPCameraData::beInputDequeue);\n \tdata->isp_[Isp::Config].dev()->bufferReady.connect(data, &PiSPCameraData::beOutputDequeue);\n \tdata->isp_[Isp::Output0].dev()->bufferReady.connect(data, &PiSPCameraData::beOutputDequeue);\n \tdata->isp_[Isp::Output1].dev()->bufferReady.connect(data, &PiSPCameraData::beOutputDequeue);\n-\tdata->cfe_[Cfe::Embedded].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue);\n-\n-\tdata->csi2Subdev_ = std::make_unique<V4L2Subdevice>(cfe->getEntityByName(\"csi2\"));\n-\tdata->feSubdev_ = std::make_unique<V4L2Subdevice>(cfe->getEntityByName(\"pisp-fe\"));\n-\tdata->csi2Subdev_->open();\n-\tdata->feSubdev_->open();\n \n \t/*\n-\t * Open all CFE and ISP streams. The exception is the embedded data\n-\t * stream, which only gets opened below if the IPA reports that the sensor\n-\t * supports embedded data.\n-\t *\n \t * The below grouping is just for convenience so that we can easily\n \t * iterate over all streams in one go.\n \t */\n-\tdata->streams_.push_back(&data->cfe_[Cfe::Output0]);\n-\tdata->streams_.push_back(&data->cfe_[Cfe::Config]);\n-\tdata->streams_.push_back(&data->cfe_[Cfe::Stats]);\n-\tif (data->sensorMetadata_)\n-\t\tdata->streams_.push_back(&data->cfe_[Cfe::Embedded]);\n-\n \tdata->streams_.push_back(&data->isp_[Isp::Input]);\n \tdata->streams_.push_back(&data->isp_[Isp::Output0]);\n \tdata->streams_.push_back(&data->isp_[Isp::Output1]);\n@@ -1108,38 +1199,63 @@ int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &came\n \tdata->streams_.push_back(&data->isp_[Isp::StitchInput]);\n \tdata->streams_.push_back(&data->isp_[Isp::StitchOutput]);\n \n+\t/* Applications may ask for these stream. */\n+\tstreams.insert(&data->isp_[Isp::Output0]);\n+\tstreams.insert(&data->isp_[Isp::Output1]);\n+\n+\treturn 0;\n+}\n+\n+std::shared_ptr<Camera>\n+PipelineHandlerPiSP::platformCreateCamera(std::unique_ptr<RPi::CameraData> &cameraData,\n+\t\t\t\t\t MediaDevice *cfe, MediaDevice *isp)\n+{\n+\tPiSPCameraData *data = static_cast<PiSPCameraData *>(cameraData.get());\n+\tint ret;\n+\tstd::set<Stream *> streams;\n+\n+\t/* cfe is a null pointer when making a memory camera that doesn't use the front end. */\n+\tif (cfe) {\n+\t\tret = createCameraCfe(data, cfe, streams);\n+\t\tif (ret)\n+\t\t\treturn nullptr;\n+\t}\n+\n+\tret = createCameraBe(data, isp, streams);\n+\tif (ret)\n+\t\treturn nullptr;\n+\n+\t/* All the streams must open successfully. */\n \tfor (auto stream : data->streams_) {\n \t\tret = stream->dev()->open();\n \t\tif (ret)\n-\t\t\treturn ret;\n+\t\t\treturn nullptr;\n \t}\n \n-\t/* Write up all the IPA connections. */\n+\t/* Wire up all the IPA connections. */\n \tdata->ipa_->prepareIspComplete.connect(data, &PiSPCameraData::prepareIspComplete);\n \tdata->ipa_->processStatsComplete.connect(data, &PiSPCameraData::processStatsComplete);\n-\tdata->ipa_->setCameraTimeout.connect(data, &PiSPCameraData::setCameraTimeout);\n-\n-\t/*\n-\t * List the available streams an application may request. At present, we\n-\t * do not advertise CFE Embedded and ISP Statistics streams, as there\n-\t * is no mechanism for the application to request non-image buffer formats.\n-\t */\n-\tstd::set<Stream *> streams;\n-\tstreams.insert(&data->cfe_[Cfe::Output0]);\n-\tstreams.insert(&data->isp_[Isp::Output0]);\n-\tstreams.insert(&data->isp_[Isp::Output1]);\n \n \t/* Create and register the camera. */\n-\tconst std::string &id = data->sensor_->id();\n+\tconst std::string &id = cfe ? data->sensor_->id() : \"memory\";\n \tstd::shared_ptr<Camera> camera =\n \t\tCamera::create(std::move(cameraData), id, streams);\n-\tPipelineHandler::registerCamera(std::move(camera));\n \n \tLOG(RPI, Info) << \"Registered camera \" << id\n-\t\t << \" to CFE device \" << cfe->deviceNode()\n+\t\t << (cfe ? \" to CFE device \" + cfe->deviceNode() : \"\")\n \t\t << \" and ISP device \" << isp->deviceNode()\n \t\t << \" using PiSP variant \" << data->pispVariant_.Name();\n \n+\treturn camera;\n+}\n+\n+int PipelineHandlerPiSP::platformRegister(std::unique_ptr<RPi::CameraData> &cameraData,\n+\t\t\t\t\t std::shared_ptr<MediaDevice> cfe,\n+\t\t\t\t\t std::shared_ptr<MediaDevice> isp)\n+{\n+\tstd::shared_ptr<Camera> camera = platformCreateCamera(cameraData, cfe.get(), isp.get());\n+\tPipelineHandler::registerCamera(std::move(camera));\n+\n \treturn 0;\n }\n \n", "prefixes": [ "06/11" ] }