Patch Detail
Show a patch.
GET /api/1.1/patches/24243/?format=api
{ "id": 24243, "url": "https://patchwork.libcamera.org/api/1.1/patches/24243/?format=api", "web_url": "https://patchwork.libcamera.org/patch/24243/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/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": "<20250827090739.86955-8-david.plowman@raspberrypi.com>", "date": "2025-08-27T09:07:34", "name": "[RFC,07/12] libcamera: pipeline: rpi: Allow creation of the first \"memory\" camera", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "2d2bec52bac63e34e5704112841ce804a6d6e1cb", "submitter": { "id": 42, "url": "https://patchwork.libcamera.org/api/1.1/people/42/?format=api", "name": "David Plowman", "email": "david.plowman@raspberrypi.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/24243/mbox/", "series": [ { "id": 5407, "url": "https://patchwork.libcamera.org/api/1.1/series/5407/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5407", "date": "2025-08-27T09:07:27", "name": "Bayer Re-Processing", "version": 1, "mbox": "https://patchwork.libcamera.org/series/5407/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/24243/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/24243/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 5CFB4C332B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 Aug 2025 09:08:03 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 25883692F7;\n\tWed, 27 Aug 2025 11:08:01 +0200 (CEST)", "from mail-wm1-x333.google.com (mail-wm1-x333.google.com\n\t[IPv6:2a00:1450:4864:20::333])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 87B3A692E9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Aug 2025 11:07:49 +0200 (CEST)", "by mail-wm1-x333.google.com with SMTP id\n\t5b1f17b1804b1-45a1b0c52f3so40411945e9.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Aug 2025 02:07:49 -0700 (PDT)", "from raspberrypi.pitowers.org\n\t([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b])\n\tby smtp.gmail.com with ESMTPSA id\n\t5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.47\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 27 Aug 2025 02:07:47 -0700 (PDT)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"BfmQoCW1\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1756285669; x=1756890469;\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=15ju4tj93kD+K5/upT09hykhZm9/EYdCq0k49NZ7haY=;\n\tb=BfmQoCW1pGP9hwNAmcFRaCB6YrvMxcENv8qYDYPyGxiqWYYYrYqJeoPl7tHOZ230Sm\n\tRo7RdRz6NoWtC8CohJWmhUgy4IhXLKIC9NI01vK+DvZfoH4c0yVACz7HH85V9PGteRar\n\tByvucFj0hJQQlYLkz4y0Ab6fD0AuCVBgUHVM7kph/nVOOzBs65bfTo30reGZbVpRGwKR\n\tkV+HGRVQbaKzXAWdf6tXj1t2AgrX596hs/kRB6l2MxXB7Qq3vwa1MvK/P3+g9TVa1I+d\n\tUEaKDXy8+bbm633oR2OkkEfRmn1FVZU1xLRDYjCYvAcoS3qJCStlX0HlAvVIJldjyaYw\n\t6RNg==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1756285669; x=1756890469;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=15ju4tj93kD+K5/upT09hykhZm9/EYdCq0k49NZ7haY=;\n\tb=fgicWQLarH7GOzX0LDomTTwSy+AKDsBAo//pGdLOhp79bAxy5Q6Zphx719j6xn+7CZ\n\t0tBeeTbyO5nkMCS0kxRpDz/+RcbGmOYFNgekhPQclQjvQPIeffHCqBcyiX1KxXXbjt8X\n\ti0DEt0sIzwr3hvXbUhrnZ6pmBNnZIjjqXS+uiFzAsvCEAPOxZGQt0sR7Bgqg+AOtBFWc\n\tNqNJ1eWaZwFOWcSYNvlvlI3jGUd17+qfSOq8UQYJ3uyHOsJuJlX2Zs3rOG4d0pvd7DL6\n\t5CcWWD+JYARb5kmfxoHSJBRGBclvYEo6VNSsfe+whaZxdfbsVQMpXA/GvM083b5hHvFn\n\tgdAw==", "X-Gm-Message-State": "AOJu0YwZroHKwMIOwFUgyvuDqZitwlfjEvpT2XVGf0Dam5ViSjWZMnow\n\tfRZ4W/3f2Xs18tvZ/VFJ/6FCeuYesHw+bQ/xzz/YJTS+WiH7k1DYrv6UsaiusM0G/5If4s+8WwL\n\t3D9io", "X-Gm-Gg": "ASbGncsQhu0DMcRNTDqxoKRN/XiOov2P8UI0WzjH7PHlb8fBxvlaaVKecpq0gHwQzQ2\n\tfgfZuwvBHRQMgH4QrWps/vmom6sB0vMRZ/5bCyM5v5khBVk371DVpT8DWPbjomSZow8Ehz0qp4X\n\t0ANdsd0XwGjv9EQ/mcFVQ2ESWWChg8VeLKB+Pa5bOo4H/0ZikavEdoPgcoRGEN6O4dR9MHTEvGX\n\tE/5FwL5IuCj/LK5xXaX/+n5LNpwfF1+7CBtfXQXnpYPgPJYn6Af554tzcrpDZQ0bylHUvWOIAuK\n\tElFcfxZJljdNh5ugoqFuMMjTTici8BFyDFjpQ+mFrLtio5klxab0FIcl1oL6+/+j+ArnRZNy/Yt\n\t9v3pFzDSJpyKsQ1axMqI3aDcGZwdQLOeWpPniz1E5JgQESPwFYS9rg3eCdsRlmfSfh+MyPBW5ga\n\tqQNw/EyL+ddfC/leCZ/rggl4s7+stY1ImynXMZQAkjSaWQRqML8Q==", "X-Google-Smtp-Source": "AGHT+IFZErb7y1K1DBt+l1CjR7+seOHhh31OzJWDN4JYPLdyjqr1j63cYEicoT3yt+XAkJNzo/QcYw==", "X-Received": "by 2002:a05:600c:a47:b0:456:18cf:66b5 with SMTP id\n\t5b1f17b1804b1-45b517caa5emr140404875e9.22.1756285668398; \n\tWed, 27 Aug 2025 02:07:48 -0700 (PDT)", "From": "David Plowman <david.plowman@raspberrypi.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "David Plowman <david.plowman@raspberrypi.com>", "Subject": "[RFC PATCH 07/12] libcamera: pipeline: rpi: Allow creation of the\n\tfirst \"memory\" camera", "Date": "Wed, 27 Aug 2025 10:07:34 +0100", "Message-Id": "<20250827090739.86955-8-david.plowman@raspberrypi.com>", "X-Mailer": "git-send-email 2.39.5", "In-Reply-To": "<20250827090739.86955-1-david.plowman@raspberrypi.com>", "References": "<20250827090739.86955-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": "Signed-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 | 218 ++++++++++++++----\n 3 files changed, 187 insertions(+), 51 deletions(-)", "diff": "diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\nindex 563df198..1d4d6088 100644\n--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n@@ -1170,6 +1170,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 4bce4ec4..397ad6f8 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 745cb546..d18035ec 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 MediaDevice *cfe, MediaDevice *isp) override;\n };\n@@ -888,10 +895,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@@ -914,6 +919,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+\tMediaDevice *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);\n+\n+\treturn camera;\n+}\n+\n int PipelineHandlerPiSP::prepareBuffers(Camera *camera)\n {\n \tPiSPCameraData *data = cameraData(camera);\n@@ -1021,16 +1104,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 MediaDevice *cfe, 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@@ -1040,13 +1158,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@@ -1069,34 +1180,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@@ -1106,38 +1198,62 @@ 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 MediaDevice *cfe, MediaDevice *isp)\n+{\n+\tstd::shared_ptr<Camera> camera = platformCreateCamera(cameraData, cfe, isp);\n+\tPipelineHandler::registerCamera(std::move(camera));\n+\n \treturn 0;\n }\n \n", "prefixes": [ "RFC", "07/12" ] }