From patchwork Wed Aug 27 09:07:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24238 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 A3584BD87C for ; Wed, 27 Aug 2025 09:07:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3F6B9692EE; Wed, 27 Aug 2025 11:07:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="JncETe+o"; dkim-atps=neutral Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C85CA613C0 for ; Wed, 27 Aug 2025 11:07:44 +0200 (CEST) Received: by mail-wr1-x434.google.com with SMTP id ffacd0b85a97d-3c73d3ebff0so293571f8f.1 for ; Wed, 27 Aug 2025 02:07:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285664; x=1756890464; 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=KWoEiVaKZRbolQ7JZ2mn3Ccm5Fq8zD+7dRFyWs6vnD4=; b=JncETe+ouofaKkULrRNzvqJQ7/q//a3pEj2LTYAIrFhE6QNR/+20abOzvoFVExAoGn qwuguPC1ar0TXyI9gDtkUtLuFomQQmPFvgDvQMt4AZShi3WI5zNQw+6j22st1rhU2yI7 bKjiND0FMhdESmovNLQTcRsMtj5IxHjIBiqnjlpigO3FTvjAN7hEKNTipTSzc2mBQXhg fv0bYGc3ul7C3u7bTBNRAwsnKWxH2M27/voH199HGCjkI11w8b9EiZbwW6FO8ERnCweB tIxOcbWq81DKDm5MRjw3uj4h7+ro8glzhkedi32I3b6ZgEU6TiI7tIZt+3tbaVC5MBwJ ixzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285664; x=1756890464; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KWoEiVaKZRbolQ7JZ2mn3Ccm5Fq8zD+7dRFyWs6vnD4=; b=anUoNaU2jI4iI/U114Ha9o0KFEDm55266GmxTCxnVrICbuffmzPS0HTlpAoZO/lFZq 6ufyi3lBYIf51x4MoN5/wi8mTv43m41tCYTY8cV6rN8PKWeSb8SCKGmqykGmP2knHVb9 gy2a34ENNvdBcMo5NPSWYvETj/Sv9t6IoaaF3zhWGw4EsnAswjOSihFx4HQxdDZ697Q9 phQxqCwi5D5RvqdQAvC3w5jlfgWOv0JZZCIGLun4f4NBeH5B0CxV2LOD+viwgh7vDhEf jx4mVR82EdQe87Sp3MrctEwmq+/eVTz1q5e1jNQsC++B7O4oC1ZauTQ4cQ6reFCBBFwo ZyLg== X-Gm-Message-State: AOJu0Yyyl9Kv5oXlutEwtcy5Ucg+jrHRnVZSK057BOeDzSAXWUIdy0a5 Z3vflALWEyy4Jp8F6nHE/xk8Qeen35onbxqvxcilquM0JLfSEAlM6ZY5puZUrIj6NP4NhmYYDN0 amwSt X-Gm-Gg: ASbGnct4rTqhadkyhq288ZCJgJlB16w2LbWOwPSMYvpj+I/ZygOa29Xwm8it4sINKR+ Ldupxj3Qfez89Jj0+Rct+i0quW5PY7IlxxJ0RKdus31JrbdMAGSjAun39mU7JaHt8leUge06HbV ec185D4qG++GNKce+oxkYW5u0MRnAOO87GBfST46A/oEnGIxEYn7oJk63C+3CWwxbuebpU9VXJg uj/ZoYcsKI69gIyRykask4m8RHod2/LITWVq1yktiI+1UFSS4WkMBhX3kFvNPLe6lqBSUcKRpsM g4UunnoDhFVkKmWkL+8E09Hf5zKhnjoCSnoAEQrMBEUIB2qTWAnAFmvqTVMASERsFpaULFXb4tm jRmI5uEIoiCg2Mi9Q/ypWgRsCylKd2P/koYmY69QbUiZCP1/UkY1bUVVMrkuJke5bTiq30HABI6 Ewr7qySKOl07MmlJanomq1TDDRcJCbmJHSCLGFzIU= X-Google-Smtp-Source: AGHT+IFifNTZFgU4+DBCq+DKwm76bd4pDL7riH7TdCNJsx1AB+bE11Wwa0/eRmX1k/hRHoLeOj3CWQ== X-Received: by 2002:a5d:5d10:0:b0:3c5:8300:978d with SMTP id ffacd0b85a97d-3cbb15ca07fmr3725265f8f.22.1756285663781; Wed, 27 Aug 2025 02:07:43 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:43 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 01/12] libcamera: Infrastructure to ask for "memory" cameras Date: Wed, 27 Aug 2025 10:07:28 +0100 Message-Id: <20250827090739.86955-2-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 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" 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 | 40 +++++++++++++++++++ 4 files changed, 57 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 0150ca61..a490cb25 100644 --- a/include/libcamera/internal/camera_manager.h +++ b/include/libcamera/internal/camera_manager.h @@ -49,6 +49,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 * @@ -64,6 +67,8 @@ private: std::unique_ptr enumerator_; + std::vector memoryCameras_; + std::unique_ptr ipaManager_; ProcessManager processManager_; }; diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index e89d6a33..0210d48b 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(MediaDevice *media); diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index f81794bf..580c31bf 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -152,6 +152,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); @@ -164,6 +171,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); @@ -399,6 +419,26 @@ std::shared_ptr CameraManager::get(std::string_view id) return nullptr; } +std::vector CameraManager::memoryCameras() const +{ + return _d()->memoryCameras_; +} + +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 From patchwork Wed Aug 27 09:07:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24239 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 316F7BD87C for ; Wed, 27 Aug 2025 09:07:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1B94A692FB; Wed, 27 Aug 2025 11:07:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="tOkjfdeY"; dkim-atps=neutral Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 772C2692EB for ; Wed, 27 Aug 2025 11:07:45 +0200 (CEST) Received: by mail-wm1-x32a.google.com with SMTP id 5b1f17b1804b1-45a1b004954so51909275e9.0 for ; Wed, 27 Aug 2025 02:07:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285665; x=1756890465; 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=Sua0fW4TmtI2NRqqSMfXISvx8gNaU/HRu7j90J3GPoE=; b=tOkjfdeYkWgFASAOMkXgs44TGSUuWXCJ473dH3dVmLsFIkFnB9ahqpXQ1vzu5J0n6p uQRlM+3PqvW7VyrcJOGDayPA5+ctnt5BdaRMS/nvbvyp7PvKmEZKpZmvbZx8KeYP/4YA hQU3DclF3IbeGZ2hOZ3teaamvIubKQiEF/vyUqi+K/UvffSPGxP7bX+tem10lGHu+At8 nHK1KJ87i1Pzbob6Bk75xVUgRo88vFV/7tYVI5xh2StK9J7Gi6eEFtKqyu9a4S9wez8d B5zFZXdl56WEFOhUs+dOO+09pHWWkMyYswj1S4UjnEPjpwfOrzLDQDKFsgaq6dnvq4ZR 0VnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285665; x=1756890465; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Sua0fW4TmtI2NRqqSMfXISvx8gNaU/HRu7j90J3GPoE=; b=AHOHgLYLzN9Z1wHgiaggPHu69Mzj7rwjuF0hrJJtBhC24L9ubSDXt3+0MrRZIqzPzs ZwvHV1d0QAwoKXgXBLERW7c7IxKyPStOPsMsaRAtHaG1tM1Rrqg335HXK+dqe8svmnWq 8VaC6sAARn/vu8c8SadJI2Zr4aBTo0fc+bd9iZw1kLwJjUQfYNLyehk2CVpm1g9lPXmd 8k9E/NQg6Re0WuxTHMDb86UdPHlu59vtxN7PiQJeE34AV4j2Bhec1ZK1ep9Sa/5mJrfP Q2uqg/XaG/ewOACdOcyVDPVQpcOetpiha3QUxbdJTRwk59lTQYazgj2osxosaBJPwQ9s 5gyg== X-Gm-Message-State: AOJu0YyT+Eam/WCtAbTi412Q/4glLAyqbSpNVRaNXz3fhnY6n/2Is5+D ZYEve/syfbjcng8U5kmQDWDoklu2WsQXKfyPo+EEijezbiQtcJRKybVptYLLEwSPKeZqeL+cyKz KEsrN X-Gm-Gg: ASbGncvW0HL0YqWk1cgyfCv9n8XVgjc8PeWvbNqWAC5lBHkApTz8ZfmDoljiw40ejKB te30IY+C3ZMJNA7Yo+N2WBzfnJJjhC8DHSwJknpWiy4hDlzbR2IGXCmSer1iI0XTjz9S4swNWIC W8tMSrUORkqyM0w/tSRfWCo8ScM8KmUUHlpm0TRcbi878oibKlhnyUQNuap6namZ7pvQCI1nJO3 inrz1A/Zp9diMB+wg78LJVvfg+wfqRe8I9q05yZKGgevMs6dPxal+RDn283x/sDc2Xdt8K4YrDQ MKmTz+X+wVbdm1yBKui7LRlSLFjNmeXD0AdWd+TjtsiG8ANQ5fha23Ib4bSzKZU91C3mMyvnv8E qlDW43wDCz5Z+w5sgphx3F7pTNQXMzn9HEyO1+Taerfz6oQ2Xc4OconV2gsxT0NDjRZIil1zkBf CVaETBkB584aKhQlZJ5r1sEZhyOmtkb9UueAsiMFc5aoLsOKEnrdqQ2aZpfquG X-Google-Smtp-Source: AGHT+IEMuPeTAyXray2xtje4tJ6CkmcQAi2cZ/XeJbdvG6af5uog1UtlaKbu2svo/w6KIUd2qV8g/w== X-Received: by 2002:a05:600c:154f:b0:458:6733:fb43 with SMTP id 5b1f17b1804b1-45b517c552dmr144163855e9.19.1756285664593; Wed, 27 Aug 2025 02:07:44 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:44 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 02/12] libcamera: Add BayerFormat::toMbusCode Date: Wed, 27 Aug 2025 10:07:29 +0100 Message-Id: <20250827090739.86955-3-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 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" Multiple places now need this, so centralise it here. Signed-off-by: David Plowman --- include/libcamera/internal/bayer_format.h | 1 + src/libcamera/bayer_format.cpp | 124 ++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/include/libcamera/internal/bayer_format.h b/include/libcamera/internal/bayer_format.h index 5c14bb5f..f2f22932 100644 --- a/include/libcamera/internal/bayer_format.h +++ b/include/libcamera/internal/bayer_format.h @@ -53,6 +53,7 @@ public: std::string toString() const; + unsigned int toMbusCode() const; V4L2PixelFormat toV4L2PixelFormat() const; static BayerFormat fromV4L2PixelFormat(V4L2PixelFormat v4l2Format); PixelFormat toPixelFormat() const; diff --git a/src/libcamera/bayer_format.cpp b/src/libcamera/bayer_format.cpp index 3dab91fc..9e9d50fc 100644 --- a/src/libcamera/bayer_format.cpp +++ b/src/libcamera/bayer_format.cpp @@ -331,6 +331,130 @@ std::ostream &operator<<(std::ostream &out, const BayerFormat &f) return out; } +const std::vector> BayerToMbusCodeMap{ + { + { BayerFormat::BGGR, 8, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SBGGR8_1X8, + }, + { + { BayerFormat::GBRG, 8, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGBRG8_1X8, + }, + { + { BayerFormat::GRBG, 8, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGRBG8_1X8, + }, + { + { BayerFormat::RGGB, 8, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SRGGB8_1X8, + }, + { + { BayerFormat::BGGR, 10, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SBGGR10_1X10, + }, + { + { BayerFormat::GBRG, 10, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGBRG10_1X10, + }, + { + { BayerFormat::GRBG, 10, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGRBG10_1X10, + }, + { + { BayerFormat::RGGB, 10, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SRGGB10_1X10, + }, + { + { BayerFormat::BGGR, 12, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SBGGR12_1X12, + }, + { + { BayerFormat::GBRG, 12, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGBRG12_1X12, + }, + { + { BayerFormat::GRBG, 12, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGRBG12_1X12, + }, + { + { BayerFormat::RGGB, 12, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SRGGB12_1X12, + }, + { + { BayerFormat::BGGR, 14, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SBGGR14_1X14, + }, + { + { BayerFormat::GBRG, 14, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGBRG14_1X14, + }, + { + { BayerFormat::GRBG, 14, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGRBG14_1X14, + }, + { + { BayerFormat::RGGB, 14, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SRGGB14_1X14, + }, + { + { BayerFormat::BGGR, 16, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SBGGR16_1X16, + }, + { + { BayerFormat::GBRG, 16, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGBRG16_1X16, + }, + { + { BayerFormat::GRBG, 16, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SGRBG16_1X16, + }, + { + { BayerFormat::RGGB, 16, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_SRGGB16_1X16, + }, + { + { BayerFormat::BGGR, 16, BayerFormat::Packing::PISP1 }, + MEDIA_BUS_FMT_SBGGR16_1X16, + }, + { + { BayerFormat::GBRG, 16, BayerFormat::Packing::PISP1 }, + MEDIA_BUS_FMT_SGBRG16_1X16, + }, + { + { BayerFormat::GRBG, 16, BayerFormat::Packing::PISP1 }, + MEDIA_BUS_FMT_SGRBG16_1X16, + }, + { + { BayerFormat::RGGB, 16, BayerFormat::Packing::PISP1 }, + MEDIA_BUS_FMT_SRGGB16_1X16, + }, + { + { BayerFormat::RGGB, 16, BayerFormat::Packing::PISP1 }, + MEDIA_BUS_FMT_SRGGB16_1X16, + }, + { + { BayerFormat::MONO, 16, BayerFormat::Packing::None }, + MEDIA_BUS_FMT_Y16_1X16, + }, + { + { BayerFormat::MONO, 16, BayerFormat::Packing::PISP1 }, + MEDIA_BUS_FMT_Y16_1X16, + }, +}; + +unsigned int BayerFormat::toMbusCode() const +{ + const auto it = std::find_if(BayerToMbusCodeMap.begin(), BayerToMbusCodeMap.end(), + [this](const std::pair &match) { + return *this == match.first; + }); + + if (it != BayerToMbusCodeMap.end()) + return it->second; + + return 0; +} + /** * \fn bool operator!=(const BayerFormat &lhs, const BayerFormat &rhs) * \brief Compare two BayerFormats for inequality From patchwork Wed Aug 27 09:07:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24240 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 96391C32BB for ; Wed, 27 Aug 2025 09:07:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E737A69301; Wed, 27 Aug 2025 11:07:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="AJIRPgjW"; dkim-atps=neutral Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 62CE8692F5 for ; Wed, 27 Aug 2025 11:07:46 +0200 (CEST) Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-45b5c12dd87so30987125e9.2 for ; Wed, 27 Aug 2025 02:07:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285665; x=1756890465; 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=sgDB9QwlZ/6ZlpG67CFAzzVzDYU+hnHDTrA998eUhaQ=; b=AJIRPgjW6Zb14JD+rlG8pLFwhhQjgBIe5Akw/CD15owkraHOF/WxtmUTSwYfnwhktW /QIgJEHGyqKUAkJIt7AHb/C0fV7JJ6eyHV7pQf3nqWcoHqYJZHvi4z/ndG+fB/7ffUa+ ayRfovI3/vOu/kqzWN0K3IQ2h+dHtG31MXSWpzIz6kpT6THBkI2vPS1+87l4GtyNVhzl 9sBLLipfmDoV6R7CL9h99NoFjs2CZX1ZKCipGwmeBCwdT+qEWKQzstk3SA15XrwuRZ9j sKGScPFBaQflbgdpEjeaXf42uTByQzF2+/OVb2pln15bztDqqnjW1FgZpD1LE1AKTl/s C3kQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285665; x=1756890465; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=sgDB9QwlZ/6ZlpG67CFAzzVzDYU+hnHDTrA998eUhaQ=; b=RPp7G4w/2TS1w9v3tuNUbtH0xxiYeQH8lYvi4jWAyy86a9TzGGJ/wpvUxczuJ+IBap 5HnMJvuxIQ/MHGlqAZbp5GJ4VNkZ5Q5Vxx2hMduwmtJCXzPw54oK7e8kGMkuOP9dmZNf 4GxrCMgD8Wx/TQ1AhpYHVFzjfcF6m1ZgElPNqxOURDvnrvn3QnnHPFqJzvCG/A6+aVHA yFf/xkIUDj4IdUswFBLGocM1rMJ7iMBo9giXq1iGpszMY/xqLWJ9dqmNIUxZMB1NXDQU yQU5/fyGWVagoGkt7t9om7poORB/n4KPIr1OE8rrv75phGExrTFwAZ/Hbyk2b3W1cHwR FgUw== X-Gm-Message-State: AOJu0Yz9FaBLBmhGHAv59QKMQdAbIw6VUrxSFoo4/EZ9lnewa60p6orE s1n1Qhsc4lQuvW1S4vlTXCOqfds02JV837r+ExXOFzhFUxtgPYmOE4VlgHo0+870EBjc8lJLHIm AepfS X-Gm-Gg: ASbGncsUn2VFw4qZYNQIcf/3HHE8IWR/tiJZoN3ebsnHWOBBu1FKf7chIqFGC6xTaGJ mbPyUn9dUjzfeeMOcAfO2YTF80fbjA86b5yv7Pwyzm15LyVFgfm6kfWFJ2EFTbRwo7RTWhbkmVF 9g3crgA7a1giaFjthotpAz/DiY4ULSYwYaUGdmWQxT3WS82y93HSF4Na8XqdDEnm3zei1Q2ewg5 GhQkfg81o/OOW+OzdkeVOplZv2WFseIpuJxmBToXEu1Az2uM0oDexWxeM2nneEQNvfA1dQ4TQFo YXvyKaYf5H2lwxGhszIARBK+SHcdoBQtUIzmZ89CyNewfggc9zD5asqBIN460NR6NOFmfjLVmJC Y7rDCYelCH9k2bmluFF/8MBIR6uVdWqWXsIx6zk2XSgVWPPDrhdNipXNH/OKo9IfrmFOHEQYiXO SxxzreCYX82nPEyhKFVpX/+kKoUu4SXPqfmr9xuX+mLHzT6hT4FQ== X-Google-Smtp-Source: AGHT+IFXVs/tZ6HQFOlr+O1lToHW9ohRWkLirdiwLq4uMoHV3A1W9ChsPO+5IzKVSh0bI6EQLgbyxw== X-Received: by 2002:a05:600c:1c0c:b0:458:bda4:43df with SMTP id 5b1f17b1804b1-45b727a2c43mr10026805e9.17.1756285665249; Wed, 27 Aug 2025 02:07:45 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:44 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 03/12] pipeline: rpi: pisp: Use the new BayerFormat::toMbusCode() instead Date: Wed, 27 Aug 2025 10:07:30 +0100 Message-Id: <20250827090739.86955-4-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 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" We now have a centralised version of bayerToMbusCode - use it instead. Signed-off-by: David Plowman --- src/libcamera/pipeline/rpi/pisp/pisp.cpp | 47 +----------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp index ec52f6f2..745cb546 100644 --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -55,55 +55,12 @@ enum class Isp : unsigned int { Input, Output0, Output1, TdnInput, TdnOutput, constexpr unsigned int DefaultCompressionOffset = 2048; constexpr unsigned int DefaultCompressionMode = 1; -const std::vector> BayerToMbusCodeMap{ - { { BayerFormat::BGGR, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR8_1X8, }, - { { BayerFormat::GBRG, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG8_1X8, }, - { { BayerFormat::GRBG, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG8_1X8, }, - { { BayerFormat::RGGB, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB8_1X8, }, - { { BayerFormat::BGGR, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR10_1X10, }, - { { BayerFormat::GBRG, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG10_1X10, }, - { { BayerFormat::GRBG, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG10_1X10, }, - { { BayerFormat::RGGB, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB10_1X10, }, - { { BayerFormat::BGGR, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR12_1X12, }, - { { BayerFormat::GBRG, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG12_1X12, }, - { { BayerFormat::GRBG, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG12_1X12, }, - { { BayerFormat::RGGB, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB12_1X12, }, - { { BayerFormat::BGGR, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR14_1X14, }, - { { BayerFormat::GBRG, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG14_1X14, }, - { { BayerFormat::GRBG, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG14_1X14, }, - { { BayerFormat::RGGB, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB14_1X14, }, - { { BayerFormat::BGGR, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR16_1X16, }, - { { BayerFormat::GBRG, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG16_1X16, }, - { { BayerFormat::GRBG, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG16_1X16, }, - { { BayerFormat::RGGB, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB16_1X16, }, - { { BayerFormat::BGGR, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SBGGR16_1X16, }, - { { BayerFormat::GBRG, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SGBRG16_1X16, }, - { { BayerFormat::GRBG, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SGRBG16_1X16, }, - { { BayerFormat::RGGB, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SRGGB16_1X16, }, - { { BayerFormat::RGGB, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SRGGB16_1X16, }, - { { BayerFormat::MONO, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_Y16_1X16, }, - { { BayerFormat::MONO, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_Y16_1X16, }, -}; - -unsigned int bayerToMbusCode(const BayerFormat &bayer) -{ - const auto it = std::find_if(BayerToMbusCodeMap.begin(), BayerToMbusCodeMap.end(), - [bayer](const std::pair &match) { - return bayer == match.first; - }); - - if (it != BayerToMbusCodeMap.end()) - return it->second; - - return 0; -} - uint32_t mbusCodeUnpacked16(unsigned int code) { BayerFormat bayer = BayerFormat::fromMbusCode(code); BayerFormat bayer16(bayer.order, 16, BayerFormat::Packing::None); - return bayerToMbusCode(bayer16); + return bayer16.toMbusCode(); } uint8_t toPiSPBayerOrder(V4L2PixelFormat format) @@ -2217,7 +2174,7 @@ int PiSPCameraData::configureEntities(V4L2SubdeviceFormat sensorFormat, cfe_[Cfe::Output0].dev()->getFormat(&feOutputFormat); BayerFormat feOutputBayer = BayerFormat::fromV4L2PixelFormat(feOutputFormat.fourcc); - feFormat.code = bayerToMbusCode(feOutputBayer); + feFormat.code = feOutputBayer.toMbusCode(); ret = feSubdev_->setFormat(feVideo0SourcePad, &feFormat); return ret; From patchwork Wed Aug 27 09:07:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24241 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 4D249C332A for ; Wed, 27 Aug 2025 09:08:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C50DB692F3; Wed, 27 Aug 2025 11:07:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="Ya7X111c"; dkim-atps=neutral Received: from mail-wm1-x32f.google.com (mail-wm1-x32f.google.com [IPv6:2a00:1450:4864:20::32f]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0B01D613C0 for ; Wed, 27 Aug 2025 11:07:47 +0200 (CEST) Received: by mail-wm1-x32f.google.com with SMTP id 5b1f17b1804b1-45a1b001f55so35020055e9.0 for ; Wed, 27 Aug 2025 02:07:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285666; x=1756890466; 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=/ukKij3qlWIWS1fgolUGyGco5PZGZyPfImO0OUOmtR4=; b=Ya7X111c6RbEUsnLV9ZOk0M2xLnOnEonj10WToCED+pLK1I7OlXpV4gokEL99Ou8WP qmyP7R66sxGnzXs2nBZqGiiFD56IoveTMRL8suFC58LRzScWNJtN8Bzj+jSZAJbsiirL xS7/4wJ0Ve+bKtEP8yd8T8jWHFuepPPX1c00hqe1+3+1H2UezZxz3sos685gATqUGszu hN3zHxW1E3Sek7AJ8ttYuJ0Ieid2V/dVTm447U0ry0fZKXmg63HyJ5Flny5zRWpSn+oV ZNU5k3VMG2K+q4m8FqrUNRl7l/Fb4TmwiljkIEf+flLZm9wyobfZmzDYf9VUipa12aks Yrfg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285666; x=1756890466; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/ukKij3qlWIWS1fgolUGyGco5PZGZyPfImO0OUOmtR4=; b=fkZJxcTjAC7eERTIWh49aWzSX2CqNfyib6/raPa+Msy+qqT4LOx/yH4mjqPUr4AX7I 8ilTDVEDwgHAsvBln2QfdXUN7OaTNBfVTVdr/sWLTCD0DVFHHgGJis8USb2YYYjJCmph N7CWWxYaRriE9z83s9QRUzUN7nAEqMoPgAzDXx8kOaR3yIjopZjzOP3VyxvgTkdaKxLu NU3wqRg5U3p22WFpzqY1Y9/IHWB6+p5J4VRNZY6a2cfx02u3t4tvnRsveNynMd13NLRK h5M1UCvkB86jq4YBdiYW2J6uGOxae5VNqmKcrty/HBvBeKmDfFPsAOAXtk8yRtqWPOku CD2Q== X-Gm-Message-State: AOJu0YzAFpRquJ0bDbtQ1UES6vSg8lDQm7Zr3q9iE+oGG7jOx5nXmaLY MLMlz+wzqXaSofUYszLejAD7CVqgVJyGJYeRdG8ex/rrKtxPT0EIDZkIEkfvc2eVCoIHk1XW82O pIkbl X-Gm-Gg: ASbGnctrlAhPL/dD4oMs9OH4iwvH8rItbFa+CNTy+MtdWzMSbygal+HEiOOz2+zw1gO IaITkDn7NinM2AJ15DEUS57x8+C2BUU0Hs0I138VNl7WE5LVYeui2gX+2JaUCy9WwpQgyzn+dvC Z8N/VpFeQpeDXozmgI7SYTKF4XYdPlDF50JkmaLRMPlBGPaE1gZTO+hdq6VKCQfTKWz6rOqMmku SfcFvanUi5URq9nysGgrHRMpUu0AOHPIPAiihYENkRdXdFc6KnCuCsskpDGyJmx6XyTkp/q7RVR vTOyU28lpHmzLfVV9OPArbhP7iGlH5pN4inS1uH5HwXR0EHMgEwBcLN8dacq7DPcWSi90YvlKlu sjerdGU7u1tpkEX7f2wwoNOP8Bj9QqUFOeRWT33xdF0jP/1n4x4kf/gpCvckntkX8UnwEOBW9fo 0KpzYV3x/gGRAE0hy6qTjhAdQFyjP1dGNFTK8TS7Y= X-Google-Smtp-Source: AGHT+IFrqXtYWNNI7kOxZhQTXaKo14u4GDX8IVvUK40u5qGFL1Ef2b5jL/CX5GjZzsQF71Hya3XR/w== X-Received: by 2002:a05:600c:4f4d:b0:456:1b6f:c888 with SMTP id 5b1f17b1804b1-45b62586a5dmr80714365e9.23.1756285666057; Wed, 27 Aug 2025 02:07:46 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:45 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 04/12] libcamera: Add a direction (input or output) to the stream configuration Date: Wed, 27 Aug 2025 10:07:31 +0100 Message-Id: <20250827090739.86955-5-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 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" We are now going to support input streams as well as output streams, for example for passing in the Bayer image for raw re-processing. Signed-off-by: David Plowman --- include/libcamera/stream.h | 10 ++++++++++ src/libcamera/stream.cpp | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index b5e8f0a9..39fed302 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -37,6 +37,11 @@ private: std::map> formats_; }; +enum class StreamDirection { + Input, + Output +}; + struct StreamConfiguration { StreamConfiguration(); StreamConfiguration(const StreamFormats &formats); @@ -46,6 +51,8 @@ struct StreamConfiguration { unsigned int stride; unsigned int frameSize; + StreamDirection direction; + unsigned int bufferCount; std::optional colorSpace; @@ -53,6 +60,8 @@ struct StreamConfiguration { Stream *stream() const { return stream_; } void setStream(Stream *stream) { stream_ = stream; } const StreamFormats &formats() const { return formats_; } + bool isOutput() const { return direction == StreamDirection::Output; } + bool isInput() const { return direction == StreamDirection::Input; } std::string toString() const; @@ -68,6 +77,7 @@ enum class StreamRole { StillCapture, VideoRecording, Viewfinder, + RawInput }; std::ostream &operator<<(std::ostream &out, StreamRole role); diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index f091487c..e970c8e5 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -280,8 +280,8 @@ SizeRange StreamFormats::range(const PixelFormat &pixelformat) const * handlers provide StreamFormats. */ StreamConfiguration::StreamConfiguration() - : pixelFormat(0), stride(0), frameSize(0), bufferCount(0), - stream_(nullptr) + : pixelFormat(0), stride(0), frameSize(0), + direction(StreamDirection::Output), bufferCount(0), stream_(nullptr) { } @@ -409,6 +409,9 @@ std::ostream &operator<<(std::ostream &out, const StreamConfiguration &cfg) { out << cfg.size << "-" << cfg.pixelFormat << "/" << ColorSpace::toString(cfg.colorSpace); + if (cfg.direction == StreamDirection::Input) + out << "/" + << "in"; return out; } From patchwork Wed Aug 27 09:07:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24242 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 D641FBD87C for ; Wed, 27 Aug 2025 09:08:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AA34E692FA; Wed, 27 Aug 2025 11:07:58 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="KKctlzDv"; dkim-atps=neutral Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F3EDA692F7 for ; Wed, 27 Aug 2025 11:07:47 +0200 (CEST) Received: by mail-wr1-x436.google.com with SMTP id ffacd0b85a97d-3c7edd71bbfso3636341f8f.0 for ; Wed, 27 Aug 2025 02:07:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285667; x=1756890467; 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=UzXPozUYv5GDAfASkNVE9/MfzThAtu3k+xq8xNPN7tk=; b=KKctlzDvidkFK7SBzhCXek4G1g1JIe2C56D7K1YgVUYe5nz/g1Nq73f/FBPsIZHyQD eYLF5Z5S4M5MoZn5cDozJ15q0yST15rryZsBgE0XD38ayN7igcdg3p5Sr3zOFkLNoTj/ y5hLCUdmGi4Y17VBY4tu74WYOighzJNZ8la6X73+l+zHzZEvj2lBFEhac/DMvQ2V0aTe RUn8uLiHdSZGLKfBH8S1E6f69uw6I7yRW/K5O1PGZWlLVmadRbMN7JUDkhaPPzU+AZWm rtbYuKM7+eZ8GWWwsQwiEcfldkr3Sjib6ecr2q+3mUUEViYl3nzBczPVPl97MEpIxtdn /FPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285667; x=1756890467; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UzXPozUYv5GDAfASkNVE9/MfzThAtu3k+xq8xNPN7tk=; b=C6YNH4ygMFExeJTQdO+YbA72fADqK+Nfm/Cb2ZJ+YvW7iltfitJWt2cxJJmgLrXian ySjh3ba/bPTmU7/WyhcEHouEFgLT89itSkevlFR/RlOEaWt29WXjUoaAfZa/XDi5QuH+ tgiSB9/YgtoffJGc79sIyedl6D3LKvPwhyWBQ/bZeYgXIWKnValG7G10fVRnHKU64sR+ 4TVDysgE9e67cD4RZgUS4U+KrCga19pGdc6FP5yYGslHdjnICMwcTUMle0ZgFpxlQXNQ f14LEbmtjyhiVYZoYORBd3G9KVqNzEn+QmlFMDRlh9AJFpWqaVGwvRzDpUbHxmgISvvL JTjw== X-Gm-Message-State: AOJu0Ywdhmipg8McuKVfw/Bhu+NPkuRufT0qraRvR6WAL8LqvQ3O157G dbf2iAOv3j55Iawd2w75L4/UzDMYX/ZntVCiKX3ou0J0dH0tDAmElBCRevPRGeyueV55D8HxO9f N5oLK X-Gm-Gg: ASbGncsHJBYXYf1qUFfP4q+/LlHlE3PbsDX02ReFtiY6uvINA/vW/qvfnfdAT0pUzyM lEzCv/UAQfjFFCwj6fjwky+XUhzMWVZMgDlGaZlIOP/tvs3k7bmhQrSFo9yOuBhcx8e7Wc0tBas De8kfJIy/s2x050DepALZzwv0VgQXrcTk7SFrEcqYsz6uzZ2nibHL6LnwJfrisbzRgSt4ntrpKm +nf5ktXNkkafR3cHa4MVyc/2IZg/KdSu3vrP9PAarXuGMbH++n+WzEx3kbmIeEP6YyehY9KK3BO bTfZNmOHR5lu9m0sQREQg1dP/gvjjkwnjmy/HOWCJzpTdTAsjyp/MGy87EpeN5C1MwQmbalSsqZ OPooorcznXNQSvEZhXKeqQCS8vmWORMf35T/LsV0DvvTosTgDkbyCauB7q+lfATeyfuIvgAuFTE e135pYeCufdARJm4Lh+MyrOBuCuNP1UUJmHr+vJHs2uiZ6aoQZOA== X-Google-Smtp-Source: AGHT+IHTxJDYbkbqL+XrgmjrdSex1k4ATWeiNZ0VWpCeSYkG/ksNWa7D00eeYqBSHsWQevtWwwgHgA== X-Received: by 2002:a05:6000:43d7:b0:3c9:ad8:fec9 with SMTP id ffacd0b85a97d-3c90ad9064dmr9354434f8f.58.1756285666758; Wed, 27 Aug 2025 02:07:46 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:46 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 05/12] libcamera: sensor: Add CameraSensorMemory class Date: Wed, 27 Aug 2025 10:07:32 +0100 Message-Id: <20250827090739.86955-6-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 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" Representation of a "camera" that actually takes its input from a memoery buffer. Signed-off-by: David Plowman --- include/libcamera/internal/camera_sensor.h | 2 + .../libcamera/internal/camera_sensor_memory.h | 109 ++++++++ include/libcamera/internal/meson.build | 1 + src/libcamera/sensor/camera_sensor_memory.cpp | 237 ++++++++++++++++++ src/libcamera/sensor/meson.build | 1 + 5 files changed, 350 insertions(+) create mode 100644 include/libcamera/internal/camera_sensor_memory.h create mode 100644 src/libcamera/sensor/camera_sensor_memory.cpp diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index 13048f32..2b719d8c 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -48,6 +48,8 @@ public: virtual CameraLens *focusLens() = 0; + virtual bool isMemory() const { return false; } + virtual const std::vector &mbusCodes() const = 0; virtual std::vector sizes(unsigned int mbusCode) const = 0; virtual Size resolution() const = 0; diff --git a/include/libcamera/internal/camera_sensor_memory.h b/include/libcamera/internal/camera_sensor_memory.h new file mode 100644 index 00000000..4552bff7 --- /dev/null +++ b/include/libcamera/internal/camera_sensor_memory.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Raspberry Pi plc + * + * camera_sensor_memory.h - A fake camera sensor for reading raw data from memory + */ + +#pragma once + +#include +#include +#include + +#include + +#include "libcamera/internal/camera_sensor.h" + +namespace libcamera { + +class BayerFormat; +class Camera; +class CameraLens; +class MediaEntity; +class SensorConfiguration; + +struct CameraSensorProperties; + +enum class Orientation; + +LOG_DECLARE_CATEGORY(CameraSensor) + +class CameraSensorMemory : public CameraSensor, protected Loggable +{ +public: + CameraSensorMemory(const StreamConfiguration &rawInput); + ~CameraSensorMemory(); + + static std::variant, int> + match(MediaEntity *entity); + + const std::string &model() const override { return model_; } + const std::string &id() const override { return id_; } + + const MediaEntity *entity() const override { return nullptr; } + V4L2Subdevice *device() override { return nullptr; } + + CameraLens *focusLens() override { return nullptr; } + + virtual bool isMemory() const override { return true; } + + const std::vector &mbusCodes() const override; + std::vector sizes(unsigned int mbusCode) const override; + Size resolution() const override; + + V4L2SubdeviceFormat getFormat(const std::vector &mbusCodes, + const Size &size, + const Size maxSize) const override; + int setFormat(V4L2SubdeviceFormat *format, + Transform transform = Transform::Identity) override; + int tryFormat(V4L2SubdeviceFormat *format) const override; + + int applyConfiguration(const SensorConfiguration &config, + Transform transform = Transform::Identity, + V4L2SubdeviceFormat *sensorFormat = nullptr) override; + + V4L2Subdevice::Stream imageStream() const override; + std::optional embeddedDataStream() const override; + V4L2SubdeviceFormat embeddedDataFormat() const override; + int setEmbeddedDataEnabled(bool enable) override; + + const ControlList &properties() const override; + int sensorInfo(IPACameraSensorInfo *info) const override; + Transform computeTransform(Orientation *orientation) const override; + BayerFormat::Order bayerOrder(Transform t) const override; + + const ControlInfoMap &controls() const override; + ControlList getControls(const std::vector &ids) override; + int setControls(ControlList *ctrls) override; + + const std::vector & + testPatternModes() const override { return testPatternModes_; } + int setTestPatternMode(controls::draft::TestPatternModeEnum mode) override; + const CameraSensorProperties::SensorDelays &sensorDelays() override; + +protected: + std::string logPrefix() const override; + +private: + LIBCAMERA_DISABLE_COPY(CameraSensorMemory) + + StreamConfiguration rawInput_; + + std::string model_; + std::string id_; + + BayerFormat bayerFormat_; + std::vector mbusCodes_; + + V4L2SubdeviceFormat v4l2SubdeviceFormat_; + + ControlInfoMap propertiesInfoMap_; + ControlInfoMap controlsInfoMap_; + ControlList properties_; + ControlList controls_; + + std::vector testPatternModes_; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 5c80a28c..bba9df4f 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -10,6 +10,7 @@ libcamera_internal_headers = files([ 'camera_lens.h', 'camera_manager.h', 'camera_sensor.h', + 'camera_sensor_memory.h', 'camera_sensor_properties.h', 'clock_recovery.h', 'control_serializer.h', diff --git a/src/libcamera/sensor/camera_sensor_memory.cpp b/src/libcamera/sensor/camera_sensor_memory.cpp new file mode 100644 index 00000000..dcb8679f --- /dev/null +++ b/src/libcamera/sensor/camera_sensor_memory.cpp @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, Raspberry Pi plc + * + * camera_sensor_memory.cpp - A fake camera sensor for reading raw data from memory + */ + +#include "libcamera/internal/camera_sensor_memory.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/formats.h" +#include "libcamera/internal/v4l2_subdevice.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(CameraSensor) + +static bool v4l2SubdeviceFormatEqual(const V4L2SubdeviceFormat &lhs, const V4L2SubdeviceFormat &rhs) +{ + return lhs.code == rhs.code && lhs.size == rhs.size && lhs.colorSpace == rhs.colorSpace; +} + +CameraSensorMemory::CameraSensorMemory(const StreamConfiguration &rawInput) + : rawInput_(rawInput), properties_(propertiesInfoMap_), controls_(controlsInfoMap_) +{ + model_ = "memory"; + + std::ostringstream oss; + oss << &rawInput; + id_ = oss.str(); + + /* The "camera" must appear to return the format the raw input wants. */ + bayerFormat_ = BayerFormat::fromPixelFormat(rawInput.pixelFormat); + unsigned int mbusCode = bayerFormat_.toMbusCode(); + mbusCodes_ = { mbusCode }; + + v4l2SubdeviceFormat_ = V4L2SubdeviceFormat{ + .code = mbusCode, + .size = rawInput.size, + .colorSpace = ColorSpace::Raw, + }; +} + +CameraSensorMemory::~CameraSensorMemory() = default; + +std::variant, int> +CameraSensorMemory::match([[maybe_unused]] MediaEntity *entity) +{ + return {}; +} + +const std::vector &CameraSensorMemory::mbusCodes() const +{ + return mbusCodes_; +} + +std::vector CameraSensorMemory::sizes(unsigned int mbusCode) const +{ + if (mbusCode == mbusCodes_[0]) + return { rawInput_.size }; + else + return {}; +} + +Size CameraSensorMemory::resolution() const +{ + return rawInput_.size; +} + +V4L2SubdeviceFormat CameraSensorMemory::getFormat(const std::vector &mbusCodes, + [[maybe_unused]] const Size &size, + const Size maxSize) const +{ + if (std::find(mbusCodes.begin(), mbusCodes.end(), mbusCodes_[0]) == mbusCodes.end()) + return {}; + + if (maxSize.width < rawInput_.size.width || maxSize.height < rawInput_.size.height) + return {}; + + return v4l2SubdeviceFormat_; +} + +int CameraSensorMemory::setFormat(V4L2SubdeviceFormat *format, + Transform transform) +{ + if (v4l2SubdeviceFormatEqual(*format, v4l2SubdeviceFormat_) && + transform == Transform::Identity) + return 0; + + return -EPERM; +} + +int CameraSensorMemory::tryFormat(V4L2SubdeviceFormat *format) const +{ + if (v4l2SubdeviceFormatEqual(*format, v4l2SubdeviceFormat_)) + return 0; + + return -EPERM; +} + +int CameraSensorMemory::applyConfiguration(const SensorConfiguration &config, + Transform transform, + V4L2SubdeviceFormat *sensorFormat) +{ + if (config.bitDepth != bayerFormat_.bitDepth || + config.outputSize != rawInput_.size || + config.binning.binX != 1 || config.binning.binY != 1 || + config.skipping.xOddInc != 1 || config.skipping.xEvenInc != 1 || + config.skipping.yOddInc != 1 || config.skipping.yEvenInc != 1 || + transform != Transform::Identity) + return -EPERM; + + if (sensorFormat) + *sensorFormat = v4l2SubdeviceFormat_; + + return 0; +} + +V4L2Subdevice::Stream CameraSensorMemory::imageStream() const +{ + return V4L2Subdevice::Stream(); +} + +std::optional CameraSensorMemory::embeddedDataStream() const +{ + return {}; +} + +V4L2SubdeviceFormat CameraSensorMemory::embeddedDataFormat() const +{ + return {}; +} + +int CameraSensorMemory::setEmbeddedDataEnabled(bool enable) +{ + return enable ? -ENOSTR : 0; +} + +const ControlList &CameraSensorMemory::properties() const +{ + return properties_; +} + +int CameraSensorMemory::sensorInfo([[maybe_unused]] IPACameraSensorInfo *info) const +{ + info->model = model(); + + info->bitsPerPixel = bayerFormat_.bitDepth; + info->cfaPattern = properties::draft::RGB; + + info->activeAreaSize = rawInput_.size; + info->analogCrop = Rectangle(rawInput_.size); + info->outputSize = rawInput_.size; + + /* + * These are meaningless for us, fill with ones rather than zeros because the + * code will divide by some of these numbers. + */ + info->pixelRate = 1; + info->minLineLength = 1; + info->maxLineLength = 1; + info->minFrameLength = 1; + info->maxFrameLength = 1; + + return 0; +} + +Transform CameraSensorMemory::computeTransform(Orientation *orientation) const +{ + *orientation = Orientation::Rotate0; + return Transform::Identity; +} + +BayerFormat::Order CameraSensorMemory::bayerOrder([[maybe_unused]] Transform t) const +{ + return bayerFormat_.order; +} + +const ControlInfoMap &CameraSensorMemory::controls() const +{ + return *controls_.infoMap(); +} + +ControlList CameraSensorMemory::getControls([[maybe_unused]] const std::vector &ids) +{ + return ControlList(); +} + +int CameraSensorMemory::setControls([[maybe_unused]] ControlList *ctrls) +{ + return -EPERM; +} + +int CameraSensorMemory::setTestPatternMode([[maybe_unused]] controls::draft::TestPatternModeEnum mode) +{ + return -EPERM; +} + +const CameraSensorProperties::SensorDelays &CameraSensorMemory::sensorDelays() +{ + static constexpr CameraSensorProperties::SensorDelays defaultSensorDelays = { + .exposureDelay = 2, + .gainDelay = 1, + .vblankDelay = 2, + .hblankDelay = 2, + }; + + return defaultSensorDelays; /* but doesn't mean anything */ +} + +std::string CameraSensorMemory::logPrefix() const +{ + return "'memory'"; +} + +/* + * We're not going to register this camera sensor as it doesn't match media entities + * like other sensors. Pipeline handlers will have to call it explicitly. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/sensor/meson.build b/src/libcamera/sensor/meson.build index dce74ed6..b9b87612 100644 --- a/src/libcamera/sensor/meson.build +++ b/src/libcamera/sensor/meson.build @@ -3,6 +3,7 @@ libcamera_internal_sources += files([ 'camera_sensor.cpp', 'camera_sensor_legacy.cpp', + 'camera_sensor_memory.cpp', 'camera_sensor_properties.cpp', 'camera_sensor_raw.cpp', ]) From patchwork Wed Aug 27 09:07:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24244 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 CCF20C32BB for ; Wed, 27 Aug 2025 09:08:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E6CBA692F9; Wed, 27 Aug 2025 11: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="qATNoWiE"; dkim-atps=neutral Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0FBC5692FA for ; Wed, 27 Aug 2025 11:07:49 +0200 (CEST) Received: by mail-wm1-x333.google.com with SMTP id 5b1f17b1804b1-45a1b0c82eeso56313375e9.3 for ; Wed, 27 Aug 2025 02:07:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285668; x=1756890468; 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=T42Vu1sKWJ+klwmelqzNqd2d2nbWbW0AIllMHaePkcM=; b=qATNoWiEz6/N6tdJU8xrM+AZXR9frbhXm6SBd89rwPCEqyIuM0HU2bZK9dKuHa+fa8 vTM5iVStVu14NtZ22ERaYcgFJXhZirH+pdKNnKgeOCmPIpJIs5N8jiJSL2xO/92SVt1y oQkR7AHq2WVJ6dEGjZMGr2ebGCMVvl64icsVZtBgBM8rgdHhlI8ZsMdbSW1DaoEhQ21P Z7vLPZ0m+dV0XK5+YMY7kHtYmdW+M8pDQMV5BpcbhQiLFgTqjobDtSjarxH6VcIzBXrH vVn/tM+sA7v2dfTUUPuIxmkwoavk5lUBlCRsNXoj+u+k0hVVtMBqoL3+uIZN/9ld9a+d Pm1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285668; x=1756890468; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=T42Vu1sKWJ+klwmelqzNqd2d2nbWbW0AIllMHaePkcM=; b=rtcf49YFsiwpFI/85nPDrp7hCLtd0UB9GX2/5x+tUx1G4y5hhHrSrc6XriCcKCWDur EkJkHkDjz0C78UYYyqWyqPDWrMn88gjzQH0vManbxL54BLvP42D6S/amv5GgoCUFcy43 M5x8NUmdAOIXnoN8sisNjXVMZZY5mUG622pJ34e0h1jzt9YtjYH2MrhilkVLERgL9vIc KoCY/8FNp6VBC1XKUdv0ftIuhHZODhpAzdVfHXhBGsYYb0c1Djz7U1J9+/WgV/p3VD1T fSXfPUtkN5ORRVe5ElwFzAFSZ1/TFqJlemVBPPOQFETRlo1nsFwEp5CSM6H64o5CD820 es2w== X-Gm-Message-State: AOJu0Yxkm/eGHCMPxd/iOLLXqAOxwu0kIwIaRh6MIfKNgZ+scDWN92fH Besk98ClZUAxTcMKk6svz7eTgkGH961rUNRxyO5YKM+o6wBMZi+aEjgQB/sl34STcPlyM/SOdML 852KW X-Gm-Gg: ASbGncu+rvF3Pz3bKXMENNpcI6ZxXQZtuCVJ4EnnY/6+KSjcQ+g5BZcPNq3i7iOoIFQ 6lhicZBZZg4m2IorcGxYRTi5sK1wEaExicN2cSwOmsPBmXwmrkNdJSAMoXI6FdVLyy8vq62cIwe oa5GJEmnO/lwN1L7ht8B2eKjyzmdEsKvjyKMhr2WQBVhIffmOsSYQ/EA4tGvvG5kiiawujxmbq8 d9PGpW389mwWg7hcFB9Qs/mZQFnedlmfHAmbM4ItnygIgszZbfiWxXCORNdE9622jXC6uNUC4jh MVD4x8Yor2F6i3SGhUl81e60+aP5SAftuqf9Hv2f5ic/0MD/NVqmB/5un3W0x5/BBTD3alxw41q mlY78NZsDPzALQNfCz9lJIVRWGrXYEf1kQj+T6lvkfm8W0tWn2srmZQaIWhCouGDy84/WPg7US8 lWX1vCuBk3g7/fgrZ4QZu0xHdbpaJOf3om5YwnVIY= X-Google-Smtp-Source: AGHT+IFVeAbZPY13Bbs3QXAlqrAwgB+1pWvQwSdNED+RoIYRL63nPnVv/tIE37cp2Ujg1hFLbIUVqQ== X-Received: by 2002:a05:600c:4853:b0:458:bb0e:8cda with SMTP id 5b1f17b1804b1-45b5974de01mr97933265e9.17.1756285667591; Wed, 27 Aug 2025 02:07:47 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:47 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 06/12] ipa: rpi: cam_helper: Add CamHelperDefault class Date: Wed, 27 Aug 2025 10:07:33 +0100 Message-Id: <20250827090739.86955-7-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 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" This will help make "memory cameras" work where there is no real sensor. Signed-off-by: David Plowman --- src/ipa/rpi/cam_helper/cam_helper_default.cpp | 45 +++++++++++++++++++ src/ipa/rpi/cam_helper/meson.build | 1 + 2 files changed, 46 insertions(+) create mode 100644 src/ipa/rpi/cam_helper/cam_helper_default.cpp diff --git a/src/ipa/rpi/cam_helper/cam_helper_default.cpp b/src/ipa/rpi/cam_helper/cam_helper_default.cpp new file mode 100644 index 00000000..99801cc3 --- /dev/null +++ b/src/ipa/rpi/cam_helper/cam_helper_default.cpp @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2025, Raspberry Pi Ltd + * + * default camera helper for unknown sensors + */ + +#include +#include +#include +#include + +#include "cam_helper.h" + +using namespace RPiController; + +class CamHelperDefault : public CamHelper +{ +public: + CamHelperDefault(); + uint32_t gainCode(double gain) const override; + double gain(uint32_t gainCode) const override; +}; + +CamHelperDefault::CamHelperDefault() + : CamHelper({}, 0) +{ +} + +uint32_t CamHelperDefault::gainCode([[maybe_unused]] double gain) const +{ + return 0; +} + +double CamHelperDefault::gain([[maybe_unused]] uint32_t gainCode) const +{ + return 1.0; +} + +static CamHelper *create() +{ + return new CamHelperDefault(); +} + +static RegisterCamHelper reg("default", &create); diff --git a/src/ipa/rpi/cam_helper/meson.build b/src/ipa/rpi/cam_helper/meson.build index 7433cffd..6f4c86e7 100644 --- a/src/ipa/rpi/cam_helper/meson.build +++ b/src/ipa/rpi/cam_helper/meson.build @@ -2,6 +2,7 @@ rpi_ipa_cam_helper_sources = files([ 'cam_helper.cpp', + 'cam_helper_default.cpp', 'cam_helper_ov5647.cpp', 'cam_helper_imx219.cpp', 'cam_helper_imx283.cpp', From patchwork Wed Aug 27 09:07:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24243 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 5CFB4C332B for ; Wed, 27 Aug 2025 09:08:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 25883692F7; Wed, 27 Aug 2025 11:08:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="BfmQoCW1"; dkim-atps=neutral Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 87B3A692E9 for ; Wed, 27 Aug 2025 11:07:49 +0200 (CEST) Received: by mail-wm1-x333.google.com with SMTP id 5b1f17b1804b1-45a1b0c52f3so40411945e9.3 for ; Wed, 27 Aug 2025 02:07:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285669; x=1756890469; 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=15ju4tj93kD+K5/upT09hykhZm9/EYdCq0k49NZ7haY=; b=BfmQoCW1pGP9hwNAmcFRaCB6YrvMxcENv8qYDYPyGxiqWYYYrYqJeoPl7tHOZ230Sm Ro7RdRz6NoWtC8CohJWmhUgy4IhXLKIC9NI01vK+DvZfoH4c0yVACz7HH85V9PGteRar ByvucFj0hJQQlYLkz4y0Ab6fD0AuCVBgUHVM7kph/nVOOzBs65bfTo30reGZbVpRGwKR kV+HGRVQbaKzXAWdf6tXj1t2AgrX596hs/kRB6l2MxXB7Qq3vwa1MvK/P3+g9TVa1I+d UEaKDXy8+bbm633oR2OkkEfRmn1FVZU1xLRDYjCYvAcoS3qJCStlX0HlAvVIJldjyaYw 6RNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285669; x=1756890469; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=15ju4tj93kD+K5/upT09hykhZm9/EYdCq0k49NZ7haY=; b=fgicWQLarH7GOzX0LDomTTwSy+AKDsBAo//pGdLOhp79bAxy5Q6Zphx719j6xn+7CZ 0tBeeTbyO5nkMCS0kxRpDz/+RcbGmOYFNgekhPQclQjvQPIeffHCqBcyiX1KxXXbjt8X i0DEt0sIzwr3hvXbUhrnZ6pmBNnZIjjqXS+uiFzAsvCEAPOxZGQt0sR7Bgqg+AOtBFWc NqNJ1eWaZwFOWcSYNvlvlI3jGUd17+qfSOq8UQYJ3uyHOsJuJlX2Zs3rOG4d0pvd7DL6 5CcWWD+JYARb5kmfxoHSJBRGBclvYEo6VNSsfe+whaZxdfbsVQMpXA/GvM083b5hHvFn gdAw== X-Gm-Message-State: AOJu0YwZroHKwMIOwFUgyvuDqZitwlfjEvpT2XVGf0Dam5ViSjWZMnow fRZ4W/3f2Xs18tvZ/VFJ/6FCeuYesHw+bQ/xzz/YJTS+WiH7k1DYrv6UsaiusM0G/5If4s+8WwL 3D9io X-Gm-Gg: ASbGncsQhu0DMcRNTDqxoKRN/XiOov2P8UI0WzjH7PHlb8fBxvlaaVKecpq0gHwQzQ2 fgfZuwvBHRQMgH4QrWps/vmom6sB0vMRZ/5bCyM5v5khBVk371DVpT8DWPbjomSZow8Ehz0qp4X 0ANdsd0XwGjv9EQ/mcFVQ2ESWWChg8VeLKB+Pa5bOo4H/0ZikavEdoPgcoRGEN6O4dR9MHTEvGX E/5FwL5IuCj/LK5xXaX/+n5LNpwfF1+7CBtfXQXnpYPgPJYn6Af554tzcrpDZQ0bylHUvWOIAuK ElFcfxZJljdNh5ugoqFuMMjTTici8BFyDFjpQ+mFrLtio5klxab0FIcl1oL6+/+j+ArnRZNy/Yt 9v3pFzDSJpyKsQ1axMqI3aDcGZwdQLOeWpPniz1E5JgQESPwFYS9rg3eCdsRlmfSfh+MyPBW5ga qQNw/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 5b1f17b1804b1-45b517caa5emr140404875e9.22.1756285668398; Wed, 27 Aug 2025 02:07:48 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:47 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 07/12] libcamera: pipeline: rpi: Allow creation of the first "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 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" Signed-off-by: David Plowman --- .../pipeline/rpi/common/pipeline_base.cpp | 19 ++ .../pipeline/rpi/common/pipeline_base.h | 1 + src/libcamera/pipeline/rpi/pisp/pisp.cpp | 218 ++++++++++++++---- 3 files changed, 187 insertions(+), 51 deletions(-) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 563df198..1d4d6088 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -1170,6 +1170,25 @@ int CameraData::loadIPA(ipa::RPi::InitResult *result) return ipa_->init(settings, params, result); } +int CameraData::loadNamedIPA(std::string const &tuningFile, ipa::RPi::InitResult *result) +{ + int ret; + + ipa_ = IPAManager::createIPA(pipe(), 1, 1); + + if (!ipa_) + return -ENOENT; + + IPASettings settings(tuningFile, "default"); + ipa::RPi::InitParams params; + + ret = platformInitIpa(params); + if (ret) + return ret; + + return ipa_->init(settings, params, result); +} + int CameraData::configureIPA(const CameraConfiguration *config, ipa::RPi::ConfigResult *result) { ipa::RPi::ConfigParams params; diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h index 4bce4ec4..397ad6f8 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h @@ -72,6 +72,7 @@ public: int loadPipelineConfiguration(); int loadIPA(ipa::RPi::InitResult *result); + int loadNamedIPA(std::string const &settings, ipa::RPi::InitResult *result); int configureIPA(const CameraConfiguration *config, ipa::RPi::ConfigResult *result); virtual int platformInitIpa(ipa::RPi::InitParams ¶ms) = 0; virtual int platformConfigureIpa(ipa::RPi::ConfigParams ¶ms) = 0; diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp index 745cb546..d18035ec 100644 --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -815,6 +815,11 @@ public: bool match(DeviceEnumerator *enumerator) override; + bool supportsMemoryCamera() override; + + std::shared_ptr createMemoryCamera(DeviceEnumerator *enumerator, + std::string_view settings) override; + private: PiSPCameraData *cameraData(Camera *camera) { @@ -822,6 +827,8 @@ private: } int prepareBuffers(Camera *camera) override; + std::shared_ptr platformCreateCamera(std::unique_ptr &cameraData, + MediaDevice *cfe, MediaDevice *isp); int platformRegister(std::unique_ptr &cameraData, MediaDevice *cfe, MediaDevice *isp) override; }; @@ -888,10 +895,8 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator) PiSPCameraData *pisp = static_cast(cameraData.get()); - pisp->fe_ = SharedMemObject - ("pisp_frontend", true, pisp->pispVariant_); - pisp->be_ = SharedMemObject - ("pisp_backend", BackEnd::Config({}), pisp->pispVariant_); + pisp->fe_ = SharedMemObject("pisp_frontend", true, pisp->pispVariant_); + pisp->be_ = SharedMemObject("pisp_backend", BackEnd::Config({}), pisp->pispVariant_); if (!pisp->fe_.fd().isValid() || !pisp->be_.fd().isValid()) { LOG(RPI, Error) << "Failed to create ISP shared objects"; @@ -914,6 +919,84 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator) return false; } +bool PipelineHandlerPiSP::supportsMemoryCamera() +{ + return true; +} + +static bool get_variant(unsigned int be_version, const libpisp::PiSPVariant **variant) +{ + for (const auto &hw : libpisp::get_variants()) { + if (hw.BackEndVersion() == be_version) { + *variant = &hw; + return true; + } + } + + return false; +} + +std::shared_ptr +PipelineHandlerPiSP::createMemoryCamera(DeviceEnumerator *enumerator, + std::string_view settings) +{ + DeviceMatch isp("pispbe"); + isp.add("pispbe-input"); + isp.add("pispbe-config"); + isp.add("pispbe-output0"); + isp.add("pispbe-output1"); + isp.add("pispbe-tdn_output"); + isp.add("pispbe-tdn_input"); + isp.add("pispbe-stitch_output"); + isp.add("pispbe-stitch_input"); + MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp); + + if (!ispDevice) { + LOG(RPI, Warning) << "Unable to acquire ISP instance"; + return nullptr; + } + + const libpisp::PiSPVariant *variant = nullptr; + if (!get_variant(ispDevice->hwRevision(), &variant)) { + LOG(RPI, Warning) << "Failed to find variant"; + return nullptr; + } + + std::unique_ptr cameraData = + std::make_unique(this, *variant); + PiSPCameraData *pisp = + static_cast(cameraData.get()); + + /* Only need the back end, but creating the front end makes things easier */ + pisp->fe_ = SharedMemObject("pisp_frontend", true, pisp->pispVariant_); + pisp->be_ = SharedMemObject("pisp_backend", BackEnd::Config({}), pisp->pispVariant_); + + if (!pisp->fe_.fd().isValid() || !pisp->be_.fd().isValid()) { + LOG(RPI, Error) << "Failed to create ISP shared objects"; + return nullptr; + } + + /* + * Next, we want to do PipelineHandlerBase::registerCamera, including: + * loadIPA + * platformReigster + * loadPipelineConfiguration + */ + + /* loadIPA is a bit different for us as we have a filename */ + ipa::RPi::InitResult result; + std::string configFile = std::string(settings); + if (pisp->loadNamedIPA(configFile, &result)) { + LOG(RPI, Error) << "Failed to load a suitable IPA library"; + return nullptr; + } + LOG(RPI, Info) << "Loaded IPA library " << configFile << " for memory camera"; + + std::shared_ptr camera = platformCreateCamera(cameraData, nullptr, ispDevice); + + return camera; +} + int PipelineHandlerPiSP::prepareBuffers(Camera *camera) { PiSPCameraData *data = cameraData(camera); @@ -1021,16 +1104,51 @@ int PipelineHandlerPiSP::prepareBuffers(Camera *camera) return 0; } -int PipelineHandlerPiSP::platformRegister(std::unique_ptr &cameraData, - MediaDevice *cfe, MediaDevice *isp) +static int createCameraCfe(PiSPCameraData *data, MediaDevice *cfe, std::set &streams) { - PiSPCameraData *data = static_cast(cameraData.get()); - int ret; - MediaEntity *cfeImage = cfe->getEntityByName("rp1-cfe-fe_image0"); MediaEntity *cfeEmbedded = cfe->getEntityByName("rp1-cfe-embedded"); MediaEntity *cfeStats = cfe->getEntityByName("rp1-cfe-fe_stats"); MediaEntity *cfeConfig = cfe->getEntityByName("rp1-cfe-fe_config"); + + /* Locate and open the cfe video streams. */ + data->cfe_[Cfe::Output0] = RPi::Stream("CFE Image", cfeImage, StreamFlag::RequiresMmap); + data->cfe_[Cfe::Embedded] = RPi::Stream("CFE Embedded", cfeEmbedded); + data->cfe_[Cfe::Stats] = RPi::Stream("CFE Stats", cfeStats); + data->cfe_[Cfe::Config] = RPi::Stream("CFE Config", cfeConfig, + StreamFlag::Recurrent | StreamFlag::RequiresMmap); + + /* Wire up all the buffer connections. */ + data->cfe_[Cfe::Output0].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue); + data->cfe_[Cfe::Stats].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue); + data->cfe_[Cfe::Config].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue); + data->cfe_[Cfe::Embedded].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue); + + data->csi2Subdev_ = std::make_unique(cfe->getEntityByName("csi2")); + data->feSubdev_ = std::make_unique(cfe->getEntityByName("pisp-fe")); + data->csi2Subdev_->open(); + data->feSubdev_->open(); + + /* + * The below grouping is just for convenience so that we can easily + * iterate over all streams in one go. + */ + data->streams_.push_back(&data->cfe_[Cfe::Output0]); + data->streams_.push_back(&data->cfe_[Cfe::Config]); + data->streams_.push_back(&data->cfe_[Cfe::Stats]); + if (data->sensorMetadata_) + data->streams_.push_back(&data->cfe_[Cfe::Embedded]); + + data->ipa_->setCameraTimeout.connect(data, &PiSPCameraData::setCameraTimeout); + + /* Applications may ask for this stream. */ + streams.insert(&data->cfe_[Cfe::Output0]); + + return 0; +} + +static int createCameraBe(PiSPCameraData *data, MediaDevice *isp, std::set &streams) +{ MediaEntity *ispInput = isp->getEntityByName("pispbe-input"); MediaEntity *IpaPrepare = isp->getEntityByName("pispbe-config"); MediaEntity *ispOutput0 = isp->getEntityByName("pispbe-output0"); @@ -1040,13 +1158,6 @@ int PipelineHandlerPiSP::platformRegister(std::unique_ptr &came MediaEntity *ispStitchOutput = isp->getEntityByName("pispbe-stitch_output"); MediaEntity *ispStitchInput = isp->getEntityByName("pispbe-stitch_input"); - /* Locate and open the cfe video streams. */ - data->cfe_[Cfe::Output0] = RPi::Stream("CFE Image", cfeImage, StreamFlag::RequiresMmap); - data->cfe_[Cfe::Embedded] = RPi::Stream("CFE Embedded", cfeEmbedded); - data->cfe_[Cfe::Stats] = RPi::Stream("CFE Stats", cfeStats); - data->cfe_[Cfe::Config] = RPi::Stream("CFE Config", cfeConfig, - StreamFlag::Recurrent | StreamFlag::RequiresMmap); - /* Tag the ISP input stream as an import stream. */ data->isp_[Isp::Input] = RPi::Stream("ISP Input", ispInput, StreamFlag::ImportOnly); @@ -1069,34 +1180,15 @@ int PipelineHandlerPiSP::platformRegister(std::unique_ptr &came StreamFlag::Recurrent); /* Wire up all the buffer connections. */ - data->cfe_[Cfe::Output0].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue); - data->cfe_[Cfe::Stats].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue); - data->cfe_[Cfe::Config].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue); data->isp_[Isp::Input].dev()->bufferReady.connect(data, &PiSPCameraData::beInputDequeue); data->isp_[Isp::Config].dev()->bufferReady.connect(data, &PiSPCameraData::beOutputDequeue); data->isp_[Isp::Output0].dev()->bufferReady.connect(data, &PiSPCameraData::beOutputDequeue); data->isp_[Isp::Output1].dev()->bufferReady.connect(data, &PiSPCameraData::beOutputDequeue); - data->cfe_[Cfe::Embedded].dev()->bufferReady.connect(data, &PiSPCameraData::cfeBufferDequeue); - - data->csi2Subdev_ = std::make_unique(cfe->getEntityByName("csi2")); - data->feSubdev_ = std::make_unique(cfe->getEntityByName("pisp-fe")); - data->csi2Subdev_->open(); - data->feSubdev_->open(); /* - * Open all CFE and ISP streams. The exception is the embedded data - * stream, which only gets opened below if the IPA reports that the sensor - * supports embedded data. - * * The below grouping is just for convenience so that we can easily * iterate over all streams in one go. */ - data->streams_.push_back(&data->cfe_[Cfe::Output0]); - data->streams_.push_back(&data->cfe_[Cfe::Config]); - data->streams_.push_back(&data->cfe_[Cfe::Stats]); - if (data->sensorMetadata_) - data->streams_.push_back(&data->cfe_[Cfe::Embedded]); - data->streams_.push_back(&data->isp_[Isp::Input]); data->streams_.push_back(&data->isp_[Isp::Output0]); data->streams_.push_back(&data->isp_[Isp::Output1]); @@ -1106,38 +1198,62 @@ int PipelineHandlerPiSP::platformRegister(std::unique_ptr &came data->streams_.push_back(&data->isp_[Isp::StitchInput]); data->streams_.push_back(&data->isp_[Isp::StitchOutput]); + /* Applications may ask for these stream. */ + streams.insert(&data->isp_[Isp::Output0]); + streams.insert(&data->isp_[Isp::Output1]); + + return 0; +} + +std::shared_ptr +PipelineHandlerPiSP::platformCreateCamera(std::unique_ptr &cameraData, + MediaDevice *cfe, MediaDevice *isp) +{ + PiSPCameraData *data = static_cast(cameraData.get()); + int ret; + std::set streams; + + /* cfe is a null pointer when making a memory camera that doesn't use the front end. */ + if (cfe) { + ret = createCameraCfe(data, cfe, streams); + if (ret) + return nullptr; + } + + ret = createCameraBe(data, isp, streams); + if (ret) + return nullptr; + + /* All the streams must open successfully. */ for (auto stream : data->streams_) { ret = stream->dev()->open(); if (ret) - return ret; + return nullptr; } - /* Write up all the IPA connections. */ + /* Wire up all the IPA connections. */ data->ipa_->prepareIspComplete.connect(data, &PiSPCameraData::prepareIspComplete); data->ipa_->processStatsComplete.connect(data, &PiSPCameraData::processStatsComplete); - data->ipa_->setCameraTimeout.connect(data, &PiSPCameraData::setCameraTimeout); - - /* - * List the available streams an application may request. At present, we - * do not advertise CFE Embedded and ISP Statistics streams, as there - * is no mechanism for the application to request non-image buffer formats. - */ - std::set streams; - streams.insert(&data->cfe_[Cfe::Output0]); - streams.insert(&data->isp_[Isp::Output0]); - streams.insert(&data->isp_[Isp::Output1]); /* Create and register the camera. */ - const std::string &id = data->sensor_->id(); + const std::string &id = cfe ? data->sensor_->id() : "memory"; std::shared_ptr camera = Camera::create(std::move(cameraData), id, streams); - PipelineHandler::registerCamera(std::move(camera)); LOG(RPI, Info) << "Registered camera " << id - << " to CFE device " << cfe->deviceNode() + << (cfe ? " to CFE device " + cfe->deviceNode() : "") << " and ISP device " << isp->deviceNode() << " using PiSP variant " << data->pispVariant_.Name(); + return camera; +} + +int PipelineHandlerPiSP::platformRegister(std::unique_ptr &cameraData, + MediaDevice *cfe, MediaDevice *isp) +{ + std::shared_ptr camera = platformCreateCamera(cameraData, cfe, isp); + PipelineHandler::registerCamera(std::move(camera)); + return 0; } From patchwork Wed Aug 27 09:07:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24246 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 7C2D6C332A for ; Wed, 27 Aug 2025 09:08:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7AC4F69311; Wed, 27 Aug 2025 11:08:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="ROR2Bi/A"; dkim-atps=neutral Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F75A692FD for ; Wed, 27 Aug 2025 11:07:50 +0200 (CEST) Received: by mail-wm1-x329.google.com with SMTP id 5b1f17b1804b1-45b627ea685so20862995e9.1 for ; Wed, 27 Aug 2025 02:07:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285669; x=1756890469; 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=yXana9Nl9PmBQf3mtP+lNFgt1GdsOJPf083APJVKErk=; b=ROR2Bi/AKs6+MFSVOx+w8agilhcfsfdJHyJ61ywB9K6f3DYftgwUbe3wHHm1JinMKL iC/5rKzm6jM0VtnPC/u6o/FoqkLTbTeaKLb02C+4CVLXD5Eau03McfxotfzXRgo1gy3n GmW3/SO4wzF30hwGOPY46IHTcl0eu5D9evDW2YYZPV8bHRoA/PQynQaDoM6+okK+wBKC MvmZtAjPP4Ceaeis6m2mA11Ci6oVgH07y0l4nHdyM9Z7S1cJKAiPJRjF3iLq23mUaTqQ 4+9/s8TLJa3S9JjF6KRyYUxwuPxrfQ/K9UMNO0IDJh1Q7BUIezYG5Qc1vibqy9IPgjMe fE3Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285669; x=1756890469; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=yXana9Nl9PmBQf3mtP+lNFgt1GdsOJPf083APJVKErk=; b=JIUwOw2/wRvfz0NhsLDDZadEMGbDrOLHxu7l8gFLe97YGhlAKFqlYQqtjWdYyu0DB0 ISgAjjJqEaYazZe8ti/wSiXIoEjhDzmMGH3z8PoFXW6NvRv7nZO1LKRyCKLaDvzrQePQ L/hZPMsYompGB3B3hLbPNqST8P9caxLn3+fVFXgtBd2F4fVHAdMDwcd4335dYCnEK19v lNz4xhwtEO5xGk6GL6jFGmIWJe3VuUcGpzGHGBGTwdvghoOJI/DhpEnbovadogiolQzh WUZiBh2d+oDbwdlcBPNGitAoKar7cimm2pRlj0eGDDqeyDQC42Rztt4p+zpYNfZNS+2s 2jrA== X-Gm-Message-State: AOJu0Yy5Lz9GBKsQKHPSETEdmud5JLONdGfGzc51+w4Oz9b+fUX+GNeU Ayl60oNvbas5do3Gtl9yneOzPEWtkiSvEsPODqEz4W7RHhnnFzTp/aXP4AhQfbwLZimW0d2/fZW +OCv5 X-Gm-Gg: ASbGncueShnRArTIoRbeISuSlUeq2nsdn+8f1B/j/ZzDpFJC5t/ab+WPTIj+uyP7ZTe u4qTIGLGtBhWesFY2JI8TWbFl3eJE8tQGsDaUMiGJ2UWGhgZrAZSVxWanzI7j6GavruCz3Dlf5u xTt50RnZ4cIYjp1zZPdR1/zqu+EF1vF+AdepoQi2KDJnaT2zQiMCJ9BMgVRFBooTMjn+kJOFXPo Hc/mPyqKlziw+FemFJuSEntyDy3IEYAMNF0tRce5P6Sl+Dt6N5q25UNZlgxHwxSjGQ4O5YvRM4t i4nxpcIL8Sn0D0YMf0c1Nw3wT04qhKYZS7ZPDznuEm+FVCGxRHCLCE/lOcJsNYNiLijjSg604u/ fKAgXCd1KVPwjecVxt9SsojSv3WHxL/mOsxgDt5ZRy5CCDn23yn1fHHM46gRsh8XyDcO+KmhY6W Z80dnmnyEIk3Hq5Htl1C2ZS0BJukv40ENFewSkPDOpz2OqevDsSQ== X-Google-Smtp-Source: AGHT+IFdJ2JmuF2Kd0FPRuYgKB+Mcc4NY+7KxPR6UA8b0mlGe762mcPjkcZs6poHBozGRTWBPVio3Q== X-Received: by 2002:a05:6000:18a2:b0:3c8:dc75:e9ea with SMTP id ffacd0b85a97d-3c8dc75eddbmr7517341f8f.28.1756285669232; Wed, 27 Aug 2025 02:07:49 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:48 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 08/12] pipeline: rpi: Allow generation of raw input configurations Date: Wed, 27 Aug 2025 10:07:35 +0100 Message-Id: <20250827090739.86955-9-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 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" Support the RawInput stream role, which makes a raw stream that is marked as an input (for example, for Bayer re-processing). Signed-off-by: David Plowman --- .../pipeline/rpi/common/pipeline_base.cpp | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 1d4d6088..e7b01f9f 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -393,12 +393,23 @@ PipelineHandlerBase::generateConfiguration(Camera *camera, Span colorSpace; + StreamDirection direction; if (roles.empty()) return config; - Size sensorSize = data->sensor_->resolution(); + /* + * When running memory to memory, without an actual sensor, we can't ask for its size. + * We'll make a CameraSensorMemory, to match the raw input stream configuration in due + * course, but for now use a placeholder size in this case. + */ + Size sensorSize = Size(640, 480); + if (data->sensor_) + sensorSize = data->sensor_->resolution(); + for (const StreamRole role : roles) { + direction = StreamDirection::Output; + switch (role) { case StreamRole::Raw: size = sensorSize; @@ -410,6 +421,15 @@ PipelineHandlerBase::generateConfiguration(Camera *camera, SpanispFormats(); pixelFormat = formats::YUV420; @@ -495,6 +515,7 @@ PipelineHandlerBase::generateConfiguration(Camera *camera, SpanaddConfiguration(cfg); } From patchwork Wed Aug 27 09:07:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24245 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 49CF2C332C for ; Wed, 27 Aug 2025 09:08:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B4C3E692FB; Wed, 27 Aug 2025 11:08:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="Aj80iUXg"; dkim-atps=neutral Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 01D90692F9 for ; Wed, 27 Aug 2025 11:07:51 +0200 (CEST) Received: by mail-wm1-x32b.google.com with SMTP id 5b1f17b1804b1-45b4e5c3d0fso15953315e9.2 for ; Wed, 27 Aug 2025 02:07:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285670; x=1756890470; 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=/8DD2bSs3QnQLjUdI5vBu7DuexdVhZjBW7O248brbbE=; b=Aj80iUXghkfdxygyRA61xJuCo/O7Ph6PfHM9ms57YMJrkUvo/JjiLLRobuMyzzkNiD ql+hgZ2LLujzufAfUZZOdl1fBKkbWVQ7vbklzPeogE7JANwv5TxsTO5i/r7ZdaWyiSbh 94eSfhQydxLLWP+dmQ5hn2vm/vHgLWHc+pa2AuTeXmuBFWYaSEu3vhoHUF52TzBNc1OD NWJvJoQwApL41Rm/KY2gMHbKi4xQr+wssuzhiWEqmeoZTZI1YVfQTQ7kOwee03xNv8lg x5XZwpH4uOHBpwEjRG08wB5SbFFB6OtI+a7d9KOKv3JNDJTa4oOsHpyIMeqx8zMUFJOr EIOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285670; x=1756890470; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/8DD2bSs3QnQLjUdI5vBu7DuexdVhZjBW7O248brbbE=; b=cJkAMs+SShcX0q0I1dYWMQ4D//5msNZXWvKrNRvx+x/J+rCGM6SBKBc3mBaCAAcv2K Jj4ayYKiX0F787v6+MScbMhKNyNbAfNNAN6wgazIQDxZivZcMgvR8WLfxxWK6lC1teJN 2ay4Y/9XowthFEvklOWjnuAt7wCwvEtQKfv1q8dQtezOzoTJUUedqogDs22/o/bMlLrT ZMXcodUXg1TSvBIt04auLjsyuj0KNupFT7LKps2RHOpKUEIM6csB2ohGdH4jGwFMUvQn D2W09V6Yvnc8FoZJ4QVau0RD9RSR0VkiuyN4pjoqx+DmZ5zWF4MkE23TX6+3CxAwAvnV wwcQ== X-Gm-Message-State: AOJu0Yz4tqNBLEKBGOIjghM0CdJvrRj1PryuIsh1B+Ob4GkqKqCRUaNH IL6aWPt6GZlJApZAHYsZtoz4jmYemvtVkUZBcWmMPPC7rWP6R6xef8c5mvKKB2FcsL/P/8660rD qU5L5 X-Gm-Gg: ASbGnct82n0DejXhkNuMzSsmHWXH979XAv0CLURrReOCyc2DAyBWECh31iPUdhGmSwP Hr4+W3jLgx9qtyIIotsL4gdk1MqEaje3QkOF1ZQlGcGku+YuhjN7jZ7U4kk7UqpyQRDAUBGwmEt JnqNX1g+ycfCEBEnDYPcsldnCSbbPkvG2nLn4iFTKQ4v8R9BeTe4iMbVYNaMW7XV7BYf3x99AGx 02e8bibqR4q6pbcS4c4Xfx7pqI3AKX2FZ639VLdOpiVwemW2wMZrPqIVK5S8FG5ap+sGA7j8orG Ylev9j1+Hb4KPyJvGdurS3bWOawnPaWf88YflLPY0b+z8myezaZ4GJjjkrOjkKOypJiJfWRTIzP EafNvhe3DoIRbRTNM2qM6C8jdQ3DtY6c45FyR3Dlgy1kV7fYNxG4wfeMblk9VlkmTFh/66LvXkT uWVdrcjBUPQnEro5JBl5QHSqn7fEkXWBWqYpTb4VY= X-Google-Smtp-Source: AGHT+IFGLMLtWpyI3x678rb7MLNBvH1tcYA3tf3Fqd+ysFpsR3zRnW8J7R3sBx3159DRC195IuYxng== X-Received: by 2002:a05:600c:3596:b0:458:bd31:2c35 with SMTP id 5b1f17b1804b1-45b517cca56mr171400475e9.25.1756285669923; Wed, 27 Aug 2025 02:07:49 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:49 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 09/12] libcamera: Don't wait for input streams to complete Date: Wed, 27 Aug 2025 10:07:36 +0100 Message-Id: <20250827090739.86955-10-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 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" Don't add buffers corresponding to input streams to the "pending" list. These buffers don't "complete" in the normal way, which would stop a request from ever completing. Signed-off-by: David Plowman --- src/libcamera/request.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 7f1e11e8..11de57d6 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -491,7 +491,9 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer, } buffer->_d()->setRequest(this); - _d()->pending_.insert(buffer); + /* Don't want to wait for input buffers as they don't "complete". */ + if (!stream->configuration().isInput()) + _d()->pending_.insert(buffer); if (fence && fence->isValid()) buffer->_d()->setFence(std::move(fence)); From patchwork Wed Aug 27 09:07:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24247 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 F20B6C332D for ; Wed, 27 Aug 2025 09:08:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3B4C6692F3; Wed, 27 Aug 2025 11:08:09 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="h1wuLYUG"; 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 B1F40692EF for ; Wed, 27 Aug 2025 11:07:52 +0200 (CEST) Received: by mail-wm1-x332.google.com with SMTP id 5b1f17b1804b1-45a20c51c40so50402225e9.3 for ; Wed, 27 Aug 2025 02:07:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285672; x=1756890472; 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=Cvoka5m82n+rWiPnVl3CH3ZzB0QBvy8hzVw8dQpv3g8=; b=h1wuLYUG5vmjLZzR5slJFJJohe5JS6T/VtMGXIPH73XVsQkDMG3VXt79qA0G/sEGJR N/wJ2FGAvqv0LBLzYJFtdL4Fk8W7p8Mzownu6pxIjdOzjif2CPQA//ZJvUGlP5X5S7dr 3kGKl6tt5ksyG/U9t0QDZtI/ohLjA2Q7cbORXdHao/0APBc2+B3/8wpoO+VxPs368EcP grKyt+kVl5tXZZ8RcWJKcQS63m23xH9Zx2fShcKUKPB9u12JfhBDtrqZSH3gIeC3jkhj 32oU4xKuANhaZK3u13W8ZeSgTN0MPukcZc29c7atmR8REhQfogaXY8a+OiCW7Q7+E1AI z7ow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285672; x=1756890472; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Cvoka5m82n+rWiPnVl3CH3ZzB0QBvy8hzVw8dQpv3g8=; b=cDINhtEU6DK0k9JeqRpVMzogERZbBoec4wWV9QGsdV7HLSnLf6tm/uiVNRzeEcd5od K6vIVE26Jk5Lb5Evf4QWWsgMx99o/GbkBiih8JJMoMGZXvStTtadc10CsJ8py9XWzuSf 8BkA/ZtSB7Wp5jKqIErYoa4XeQeD52OgW1UASw6rFvT0WoNKMo/YAsgIxH8tGK0HxmZu 8cJAwymx2q36K+OfkLyEScR1xRafl/oOa/n4WVOjGEX0bwyVDxaL3LxL/GyIir4dFumF SvxH+2kkyhlsUsd2UcPC6RNb10KASHI7vuBLizoP24o/KfCvLTK5jwz1KwgQSUTV7sJH FTvg== X-Gm-Message-State: AOJu0YwGXAT5S5ZXFJBKg2+XoYFR28vF6StmT/0VKO0q3yyesXu2S/AR 2IfgcujifWfQw+2oX2NCgvAROnaq8H2jvgwiK10XeBpKfDhN3nUWUEQF7WxTQSraC4k1vT5QOyQ wCKLG X-Gm-Gg: ASbGncvhO1s+FRKB8Bphoyi7r1ok5jTIPSoXZmlbLWfuiyuHXXDojcoC+w2RBoCT3o5 n+P27F13h+a2oVk6Z0XrFHbIxGdvTAJxOVes1LHlg1Cn547j4vZ1mBq0Gta3r/5vbRV9VPK+gg5 bEK0jR0BXM8wjPmOcGv5G3xPRHIFXzdG2WopDBCBjwe9z0ypEGFbCrn2J2w2u9eaWUsHZ3bqE43 VVv8W4L9IQB07bNAQRCYWZ9KWX61IcanwE0omnO/XqvBkUhMGI4cZ79yAK7mcXYv0U8+xEneUP5 vqje0pbGhph4pPfp+roov5mcHGn0P7uFcLEDXGcka6r2Hp5WRp4Aek4BJVp4i9uWAkqWsOIfvVr iAPE7XJ8VYekzcLHISEzzAPBY9+k2WGmv9MdCBgl4NjnAYrnMJbOygKrW05llYua4IQm/GLCJ7z ADFCnX/n6oxi4cgssaxkRDLWsQPkhJYu/8fyMXvFyKb3u/D2Ryrw== X-Google-Smtp-Source: AGHT+IE+Ne/Sh4AIanjMEq2l5OyGWsralWvadk7iMtuz3JO8IOaj2MOsX91nLBvKiKdIYpVEeJxhvQ== X-Received: by 2002:a05:600c:1ca5:b0:459:ddd6:1cc7 with SMTP id 5b1f17b1804b1-45b69616f89mr33246145e9.0.1756285670764; Wed, 27 Aug 2025 02:07:50 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:50 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 10/12] ipa: rpi: Support memory cameras Date: Wed, 27 Aug 2025 10:07:37 +0100 Message-Id: <20250827090739.86955-11-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 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" Add support for "memory cameras" (for Bayer reprocessing). Mostly very minor changes, but the way we fill in certain bits of metadata before runningthe IPAs changes significantly (see prepareIspFillMetadata). For example, regular sensors get device status information from the the sensor (or possibly from values we wrote to the sensor a few frames back), whereas "memory cameras" assume that the exposure/gain values passed in with the request controls will be the ones for setting up the tuning algorithms. Signed-off-by: David Plowman --- src/ipa/rpi/common/ipa_base.cpp | 135 +++++++++++++++++++++++++------- src/ipa/rpi/common/ipa_base.h | 5 ++ 2 files changed, 111 insertions(+), 29 deletions(-) diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp index f2c51f80..d33da113 100644 --- a/src/ipa/rpi/common/ipa_base.cpp +++ b/src/ipa/rpi/common/ipa_base.cpp @@ -194,6 +194,8 @@ int32_t IpaBase::init(const IPASettings &settings, const InitParams ¶ms, Ini int32_t IpaBase::configure(const IPACameraSensorInfo &sensorInfo, const ConfigParams ¶ms, ConfigResult *result) { + isMemoryCamera_ = sensorInfo.model == "memory"; + sensorCtrls_ = params.sensorControls; if (!validateSensorControls()) { @@ -308,10 +310,13 @@ void IpaBase::start(const ControlList &controls, StartResult *result) /* * SwitchMode may supply updated exposure/gain values to use. * agcStatus_ will store these values for us to use until delayed_status values - * start to appear. + * start to appear. Initialise digital gain to 1, as we'll otherwise end up with + * completely black output if AGC isn't running (which is unusual, but does + * happen with memory cameras). */ agcStatus_.exposureTime = 0.0s; agcStatus_.analogueGain = 0.0; + agcStatus_.digitalGain = 1.0; metadata.get("agc.status", agcStatus_); if (agcStatus_.exposureTime && agcStatus_.analogueGain) { @@ -415,6 +420,75 @@ void IpaBase::unmapBuffers(const std::vector &ids) } } +void IpaBase::prepareIspFillMetadata(const PrepareParams ¶ms, unsigned int ipaContext, + Span &embeddedBuffer, bool &hdrChange) +{ + RPiController::Metadata &rpiMetadata = rpiMetadata_[ipaContext]; + + rpiMetadata.clear(); + hdrChange = false; + + if (!isMemoryCamera_) { + /* + * Regular cameras need to get the device status from the sensor, find the + * appropriate embedded data buffers (if any), and so forth. + */ + fillDeviceStatus(params.sensorControls, ipaContext); + fillSyncParams(params, ipaContext); + + if (params.buffers.embedded) { + /* + * Pipeline handler has supplied us with an embedded data buffer, + * we must pass it to the CamHelper for parsing. + */ + auto it = buffers_.find(params.buffers.embedded); + ASSERT(it != buffers_.end()); + embeddedBuffer = it->second.planes()[0]; + } + + /* + * AGC wants to know the algorithm status from the time it actioned the + * sensor exposure/gain changes. So fetch it from the metadata list + * indexed by the IPA cookie returned, and put it in the current frame + * metadata. + * + * Note if the HDR mode has changed, as things like tonemaps may need updating. + */ + AgcStatus agcStatus; + RPiController::Metadata &delayedMetadata = rpiMetadata_[params.delayContext]; + if (!delayedMetadata.get("agc.status", agcStatus)) { + rpiMetadata.set("agc.delayed_status", agcStatus); + hdrChange = agcStatus.hdr.mode != hdrStatus_.mode; + hdrStatus_ = agcStatus.hdr; + } + } else { + /* + * Memory cameras make the device status from exposure/gain information passed + * in the request controls. Making a "fake" device status like this will cause + * the correct values to be used to set up all the tuning algorithms for this + * frame. + */ + DeviceStatus deviceStatus = {}; + + const auto exposureTime = params.requestControls.get(controls::ExposureTime); + if (exposureTime) + deviceStatus.exposureTime = Duration(*exposureTime * 1000); + else + deviceStatus.exposureTime = Duration(1ms); + + const auto analogueGain = params.requestControls.get(controls::AnalogueGain); + if (analogueGain) + deviceStatus.analogueGain = *analogueGain; + else + deviceStatus.analogueGain = 1.0; + + LOG(IPARPI, Debug) << "Exposure time " << deviceStatus.exposureTime + << " AG " << deviceStatus.analogueGain; + + rpiMetadata.set("device.status", deviceStatus); + } +} + void IpaBase::prepareIsp(const PrepareParams ¶ms) { applyControls(params.requestControls); @@ -428,37 +502,14 @@ void IpaBase::prepareIsp(const PrepareParams ¶ms) unsigned int ipaContext = params.ipaContext % rpiMetadata_.size(); RPiController::Metadata &rpiMetadata = rpiMetadata_[ipaContext]; Span embeddedBuffer; - - rpiMetadata.clear(); - fillDeviceStatus(params.sensorControls, ipaContext); - fillSyncParams(params, ipaContext); - - if (params.buffers.embedded) { - /* - * Pipeline handler has supplied us with an embedded data buffer, - * we must pass it to the CamHelper for parsing. - */ - auto it = buffers_.find(params.buffers.embedded); - ASSERT(it != buffers_.end()); - embeddedBuffer = it->second.planes()[0]; - } + bool hdrChange; /* - * AGC wants to know the algorithm status from the time it actioned the - * sensor exposure/gain changes. So fetch it from the metadata list - * indexed by the IPA cookie returned, and put it in the current frame - * metadata. - * - * Note if the HDR mode has changed, as things like tonemaps may need updating. + * This call fills in certain metadata items that subsequent calls to prepare + * will expect to find. Note that different things happen here for regular + * sensors and "memory cameras". */ - AgcStatus agcStatus; - bool hdrChange = false; - RPiController::Metadata &delayedMetadata = rpiMetadata_[params.delayContext]; - if (!delayedMetadata.get("agc.status", agcStatus)) { - rpiMetadata.set("agc.delayed_status", agcStatus); - hdrChange = agcStatus.hdr.mode != hdrStatus_.mode; - hdrStatus_ = agcStatus.hdr; - } + prepareIspFillMetadata(params, ipaContext, embeddedBuffer, hdrChange); /* * This may overwrite the DeviceStatus using values from the sensor @@ -648,6 +699,18 @@ void IpaBase::setMode(const IPACameraSensorInfo &sensorInfo) */ mode_.sensitivity = helper_->getModeSensitivity(mode_); + if (isMemoryCamera_) { + /* + * For memory cameras, the min/max gain/exposure doesn't make much + * sense (and our "sensor" won't have any V4L2 controls), but we do + * need to set the camera mode information that we have so far, so + * that the control algorithms will see it. + */ + helper_->setCameraMode(mode_); + + return; + } + const ControlInfo &gainCtrl = sensorCtrls_.at(V4L2_CID_ANALOGUE_GAIN); const ControlInfo &exposureTimeCtrl = sensorCtrls_.at(V4L2_CID_EXPOSURE); @@ -688,6 +751,10 @@ void IpaBase::setCameraTimeoutValue() bool IpaBase::validateSensorControls() { + /* Don't need any of these controls with memory cameras. */ + if (isMemoryCamera_) + return true; + static const uint32_t ctrls[] = { V4L2_CID_ANALOGUE_GAIN, V4L2_CID_EXPOSURE, @@ -953,6 +1020,11 @@ void IpaBase::applyControls(const ControlList &controls) case controls::EXPOSURE_TIME: { RPiController::AgcAlgorithm *agc = dynamic_cast( controller_.getAlgorithm("agc")); + + /* Don't print a "no AGC" warning if this is a memory camera. */ + if (!agc && isMemoryCamera_) + break; + if (!agc) { LOG(IPARPI, Warning) << "Could not set EXPOSURE_TIME - no AGC algorithm"; @@ -979,6 +1051,11 @@ void IpaBase::applyControls(const ControlList &controls) case controls::ANALOGUE_GAIN: { RPiController::AgcAlgorithm *agc = dynamic_cast( controller_.getAlgorithm("agc")); + + /* Don't print a "no AGC" warning if this is a memory camera. */ + if (!agc && isMemoryCamera_) + break; + if (!agc) { LOG(IPARPI, Warning) << "Could not set ANALOGUE_GAIN - no AGC algorithm"; diff --git a/src/ipa/rpi/common/ipa_base.h b/src/ipa/rpi/common/ipa_base.h index 39feb7ef..9460ccd4 100644 --- a/src/ipa/rpi/common/ipa_base.h +++ b/src/ipa/rpi/common/ipa_base.h @@ -45,6 +45,9 @@ public: void mapBuffers(const std::vector &buffers) override; void unmapBuffers(const std::vector &ids) override; + void prepareIspFillMetadata(const PrepareParams ¶ms, unsigned int ipaContext, + Span &embeddedBuffer, bool &hdrChange); + void prepareIsp(const PrepareParams ¶ms) override; void processStats(const ProcessParams ¶ms) override; @@ -143,6 +146,8 @@ private: utils::Duration manualPeriod; } flickerState_; + bool isMemoryCamera_; + bool cnnEnableInputTensor_; bool awbEnabled_; From patchwork Wed Aug 27 09:07:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24248 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 D3858BD87C for ; Wed, 27 Aug 2025 09:08:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4C4F2692F9; Wed, 27 Aug 2025 11:08:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="kSgHokGk"; dkim-atps=neutral Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E558869300 for ; Wed, 27 Aug 2025 11:07:52 +0200 (CEST) Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-45a286135c8so3536485e9.0 for ; Wed, 27 Aug 2025 02:07:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285672; x=1756890472; 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=WcH7qPcpnlexlEHUZ82vhB+0IeLIPHEAtdRfHfWypxo=; b=kSgHokGk9YcXpqBf1LL/STSscn6Yu1Zb1Ck+VzNqpsZQqP8uChGVdUXn+UPhDq8QQk aX5Hti1v573akB0+oVqPE9MnKunBYB8s6EHvLxn4x13oGBZF5LBB4sRTEcVbyQp+sg8K 8cPK0ROlxKQgWmIkuTRWYbR0trfpzi5HW4tSgrMndXtjekoMVq4U41+G/njaYuYRUnrj yQA4WizqC9ZAG06SrUNwNViEegxoDSHMlhJG5qZH8i5DB1MCGbBRoYWdpYDg6JpbAzAJ a3G+SLOsx29AsqePC9ZtCvWt6eVEQrbtC50bmswjbm6+w6Wavyy4Dn5flNM5gnrST/IN o1hQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285672; x=1756890472; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WcH7qPcpnlexlEHUZ82vhB+0IeLIPHEAtdRfHfWypxo=; b=qVbMM/sbl5BB4YaD8qLehs18v/HDMT99QiRmeQw8L5FYq94qfVwqbD4RUGDHZZRLNS KZFcfPgErucal5sxIqjGZCSZd3eNukwAs3LOcD/Ubi1GJNj0YuC0xDenMBF9nkQwZq7L Qhe0hv6FSwZ/qamIUBVEX8TUkW2ldLlYNEG2rtm4d/FOy8p3W3JyZNib3lJMPyYkjUS4 vtXze+l3HzUkLsRQ2grV0am4rQtzFjjO9szxZ6wU/D7mw7xkIqhASAU4G24yaVzcjen2 MfEOM8CFJQtNtHkoIAb22l0eSNQfXTqDTJ6A7GU40M+mQBh4uMYz7xcnbK0WJ0K4mbL7 KDVA== X-Gm-Message-State: AOJu0Yx+4TWrsN4XDlLVmaSuZc71jijBwl4X8Oc66XhvQLQI+MdoGLfk ycPDwk+qC/qKXCcZCcd/npCynP9lWKEKcZkydoPnfON7wDNZZ1zP75BkCPQ/orhJ58hKjjX/+FB IdcI7 X-Gm-Gg: ASbGncvtr99E2rJBBJVU8RWOOCGeFKB/asjyw6Xp98gyTzZBWyn86GKdq3hct4/o5E7 RV1g30k2lo0fYwELB9vLdO9BQNoXmuioKOyPfQKjXPePwew6qPGsQRhp/2OgnhHAVt2hISLBhB5 E50e+oLbhfRxWl5E7nxh1+RzVfypmrjykDHjH9nyvxfXEUsgzQUgJ25ED3cEzylsegMf5STfVys FYEh01Jc50JLtZLFuRxpqx/yJPNjW7T+6MZbKkgy6bA2FPUjjCY8BEsBO82I8Ftyn47dncuEox7 hKDyRvkcofaIdidVYzFKei/43g7L6X6H6ZRSxvNhDmajxMC5DtiqUXYE60LRBqUBUTfqdXmJaUC e2hq/rO4RCAHEvlmFslCHH1GHsnzq9Zx0dv5K8wE6XHUX+1ZuDJxmXszm2YTWeMJhVndAl+hwOv T4HSAQ2TTL8VydDY+uaYFLyDgrcDj5GfMJr4mhthFxLly6CMOeKtm4zltFH14V X-Google-Smtp-Source: AGHT+IE98sXfpWSukxZDWQJbuUxVTl0vaUG9RKGu+/TA2aYhc4GtqOrvwdIan713BZyt05IUkkWbHA== X-Received: by 2002:a05:600c:5246:b0:458:6f13:aa4a with SMTP id 5b1f17b1804b1-45b68b79262mr42107925e9.6.1756285671671; Wed, 27 Aug 2025 02:07:51 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:51 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 11/12] pipeline: rpi: Support memory cameras Date: Wed, 27 Aug 2025 10:07:38 +0100 Message-Id: <20250827090739.86955-12-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 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" Mostly small changes to support memory cameras (for Bayer reprocessing) in the pipeline handler. Firstly, we make a "CameraSensorMemory" as the sensor as soon as we have the raw input buffer configuration, which helps the rest of the to work with fewer changes. The PiSP platformConfigure method is refactored to split the Cfe and Isp parts into separate functions. Memory cameras then omit platformConfigureCfe but run platformConfigureIsp as before. Signed-off-by: David Plowman --- .../pipeline/rpi/common/pipeline_base.cpp | 34 ++++- .../pipeline/rpi/common/pipeline_base.h | 4 +- src/libcamera/pipeline/rpi/pisp/pisp.cpp | 141 ++++++++++++------ 3 files changed, 122 insertions(+), 57 deletions(-) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index e7b01f9f..31bacc7c 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -20,6 +20,7 @@ #include #include "libcamera/internal/camera_lens.h" +#include "libcamera/internal/camera_sensor_memory.h" #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/v4l2_subdevice.h" @@ -170,15 +171,9 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() status = validateColorSpaces(ColorSpaceFlag::StreamsShareColorSpace); /* - * Validate the requested transform against the sensor capabilities and - * rotation and store the final combined transform that configure() will - * need to apply to the sensor to save us working it out again. + * Separate the raw and output streams first, to make it easier to + * detect the raw reprocessing use case. */ - Orientation requestedOrientation = orientation; - combinedTransform_ = data_->sensor_->computeTransform(&orientation); - if (orientation != requestedOrientation) - status = Adjusted; - rawStreams_.clear(); outStreams_.clear(); unsigned int rawStreamIndex = 0; @@ -191,6 +186,29 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() outStreams_.emplace_back(outStreamIndex++, &cfg); } + /* + * For the reprocessing use case, make a "memory camera" to match the + * raw input buffer. This will make all the subsequent code run more like + * the regular sensor case. + */ + if (rawStreams_[0].cfg->isInput()) { + LOG(RPI, Debug) << "Raw reprocessing use case for " << *rawStreams_[0].cfg; + data_->sensor_ = std::make_unique(*rawStreams_[0].cfg); + /* We can fill in the only sensor format we support! */ + auto const mbusCode = data_->sensor_->mbusCodes()[0]; + data_->sensorFormats_.emplace(mbusCode, data_->sensor_->sizes(mbusCode)); + } + + /* + * Validate the requested transform against the sensor capabilities and + * rotation and store the final combined transform that configure() will + * need to apply to the sensor to save us working it out again. + */ + Orientation requestedOrientation = orientation; + combinedTransform_ = data_->sensor_->computeTransform(&orientation); + if (orientation != requestedOrientation) + status = Adjusted; + /* Sort the streams so the highest resolution is first. */ std::sort(rawStreams_.begin(), rawStreams_.end(), [](auto &l, auto &r) { return l.cfg->size > r.cfg->size; }); diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h index 397ad6f8..c53abaa7 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h @@ -246,7 +246,7 @@ private: class RPiCameraConfiguration final : public CameraConfiguration { public: - RPiCameraConfiguration(const CameraData *data) + RPiCameraConfiguration(CameraData *data) : CameraConfiguration(), data_(data) { } @@ -288,7 +288,7 @@ public: std::optional rgbColorSpace_; private: - const CameraData *data_; + CameraData *data_; }; } /* namespace RPi */ diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp index d18035ec..bb22e6d2 100644 --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -756,6 +756,10 @@ public: bool adjustDeviceFormat(V4L2DeviceFormat &format) const; private: + int platformConfigureCfe(const RPi::RPiCameraConfiguration *rpiConfig, + V4L2DeviceFormat &cfeFormat); + int platformConfigureIsp(const RPi::RPiCameraConfiguration *rpiConfig, + V4L2DeviceFormat cfeFormat); int platformConfigure(const RPi::RPiCameraConfiguration *rpiConfig) override; int platformConfigureIpa([[maybe_unused]] ipa::RPi::ConfigParams ¶ms) override @@ -994,6 +998,12 @@ PipelineHandlerPiSP::createMemoryCamera(DeviceEnumerator *enumerator, std::shared_ptr camera = platformCreateCamera(cameraData, nullptr, ispDevice); + int ret = pisp->loadPipelineConfiguration(); + if (ret) { + LOG(RPI, Error) << "Unable to load pipeline configuration"; + return nullptr; + } + return camera; } @@ -1272,10 +1282,14 @@ PiSPCameraData::platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const } if (!rawStreams.empty()) { - rawStreams[0].dev = cfe_[Cfe::Output0].dev(); - StreamConfiguration *rawStream = rawStreams[0].cfg; BayerFormat bayer = BayerFormat::fromPixelFormat(rawStream->pixelFormat); + + if (rawStream->isInput()) + rawStreams[0].dev = isp_[Isp::Input].dev(); + else + rawStreams[0].dev = cfe_[Cfe::Output0].dev(); + /* * We cannot output CSI2 packed or non 16-bit output from the frontend, * so signal the output as unpacked 16-bits in these cases. @@ -1295,7 +1309,7 @@ PiSPCameraData::platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const } rawStreams[0].format = - RPi::PipelineHandlerBase::toV4L2DeviceFormat(cfe_[Cfe::Output0].dev(), rawStream); + RPi::PipelineHandlerBase::toV4L2DeviceFormat(rawStreams[0].dev, rawStream); computeOptimalStride(rawStreams[0].format); } @@ -1489,13 +1503,13 @@ bool PiSPCameraData::adjustDeviceFormat(V4L2DeviceFormat &format) const return false; } -int PiSPCameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfig) +int PiSPCameraData::platformConfigureCfe(const RPi::RPiCameraConfiguration *rpiConfig, + V4L2DeviceFormat &cfeFormat) { const std::vector &rawStreams = rpiConfig->rawStreams_; - const std::vector &outStreams = rpiConfig->outStreams_; int ret; V4L2VideoDevice *cfe = cfe_[Cfe::Output0].dev(); - V4L2DeviceFormat cfeFormat; + V4L2DeviceFormat format; /* * See which streams are requested, and route the user @@ -1540,8 +1554,59 @@ int PiSPCameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConf } ret = cfe->setFormat(&cfeFormat); - if (ret) + + /* CFE statistics output format. */ + format = {}; + format.fourcc = V4L2PixelFormat(V4L2_META_FMT_RPI_FE_STATS); + ret = cfe_[Cfe::Stats].dev()->setFormat(&format); + if (ret) { + LOG(RPI, Error) << "Failed to set format on CFE stats stream: " + << format.toString(); + return ret; + } + + /* CFE config format. */ + format = {}; + format.fourcc = V4L2PixelFormat(V4L2_META_FMT_RPI_FE_CFG); + ret = cfe_[Cfe::Config].dev()->setFormat(&format); + if (ret) { + LOG(RPI, Error) << "Failed to set format on CFE config stream: " + << format.toString(); return ret; + } + + /* + * Configure the CFE embedded data output format only if the sensor + * supports it. + */ + V4L2SubdeviceFormat embeddedFormat; + if (sensorMetadata_) { + sensor_->device()->getFormat(1, &embeddedFormat); + format = {}; + format.fourcc = V4L2PixelFormat(V4L2_META_FMT_SENSOR_DATA); + format.planes[0].size = embeddedFormat.size.width * embeddedFormat.size.height; + + LOG(RPI, Debug) << "Setting embedded data format " << format.toString(); + ret = cfe_[Cfe::Embedded].dev()->setFormat(&format); + if (ret) { + LOG(RPI, Error) << "Failed to set format on CFE embedded: " + << format; + return ret; + } + } + + configureEntities(rpiConfig->sensorFormat_, embeddedFormat); + configureCfe(); + + return 0; +} + +int PiSPCameraData::platformConfigureIsp(const RPi::RPiCameraConfiguration *rpiConfig, + V4L2DeviceFormat cfeFormat) +{ + int ret; + + const std::vector &outStreams = rpiConfig->outStreams_; /* Set the TDN and Stitch node formats in case they are turned on. */ isp_[Isp::TdnOutput].dev()->setFormat(&cfeFormat); @@ -1677,53 +1742,35 @@ int PiSPCameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConf beEnabled_ = beEnables & (PISP_BE_RGB_ENABLE_OUTPUT0 | PISP_BE_RGB_ENABLE_OUTPUT1); - /* CFE statistics output format. */ - format = {}; - format.fourcc = V4L2PixelFormat(V4L2_META_FMT_RPI_FE_STATS); - ret = cfe_[Cfe::Stats].dev()->setFormat(&format); - if (ret) { - LOG(RPI, Error) << "Failed to set format on CFE stats stream: " - << format.toString(); - return ret; - } + if (beEnabled_) + configureBe(rpiConfig->yuvColorSpace_); - /* CFE config format. */ - format = {}; - format.fourcc = V4L2PixelFormat(V4L2_META_FMT_RPI_FE_CFG); - ret = cfe_[Cfe::Config].dev()->setFormat(&format); - if (ret) { - LOG(RPI, Error) << "Failed to set format on CFE config stream: " - << format.toString(); - return ret; - } + return 0; +} + +int PiSPCameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfig) +{ + /* What we call the cfeFormat here is also the input format for the ISP (Back End). */ + V4L2DeviceFormat cfeFormat; /* - * Configure the CFE embedded data output format only if the sensor - * supports it. + * First configure the CFE (if it's being used). In the case of memory cameras + * (Bayer reprocessing), there's no CFE but the raw input stream should already + * contain the correct ISP input format. */ - V4L2SubdeviceFormat embeddedFormat; - if (sensorMetadata_) { - sensor_->device()->getFormat(1, &embeddedFormat); - format = {}; - format.fourcc = V4L2PixelFormat(V4L2_META_FMT_SENSOR_DATA); - format.planes[0].size = embeddedFormat.size.width * embeddedFormat.size.height; - - LOG(RPI, Debug) << "Setting embedded data format " << format.toString(); - ret = cfe_[Cfe::Embedded].dev()->setFormat(&format); - if (ret) { - LOG(RPI, Error) << "Failed to set format on CFE embedded: " - << format; + if (cfe_[Cfe::Output0].dev()) { + /* Regular sensor. */ + int ret = platformConfigureCfe(rpiConfig, cfeFormat); + if (ret) return ret; - } + } else { + /* Memory camera. */ + cfeFormat = rpiConfig->rawStreams_[0].format; + rpiConfig->rawStreams_[0].cfg->setStream(&isp_[Isp::Input]); } - configureEntities(rpiConfig->sensorFormat_, embeddedFormat); - configureCfe(); - - if (beEnabled_) - configureBe(rpiConfig->yuvColorSpace_); - - return 0; + /* Finally configure the back end ISP. */ + return platformConfigureIsp(rpiConfig, cfeFormat); } void PiSPCameraData::platformStart() From patchwork Wed Aug 27 09:07:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 24249 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 2D6F9C332E for ; Wed, 27 Aug 2025 09:08:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6210569309; Wed, 27 Aug 2025 11:08:12 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="g52tKWAV"; dkim-atps=neutral Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 65E2469303 for ; Wed, 27 Aug 2025 11:07:53 +0200 (CEST) Received: by mail-wm1-x335.google.com with SMTP id 5b1f17b1804b1-45a1b00f23eso38669175e9.0 for ; Wed, 27 Aug 2025 02:07:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1756285673; x=1756890473; 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=9qoMSMv7GS7D3NfmPMIenbPQUZV27K9S7JmNlJHn57g=; b=g52tKWAV21Fj400oQStiwLpZrfo31zogq7am39woGNkN8STtgBXAkh+NQZn2nCKJLx f408ckGkoKIfEKQttJ+q+UpibAjjCaBxR7xRucAdxOrq1WDWIXKz30f0nRw4GhI1BceT dO2hX2gzpCbUcZx3lfJBFGW3o53OxtgdSymSBh9LTdPSVswjezsTAT8hWcL915YRd1UT b62utf+a9lmQcn5WpW1/gJ9f/uM7+MZ0AGavys3NIuFYztullkfhrhzggy0LdC6huoFW VmIbvJj/vlH4A9VsRlRCgce2bVVZnU/6suU1R9rX+LP3YojaKtEwigAkkHpjJxCdZxVz dVmQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756285673; x=1756890473; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9qoMSMv7GS7D3NfmPMIenbPQUZV27K9S7JmNlJHn57g=; b=EtH0mnnszfyeqE//Bf9kURke4yd8FD7izCmAqIXCdv3JT09pU7b/51IPZ0CTz9MjLE STLwvtc6p44PykQI+TUjePklhhsVbdk9XTj9gXuWkx5mL/hj3MkBhhwBrTbjGfLd7KZp zuyhB4fFsbCs7/kqmZvolPMJqB4SG5SmXc9CyAOnhAPMJlvxvPnAVMv5uhZteo+nZ1j2 28/mPdLDHI9n1wZxG1bqTZYU73f9+ST21IJCjTAINgdc2SjoLHKL35sqezsAesUbsf+C tcSSuxiE/aJwdmhCNy7W0pCfDBB7KH7m1PWG9GHzOE/3YpqNQD9cXAzmePvXGJKduDOr SStg== X-Gm-Message-State: AOJu0YxV7ODGlmdZZNZzr/hJyatZFhWDnIveVBML9rsARM7DMIDj1ttF /UD5DTbfxbn2eaVbpAnZ74civoaUNssS4qmC/4BXu1XsO15QTCi2vSNhynxpxcmUkVRg42v8nF3 eYRc+ X-Gm-Gg: ASbGncu+a2ymcCkro56Pdkn8Ag5aELV+hq4on1gMI7WmQOelpfPHDGKb0NhhwwrCU65 /gQcubdNr1GbJSHiCefOO+F3akD6+ifTc7AoQNFlG6SwQvOZJ7Z4qz3YL36A8r/01w07dKlk79T xN69ANTaJUKbvp8QglDIZVbAHKMZ+PP9/Ya29uIhYeHJ/mvFcRIIwIHKQ43KsPAzQVvuxWyI3k3 lJJUr9q1dntpDZKmZ0oKEn9fu38XmweEaMF3sxpXZyv4teb8xvPUUg73Rea3gAlt/1KetU0Nslq LlmUdU/rj9OmVsRZQGiN8D78Tx9zUASnoxpBq4a9U5ZW29QqtjpCu9jN7/eptYpjH8K5mFte0Ia z9rCVipZXd+B73hYHEmm/I3iQcY41+hxeRkuXmE4PcnBe4cG9F2+CSHa0dSlYTJiiLao46Ovo+r Aj03rGQ6rvBfKqp+v4nDAlEbjhFUpg6A8OM5T9Nr8pkeZ7z6//ow== X-Google-Smtp-Source: AGHT+IFsOsFg4QSpn/ny3ZFkYfdpQTWfNuDMnx5KiLyPLNutkN645L9sQgGUcUKtgPIPqG5zucklyw== X-Received: by 2002:a05:600c:b95:b0:459:d645:bff7 with SMTP id 5b1f17b1804b1-45b5179cf7dmr161674605e9.12.1756285672467; Wed, 27 Aug 2025 02:07:52 -0700 (PDT) Received: from raspberrypi.pitowers.org ([2a00:1098:3142:1f:ffc9:aff6:7f7f:893b]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b6f30fe02sm21498675e9.18.2025.08.27.02.07.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Aug 2025 02:07:51 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Cc: David Plowman Subject: [RFC PATCH 12/12] pipline: rpi: Support memory cameras processing requests Date: Wed, 27 Aug 2025 10:07:39 +0100 Message-Id: <20250827090739.86955-13-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 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" This is the final commit in the set to support memory cameras (Bayer reprocessing). There are some small fix-ups to allow the camera system to start without the CFE being involved, and we add runMemoryCamera() which pushs a buffer from the request into the Back End ISP. Signed-off-by: David Plowman --- .../pipeline/rpi/common/pipeline_base.cpp | 23 ++++---- src/libcamera/pipeline/rpi/pisp/pisp.cpp | 53 ++++++++++++++++--- 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 31bacc7c..8ca1e41f 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -727,15 +727,19 @@ int PipelineHandlerBase::start(Camera *camera, const ControlList *controls) /* A good moment to add an initial clock sample. */ data->wallClockRecovery_.addSample(); - /* - * Reset the delayed controls with the gain and exposure values set by - * the IPA. - */ - data->delayedCtrls_->reset(0); - data->state_ = CameraData::State::Idle; + /* A memory camera wouldn't have a front end device, so you would skip this. */ + if (data->frontendDevice()) { + /* + * Reset the delayed controls with the gain and exposure values set by + * the IPA. + */ + data->delayedCtrls_->reset(0); + + /* Enable SOF event generation. */ + data->frontendDevice()->setFrameStartEnabled(true); + } - /* Enable SOF event generation. */ - data->frontendDevice()->setFrameStartEnabled(true); + data->state_ = CameraData::State::Idle; data->platformStart(); @@ -762,7 +766,8 @@ void PipelineHandlerBase::stopDevice(Camera *camera) stream->dev()->streamOff(); /* Disable SOF event generation. */ - data->frontendDevice()->setFrameStartEnabled(false); + if (data->frontendDevice()) + data->frontendDevice()->setFrameStartEnabled(false); data->clearIncompleteRequests(); diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp index bb22e6d2..a637c6be 100644 --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -780,6 +780,7 @@ private: void prepareCfe(); void prepareBe(uint32_t bufferId, bool stitchSwapBuffers); + void runMemoryCamera(); void tryRunPipeline() override; struct CfeJob { @@ -1243,7 +1244,7 @@ PipelineHandlerPiSP::platformCreateCamera(std::unique_ptr &came /* Wire up all the IPA connections. */ data->ipa_->prepareIspComplete.connect(data, &PiSPCameraData::prepareIspComplete); - data->ipa_->processStatsComplete.connect(data, &PiSPCameraData::processStatsComplete); + /* We don't want the processStatsComplete callback, though, for memory cams. */ /* Create and register the camera. */ const std::string &id = cfe ? data->sensor_->id() : "memory"; @@ -1785,8 +1786,11 @@ void PiSPCameraData::platformStart() cfeJobQueue_ = {}; - for (unsigned int i = 0; i < config_.numCfeConfigQueue; i++) - prepareCfe(); + /* A memory camera wouldn't be using the CFE. */ + if (cfe_[Cfe::Output0].dev()) { + for (unsigned int i = 0; i < config_.numCfeConfigQueue; i++) + prepareCfe(); + } /* Clear the debug dump file history. */ last_dump_file_.clear(); @@ -1890,8 +1894,12 @@ void PiSPCameraData::beInputDequeue(FrameBuffer *buffer) << ", buffer id " << cfe_[Cfe::Output0].getBufferId(buffer) << ", timestamp: " << buffer->metadata().timestamp; - /* The ISP input buffer gets re-queued into CFE. */ - handleStreamBuffer(buffer, &cfe_[Cfe::Output0]); + /* + * The ISP input buffer gets re-queued into CFE (but not for memory cameras + * that aren't using the CFE). + */ + if (cfe_[Cfe::Output0].dev()) + handleStreamBuffer(buffer, &cfe_[Cfe::Output0]); handleState(); } @@ -2361,7 +2369,15 @@ void PiSPCameraData::prepareCfe() void PiSPCameraData::prepareBe(uint32_t bufferId, bool stitchSwapBuffers) { - FrameBuffer *buffer = cfe_[Cfe::Output0].getBuffers().at(bufferId).buffer; + FrameBuffer *buffer; + if (!sensor_->isMemory()) + buffer = cfe_[Cfe::Output0].getBuffers().at(bufferId).buffer; + else { + /* Memory camera. Back end input buffer is in the request. */ + Request *request = requestQueue_.front(); + const libcamera::Stream *rawStream = &isp_[Isp::Input]; + buffer = request->findBuffer(rawStream); + } LOG(RPI, Debug) << "Input re-queue to ISP, buffer id " << bufferId << ", timestamp: " << buffer->metadata().timestamp; @@ -2412,8 +2428,33 @@ void PiSPCameraData::prepareBe(uint32_t bufferId, bool stitchSwapBuffers) isp_[Isp::Config].queueBuffer(config.buffer); } +void PiSPCameraData::runMemoryCamera() +{ + Request *request = requestQueue_.front(); + + applyScalerCrop(request->controls()); + + request->metadata().clear(); + + state_ = State::Busy; + + ipa::RPi::PrepareParams params; + params.buffers.embedded = 0; + params.ipaContext = requestQueue_.front()->sequence(); + params.requestControls = request->controls(); + + LOG(RPI, Debug) << "runMemoryCamera: call prepareIsp"; + ipa_->prepareIsp(params); +} + void PiSPCameraData::tryRunPipeline() { + if (state_ == State::Idle && !requestQueue_.empty() && sensor_->isMemory()) { + runMemoryCamera(); + + return; + } + /* If any of our request or buffer queues are empty, we cannot proceed. */ if (state_ != State::Idle || requestQueue_.empty() || !cfeJobComplete()) return;