From patchwork Tue Jan 13 00:07:33 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25721 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 D54B0C323E for ; Tue, 13 Jan 2026 00:08:34 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CB73661FA0; Tue, 13 Jan 2026 01:08:33 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MuL46d3p"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 667B761FA0 for ; Tue, 13 Jan 2026 01:08:31 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B576B50A for ; Tue, 13 Jan 2026 01:08:05 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262885; bh=PAtzAHaKdBlO6Tkd0aWC59iMcw81Se8BXhuUX59gAIk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=MuL46d3ptVlny98mAm5UMMgwd5opEw6Ny0wqC7Iu3Gv4b19C9vpjSVEp3lX7THPnu 7gic0j8FrWsXF0thMziywilqLYhGGdsEGdLnwurnLMJ2hffnUJ2WQ40vAiP4LgpJbk 5B3V9NRLVo4FBwSEv7j7BkIcQD5OLawFVayxKzyU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 01/36] libcamera: Drop unneeded usage of this pointer Date: Tue, 13 Jan 2026 02:07:33 +0200 Message-ID: <20260113000808.15395-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" A few unneeded usages of the this pointer to quality access to class members have been introduced over time. Drop them. Signed-off-by: Laurent Pinchart Reviewed-by: Barnabás Pőcze --- include/libcamera/internal/shared_mem_object.h | 4 ++-- src/libcamera/camera_manager.cpp | 2 +- src/libcamera/shared_mem_object.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/libcamera/internal/shared_mem_object.h b/include/libcamera/internal/shared_mem_object.h index e9f1dacd731d..21e025513fdf 100644 --- a/include/libcamera/internal/shared_mem_object.h +++ b/include/libcamera/internal/shared_mem_object.h @@ -79,7 +79,7 @@ public: SharedMemObject(SharedMemObject &&rhs) : SharedMem(std::move(rhs)) { - this->obj_ = rhs.obj_; + obj_ = rhs.obj_; rhs.obj_ = nullptr; } @@ -92,7 +92,7 @@ public: SharedMemObject &operator=(SharedMemObject &&rhs) { SharedMem::operator=(std::move(rhs)); - this->obj_ = rhs.obj_; + obj_ = rhs.obj_; rhs.obj_ = nullptr; return *this; } diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 23185467ba02..fc6e490bc476 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -41,7 +41,7 @@ LOG_DEFINE_CATEGORY(Camera) CameraManager::Private::Private() : Thread("CameraManager"), initialized_(false) { - ipaManager_ = std::make_unique(this->configuration()); + ipaManager_ = std::make_unique(configuration()); } int CameraManager::Private::start() diff --git a/src/libcamera/shared_mem_object.cpp b/src/libcamera/shared_mem_object.cpp index d9b61d37dd43..6edab045d47e 100644 --- a/src/libcamera/shared_mem_object.cpp +++ b/src/libcamera/shared_mem_object.cpp @@ -80,8 +80,8 @@ SharedMem::SharedMem(const std::string &name, std::size_t size) */ SharedMem::SharedMem(SharedMem &&rhs) { - this->fd_ = std::move(rhs.fd_); - this->mem_ = rhs.mem_; + fd_ = std::move(rhs.fd_); + mem_ = rhs.mem_; rhs.mem_ = {}; } @@ -109,8 +109,8 @@ SharedMem::~SharedMem() */ SharedMem &SharedMem::operator=(SharedMem &&rhs) { - this->fd_ = std::move(rhs.fd_); - this->mem_ = rhs.mem_; + fd_ = std::move(rhs.fd_); + mem_ = rhs.mem_; rhs.mem_ = {}; return *this; } From patchwork Tue Jan 13 00:07:34 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25722 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 25ED5BDCBF for ; Tue, 13 Jan 2026 00:08:36 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5B13D61FC2; Tue, 13 Jan 2026 01:08:35 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="kOr+ovBq"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DD35161FB7 for ; Tue, 13 Jan 2026 01:08:32 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 32DF250A for ; Tue, 13 Jan 2026 01:08:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262887; bh=r43+7FueC3TwfykC3fDq5vMzaTlx1yuToFECMfVCYyw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=kOr+ovBq59VEcP2Dz8urQR4fidWvOp5netH03sIoYuTdfw3u+XlFaZu0JGmVrGc+F hOouU5W51J0cDUub5wu/r90AUbo203ZvWa/KXtdJqmn2F6YMrGCdIW6LAbedFmHysx XkNtSyE4Xz3MeYFQChVLP1DQPn3U7jlqZfm9yNy0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 02/36] libcamera: request: Move all private member variables to Private class Date: Tue, 13 Jan 2026 02:07:34 +0200 Message-ID: <20260113000808.15395-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The Request class has a set of private member variables, with some of them stored in the Request class itself, and some in the Request::Private class. Storing the variables in the Request class itself has the advantage that accessors can be inline, at the cost of ABI breakage if variables need to be added, removed or otherwise modified. The controls_ and metadata_ variables have recently been turned from pointers to instances. This broke the ABI. To avoid further breakages, move all remaining private member variables to Request::Private. The performance impact of not inlining accessors will be negligible. While at it, drop an unneeded class forward declaration. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/request.h | 12 ++- include/libcamera/request.h | 15 +--- src/libcamera/request.cpp | 106 +++++++++++++++------------ 3 files changed, 71 insertions(+), 62 deletions(-) diff --git a/include/libcamera/internal/request.h b/include/libcamera/internal/request.h index 693097ee9a26..7715077b3f7c 100644 --- a/include/libcamera/internal/request.h +++ b/include/libcamera/internal/request.h @@ -30,7 +30,7 @@ class Request::Private : public Extensible::Private LIBCAMERA_DECLARE_PUBLIC(Request) public: - Private(Camera *camera); + Private(Camera *camera, uint64_t cookie); ~Private(); Camera *camera() const { return camera_; } @@ -41,7 +41,7 @@ public: bool completeBuffer(FrameBuffer *buffer); void complete(); void cancel(); - void reset(); + void reset(Request::ReuseFlag flags); void prepare(std::chrono::milliseconds timeout = 0ms); Signal<> prepared; @@ -56,14 +56,20 @@ private: void timeout(); Camera *camera_; + const uint64_t cookie_; + + Status status_; bool cancelled_; uint32_t sequence_ = 0; bool prepared_ = false; + ControlList controls_; + ControlList metadata_; + BufferMap bufferMap_; + std::unordered_set pending_; std::map notifiers_; std::unique_ptr timer_; - ControlList metadata_; }; } /* namespace libcamera */ diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 290983f61352..08ac6e8daba7 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -22,7 +22,6 @@ namespace libcamera { class Camera; -class CameraControlValidator; class FrameBuffer; class Stream; @@ -49,16 +48,16 @@ public: void reuse(ReuseFlag flags = Default); - ControlList &controls() { return controls_; } + ControlList &controls(); const ControlList &metadata() const; - const BufferMap &buffers() const { return bufferMap_; } + const BufferMap &buffers() const; int addBuffer(const Stream *stream, FrameBuffer *buffer, std::unique_ptr &&fence = {}); FrameBuffer *findBuffer(const Stream *stream) const; uint32_t sequence() const; - uint64_t cookie() const { return cookie_; } - Status status() const { return status_; } + uint64_t cookie() const; + Status status() const; bool hasPendingBuffers() const; @@ -66,12 +65,6 @@ public: private: LIBCAMERA_DISABLE_COPY(Request) - - ControlList controls_; - BufferMap bufferMap_; - - const uint64_t cookie_; - Status status_; }; std::ostream &operator<<(std::ostream &out, const Request &r); diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index 57f1f060d5b4..9d30091a9af7 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -52,12 +52,16 @@ LOG_DEFINE_CATEGORY(Request) /** * \brief Create a Request::Private - * \param camera The Camera that creates the request + * \param[in] camera The Camera that creates the request + * \param[in] cookie Opaque cookie for application use * * \todo Add a validator for metadata controls. */ -Request::Private::Private(Camera *camera) - : camera_(camera), cancelled_(false), metadata_(controls::controls) +Request::Private::Private(Camera *camera, uint64_t cookie) + : camera_(camera), cookie_(cookie), status_(RequestPending), + cancelled_(false), + controls_(camera->controls(), camera->_d()->validator()), + metadata_(controls::controls) { } @@ -132,7 +136,7 @@ void Request::Private::complete() ASSERT(request->status() == RequestPending); ASSERT(!hasPendingBuffers()); - request->status_ = cancelled_ ? RequestCancelled : RequestComplete; + status_ = cancelled_ ? RequestCancelled : RequestComplete; LOG(Request, Debug) << request->toString(); @@ -174,18 +178,38 @@ void Request::Private::cancel() /** * \brief Reset the request internal data to default values + * \param[in] flags Indicate whether or not to reuse the buffers * * After calling this function, all request internal data will have default - * values as if the Request::Private instance had just been constructed. + * values as if the Request::Private instance had just been constructed, with + * the exception of bufferMap_ if the Request::ReuseFlag::ReuseBuffers flag is + * set in \a flags. */ -void Request::Private::reset() +void Request::Private::reset(Request::ReuseFlag flags) { - sequence_ = 0; + status_ = RequestPending; cancelled_ = false; + sequence_ = 0; prepared_ = false; + + controls_.clear(); + metadata_.clear(); + pending_.clear(); notifiers_.clear(); timer_.reset(); + + if (flags & ReuseBuffers) { + Request *request = _o(); + + for (auto pair : bufferMap_) { + FrameBuffer *buffer = pair.second; + buffer->_d()->setRequest(request); + pending_.insert(buffer); + } + } else { + bufferMap_.clear(); + } } /* @@ -286,9 +310,8 @@ void Request::Private::notifierActivated(FrameBuffer *buffer) ASSERT(it != notifiers_.end()); notifiers_.erase(it); - Request *request = _o(); LOG(Request, Debug) - << "Request " << request->cookie() << " buffer " << buffer + << "Request " << cookie_ << " buffer " << buffer << " fence signalled"; if (!notifiers_.empty()) @@ -305,8 +328,7 @@ void Request::Private::timeout() ASSERT(!notifiers_.empty()); notifiers_.clear(); - Request *request = _o(); - LOG(Request, Debug) << "Request prepare timeout: " << request->cookie(); + LOG(Request, Debug) << "Request prepare timeout: " << cookie_; cancel(); @@ -361,13 +383,11 @@ void Request::Private::timeout() * completely opaque to libcamera. */ Request::Request(Camera *camera, uint64_t cookie) - : Extensible(std::make_unique(camera)), - controls_(camera->controls(), camera->_d()->validator()), - cookie_(cookie), status_(RequestPending) + : Extensible(std::make_unique(camera, cookie)) { LIBCAMERA_TRACEPOINT(request_construct, this); - LOG(Request, Debug) << "Created request - cookie: " << cookie_; + LOG(Request, Debug) << "Created request - cookie: " << cookie; } Request::~Request() @@ -389,26 +409,10 @@ void Request::reuse(ReuseFlag flags) { LIBCAMERA_TRACEPOINT(request_reuse, this); - _d()->reset(); - - if (flags & ReuseBuffers) { - for (auto pair : bufferMap_) { - FrameBuffer *buffer = pair.second; - buffer->_d()->setRequest(this); - _d()->pending_.insert(buffer); - } - } else { - bufferMap_.clear(); - } - - status_ = RequestPending; - - controls_.clear(); - _d()->metadata_.clear(); + _d()->reset(flags); } /** - * \fn Request::controls() * \brief Retrieve the request's ControlList * * Requests store a list of controls to be applied to all frames captured for @@ -422,6 +426,10 @@ void Request::reuse(ReuseFlag flags) * * \return A reference to the ControlList in this request */ +ControlList &Request::controls() +{ + return _d()->controls_; +} /** * \brief Retrieve the request's metadata @@ -433,14 +441,19 @@ const ControlList &Request::metadata() const } /** - * \fn Request::buffers() * \brief Retrieve the request's streams to buffers map * * Return a reference to the map that associates each Stream part of the - * request to the FrameBuffer the Stream output should be directed to. + * request to the FrameBuffer the Stream output should be directed to. If a + * stream is not utilised in this request there will be no buffer for that + * stream in the map. * * \return The map of Stream to FrameBuffer */ +const Request::BufferMap &Request::buffers() const +{ + return _d()->bufferMap_; +} /** * \brief Add a FrameBuffer with its associated Stream to the Request @@ -493,7 +506,7 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer, return -EEXIST; } - auto [it, inserted] = bufferMap_.try_emplace(stream, buffer); + auto [it, inserted] = _d()->bufferMap_.try_emplace(stream, buffer); if (!inserted) { LOG(Request, Error) << "FrameBuffer already set for stream"; return -EEXIST; @@ -508,15 +521,6 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer, return 0; } -/** - * \var Request::bufferMap_ - * \brief Mapping of streams to buffers for this request - * - * The bufferMap_ tracks the buffers associated with each stream. If a stream is - * not utilised in this request there will be no buffer for that stream in the - * map. - */ - /** * \brief Return the buffer associated with a stream * \param[in] stream The stream the buffer is associated to @@ -525,8 +529,8 @@ int Request::addBuffer(const Stream *stream, FrameBuffer *buffer, */ FrameBuffer *Request::findBuffer(const Stream *stream) const { - const auto it = bufferMap_.find(stream); - if (it == bufferMap_.end()) + const auto it = _d()->bufferMap_.find(stream); + if (it == _d()->bufferMap_.end()) return nullptr; return it->second; @@ -553,13 +557,15 @@ uint32_t Request::sequence() const } /** - * \fn Request::cookie() * \brief Retrieve the cookie set when the request was created * \return The request cookie */ +uint64_t Request::cookie() const +{ + return _d()->cookie_; +} /** - * \fn Request::status() * \brief Retrieve the request completion status * * The request status indicates whether the request has completed successfully @@ -570,6 +576,10 @@ uint32_t Request::sequence() const * * \return The request completion status */ +Request::Status Request::status() const +{ + return _d()->status_; +} /** * \brief Check if a request has buffers yet to be completed From patchwork Tue Jan 13 00:07:35 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25723 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 81BD6C323E for ; Tue, 13 Jan 2026 00:08:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2B22361FC3; Tue, 13 Jan 2026 01:08:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="p4jvYH72"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 61A3761FBC for ; Tue, 13 Jan 2026 01:08:34 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 9E7FA66B for ; Tue, 13 Jan 2026 01:08:08 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262888; bh=WsJIqEiDLuJVipvG1aa37QPP5JBilyn21MSnGgTO8eQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=p4jvYH722qwqt+L7ratN/aV+JyI+Zeho4q6nFxLmGXVrGRmtaMq8466uQoPG3vzEa x+OrjXtQHVB8IDk8l0oNi9oNjkJoDyuuw+PkWWwYWJAEhzVD006o0GiL/QQ8P+4leW jgqj0tESf8yIa+ENtpJm+vJC2mdTPOe3IGiWDQMc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 03/36] libcamera: Replace plain pointers with std::unique<> Date: Tue, 13 Jan 2026 02:07:35 +0200 Message-ID: <20260113000808.15395-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" libcamera uses std::unique_ptr<> to simplify life time management of objects and avoid leaks. For historical reasons there are a fair number of plain pointers with manual memory management. Replace them with std::unique_ptr<> when the conversion is simple. Signed-off-by: Laurent Pinchart --- .../guides/application-developer.rst | 5 +++-- Documentation/guides/pipeline-handler.rst | 7 +++--- .../internal/device_enumerator_udev.h | 2 +- include/libcamera/internal/ipc_unixsocket.h | 3 ++- include/libcamera/internal/v4l2_device.h | 2 +- include/libcamera/internal/v4l2_videodevice.h | 12 +++++----- src/apps/qcam/main.cpp | 5 ++--- src/apps/qcam/main_window.cpp | 11 +++++----- src/apps/qcam/main_window.h | 2 +- src/libcamera/device_enumerator_udev.cpp | 6 ++--- src/libcamera/ipc_unixsocket.cpp | 7 +++--- src/libcamera/v4l2_device.cpp | 5 +++-- src/libcamera/v4l2_videodevice.cpp | 22 ++++++++----------- src/v4l2/v4l2_camera.cpp | 7 +++--- src/v4l2/v4l2_camera.h | 2 +- src/v4l2/v4l2_compat_manager.cpp | 18 +++++---------- src/v4l2/v4l2_compat_manager.h | 2 +- 17 files changed, 52 insertions(+), 66 deletions(-) diff --git a/Documentation/guides/application-developer.rst b/Documentation/guides/application-developer.rst index 06c07d1e9449..d981b6a4f9e7 100644 --- a/Documentation/guides/application-developer.rst +++ b/Documentation/guides/application-developer.rst @@ -279,7 +279,8 @@ as the parameter of the ``FrameBufferAllocator::buffers()`` function. .. code:: cpp - FrameBufferAllocator *allocator = new FrameBufferAllocator(camera); + std::unique_ptr allocator = + std::make_unique(camera); for (StreamConfiguration &cfg : *config) { int ret = allocator->allocate(cfg.stream()); @@ -539,7 +540,7 @@ uses, so needs to do the following: camera->stop(); allocator->free(stream); - delete allocator; + allocator.reset(); camera->release(); camera.reset(); cm->stop(); diff --git a/Documentation/guides/pipeline-handler.rst b/Documentation/guides/pipeline-handler.rst index 85d9cc870021..c28eccb7cf0e 100644 --- a/Documentation/guides/pipeline-handler.rst +++ b/Documentation/guides/pipeline-handler.rst @@ -424,20 +424,19 @@ it will be used: { public: VividCameraData(PipelineHandler *pipe, MediaDevice *media) - : Camera::Private(pipe), media_(media), video_(nullptr) + : Camera::Private(pipe), media_(media) { } ~VividCameraData() { - delete video_; } int init(); void bufferReady(FrameBuffer *buffer); MediaDevice *media_; - V4L2VideoDevice *video_; + std::unique_ptr video_; Stream stream_; }; @@ -468,7 +467,7 @@ open a single capture device named 'vivid-000-vid-cap' by the device. int VividCameraData::init() { - video_ = new V4L2VideoDevice(media_->getEntityByName("vivid-000-vid-cap")); + video_ = std::make_unique(media_->getEntityByName("vivid-000-vid-cap")); if (video_->open()) return -ENODEV; diff --git a/include/libcamera/internal/device_enumerator_udev.h b/include/libcamera/internal/device_enumerator_udev.h index 0bf78b551e75..1ce988ab84d1 100644 --- a/include/libcamera/internal/device_enumerator_udev.h +++ b/include/libcamera/internal/device_enumerator_udev.h @@ -69,7 +69,7 @@ private: struct udev *udev_; struct udev_monitor *monitor_; - EventNotifier *notifier_; + std::unique_ptr notifier_; std::set orphans_; std::unordered_set devices_; diff --git a/include/libcamera/internal/ipc_unixsocket.h b/include/libcamera/internal/ipc_unixsocket.h index 48bb7a9422b5..57614fa3f0c7 100644 --- a/include/libcamera/internal/ipc_unixsocket.h +++ b/include/libcamera/internal/ipc_unixsocket.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include @@ -53,7 +54,7 @@ private: UniqueFD fd_; bool headerReceived_; struct Header header_; - EventNotifier *notifier_; + std::unique_ptr notifier_; }; } /* namespace libcamera */ diff --git a/include/libcamera/internal/v4l2_device.h b/include/libcamera/internal/v4l2_device.h index dbbd118abd00..8c4c59bf7773 100644 --- a/include/libcamera/internal/v4l2_device.h +++ b/include/libcamera/internal/v4l2_device.h @@ -89,7 +89,7 @@ private: std::string deviceNode_; UniqueFD fd_; - EventNotifier *fdEventNotifier_; + std::unique_ptr fdEventNotifier_; bool frameStartEnabled_; }; diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h index 57db0036db6b..10367e4e178a 100644 --- a/include/libcamera/internal/v4l2_videodevice.h +++ b/include/libcamera/internal/v4l2_videodevice.h @@ -280,10 +280,10 @@ private: enum v4l2_buf_type bufferType_; enum v4l2_memory memoryType_; - V4L2BufferCache *cache_; + std::unique_ptr cache_; std::map queuedBuffers_; - EventNotifier *fdBufferNotifier_; + std::unique_ptr fdBufferNotifier_; State state_; std::optional firstFrame_; @@ -301,14 +301,14 @@ public: int open(); void close(); - V4L2VideoDevice *output() { return output_; } - V4L2VideoDevice *capture() { return capture_; } + V4L2VideoDevice *output() { return output_.get(); } + V4L2VideoDevice *capture() { return capture_.get(); } private: std::string deviceNode_; - V4L2VideoDevice *output_; - V4L2VideoDevice *capture_; + std::unique_ptr output_; + std::unique_ptr capture_; }; } /* namespace libcamera */ diff --git a/src/apps/qcam/main.cpp b/src/apps/qcam/main.cpp index d0bde14130fb..8c43d43f0dca 100644 --- a/src/apps/qcam/main.cpp +++ b/src/apps/qcam/main.cpp @@ -73,7 +73,7 @@ int main(int argc, char **argv) sa.sa_handler = &signalHandler; sigaction(SIGINT, &sa, nullptr); - CameraManager *cm = new libcamera::CameraManager(); + std::unique_ptr cm = std::make_unique(); ret = cm->start(); if (ret) { @@ -82,13 +82,12 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - MainWindow *mainWindow = new MainWindow(cm, options); + MainWindow *mainWindow = new MainWindow(cm.get(), options); mainWindow->show(); ret = app.exec(); delete mainWindow; cm->stop(); - delete cm; return ret; } diff --git a/src/apps/qcam/main_window.cpp b/src/apps/qcam/main_window.cpp index 96a2d50901b7..e84e19d70728 100644 --- a/src/apps/qcam/main_window.cpp +++ b/src/apps/qcam/main_window.cpp @@ -86,8 +86,8 @@ private: }; MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) - : saveRaw_(nullptr), options_(options), cm_(cm), allocator_(nullptr), - isCapturing_(false), captureRaw_(false) + : saveRaw_(nullptr), options_(options), cm_(cm), isCapturing_(false), + captureRaw_(false) { int ret; @@ -449,7 +449,7 @@ int MainWindow::startCapture() saveRaw_->setEnabled(config_->size() == 2); /* Allocate and map buffers. */ - allocator_ = new FrameBufferAllocator(camera_); + allocator_ = std::make_unique(camera_); for (StreamConfiguration &config : *config_) { Stream *stream = config.stream(); @@ -530,8 +530,7 @@ error: freeBuffers_.clear(); - delete allocator_; - allocator_ = nullptr; + allocator_.reset(); return ret; } @@ -563,7 +562,7 @@ void MainWindow::stopCapture() requests_.clear(); freeQueue_.clear(); - delete allocator_; + allocator_.reset(); isCapturing_ = false; diff --git a/src/apps/qcam/main_window.h b/src/apps/qcam/main_window.h index 81fcf915ade5..20d369ad2318 100644 --- a/src/apps/qcam/main_window.h +++ b/src/apps/qcam/main_window.h @@ -109,7 +109,7 @@ private: /* Camera manager, camera, configuration and buffers */ libcamera::CameraManager *cm_; std::shared_ptr camera_; - libcamera::FrameBufferAllocator *allocator_; + std::unique_ptr allocator_; std::unique_ptr config_; std::map> mappedBuffers_; diff --git a/src/libcamera/device_enumerator_udev.cpp b/src/libcamera/device_enumerator_udev.cpp index 3195dd06e2fc..8b9376ca6ac4 100644 --- a/src/libcamera/device_enumerator_udev.cpp +++ b/src/libcamera/device_enumerator_udev.cpp @@ -28,14 +28,12 @@ namespace libcamera { LOG_DECLARE_CATEGORY(DeviceEnumerator) DeviceEnumeratorUdev::DeviceEnumeratorUdev() - : udev_(nullptr), monitor_(nullptr), notifier_(nullptr) + : udev_(nullptr), monitor_(nullptr) { } DeviceEnumeratorUdev::~DeviceEnumeratorUdev() { - delete notifier_; - if (monitor_) udev_monitor_unref(monitor_); if (udev_) @@ -212,7 +210,7 @@ done: return ret; int fd = udev_monitor_get_fd(monitor_); - notifier_ = new EventNotifier(fd, EventNotifier::Read); + notifier_ = std::make_unique(fd, EventNotifier::Read); notifier_->activated.connect(this, &DeviceEnumeratorUdev::udevNotify); return 0; diff --git a/src/libcamera/ipc_unixsocket.cpp b/src/libcamera/ipc_unixsocket.cpp index 002053e35557..6ec5a5cb6595 100644 --- a/src/libcamera/ipc_unixsocket.cpp +++ b/src/libcamera/ipc_unixsocket.cpp @@ -70,7 +70,7 @@ LOG_DEFINE_CATEGORY(IPCUnixSocket) */ IPCUnixSocket::IPCUnixSocket() - : headerReceived_(false), notifier_(nullptr) + : headerReceived_(false) { } @@ -130,7 +130,7 @@ int IPCUnixSocket::bind(UniqueFD fd) return -EINVAL; fd_ = std::move(fd); - notifier_ = new EventNotifier(fd_.get(), EventNotifier::Read); + notifier_ = std::make_unique(fd_.get(), EventNotifier::Read); notifier_->activated.connect(this, &IPCUnixSocket::dataNotifier); return 0; @@ -146,8 +146,7 @@ void IPCUnixSocket::close() if (!isBound()) return; - delete notifier_; - notifier_ = nullptr; + notifier_.reset(); fd_.reset(); headerReceived_ = false; diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 1582c03efacd..206efb0d951d 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -123,7 +123,8 @@ int V4L2Device::setFd(UniqueFD fd) fd_ = std::move(fd); - fdEventNotifier_ = new EventNotifier(fd_.get(), EventNotifier::Exception); + fdEventNotifier_ = std::make_unique(fd_.get(), + EventNotifier::Exception); fdEventNotifier_->activated.connect(this, &V4L2Device::eventAvailable); fdEventNotifier_->setEnabled(false); @@ -142,7 +143,7 @@ void V4L2Device::close() if (!isOpen()) return; - delete fdEventNotifier_; + fdEventNotifier_.reset(); fd_.reset(); } diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 25b61d049a0e..ddb757b04e59 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -535,8 +535,7 @@ std::ostream &operator<<(std::ostream &out, const V4L2DeviceFormat &f) */ V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode) : V4L2Device(deviceNode), formatInfo_(nullptr), cache_(nullptr), - fdBufferNotifier_(nullptr), state_(State::Stopped), - watchdogDuration_(0.0) + state_(State::Stopped), watchdogDuration_(0.0) { /* * We default to an MMAP based CAPTURE video device, however this will @@ -626,7 +625,7 @@ int V4L2VideoDevice::open() return -EINVAL; } - fdBufferNotifier_ = new EventNotifier(fd(), notifierType); + fdBufferNotifier_ = std::make_unique(fd(), notifierType); fdBufferNotifier_->activated.connect(this, &V4L2VideoDevice::bufferAvailable); fdBufferNotifier_->setEnabled(false); @@ -715,7 +714,7 @@ int V4L2VideoDevice::open(SharedFD handle, enum v4l2_buf_type type) return -EINVAL; } - fdBufferNotifier_ = new EventNotifier(fd(), notifierType); + fdBufferNotifier_ = std::make_unique(fd(), notifierType); fdBufferNotifier_->activated.connect(this, &V4L2VideoDevice::bufferAvailable); fdBufferNotifier_->setEnabled(false); @@ -760,7 +759,7 @@ void V4L2VideoDevice::close() return; releaseBuffers(); - delete fdBufferNotifier_; + fdBufferNotifier_.reset(); formatInfo_ = nullptr; @@ -1374,7 +1373,7 @@ int V4L2VideoDevice::allocateBuffers(unsigned int count, if (ret < 0) return ret; - cache_ = new V4L2BufferCache(*buffers); + cache_ = std::make_unique(*buffers); memoryType_ = V4L2_MEMORY_MMAP; return ret; @@ -1599,7 +1598,7 @@ int V4L2VideoDevice::importBuffers(unsigned int count) if (ret) return ret; - cache_ = new V4L2BufferCache(count); + cache_ = std::make_unique(count); LOG(V4L2, Debug) << "Prepared to import " << count << " buffers"; @@ -1621,8 +1620,7 @@ int V4L2VideoDevice::releaseBuffers() LOG(V4L2, Debug) << "Releasing buffers"; - delete cache_; - cache_ = nullptr; + cache_.reset(); return requestBuffers(0, memoryType_); } @@ -2199,14 +2197,12 @@ V4L2PixelFormat V4L2VideoDevice::toV4L2PixelFormat(const PixelFormat &pixelForma V4L2M2MDevice::V4L2M2MDevice(const std::string &deviceNode) : deviceNode_(deviceNode) { - output_ = new V4L2VideoDevice(deviceNode); - capture_ = new V4L2VideoDevice(deviceNode); + output_ = std::make_unique(deviceNode); + capture_ = std::make_unique(deviceNode); } V4L2M2MDevice::~V4L2M2MDevice() { - delete capture_; - delete output_; } /** diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 94d138cd5710..412ab4ea678e 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -20,7 +20,7 @@ LOG_DECLARE_CATEGORY(V4L2Compat) V4L2Camera::V4L2Camera(std::shared_ptr camera) : camera_(camera), controls_(controls::controls), isRunning_(false), - bufferAllocator_(nullptr), efd_(-1), bufferAvailableCount_(0) + efd_(-1), bufferAvailableCount_(0) { camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete); } @@ -43,7 +43,7 @@ int V4L2Camera::open(StreamConfiguration *streamConfig) return -EINVAL; } - bufferAllocator_ = new FrameBufferAllocator(camera_); + bufferAllocator_ = std::make_unique(camera_); *streamConfig = config_->at(0); return 0; @@ -53,8 +53,7 @@ void V4L2Camera::close() { requestPool_.clear(); - delete bufferAllocator_; - bufferAllocator_ = nullptr; + bufferAllocator_.reset(); camera_->release(); } diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index 9bd161b909de..3d09ae7d6057 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -80,7 +80,7 @@ private: bool isRunning_; libcamera::Mutex bufferLock_; - libcamera::FrameBufferAllocator *bufferAllocator_; + std::unique_ptr bufferAllocator_; std::vector> requestPool_; diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp index f53fb300dde8..a92f2e2944fc 100644 --- a/src/v4l2/v4l2_compat_manager.cpp +++ b/src/v4l2/v4l2_compat_manager.cpp @@ -54,25 +54,21 @@ V4L2CompatManager::~V4L2CompatManager() { files_.clear(); mmaps_.clear(); + proxies_.clear(); - if (cm_) { - proxies_.clear(); + if (cm_) cm_->stop(); - delete cm_; - cm_ = nullptr; - } } int V4L2CompatManager::start() { - cm_ = new CameraManager(); + cm_ = std::make_unique(); int ret = cm_->start(); if (ret) { LOG(V4L2Compat, Error) << "Failed to start camera manager: " << strerror(-ret); - delete cm_; - cm_ = nullptr; + cm_.reset(); return ret; } @@ -83,10 +79,8 @@ int V4L2CompatManager::start() * created here to wrap a camera device. */ auto cameras = cm_->cameras(); - for (auto [index, camera] : utils::enumerate(cameras)) { - V4L2CameraProxy *proxy = new V4L2CameraProxy(index, camera); - proxies_.emplace_back(proxy); - } + for (auto [index, camera] : utils::enumerate(cameras)) + proxies_.emplace_back(std::make_unique(index, camera)); return 0; } diff --git a/src/v4l2/v4l2_compat_manager.h b/src/v4l2/v4l2_compat_manager.h index f7c6f1228282..13673d604a63 100644 --- a/src/v4l2/v4l2_compat_manager.h +++ b/src/v4l2/v4l2_compat_manager.h @@ -61,7 +61,7 @@ private: FileOperations fops_; - libcamera::CameraManager *cm_; + std::unique_ptr cm_; std::vector> proxies_; std::map> files_; From patchwork Tue Jan 13 00:07:36 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25724 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 8E455C3274 for ; Tue, 13 Jan 2026 00:08:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1957E61FC0; Tue, 13 Jan 2026 01:08:39 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Zpx8fJFo"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0C14A61FC0 for ; Tue, 13 Jan 2026 01:08:35 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 3996CBCA for ; Tue, 13 Jan 2026 01:08:10 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262890; bh=NMLsvxXt5ycZ1dFg59O0WDjl2oiJjwYRnecIAFHTfRM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Zpx8fJFodreE2oc2VotV+gXvjAcX76KiE52GJAek1Zu0dHcFDZR8732fsRs2EF+Mr 4xZBivFF/T1qcLZiS1zuIdwS/aAU8cBO2y7Yn6rXNGcwGCa+uetQE/WCBnysKdoiad W6H5ELvRplgRSMGpdUwlTwbjf0fRJ1f8E2yFf+uA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 04/36] libcamera: pipeline_handler: Add createIPA() function Date: Tue, 13 Jan 2026 02:07:36 +0200 Message-ID: <20260113000808.15395-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" IPA proxies are created with a call to IPAManager::createIPA(), which is a static member function. This requires a complicated dance in the createIPA() function to retrieve the IPAManager instance through the camera manager, itself retrieved from the pipeline handler. Simplify the code by turning IPAManager::createIPA() into a non-static member function, and providing a wrapper in the PipelineHandler class to keep instantiation of IPA proxies easy in pipeline handlers. Signed-off-by: Laurent Pinchart Reviewed-by: Barnabás Pőcze --- Documentation/guides/ipa.rst | 8 +++--- include/libcamera/internal/ipa_manager.h | 25 ++++++++----------- include/libcamera/internal/pipeline_handler.h | 11 +++++++- src/libcamera/ipa_manager.cpp | 1 + src/libcamera/pipeline/ipu3/ipu3.cpp | 3 +-- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 3 +-- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 3 +-- .../pipeline/rpi/common/pipeline_base.cpp | 3 +-- src/libcamera/pipeline/vimc/vimc.cpp | 3 +-- src/libcamera/pipeline_handler.cpp | 10 ++++++++ src/libcamera/software_isp/software_isp.cpp | 3 +-- test/ipa/ipa_interface_test.cpp | 3 +-- 12 files changed, 43 insertions(+), 33 deletions(-) diff --git a/Documentation/guides/ipa.rst b/Documentation/guides/ipa.rst index 25deadefaf7c..42993924dd79 100644 --- a/Documentation/guides/ipa.rst +++ b/Documentation/guides/ipa.rst @@ -387,20 +387,20 @@ In the pipeline handler, we first need to construct a specialized IPA proxy. From the point of view of the pipeline hander, this is the object that is the IPA. -To do so, we invoke the IPAManager: +To do so, we call the PipelineHandler::createIPA() function: .. code-block:: C++ std::unique_ptr ipa_ = - IPAManager::createIPA(pipe_, 1, 1); + pipe_->createIPA(1, 1); The ipa::rpi namespace comes from the namespace that we defined in the mojo data definition file, in the "Namespacing" section. The name of the proxy, IPAProxyRPi, comes from the name given to the main IPA interface, IPARPiInterface, in the "The Main IPA interface" section. -The return value of IPAManager::createIPA shall be error-checked, to confirm -that the returned pointer is not a nullptr. +The return value of createIPA() shall be error-checked, to confirm that the +returned pointer is not a nullptr. After this, before initializing the IPA, slots should be connected to all of the IPA's signals, as defined in the Event IPA interface: diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h index f8ce780169e6..ecb6ae896e0c 100644 --- a/include/libcamera/internal/ipa_manager.h +++ b/include/libcamera/internal/ipa_manager.h @@ -17,15 +17,16 @@ #include #include "libcamera/internal/camera_manager.h" -#include "libcamera/internal/global_configuration.h" -#include "libcamera/internal/ipa_module.h" -#include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/pub_key.h" namespace libcamera { LOG_DECLARE_CATEGORY(IPAManager) +class GlobalConfiguration; +class IPAModule; +class PipelineHandler; + class IPAManager { public: @@ -33,23 +34,18 @@ public: ~IPAManager(); template - static std::unique_ptr createIPA(PipelineHandler *pipe, - uint32_t minVersion, - uint32_t maxVersion) + std::unique_ptr createIPA(PipelineHandler *pipe, uint32_t minVersion, + uint32_t maxVersion) { - CameraManager *cm = pipe->cameraManager(); - IPAManager *self = cm->_d()->ipaManager(); - IPAModule *m = self->module(pipe, minVersion, maxVersion); + IPAModule *m = module(pipe, minVersion, maxVersion); if (!m) return nullptr; - const GlobalConfiguration &configuration = cm->_d()->configuration(); - auto proxy = [&]() -> std::unique_ptr { - if (self->isSignatureValid(m)) - return std::make_unique(m, configuration); + if (isSignatureValid(m)) + return std::make_unique(m, configuration_); else - return std::make_unique(m, configuration); + return std::make_unique(m, configuration_); }(); if (!proxy->isValid()) { @@ -77,6 +73,7 @@ private: bool isSignatureValid(IPAModule *ipa) const; + const GlobalConfiguration &configuration_; std::vector> modules_; #if HAVE_IPA_PUBKEY diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index b4f97477acec..6922ce18ec87 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -17,11 +17,13 @@ #include #include +#include "libcamera/internal/camera_manager.h" +#include "libcamera/internal/ipa_manager.h" + namespace libcamera { class Camera; class CameraConfiguration; -class CameraManager; class DeviceEnumerator; class DeviceMatch; class FrameBuffer; @@ -70,6 +72,13 @@ public: CameraManager *cameraManager() const { return manager_; } + template + std::unique_ptr createIPA(uint32_t minVersion, uint32_t maxVersion) + { + IPAManager *ipaManager = manager_->_d()->ipaManager(); + return ipaManager->createIPA(this, minVersion, maxVersion); + } + protected: void registerCamera(std::shared_ptr camera); void hotplugMediaDevice(std::shared_ptr media); diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 35171d097136..1e905e8b82e8 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -105,6 +105,7 @@ LOG_DEFINE_CATEGORY(IPAManager) * CameraManager. */ IPAManager::IPAManager(const GlobalConfiguration &configuration) + : configuration_(configuration) { #if HAVE_IPA_PUBKEY if (!pubKey_.isValid()) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 0190f677e679..06975b85be6b 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -31,7 +31,6 @@ #include "libcamera/internal/delayed_controls.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/framebuffer.h" -#include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" @@ -1152,7 +1151,7 @@ int PipelineHandlerIPU3::registerCameras() int IPU3CameraData::loadIPA() { - ipa_ = IPAManager::createIPA(pipe(), 1, 1); + ipa_ = pipe()->createIPA(1, 1); if (!ipa_) return -ENOENT; diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index 77f251416f71..63450820a273 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -35,7 +35,6 @@ #include "libcamera/internal/delayed_controls.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/framebuffer.h" -#include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" @@ -382,7 +381,7 @@ int MaliC55CameraData::loadIPA() if (!sensor_) return 0; - ipa_ = IPAManager::createIPA(pipe(), 1, 1); + ipa_ = pipe()->createIPA(1, 1); if (!ipa_) return -ENOENT; diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 320a4dc5a899..c7e3b185f89b 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -40,7 +40,6 @@ #include "libcamera/internal/delayed_controls.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/framebuffer.h" -#include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/media_pipeline.h" #include "libcamera/internal/pipeline_handler.h" @@ -389,7 +388,7 @@ const PipelineHandlerRkISP1 *RkISP1CameraData::pipe() const int RkISP1CameraData::loadIPA(unsigned int hwRevision, uint32_t supportedBlocks) { - ipa_ = IPAManager::createIPA(pipe(), 1, 1); + ipa_ = pipe()->createIPA(1, 1); if (!ipa_) return -ENOENT; diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index fb8e466f6e3b..7eb197ce435c 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -20,7 +20,6 @@ #include #include "libcamera/internal/camera_lens.h" -#include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/v4l2_subdevice.h" using namespace std::chrono_literals; @@ -1152,7 +1151,7 @@ int CameraData::loadIPA(ipa::RPi::InitResult *result) { int ret; - ipa_ = IPAManager::createIPA(pipe(), 1, 1); + ipa_ = pipe()->createIPA(1, 1); if (!ipa_) return -ENOENT; diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index 4a03c149a617..378928e18cc7 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -35,7 +35,6 @@ #include "libcamera/internal/camera_sensor.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/framebuffer.h" -#include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/media_device.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" @@ -489,7 +488,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) if (data->init()) return false; - data->ipa_ = IPAManager::createIPA(this, 0, 0); + data->ipa_ = createIPA(0, 0); if (!data->ipa_) { LOG(VIMC, Error) << "no matching IPA found"; return false; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 5c469e5bad24..e7145c1d4815 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -835,6 +835,16 @@ void PipelineHandler::disconnect() * \return The CameraManager for this pipeline handler */ +/** + * \fn PipelineHandler::createIPA() + * \brief Create an IPA proxy that matches this pipeline handler + * \param[in] minVersion Minimum acceptable version of IPA module + * \param[in] maxVersion Maximum acceptable version of IPA module + * + * \return A newly created IPA proxy, or nullptr if no matching IPA module is + * found or if the IPA proxy fails to initialize + */ + /** * \class PipelineHandlerFactoryBase * \brief Base class for pipeline handler factories diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index 7ad3511db28d..aa62257340d8 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -22,7 +22,6 @@ #include #include "libcamera/internal/framebuffer.h" -#include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/software_isp/debayer_params.h" #include "debayer_cpu.h" @@ -146,7 +145,7 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, debayer_->inputBufferReady.connect(this, &SoftwareIsp::inputReady); debayer_->outputBufferReady.connect(this, &SoftwareIsp::outputReady); - ipa_ = IPAManager::createIPA(pipe, 0, 0); + ipa_ = pipe->createIPA(0, 0); if (!ipa_) { LOG(SoftwareIsp, Error) << "Creating IPA for software ISP failed"; diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp index b81783664977..ccff6ac106c8 100644 --- a/test/ipa/ipa_interface_test.cpp +++ b/test/ipa/ipa_interface_test.cpp @@ -22,7 +22,6 @@ #include "libcamera/internal/camera_manager.h" #include "libcamera/internal/device_enumerator.h" -#include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/ipa_module.h" #include "libcamera/internal/pipeline_handler.h" @@ -99,7 +98,7 @@ protected: EventDispatcher *dispatcher = thread()->eventDispatcher(); Timer timer; - ipa_ = IPAManager::createIPA(pipe_.get(), 0, 0); + ipa_ = pipe_->createIPA(0, 0); if (!ipa_) { cerr << "Failed to create VIMC IPA interface" << endl; return TestFail; From patchwork Tue Jan 13 00:07:37 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25725 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 D7F66BDCBF for ; Tue, 13 Jan 2026 00:08:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 98A8161FC8; Tue, 13 Jan 2026 01:08:40 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tU2gSDhA"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 737AE61FBC for ; Tue, 13 Jan 2026 01:08:37 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id CB3BABCA for ; Tue, 13 Jan 2026 01:08:11 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262891; bh=XSnOQ+wvfNYabmcowHyySKCq4yHGxSaKkoTmkcm2RG4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=tU2gSDhAgdNRVbx0MWPMlDlgDzfoRJLOl8ODQsTlXm/nJuRsHbAH2+wErVBWm3YQE Yc5U7NJmE7ocx37hn6UncDz4tbOxd3tMSc+dWL6bAIADULXjd7k+DCv88Rtg3Yiokr fVMLSmYZDQ0RKSHWHpgOBJJmPC1pYTsDshibSZmc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 05/36] test: ipa: ipa_interface: Use IPAManager::createIPA() Date: Tue, 13 Jan 2026 02:07:37 +0200 Message-ID: <20260113000808.15395-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The goal of ipa_interface is to unit test the IPA interface. It currently creates the IPA proxy through the higher level PipelineHandler class. Use the IPAManager::createIPA() function instead to keep the focus on the components that were meant to be tested. Signed-off-by: Laurent Pinchart Reviewed-by: Barnabás Pőcze --- test/ipa/ipa_interface_test.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) -- Regards, Laurent Pinchart diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp index ccff6ac106c8..41ef81721bfa 100644 --- a/test/ipa/ipa_interface_test.cpp +++ b/test/ipa/ipa_interface_test.cpp @@ -22,6 +22,8 @@ #include "libcamera/internal/camera_manager.h" #include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/global_configuration.h" +#include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/ipa_module.h" #include "libcamera/internal/pipeline_handler.h" @@ -43,6 +45,8 @@ public: { delete notifier_; ipa_.reset(); + ipaManager_.reset(); + config_.reset(); cameraManager_.reset(); } @@ -90,6 +94,10 @@ protected: notifier_ = new EventNotifier(fd_, EventNotifier::Read, this); notifier_->activated.connect(this, &IPAInterfaceTest::readTrace); + /* Create the IPA manager. */ + config_ = std::make_unique(); + ipaManager_ = std::make_unique(*config_); + return TestPass; } @@ -98,7 +106,7 @@ protected: EventDispatcher *dispatcher = thread()->eventDispatcher(); Timer timer; - ipa_ = pipe_->createIPA(0, 0); + ipa_ = ipaManager_->createIPA(pipe_.get(), 0, 0); if (!ipa_) { cerr << "Failed to create VIMC IPA interface" << endl; return TestFail; @@ -173,6 +181,8 @@ private: std::shared_ptr pipe_; std::unique_ptr ipa_; std::unique_ptr cameraManager_; + std::unique_ptr config_; + std::unique_ptr ipaManager_; enum ipa::vimc::IPAOperationCode trace_; EventNotifier *notifier_; int fd_; From patchwork Tue Jan 13 00:07:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25726 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 8EA90C3284 for ; Tue, 13 Jan 2026 00:08:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 237DF61FBC; Tue, 13 Jan 2026 01:08:41 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="QdRMigSb"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D895A61FBC for ; Tue, 13 Jan 2026 01:08:38 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 2B9F250A for ; Tue, 13 Jan 2026 01:08:13 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262893; bh=AOHp4X54UBIvETQ4PpRRCLUk7kw9l0tcbUfHFlvVUus=; h=From:To:Subject:Date:In-Reply-To:References:From; b=QdRMigSbfk2aPT+6jGoqI4oFIWyLTXLoJ5nHZ2AEbKAwV51sFhx7cSIkRmL/Y5Dm7 37Wz82IdNGigqdSfCHnHj8yXqHITs2QjJly+QuZKS3raciyIxLhE48qqb+vEbv/Nh7 LT1RkMV5qj+8QDd/OE1PNM8sGiZxFyT5jzIvK9MY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 06/36] test: ipa: ipa_interface: Replace FIFO with pipe Date: Tue, 13 Jan 2026 02:07:38 +0200 Message-ID: <20260113000808.15395-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The ipa_interface unit test uses a FIFO to communicate with the vimc IPA module. FIFOs are named pipes, created in the file system. The path to the FIFO is hardcoded so that both the unit test and IPA module know where to locate the file. If the ipa_interface crashes for any reason, the FIFO will not be removed, and subsequent usage of the vimc IPA module will hang when trying to write to the FIFO in the IPA module. Fix this by replacing the FIFO with a pipe. Pipes are unidirectional data channels that are represented by a pair of file descriptors, without any presence in the file system. The write end of the pipe is passed to the vimc IPA module init() function, and then used the same way as the FIFO. While at it, use a std::unique_ptr to manage the notifier in the unit test instead of manually allocating and deleting the object. Signed-off-by: Laurent Pinchart --- include/libcamera/ipa/vimc.mojom | 3 +- src/ipa/vimc/vimc.cpp | 33 ++++--------------- src/libcamera/pipeline/vimc/vimc.cpp | 2 +- test/ipa/ipa_interface_test.cpp | 49 +++++++++++----------------- 4 files changed, 28 insertions(+), 59 deletions(-) diff --git a/include/libcamera/ipa/vimc.mojom b/include/libcamera/ipa/vimc.mojom index c5c5fe83734e..b1bee05a81a9 100644 --- a/include/libcamera/ipa/vimc.mojom +++ b/include/libcamera/ipa/vimc.mojom @@ -8,8 +8,6 @@ module ipa.vimc; import "include/libcamera/ipa/core.mojom"; -const string VimcIPAFIFOPath = "/tmp/libcamera_ipa_vimc_fifo"; - enum IPAOperationCode { IPAOperationNone, IPAOperationInit, @@ -26,6 +24,7 @@ enum IPAOperationCode { interface IPAVimcInterface { init(libcamera.IPASettings settings, + libcamera.SharedFD traceFd, IPAOperationCode code, [flags] TestFlag inFlags) => (int32 ret, [flags] TestFlag outFlags); diff --git a/src/ipa/vimc/vimc.cpp b/src/ipa/vimc/vimc.cpp index a1351a0f45ce..4162b848f7b1 100644 --- a/src/ipa/vimc/vimc.cpp +++ b/src/ipa/vimc/vimc.cpp @@ -33,6 +33,7 @@ public: ~IPAVimc(); int init(const IPASettings &settings, + const SharedFD &traceFd, const ipa::vimc::IPAOperationCode code, const Flags inFlags, Flags *outFlags) override; @@ -51,30 +52,28 @@ public: void computeParams(uint32_t frame, uint32_t bufferId) override; private: - void initTrace(); void trace(enum ipa::vimc::IPAOperationCode operation); - int fd_; + SharedFD fd_; std::map buffers_; }; IPAVimc::IPAVimc() - : fd_(-1) { - initTrace(); } IPAVimc::~IPAVimc() { - if (fd_ != -1) - ::close(fd_); } int IPAVimc::init(const IPASettings &settings, + const SharedFD &traceFd, const ipa::vimc::IPAOperationCode code, const Flags inFlags, Flags *outFlags) { + fd_ = traceFd; + trace(ipa::vimc::IPAOperationInit); LOG(IPAVimc, Debug) @@ -162,30 +161,12 @@ void IPAVimc::computeParams([[maybe_unused]] uint32_t frame, uint32_t bufferId) paramsComputed.emit(bufferId, flags); } -void IPAVimc::initTrace() -{ - struct stat fifoStat; - int ret = stat(ipa::vimc::VimcIPAFIFOPath.c_str(), &fifoStat); - if (ret) - return; - - ret = ::open(ipa::vimc::VimcIPAFIFOPath.c_str(), O_WRONLY | O_CLOEXEC); - if (ret < 0) { - ret = errno; - LOG(IPAVimc, Error) << "Failed to open vimc IPA test FIFO: " - << strerror(ret); - return; - } - - fd_ = ret; -} - void IPAVimc::trace(enum ipa::vimc::IPAOperationCode operation) { - if (fd_ < 0) + if (!fd_.isValid()) return; - int ret = ::write(fd_, &operation, sizeof(operation)); + int ret = ::write(fd_.get(), &operation, sizeof(operation)); if (ret < 0) { ret = errno; LOG(IPAVimc, Error) << "Failed to write to vimc IPA test FIFO: " diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index 378928e18cc7..6f89826fe149 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -499,7 +499,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) std::string conf = data->ipa_->configurationFile("vimc.conf"); Flags inFlags = ipa::vimc::TestFlag::Flag2; Flags outFlags; - data->ipa_->init(IPASettings{ conf, data->sensor_->model() }, + data->ipa_->init(IPASettings{ conf, data->sensor_->model() }, SharedFD{}, ipa::vimc::IPAOperationInit, inFlags, &outFlags); LOG(VIMC, Debug) diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp index 41ef81721bfa..c1fe2267cc6e 100644 --- a/test/ipa/ipa_interface_test.cpp +++ b/test/ipa/ipa_interface_test.cpp @@ -7,9 +7,8 @@ #include #include +#include #include -#include -#include #include #include @@ -17,8 +16,10 @@ #include #include #include +#include #include #include +#include #include "libcamera/internal/camera_manager.h" #include "libcamera/internal/device_enumerator.h" @@ -37,13 +38,13 @@ class IPAInterfaceTest : public Test, public Object { public: IPAInterfaceTest() - : trace_(ipa::vimc::IPAOperationNone), notifier_(nullptr), fd_(-1) + : trace_(ipa::vimc::IPAOperationNone) { } ~IPAInterfaceTest() { - delete notifier_; + notifier_.reset(); ipa_.reset(); ipaManager_.reset(); config_.reset(); @@ -70,28 +71,22 @@ protected: return TestPass; } - /* Create and open the communication FIFO. */ - int ret = mkfifo(ipa::vimc::VimcIPAFIFOPath.c_str(), S_IRUSR | S_IWUSR); + /* Create the communication pipe. */ + int pipefds[2]; + int ret = pipe2(pipefds, O_NONBLOCK); if (ret) { ret = errno; - cerr << "Failed to create IPA test FIFO at '" - << ipa::vimc::VimcIPAFIFOPath << "': " << strerror(ret) + cerr << "Failed to create IPA test pipe: " << strerror(ret) << endl; return TestFail; } - ret = open(ipa::vimc::VimcIPAFIFOPath.c_str(), O_RDONLY | O_NONBLOCK); - if (ret < 0) { - ret = errno; - cerr << "Failed to open IPA test FIFO at '" - << ipa::vimc::VimcIPAFIFOPath << "': " << strerror(ret) - << endl; - unlink(ipa::vimc::VimcIPAFIFOPath.c_str()); - return TestFail; - } - fd_ = ret; + pipeReadFd_ = UniqueFD(pipefds[0]); + pipeWriteFd_ = SharedFD(pipefds[1]); - notifier_ = new EventNotifier(fd_, EventNotifier::Read, this); + notifier_ = std::make_unique(pipeReadFd_.get(), + EventNotifier::Read, + this); notifier_->activated.connect(this, &IPAInterfaceTest::readTrace); /* Create the IPA manager. */ @@ -116,7 +111,7 @@ protected: std::string conf = ipa_->configurationFile("vimc.conf"); Flags inFlags; Flags outFlags; - int ret = ipa_->init(IPASettings{ conf, "vimc" }, + int ret = ipa_->init(IPASettings{ conf, "vimc" }, pipeWriteFd_, ipa::vimc::IPAOperationInit, inFlags, &outFlags); if (ret < 0) { @@ -159,20 +154,13 @@ protected: return TestPass; } - void cleanup() override - { - close(fd_); - unlink(ipa::vimc::VimcIPAFIFOPath.c_str()); - } - private: void readTrace() { ssize_t s = read(notifier_->fd(), &trace_, sizeof(trace_)); if (s < 0) { int ret = errno; - cerr << "Failed to read from IPA test FIFO at '" - << ipa::vimc::VimcIPAFIFOPath << "': " << strerror(ret) + cerr << "Failed to read from IPA test pipe: " << strerror(ret) << endl; trace_ = ipa::vimc::IPAOperationNone; } @@ -184,8 +172,9 @@ private: std::unique_ptr config_; std::unique_ptr ipaManager_; enum ipa::vimc::IPAOperationCode trace_; - EventNotifier *notifier_; - int fd_; + std::unique_ptr notifier_; + UniqueFD pipeReadFd_; + SharedFD pipeWriteFd_; }; TEST_REGISTER(IPAInterfaceTest) From patchwork Tue Jan 13 00:07:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25727 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 4DC60C3285 for ; Tue, 13 Jan 2026 00:08:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DFCAF61FCB; Tue, 13 Jan 2026 01:08:41 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="p4LjBcQi"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6912A61FBC for ; Tue, 13 Jan 2026 01:08:40 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id BD91BBCA for ; Tue, 13 Jan 2026 01:08:14 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262894; bh=qcl7+VS5Gd19/WBC7zYCeHTYe13Ymb4TPWRrZYqACho=; h=From:To:Subject:Date:In-Reply-To:References:From; b=p4LjBcQi4KwY460EN2BoXj7lTj+6Mr7mxcFgs1jiJcxQHo1fI3AwwvhD7CbKkdbfc gmX6sZ8/9JFfFgUpFDJq0dV93BP0tJkJ20laRO2pCTQLTHcN2o94u/dHuLs4xN0/e4 AHD/I6I5RZ2oO0OE0/7mEhk4b/1Qa1zy7fwHUNGs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 07/36] libcamera: camera_manager: Move IPAManager creation to start() time Date: Tue, 13 Jan 2026 02:07:39 +0200 Message-ID: <20260113000808.15395-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The IPAManager is currently instantiated when constructing the CameraManager constructor, in the CameraManager::Private constructor. This is the only sizeable object constructed with the CameraManager, all other components are constructed when starting the manager. Early construction of the IPAManager isn't wrong per-se, but prevents accessing the CameraManager from the IPAManager constructor (as the former isn't fully constructed). It also results in internal objects constructed in different threads, which isn't an issue at the moment as none of the objects constructed by the IPAManager are thread-bound, but could cause issues later. Finally, it prevents influencing the IPAManager creation with parameters passed to the CameraManager::start() function once we implement this, which would be useful for applications to override configuration parameters related to IPA modules. Move the instantiation of the IPAManager to start time to fix all those issues. Signed-off-by: Laurent Pinchart Reviewed-by: Barnabás Pőcze --- src/libcamera/camera_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index fc6e490bc476..5762c210ffc2 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -41,7 +41,6 @@ LOG_DEFINE_CATEGORY(Camera) CameraManager::Private::Private() : Thread("CameraManager"), initialized_(false) { - ipaManager_ = std::make_unique(configuration()); } int CameraManager::Private::start() @@ -94,6 +93,8 @@ void CameraManager::Private::run() int CameraManager::Private::init() { + ipaManager_ = std::make_unique(configuration()); + enumerator_ = DeviceEnumerator::create(); if (!enumerator_ || enumerator_->enumerate()) return -ENODEV; From patchwork Tue Jan 13 00:07:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25728 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 C3A2BC323E for ; Tue, 13 Jan 2026 00:08:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 88B8961FC0; Tue, 13 Jan 2026 01:08:44 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="jXFvQqbM"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E362C61FD1 for ; Tue, 13 Jan 2026 01:08:41 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 45633E01 for ; Tue, 13 Jan 2026 01:08:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262896; bh=XrvDDRv/7jQlnsUcCK0ZaJ1JLjqiX8XSetkAn/MSpfw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jXFvQqbMrks28Di+LZYrLnMp6K2Yov2RAbsewetBy5ZNG6BijleBgWFkBfoROpaAF LhtWT42rPC93iPtDJJqwCx2r2Rl3eiyeO2FhG5RAEdQ3IQ33+2MSssiVE7EzNOr98I aTShsM/9eJ9EAQ0/c2CWoWzMvTDTt+CaqZ4iMWjI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 08/36] libcamera: yaml_parser: Use std::make_unique<> Date: Tue, 13 Jan 2026 02:07:40 +0200 Message-ID: <20260113000808.15395-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The YamlParser::parse() function constructs a std::unique_ptr<> instance with a manual call to operator new. Replace it with std::make_unique<>. Signed-off-by: Laurent Pinchart Reviewed-by: Barnabás Pőcze --- src/libcamera/yaml_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index a5e424615c26..72580e901ddd 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -769,7 +769,7 @@ std::unique_ptr YamlParser::parse(File &file) if (context.init(file)) return nullptr; - std::unique_ptr root(new YamlObject()); + std::unique_ptr root = std::make_unique(); if (context.parseContent(*root)) { LOG(YamlParser, Error) From patchwork Tue Jan 13 00:07:41 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25729 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 5CAD2C3274 for ; Tue, 13 Jan 2026 00:08:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0F15861FD7; Tue, 13 Jan 2026 01:08:45 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="JtXFrXfQ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6AACB61FB7 for ; Tue, 13 Jan 2026 01:08:43 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id C3255E01 for ; Tue, 13 Jan 2026 01:08:17 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262897; bh=bfT7qpF/HC7BIMsEeY0CWElwFAD6kAmdxnrN2dLU8tw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=JtXFrXfQWoZh2WY7bw6T/QzXTXuotJjIYhC86gB6rmldEW6RzaEEKsOtdAM+w1jei Kan+FQ/a2+cbJPzpCkIs38OmtrKpz26YCI6O6+L6dlc5m/qj02OcJ6FreG7qFAEJ7Q SuI+jAEMvOIh3hULqWqy8fx22CPdozbvWt0hwQZ4= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 09/36] libcamera: yaml_parser: Rename Container to ValueContainer Date: Tue, 13 Jan 2026 02:07:41 +0200 Message-ID: <20260113000808.15395-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The YamlObject class defines two private types, Container and ListContainer. The format is an alias to std::vector, and is used to store child elements. The latter hasn't been used since commit 38987e165c28 ("libcamera: yaml_parser: Preserve order of items in dictionary"). To prepare for upcoming reworks that will use the name 'Container' as a template parameter, rename Container to ValueContainer for clarity, and drop the unused ListContainer type. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/yaml_parser.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 8c7916565946..03d6a05e2d0f 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -36,8 +36,7 @@ private: std::unique_ptr value; }; - using Container = std::vector; - using ListContainer = std::vector>; + using ValueContainer = std::vector; public: #ifndef __DOXYGEN__ @@ -48,7 +47,7 @@ public: using difference_type = std::ptrdiff_t; using iterator_category = std::forward_iterator_tag; - Iterator(typename Container::const_iterator it) + Iterator(typename ValueContainer::const_iterator it) : it_(it) { } @@ -77,14 +76,14 @@ public: } protected: - Container::const_iterator it_; + ValueContainer::const_iterator it_; }; template class Adapter { public: - Adapter(const Container &container) + Adapter(const ValueContainer &container) : container_(container) { } @@ -100,7 +99,7 @@ public: } protected: - const Container &container_; + const ValueContainer &container_; }; class ListIterator : public Iterator @@ -232,7 +231,7 @@ private: Type type_; std::string value_; - Container list_; + ValueContainer list_; std::map> dictionary_; }; From patchwork Tue Jan 13 00:07:42 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25730 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 004C4BDCBF for ; Tue, 13 Jan 2026 00:08:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8EE9061FD9; Tue, 13 Jan 2026 01:08:46 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BwYVPv/c"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D001061FD1 for ; Tue, 13 Jan 2026 01:08:44 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 275DF50A for ; Tue, 13 Jan 2026 01:08:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262899; bh=dcgyHiAYwxc6UdyxdPeoYi9mEglAy8imsqnuuKRslNc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=BwYVPv/ckMcCjkGfDmO37kd3L0HqHIikQPYsT0s3al5PoLTCBegvN5G4B9EgZCm34 E/Y32ZQdAHlFAOHV3kb9/C3fOT25J/cWx6fuyuFgucxXOgHX0iEvXR3LGVEexW2bXU /9u71oqPpijqEvz55k6XFWG2hRdhgx6ha6LGwwwg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 10/36] libcamera: yaml_parser: Rename Getter to Accessor Date: Tue, 13 Jan 2026 02:07:42 +0200 Message-ID: <20260113000808.15395-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" In preparation for support to set the value of a YamlObject, rename the Getter structure to Accessor. The structure will be extended with a set() function. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/matrix.h | 2 +- include/libcamera/internal/vector.h | 2 +- include/libcamera/internal/yaml_parser.h | 6 +++--- src/ipa/libipa/lsc_polynomial.h | 2 +- src/ipa/libipa/pwl.cpp | 2 +- src/libcamera/yaml_parser.cpp | 24 ++++++++++++------------ 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h index 1842389f2b22..67761cb6037d 100644 --- a/include/libcamera/internal/matrix.h +++ b/include/libcamera/internal/matrix.h @@ -200,7 +200,7 @@ std::ostream &operator<<(std::ostream &out, const Matrix &m) } template -struct YamlObject::Getter> { +struct YamlObject::Accessor> { std::optional> get(const YamlObject &obj) const { if (!matrixValidateYaml(obj, Rows * Cols)) diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h index 16b6aef0b38f..cfd8882ce0e6 100644 --- a/include/libcamera/internal/vector.h +++ b/include/libcamera/internal/vector.h @@ -347,7 +347,7 @@ std::ostream &operator<<(std::ostream &out, const Vector &v) } template -struct YamlObject::Getter> { +struct YamlObject::Accessor> { std::optional> get(const YamlObject &obj) const { if (!vectorValidateYaml(obj, Rows)) diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 03d6a05e2d0f..0ff026706682 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -173,7 +173,7 @@ public: template std::optional get() const { - return Getter{}.get(*this); + return Accessor{}.get(*this); } template @@ -213,7 +213,7 @@ private: LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) template - friend struct Getter; + friend struct Accessor; friend class YamlParserContext; enum class Type { @@ -224,7 +224,7 @@ private: }; template - struct Getter { + struct Accessor { std::optional get(const YamlObject &obj) const; }; diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h index c898faeb13db..df3a0d4b39c4 100644 --- a/src/ipa/libipa/lsc_polynomial.h +++ b/src/ipa/libipa/lsc_polynomial.h @@ -81,7 +81,7 @@ private: #ifndef __DOXYGEN__ template<> -struct YamlObject::Getter { +struct YamlObject::Accessor { std::optional get(const YamlObject &obj) const { std::optional cx = obj["cx"].get(); diff --git a/src/ipa/libipa/pwl.cpp b/src/ipa/libipa/pwl.cpp index 72b63c4d068d..f38573e69c13 100644 --- a/src/ipa/libipa/pwl.cpp +++ b/src/ipa/libipa/pwl.cpp @@ -435,7 +435,7 @@ std::string Pwl::toString() const */ template<> std::optional -YamlObject::Getter::get(const YamlObject &obj) const +YamlObject::Accessor::get(const YamlObject &obj) const { /* Treat a single value as single point PWL. */ if (obj.isValue()) { diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 72580e901ddd..a21e589fdd86 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -134,7 +134,7 @@ std::size_t YamlObject::size() const template<> std::optional -YamlObject::Getter::get(const YamlObject &obj) const +YamlObject::Accessor::get(const YamlObject &obj) const { if (obj.type_ != Type::Value) return std::nullopt; @@ -148,7 +148,7 @@ YamlObject::Getter::get(const YamlObject &obj) const } template -struct YamlObject::Getter || std::is_same_v || std::is_same_v || @@ -173,23 +173,23 @@ struct YamlObject::Getter; -template struct YamlObject::Getter; -template struct YamlObject::Getter; -template struct YamlObject::Getter; -template struct YamlObject::Getter; -template struct YamlObject::Getter; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; template<> std::optional -YamlObject::Getter::get(const YamlObject &obj) const +YamlObject::Accessor::get(const YamlObject &obj) const { return obj.get(); } template<> std::optional -YamlObject::Getter::get(const YamlObject &obj) const +YamlObject::Accessor::get(const YamlObject &obj) const { if (obj.type_ != Type::Value) return std::nullopt; @@ -210,7 +210,7 @@ YamlObject::Getter::get(const YamlObject &obj) const template<> std::optional -YamlObject::Getter::get(const YamlObject &obj) const +YamlObject::Accessor::get(const YamlObject &obj) const { if (obj.type_ != Type::Value) return std::nullopt; @@ -220,7 +220,7 @@ YamlObject::Getter::get(const YamlObject &obj) const template<> std::optional -YamlObject::Getter::get(const YamlObject &obj) const +YamlObject::Accessor::get(const YamlObject &obj) const { if (obj.type_ != Type::List) return std::nullopt; From patchwork Tue Jan 13 00:07:43 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25731 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 9787FC32AF for ; Tue, 13 Jan 2026 00:08:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3765161FDC; Tue, 13 Jan 2026 01:08:48 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FSV8muXB"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7FA1861FCC for ; Tue, 13 Jan 2026 01:08:46 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id CA019E01 for ; Tue, 13 Jan 2026 01:08:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262901; bh=G59KHYcrFik9PcmZ2gs4s2WjPMsap3MCsa/y+r88hHE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FSV8muXB2OVctKaJnc95NR3WN6Imx9LaN6f9/MecBiUQrOuMS3gAT8d7XkD4ruTLo YTtQH94PW9Gzr+XBFBHnMukuKxu/UUq6wX/F9PlFT89S7zpf+vdbKvKoH7/i022t8M HOkUz0TXC9hmVU4cn6xqj4YsYAMn9qIuSA6gzHyE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 11/36] libcamera: yaml_parser: Replace getList() with get() specializations Date: Tue, 13 Jan 2026 02:07:43 +0200 Message-ID: <20260113000808.15395-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The YamlObject class has two member function templates to get values: the get() function gets a scalar value, while the getList() function gets a vector of scalar values. As get() is a function template, we can provide specializations for vector types. This makes the code more systematic, and therefore more readable. Replace all getList() occurrences, and drop the getList() function. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/yaml_parser.h | 19 ---- src/ipa/libipa/agc_mean_luminance.cpp | 4 +- src/ipa/libipa/awb_bayes.cpp | 4 +- src/ipa/mali-c55/algorithms/lsc.cpp | 6 +- src/ipa/rkisp1/algorithms/agc.cpp | 2 +- src/ipa/rkisp1/algorithms/dpf.cpp | 6 +- src/ipa/rkisp1/algorithms/gsl.cpp | 8 +- src/ipa/rkisp1/algorithms/lsc.cpp | 4 +- src/ipa/rpi/controller/rpi/agc_channel.cpp | 4 +- src/ipa/rpi/controller/rpi/hdr.cpp | 8 +- src/libcamera/converter/converter_dw100.cpp | 2 +- src/libcamera/global_configuration.cpp | 2 +- .../pipeline/virtual/config_parser.cpp | 2 +- src/libcamera/yaml_parser.cpp | 102 ++++++++---------- test/yaml-parser.cpp | 4 +- 15 files changed, 75 insertions(+), 102 deletions(-) diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 0ff026706682..7953befe11e2 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -182,25 +182,6 @@ public: return get().value_or(std::forward(defaultValue)); } -#ifndef __DOXYGEN__ - template || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v> * = nullptr> -#else - template -#endif - std::optional> getList() const; - DictAdapter asDict() const { return DictAdapter{ list_ }; } ListAdapter asList() const { return ListAdapter{ list_ }; } diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp index 564d4143d363..72988096d384 100644 --- a/src/ipa/libipa/agc_mean_luminance.cpp +++ b/src/ipa/libipa/agc_mean_luminance.cpp @@ -288,9 +288,9 @@ int AgcMeanLuminance::parseExposureModes(const YamlObject &tuningData) } std::vector exposureTimes = - modeValues["exposureTime"].getList().value_or(std::vector{}); + modeValues["exposureTime"].get>().value_or(std::vector{}); std::vector gains = - modeValues["gain"].getList().value_or(std::vector{}); + modeValues["gain"].get>().value_or(std::vector{}); if (exposureTimes.size() != gains.size()) { LOG(AgcMeanLuminance, Error) diff --git a/src/ipa/libipa/awb_bayes.cpp b/src/ipa/libipa/awb_bayes.cpp index d2bcbd83d7f8..595bd0705732 100644 --- a/src/ipa/libipa/awb_bayes.cpp +++ b/src/ipa/libipa/awb_bayes.cpp @@ -211,9 +211,9 @@ int AwbBayes::readPriors(const YamlObject &tuningData) } std::vector temperatures = - p["ct"].getList().value_or(std::vector{}); + p["ct"].get>().value_or(std::vector{}); std::vector probabilities = - p["probability"].getList().value_or(std::vector{}); + p["probability"].get>().value_or(std::vector{}); if (temperatures.size() != probabilities.size()) { LOG(Awb, Error) diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp index 5b042c757bc7..f75b9cd7b7b8 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -48,11 +48,11 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData } std::vector rTable = - yamlSet["r"].getList().value_or(std::vector{}); + yamlSet["r"].get>().value_or(std::vector{}); std::vector gTable = - yamlSet["g"].getList().value_or(std::vector{}); + yamlSet["g"].get>().value_or(std::vector{}); std::vector bTable = - yamlSet["b"].getList().value_or(std::vector{}); + yamlSet["b"].get>().value_or(std::vector{}); /* * Some validation to do; only 16x16 and 32x32 tables of diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index 1ecaff680978..7cc06f91ac2b 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -55,7 +55,7 @@ int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData) } std::vector weights = - value.getList().value_or(std::vector{}); + value.get>().value_or(std::vector{}); if (weights.size() != context.hw.numHistogramWeights) { LOG(RkISP1Agc, Warning) << "Failed to read metering mode'" << key << "'"; diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 39f3e461f313..ec989bc2421f 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -72,7 +72,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, * +---------|--------> X * -4....-1 0 1 2 3 4 */ - values = dFObject["g"].getList().value_or(std::vector{}); + values = dFObject["g"].get>().value_or(std::vector{}); if (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) { LOG(RkISP1Dpf, Error) << "Invalid 'DomainFilter:g': expected " @@ -108,7 +108,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, * For a 9x9 kernel, columns -6 and 6 are dropped, so coefficient * number 6 is not used. */ - values = dFObject["rb"].getList().value_or(std::vector{}); + values = dFObject["rb"].get>().value_or(std::vector{}); if (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS && values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1) { LOG(RkISP1Dpf, Error) @@ -137,7 +137,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, const YamlObject &rFObject = tuningData["NoiseLevelFunction"]; std::vector nllValues; - nllValues = rFObject["coeff"].getList().value_or(std::vector{}); + nllValues = rFObject["coeff"].get>().value_or(std::vector{}); if (nllValues.size() != RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS) { LOG(RkISP1Dpf, Error) << "Invalid 'RangeFilter:coeff': expected " diff --git a/src/ipa/rkisp1/algorithms/gsl.cpp b/src/ipa/rkisp1/algorithms/gsl.cpp index 9604c0ac001a..7ac5dc215850 100644 --- a/src/ipa/rkisp1/algorithms/gsl.cpp +++ b/src/ipa/rkisp1/algorithms/gsl.cpp @@ -59,7 +59,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) { std::vector xIntervals = - tuningData["x-intervals"].getList().value_or(std::vector{}); + tuningData["x-intervals"].get>().value_or(std::vector{}); if (xIntervals.size() != kDegammaXIntervals) { LOG(RkISP1Gsl, Error) << "Invalid 'x' coordinates: expected " @@ -83,7 +83,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - curveYr_ = yObject["red"].getList().value_or(std::vector{}); + curveYr_ = yObject["red"].get>().value_or(std::vector{}); if (curveYr_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) { LOG(RkISP1Gsl, Error) << "Invalid 'y:red' coordinates: expected " @@ -92,7 +92,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - curveYg_ = yObject["green"].getList().value_or(std::vector{}); + curveYg_ = yObject["green"].get>().value_or(std::vector{}); if (curveYg_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) { LOG(RkISP1Gsl, Error) << "Invalid 'y:green' coordinates: expected " @@ -101,7 +101,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - curveYb_ = yObject["blue"].getList().value_or(std::vector{}); + curveYb_ = yObject["blue"].get>().value_or(std::vector{}); if (curveYb_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) { LOG(RkISP1Gsl, Error) << "Invalid 'y:blue' coordinates: expected " diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index e7301bfec863..429565a0b51f 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -252,7 +252,7 @@ private: RKISP1_CIF_ISP_LSC_SAMPLES_MAX * RKISP1_CIF_ISP_LSC_SAMPLES_MAX; std::vector table = - tuningData[prop].getList().value_or(std::vector{}); + tuningData[prop].get>().value_or(std::vector{}); if (table.size() != kLscNumSamples) { LOG(RkISP1Lsc, Error) << "Invalid '" << prop << "' values: expected " @@ -269,7 +269,7 @@ static std::vector parseSizes(const YamlObject &tuningData, const char *prop) { std::vector sizes = - tuningData[prop].getList().value_or(std::vector{}); + tuningData[prop].get>().value_or(std::vector{}); if (sizes.size() != RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE) { LOG(RkISP1Lsc, Error) << "Invalid '" << prop << "' values: expected " diff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp index 154551dfacc2..c6cf1f8903f1 100644 --- a/src/ipa/rpi/controller/rpi/agc_channel.cpp +++ b/src/ipa/rpi/controller/rpi/agc_channel.cpp @@ -66,13 +66,13 @@ readMeteringModes(std::map &metering_modes, int AgcExposureMode::read(const libcamera::YamlObject ¶ms) { - auto value = params["shutter"].getList(); + auto value = params["shutter"].get>(); if (!value) return -EINVAL; std::transform(value->begin(), value->end(), std::back_inserter(exposureTime), [](double v) { return v * 1us; }); - value = params["gain"].getList(); + value = params["gain"].get>(); if (!value) return -EINVAL; gain = std::move(*value); diff --git a/src/ipa/rpi/controller/rpi/hdr.cpp b/src/ipa/rpi/controller/rpi/hdr.cpp index f3da8291bf5d..06400ea79a95 100644 --- a/src/ipa/rpi/controller/rpi/hdr.cpp +++ b/src/ipa/rpi/controller/rpi/hdr.cpp @@ -29,7 +29,7 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod if (!params.contains("cadence")) LOG(RPiHdr, Fatal) << "No cadence for HDR mode " << name; - cadence = params["cadence"].getList().value(); + cadence = params["cadence"].get>().value(); if (cadence.empty()) LOG(RPiHdr, Fatal) << "Empty cadence in HDR mode " << name; @@ -69,14 +69,14 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod tonemap = params["tonemap"].get(ipa::Pwl{}); speed = params["speed"].get(1.0); if (params.contains("hi_quantile_targets")) { - hiQuantileTargets = params["hi_quantile_targets"].getList().value(); + hiQuantileTargets = params["hi_quantile_targets"].get>().value(); if (hiQuantileTargets.empty() || hiQuantileTargets.size() % 2) LOG(RPiHdr, Fatal) << "hi_quantile_targets much be even and non-empty"; } else hiQuantileTargets = { 0.95, 0.65, 0.5, 0.28, 0.3, 0.25 }; hiQuantileMaxGain = params["hi_quantile_max_gain"].get(1.6); if (params.contains("quantile_targets")) { - quantileTargets = params["quantile_targets"].getList().value(); + quantileTargets = params["quantile_targets"].get>().value(); if (quantileTargets.empty() || quantileTargets.size() % 2) LOG(RPiHdr, Fatal) << "quantile_targets much be even and non-empty"; } else @@ -84,7 +84,7 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod powerMin = params["power_min"].get(0.65); powerMax = params["power_max"].get(1.0); if (params.contains("contrast_adjustments")) { - contrastAdjustments = params["contrast_adjustments"].getList().value(); + contrastAdjustments = params["contrast_adjustments"].get>().value(); } else contrastAdjustments = { 0.5, 0.75 }; diff --git a/src/libcamera/converter/converter_dw100.cpp b/src/libcamera/converter/converter_dw100.cpp index df5155cfdc93..5782cd0b21b7 100644 --- a/src/libcamera/converter/converter_dw100.cpp +++ b/src/libcamera/converter/converter_dw100.cpp @@ -126,7 +126,7 @@ int ConverterDW100Module::init(const YamlObject ¶ms) return -EINVAL; } - const auto coeffs = coefficients.getList(); + const auto coeffs = coefficients.get>(); if (!coeffs) { LOG(Converter, Error) << "Dewarp parameters 'coefficients' value is not a list"; return -EINVAL; diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index e086246d6856..99d16e7c38c6 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -152,7 +152,7 @@ std::optional> GlobalConfiguration::listOption( if (!*c) return {}; } - return c->getList(); + return c->get>(); } /** diff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp index 1d3d9ba87ec0..fdc729509371 100644 --- a/src/libcamera/pipeline/virtual/config_parser.cpp +++ b/src/libcamera/pipeline/virtual/config_parser.cpp @@ -115,7 +115,7 @@ int ConfigParser::parseSupportedFormats(const YamlObject &cameraConfigData, std::vector frameRates; if (supportedResolution.contains("frame_rates")) { auto frameRatesList = - supportedResolution["frame_rates"].getList(); + supportedResolution["frame_rates"].get>(); if (!frameRatesList || (frameRatesList->size() != 1 && frameRatesList->size() != 2)) { LOG(Virtual, Error) << "Invalid frame_rates: either one or two values"; diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index a21e589fdd86..2b3723287051 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -109,12 +109,16 @@ std::size_t YamlObject::size() const /** * \fn template YamlObject::get() const + * \tparam T Type of the value * \brief Parse the YamlObject as a \a T value * * This function parses the value of the YamlObject as a \a T object, and * returns the value. If parsing fails (usually because the YamlObject doesn't * store a \a T value), std::nullopt is returned. * + * If the type \a T is an std::vector, the YamlObject will be parsed as a list + * of values. + * * \return The YamlObject value, or std::nullopt if parsing failed */ @@ -127,6 +131,9 @@ std::size_t YamlObject::size() const * returns the value. If parsing fails (usually because the YamlObject doesn't * store a \a T value), the \a defaultValue is returned. * + * Unlike the get() function, this overload does not support std::vector for the + * type \a T. + * * \return The YamlObject value, or \a defaultValue if parsing failed */ @@ -239,65 +246,50 @@ YamlObject::Accessor::get(const YamlObject &obj) const return Size(*width, *height); } -#endif /* __DOXYGEN__ */ - -/** - * \fn template YamlObject::getList() const - * \brief Parse the YamlObject as a list of \a T - * - * This function parses the value of the YamlObject as a list of \a T objects, - * and returns the value as a \a std::vector. If parsing fails, std::nullopt - * is returned. - * - * \return The YamlObject value as a std::vector, or std::nullopt if parsing - * failed - */ - -#ifndef __DOXYGEN__ - -template || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v> *> -std::optional> YamlObject::getList() const +template +struct YamlObject::Accessor, std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> { - if (type_ != Type::List) - return std::nullopt; - - std::vector values; - values.reserve(list_.size()); - - for (const YamlObject &entry : asList()) { - const auto value = entry.get(); - if (!value) + std::optional> get(const YamlObject &obj) const + { + if (obj.type_ != Type::List) return std::nullopt; - values.emplace_back(*value); + + std::vector values; + values.reserve(obj.list_.size()); + + for (const YamlObject &entry : obj.asList()) { + const auto value = entry.get(); + if (!value) + return std::nullopt; + values.emplace_back(*value); + } + + return values; } +}; - return values; -} - -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; -template std::optional> YamlObject::getList() const; - +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; #endif /* __DOXYGEN__ */ /** diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp index 1b22c87b72f1..566401afcab6 100644 --- a/test/yaml-parser.cpp +++ b/test/yaml-parser.cpp @@ -587,9 +587,9 @@ protected: return TestFail; } - const auto &values = firstElement.getList(); + const auto &values = firstElement.get>(); if (!values || values->size() != 2 || (*values)[0] != 1 || (*values)[1] != 2) { - cerr << "getList() failed to return correct vector" << std::endl; + cerr << "get() failed to return correct vector" << std::endl; return TestFail; } From patchwork Tue Jan 13 00:07:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25732 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 4BB5DC3284 for ; Tue, 13 Jan 2026 00:08:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F293861FE2; Tue, 13 Jan 2026 01:08:50 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dx6EVZrF"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1397861FA0 for ; Tue, 13 Jan 2026 01:08:48 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 6B9C8F06 for ; Tue, 13 Jan 2026 01:08:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262902; bh=g9l2EBZ7FVe+T4rOJU5XoOl6FlcCCHc/MA8OBHMJAew=; h=From:To:Subject:Date:In-Reply-To:References:From; b=dx6EVZrFtia/1BXrH40FrztA39J9tC8rGCg0QeeX13TyG2m20lYJLkz/nrjkOnkoL ygyV9orhhHunwEQ0kz3KtRA/suMB2i/ofQJJWlueb/QYoCdRYfssK059SRZigk5AgG o2B7itilHvzOiZoASQW9XQ4A5w9O6PXD1Xhq/YhI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 12/36] libcamera: yaml_parser: Add function to set a YamlObject value Date: Tue, 13 Jan 2026 02:07:44 +0200 Message-ID: <20260113000808.15395-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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 a YamlObject::set() function to set the value of an object, with specializations for scalar types. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/yaml_parser.h | 7 +++ src/libcamera/yaml_parser.cpp | 59 ++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 7953befe11e2..c98fe003c877 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -182,6 +182,12 @@ public: return get().value_or(std::forward(defaultValue)); } + template + void set(T &&value) + { + return Accessor>{}.set(*this, std::forward(value)); + } + DictAdapter asDict() const { return DictAdapter{ list_ }; } ListAdapter asList() const { return ListAdapter{ list_ }; } @@ -207,6 +213,7 @@ private: template struct Accessor { std::optional get(const YamlObject &obj) const; + void set(YamlObject &obj, T value); }; Type type_; diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 2b3723287051..9b61d3e8fc50 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -137,6 +137,20 @@ std::size_t YamlObject::size() const * \return The YamlObject value, or \a defaultValue if parsing failed */ +/** + * \fn template YamlObject::set(T &&value) + * \brief Set the value of a YamlObject + * \param[in] value The value + * + * This function sets the value stored in a YamlObject to \a value. The value is + * converted to a string in an implementation-specific way that guarantees that + * subsequent calls to get() will return the same value. + * + * Values can only be set on YamlObject of Type::Value type or empty YamlObject. + * Attempting to set a value on an object of type Type::Dict or Type::List does + * not modify the YamlObject. + */ + #ifndef __DOXYGEN__ template<> @@ -154,6 +168,16 @@ YamlObject::Accessor::get(const YamlObject &obj) const return std::nullopt; } +template<> +void YamlObject::Accessor::set(YamlObject &obj, bool value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = value ? "true" : "false"; +} + template struct YamlObject::Accessor || @@ -178,6 +202,15 @@ struct YamlObject::Accessor; @@ -194,6 +227,12 @@ YamlObject::Accessor::get(const YamlObject &obj) const return obj.get(); } +template<> +void YamlObject::Accessor::set(YamlObject &obj, float value) +{ + obj.set(std::forward(value)); +} + template<> std::optional YamlObject::Accessor::get(const YamlObject &obj) const @@ -215,6 +254,16 @@ YamlObject::Accessor::get(const YamlObject &obj) const return value; } +template<> +void YamlObject::Accessor::set(YamlObject &obj, double value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::to_string(value); +} + template<> std::optional YamlObject::Accessor::get(const YamlObject &obj) const @@ -225,6 +274,16 @@ YamlObject::Accessor::get(const YamlObject &obj) const return obj.value_; } +template<> +void YamlObject::Accessor::set(YamlObject &obj, std::string value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::move(value); +} + template<> std::optional YamlObject::Accessor::get(const YamlObject &obj) const From patchwork Tue Jan 13 00:07:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25733 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 412FAC3285 for ; Tue, 13 Jan 2026 00:08:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DAB8F61FC8; Tue, 13 Jan 2026 01:08:51 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="QWeiRx8w"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8B96F61FA0 for ; Tue, 13 Jan 2026 01:08:49 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id E7399F06 for ; Tue, 13 Jan 2026 01:08:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262904; bh=XVtOyYEbCFRCjvtXM9h5zxsGQ6SU/UvgTNZZGyL57k8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=QWeiRx8w2wh6WM7WN+JEHarBetXO7CfRu7vGZJlNdort28RyMNy3+1mo3u7cJCIdd sufsol3YbQgY8uRWSTMA16GbyEznarYkQifbcvpOunXHiDIxguFopFHQAoI1k0t5Zu tExWwNVCiYvUx04DILOgxPgpDn3uiisiO8mldR1o= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 13/36] libcamera: yaml_parser: Add functions to add children Date: Tue, 13 Jan 2026 02:07:45 +0200 Message-ID: <20260113000808.15395-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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 YamlObject::add() functions to add children to a list or dictionary object. This will be used by the YamlParserContext to replace direct access to YamlObject member variables to decouple the two classes. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/yaml_parser.h | 3 ++ src/libcamera/yaml_parser.cpp | 56 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index c98fe003c877..ede2c3de687c 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -196,6 +196,9 @@ public: bool contains(std::string_view key) const; const YamlObject &operator[](std::string_view key) const; + YamlObject *add(std::unique_ptr child); + YamlObject *add(std::string key, std::unique_ptr child); + private: LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 9b61d3e8fc50..7462e2d74179 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -448,6 +448,62 @@ const YamlObject &YamlObject::operator[](std::string_view key) const return *iter->second; } +/** + * \brief Add a child object to a list + * \param[in] child The child object + * + * Append the \a child node as the last element of this node's children list. + * This node must be empty, in which case it is converted to the Type::List + * type, or be a list. Otherwise, the \a child is discarded and the function + * returns a nullptr. + * + * \return A pointer to the child object if successfully added, nullptr + * otherwise + */ +YamlObject *YamlObject::add(std::unique_ptr child) +{ + if (type_ == Type::Empty) + type_ = Type::List; + + if (type_ != Type::List) + return nullptr; + + Value &elem = list_.emplace_back(std::string{}, std::move(child)); + return elem.value.get(); +} + +/** + * \brief Add a child object to a dictionary + * \param[in] key The dictionary key + * \param[in] child The child object + * + * Add the \a child node with the given \a key to this node's children. This + * node must be empty, in which case it is converted to the Type::Dictionary + * type, or be a dictionary. Otherwise, the \a child is discarded and the + * function returns a nullptr. + * + * Keys are unique. If a child with the same \a key already exist, the \a child + * is discarded and the function returns a nullptr. + * + * \return A pointer to the child object if successfully added, nullptr + * otherwise + */ +YamlObject *YamlObject::add(std::string key, std::unique_ptr child) +{ + if (type_ == Type::Empty) + type_ = Type::Dictionary; + + if (type_ != Type::Dictionary) + return nullptr; + + if (dictionary_.find(key) != dictionary_.end()) + return nullptr; + + Value &elem = list_.emplace_back(std::move(key), std::move(child)); + dictionary_.emplace(elem.key, elem.value.get()); + return elem.value.get(); +} + #ifndef __DOXYGEN__ class YamlParserContext From patchwork Tue Jan 13 00:07:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25734 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 E0BFDC32C1 for ; Tue, 13 Jan 2026 00:08:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6B44961FD7; Tue, 13 Jan 2026 01:08:52 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="kOVOTwCj"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0AA0D61FE4 for ; Tue, 13 Jan 2026 01:08:51 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 65DDF50A for ; Tue, 13 Jan 2026 01:08:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262905; bh=R+H6T+pUNrJoWHVo2S6YDj3RoWmlhMcmwmzu+gsvK6o=; h=From:To:Subject:Date:In-Reply-To:References:From; b=kOVOTwCjHCoufQNUYRHX1filVvyqVm2DcOQwaFOMXlBu5Te2PvC6oHRkWnbnkaECs 6Uq+dGDOW9et44RAxH8LwkbJdBSZyHBUgYbtWwvSoabZitTdKpZ03x3e2oa2VPF4Xh 09bV/ygPX+pJ0sTjT0kqpoSZ6D+B0T6Hi6AGLTeQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 14/36] libcamera: yaml_parser: Un-friend YamlParserContext from YamlObject Date: Tue, 13 Jan 2026 02:07:46 +0200 Message-ID: <20260113000808.15395-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" YamlParserContext is a friend of the YamlObject class to access private member variables. Now that YamlObject exposes functions to set a value and add children, this is not needed anymore. Decouple the two classes. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/yaml_parser.h | 1 - src/libcamera/yaml_parser.cpp | 56 +++++++++--------------- 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index ede2c3de687c..02e39e4cd7a1 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -204,7 +204,6 @@ private: template friend struct Accessor; - friend class YamlParserContext; enum class Type { Dictionary, diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 7462e2d74179..fa1a487a13dc 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -530,8 +530,8 @@ private: EventPtr nextEvent(); - void readValue(std::string &value, EventPtr event); - int parseDictionaryOrList(YamlObject::Type type, + std::string readValue(EventPtr event); + int parseDictionaryOrList(yaml_event_type_t endEventType, const std::function &parseItem); int parseNextYamlObject(YamlObject &yamlObject, EventPtr event); @@ -673,22 +673,22 @@ int YamlParserContext::parseContent(YamlObject &yamlObject) /** * \fn YamlParserContext::readValue() * \brief Parse event scalar and fill its content into a string - * \param[in] value The string reference to fill value * * A helper function to parse a scalar event as string. The caller needs to - * guarantee the event is of scaler type. + * guarantee the event is of scalar type. + * + * \return The scalar event value as a string */ -void YamlParserContext::readValue(std::string &value, EventPtr event) +std::string YamlParserContext::readValue(EventPtr event) { - value.assign(reinterpret_cast(event->data.scalar.value), - event->data.scalar.length); + return std::string{ reinterpret_cast(event->data.scalar.value), + event->data.scalar.length }; } /** * \fn YamlParserContext::parseDictionaryOrList() * \brief A helper function to abstract the common part of parsing dictionary or list - * - * \param[in] isDictionary True for parsing a dictionary, and false for a list + * \param[in] endEventType The YAML end event type (sequence or mapping) * \param[in] parseItem The callback to handle an item * * A helper function to abstract parsing an item from a dictionary or a list. @@ -703,13 +703,9 @@ void YamlParserContext::readValue(std::string &value, EventPtr event) * \return 0 on success or a negative error code otherwise * \retval -EINVAL The parser is failed to initialize */ -int YamlParserContext::parseDictionaryOrList(YamlObject::Type type, +int YamlParserContext::parseDictionaryOrList(yaml_event_type_t endEventType, const std::function &parseItem) { - yaml_event_type_t endEventType = YAML_SEQUENCE_END_EVENT; - if (type == YamlObject::Type::Dictionary) - endEventType = YAML_MAPPING_END_EVENT; - /* * Add a safety counter to make sure we don't loop indefinitely in case * the YAML file is malformed. @@ -751,24 +747,19 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even switch (event->type) { case YAML_SCALAR_EVENT: - yamlObject.type_ = YamlObject::Type::Value; - readValue(yamlObject.value_, std::move(event)); + yamlObject.set(readValue(std::move(event))); return 0; case YAML_SEQUENCE_START_EVENT: { - yamlObject.type_ = YamlObject::Type::List; - auto &list = yamlObject.list_; - auto handler = [this, &list](EventPtr evt) { - list.emplace_back(std::string{}, std::make_unique()); - return parseNextYamlObject(*list.back().value, std::move(evt)); + auto handler = [this, &yamlObject](EventPtr evt) { + YamlObject *child = yamlObject.add(std::make_unique()); + return parseNextYamlObject(*child, std::move(evt)); }; - return parseDictionaryOrList(YamlObject::Type::List, handler); + return parseDictionaryOrList(YAML_SEQUENCE_END_EVENT, handler); } case YAML_MAPPING_START_EVENT: { - yamlObject.type_ = YamlObject::Type::Dictionary; - auto &list = yamlObject.list_; - auto handler = [this, &list](EventPtr evtKey) { + auto handler = [this, &yamlObject](EventPtr evtKey) { /* Parse key */ if (evtKey->type != YAML_SCALAR_EVENT) { LOG(YamlParser, Error) << "Expect key at line: " @@ -778,26 +769,21 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even return -EINVAL; } - std::string key; - readValue(key, std::move(evtKey)); + std::string key = readValue(std::move(evtKey)); /* Parse value */ EventPtr evtValue = nextEvent(); if (!evtValue) return -EINVAL; - auto &elem = list.emplace_back(std::move(key), - std::make_unique()); - return parseNextYamlObject(*elem.value, std::move(evtValue)); + YamlObject *child = yamlObject.add(std::move(key), + std::make_unique()); + return parseNextYamlObject(*child, std::move(evtValue)); }; - int ret = parseDictionaryOrList(YamlObject::Type::Dictionary, handler); + int ret = parseDictionaryOrList(YAML_MAPPING_END_EVENT, handler); if (ret) return ret; - auto &dictionary = yamlObject.dictionary_; - for (const auto &elem : list) - dictionary.emplace(elem.key, elem.value.get()); - return 0; } From patchwork Tue Jan 13 00:07:47 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25735 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 AA823C323E for ; Tue, 13 Jan 2026 00:08:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4BC9C61FDC; Tue, 13 Jan 2026 01:08:54 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="LOt/c8mS"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8F8C461FD9 for ; Tue, 13 Jan 2026 01:08:52 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id E508E66B for ; Tue, 13 Jan 2026 01:08:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262907; bh=mIZ+S2Qh0dCnCCxu+ZOVd5YJhWRivKWsAAqIijopOOc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=LOt/c8mSxVNtCuhoE1UPC8LPqCyfC93umPav2No253n0bsxtL0UJkQD/892h/qA4Z ZMHrJ+3iKV5/TYLgSzRLd6nlHAI6+tJXuMS5TDp3k4pGlw5UKJejdmCtdC4+y/bU4m XAYb3hj6njPiUP0A6Ep1nj3ETi/zDa0IemF1kz0s= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 15/36] libcamera: yaml_parser: Move Size handling to geometry.cpp Date: Tue, 13 Jan 2026 02:07:47 +0200 Message-ID: <20260113000808.15395-16-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The YamlObject::Accessor structure is designed to extend the YamlObject class with new getter and setter types without modifying yaml_parser.cpp. This feature is used for various libcamera classes, while standard C++ types are handled in yaml_parser.cpp. The Size class is an outlier: it is a libcamera class, but is handled in yaml_parser.cpp. Move it to geometry.cpp. Drop the std::vector specialization as it is currently unused. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/yaml_parser.h | 2 -- src/ipa/libipa/lsc_polynomial.h | 2 ++ src/libcamera/geometry.cpp | 29 ++++++++++++++++++++++++ src/libcamera/yaml_parser.cpp | 25 +------------------- test/yaml-parser.cpp | 2 ++ 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 02e39e4cd7a1..7b6d16de1a04 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -17,8 +17,6 @@ #include -#include - namespace libcamera { class File; diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h index df3a0d4b39c4..c71f215de3fc 100644 --- a/src/ipa/libipa/lsc_polynomial.h +++ b/src/ipa/libipa/lsc_polynomial.h @@ -14,6 +14,8 @@ #include #include +#include + #include "libcamera/internal/yaml_parser.h" namespace libcamera { diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index 2763967a6e57..2e8e9e33ea78 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -12,6 +12,8 @@ #include +#include "libcamera/internal/yaml_parser.h" + /** * \file geometry.h * \brief Data structures related to geometric objects @@ -924,4 +926,31 @@ std::ostream &operator<<(std::ostream &out, const Rectangle &r) return out; } +#ifndef __DOXYGEN__ +/* + * The YAML data shall be a list of two numerical values containing the x and y + * coordinates, in that order. + */ +template<> +std::optional +YamlObject::Accessor::get(const YamlObject &obj) const +{ + if (obj.type_ != Type::List) + return std::nullopt; + + if (obj.list_.size() != 2) + return std::nullopt; + + auto width = obj.list_[0].value->get(); + if (!width) + return std::nullopt; + + auto height = obj.list_[1].value->get(); + if (!height) + return std::nullopt; + + return Size(*width, *height); +} +#endif /* __DOXYGEN__ */ + } /* namespace libcamera */ diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index fa1a487a13dc..46c1fb9bce7e 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -284,27 +284,6 @@ void YamlObject::Accessor::set(YamlObject &obj, std::string value) obj.value_ = std::move(value); } -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::List) - return std::nullopt; - - if (obj.list_.size() != 2) - return std::nullopt; - - auto width = obj.list_[0].value->get(); - if (!width) - return std::nullopt; - - auto height = obj.list_[1].value->get(); - if (!height) - return std::nullopt; - - return Size(*width, *height); -} - template struct YamlObject::Accessor, std::enable_if_t< std::is_same_v || @@ -316,8 +295,7 @@ struct YamlObject::Accessor, std::enable_if_t< std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || - std::is_same_v>> + std::is_same_v>> { std::optional> get(const YamlObject &obj) const { @@ -348,7 +326,6 @@ template struct YamlObject::Accessor>; template struct YamlObject::Accessor>; template struct YamlObject::Accessor>; template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; #endif /* __DOXYGEN__ */ /** diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp index 566401afcab6..01e734d23059 100644 --- a/test/yaml-parser.cpp +++ b/test/yaml-parser.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include "libcamera/internal/yaml_parser.h" #include "test.h" From patchwork Tue Jan 13 00:07:48 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25736 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 2500BC3274 for ; Tue, 13 Jan 2026 00:08:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D3A4461FE2; Tue, 13 Jan 2026 01:08:56 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="pF+0RGOu"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6037F61FDF for ; Tue, 13 Jan 2026 01:08:54 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B8ACBE01 for ; Tue, 13 Jan 2026 01:08:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262908; bh=dLCWBdsPXR0iaJdNPwthHIupa/eigp5hI/lxGEHYh1s=; h=From:To:Subject:Date:In-Reply-To:References:From; b=pF+0RGOuFn6sHDDLFTUuh+P4ok5MB2HPKSxEet7wwqABbZrNh6VGt+bsuPdiNszVd D3uj09ej+gCb05ZfjRd5Q07suza2rLh2Anjn8GAauDJy8XKmRiUeKZ/AM/qh+xl141 mDv7cHvf+2XJiy50W+PGyweXjRQnA2z63nzVdffM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 16/36] libcamera: yaml_parser: Drop unneeded \fn Doxygen commands Date: Tue, 13 Jan 2026 02:07:48 +0200 Message-ID: <20260113000808.15395-17-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" There's no need to specify the function name in Doxygen comment blocks with \fn if the documentation directly precedes the function definition. Drop the unneeded \fn. Signed-off-by: Laurent Pinchart --- src/libcamera/yaml_parser.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 46c1fb9bce7e..0ef1f3ea303b 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -86,7 +86,6 @@ YamlObject::~YamlObject() = default; */ /** - * \fn YamlObject::size() * \brief Retrieve the number of elements in a dictionary or list YamlObject * * This function retrieves the size of the YamlObject, defined as the number of @@ -541,7 +540,6 @@ YamlParserContext::~YamlParserContext() } /** - * \fn YamlParserContext::init() * \brief Initialize a parser with an opened file for parsing * \param[in] fh The YAML file to parse * @@ -580,7 +578,6 @@ int YamlParserContext::yamlRead(void *data, unsigned char *buffer, size_t size, } /** - * \fn YamlParserContext::nextEvent() * \brief Get the next event * * Get the next event in the current YAML event stream, and return nullptr when @@ -609,7 +606,6 @@ YamlParserContext::EventPtr YamlParserContext::nextEvent() } /** - * \fn YamlParserContext::parseContent() * \brief Parse the content of a YAML document * \param[in] yamlObject The result of YamlObject * @@ -648,7 +644,6 @@ int YamlParserContext::parseContent(YamlObject &yamlObject) } /** - * \fn YamlParserContext::readValue() * \brief Parse event scalar and fill its content into a string * * A helper function to parse a scalar event as string. The caller needs to @@ -663,7 +658,6 @@ std::string YamlParserContext::readValue(EventPtr event) } /** - * \fn YamlParserContext::parseDictionaryOrList() * \brief A helper function to abstract the common part of parsing dictionary or list * \param[in] endEventType The YAML end event type (sequence or mapping) * \param[in] parseItem The callback to handle an item @@ -707,7 +701,6 @@ int YamlParserContext::parseDictionaryOrList(yaml_event_type_t endEventType, } /** - * \fn YamlParserContext::parseNextYamlObject() * \brief Parse next YAML event and read it as a YamlObject * \param[in] yamlObject The result of YamlObject * \param[in] event The leading event of the object From patchwork Tue Jan 13 00:07:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25737 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 DA3D5C32DE for ; Tue, 13 Jan 2026 00:08:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6A17761FD7; Tue, 13 Jan 2026 01:08:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="LMwBATiy"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F83C61FC8 for ; Tue, 13 Jan 2026 01:08:56 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 49F4CF06 for ; Tue, 13 Jan 2026 01:08:30 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262910; bh=3/3XeS833dC0RKDMMaIuW6uxZHlGpT0KH70GyKfUqTw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=LMwBATiy2UPzCZdIzZSQMDZE5eLzVQEc/ibhMeo9EkZHAELUWTv2W1jvsVZ307giW mMpmLYDAGYHE/sNwZLFPD1GDc7mpu1k93qy6UvfImCeEcKhJ9R2QdaCadOY5ckvLQg ut5IPTJM8+pVr0e8Cbqp/84EZZuBUCyBgKZHaWf0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 17/36] libcamera: yaml_parser: Split YamlObject from YamlParser Date: Tue, 13 Jan 2026 02:07:49 +0200 Message-ID: <20260113000808.15395-18-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The YamlObject class was designed to represent data parsed from YAML files. It is outgrowing the initial needs. Move it to a separate file to prepare for a rename. Most files that include yaml_parser.h only need access to a YamlObject. Switch them to yaml_object.h. pipeline_base.cpp was including yaml_parser.h indirectly through pipeline_base.h, include it directly now. Signed-off-by: Laurent Pinchart --- .../libcamera/internal/global_configuration.h | 2 +- include/libcamera/internal/matrix.h | 2 +- include/libcamera/internal/meson.build | 1 + include/libcamera/internal/vector.h | 2 +- include/libcamera/internal/yaml_object.h | 226 +++++++++ include/libcamera/internal/yaml_parser.h | 212 +------- src/ipa/libipa/agc_mean_luminance.h | 2 +- src/ipa/libipa/awb.h | 2 +- src/ipa/libipa/awb_bayes.h | 2 +- src/ipa/libipa/interpolator.cpp | 2 - src/ipa/libipa/interpolator.h | 2 +- src/ipa/libipa/lsc_polynomial.h | 2 +- src/ipa/libipa/lux.cpp | 2 +- src/ipa/libipa/module.h | 2 +- src/ipa/mali-c55/algorithms/blc.cpp | 2 +- src/ipa/mali-c55/algorithms/lsc.cpp | 2 +- src/ipa/rkisp1/algorithms/agc.cpp | 2 +- src/ipa/rkisp1/algorithms/blc.cpp | 2 +- src/ipa/rkisp1/algorithms/ccm.cpp | 2 +- src/ipa/rkisp1/algorithms/dpcc.cpp | 2 +- src/ipa/rkisp1/algorithms/goc.cpp | 2 +- src/ipa/rkisp1/algorithms/gsl.cpp | 2 +- src/ipa/rkisp1/algorithms/lsc.cpp | 2 +- src/ipa/rkisp1/algorithms/wdr.cpp | 2 +- src/ipa/rpi/controller/algorithm.h | 2 +- src/ipa/rpi/controller/controller.h | 2 +- src/libcamera/geometry.cpp | 2 +- src/libcamera/meson.build | 1 + .../pipeline/rpi/common/pipeline_base.cpp | 1 + .../pipeline/rpi/common/pipeline_base.h | 2 +- .../pipeline/virtual/config_parser.h | 2 +- src/libcamera/pipeline/virtual/virtual.cpp | 2 +- src/libcamera/yaml_object.cpp | 477 ++++++++++++++++++ src/libcamera/yaml_parser.cpp | 458 +---------------- 34 files changed, 736 insertions(+), 694 deletions(-) create mode 100644 include/libcamera/internal/yaml_object.h create mode 100644 src/libcamera/yaml_object.cpp diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 8d09517edca1..16c6a21f2a8a 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -14,7 +14,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h index 67761cb6037d..11fccd27547e 100644 --- a/include/libcamera/internal/matrix.h +++ b/include/libcamera/internal/matrix.h @@ -14,7 +14,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index dc48619e5ac8..c24c9f062f29 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -50,6 +50,7 @@ libcamera_internal_headers = files([ 'v4l2_subdevice.h', 'v4l2_videodevice.h', 'vector.h', + 'yaml_object.h', 'yaml_parser.h', ]) diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h index cfd8882ce0e6..af24485f3bb1 100644 --- a/include/libcamera/internal/vector.h +++ b/include/libcamera/internal/vector.h @@ -19,7 +19,7 @@ #include #include "libcamera/internal/matrix.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/include/libcamera/internal/yaml_object.h b/include/libcamera/internal/yaml_object.h new file mode 100644 index 000000000000..1771f8821e2e --- /dev/null +++ b/include/libcamera/internal/yaml_object.h @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * Copyright (C) 2025, Ideas on Board + * + * libcamera YAML object + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace libcamera { + +class YamlObject +{ +private: + struct Value { + Value(std::string &&k, std::unique_ptr &&v) + : key(std::move(k)), value(std::move(v)) + { + } + std::string key; + std::unique_ptr value; + }; + + using ValueContainer = std::vector; + +public: +#ifndef __DOXYGEN__ + template + class Iterator + { + public: + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + Iterator(typename ValueContainer::const_iterator it) + : it_(it) + { + } + + Derived &operator++() + { + ++it_; + return *static_cast(this); + } + + Derived operator++(int) + { + Derived it = *static_cast(this); + it_++; + return it; + } + + friend bool operator==(const Iterator &a, const Iterator &b) + { + return a.it_ == b.it_; + } + + friend bool operator!=(const Iterator &a, const Iterator &b) + { + return a.it_ != b.it_; + } + + protected: + ValueContainer::const_iterator it_; + }; + + template + class Adapter + { + public: + Adapter(const ValueContainer &container) + : container_(container) + { + } + + Iterator begin() const + { + return Iterator{ container_.begin() }; + } + + Iterator end() const + { + return Iterator{ container_.end() }; + } + + protected: + const ValueContainer &container_; + }; + + class ListIterator : public Iterator + { + public: + using value_type = const YamlObject &; + using pointer = const YamlObject *; + using reference = value_type; + + value_type operator*() const + { + return *it_->value.get(); + } + + pointer operator->() const + { + return it_->value.get(); + } + }; + + class DictIterator : public Iterator + { + public: + using value_type = std::pair; + using pointer = value_type *; + using reference = value_type &; + + value_type operator*() const + { + return { it_->key, *it_->value.get() }; + } + }; + + class DictAdapter : public Adapter + { + public: + using key_type = std::string; + }; + + class ListAdapter : public Adapter + { + }; +#endif /* __DOXYGEN__ */ + + YamlObject(); + ~YamlObject(); + + bool isValue() const + { + return type_ == Type::Value; + } + bool isList() const + { + return type_ == Type::List; + } + bool isDictionary() const + { + return type_ == Type::Dictionary; + } + bool isEmpty() const + { + return type_ == Type::Empty; + } + explicit operator bool() const + { + return type_ != Type::Empty; + } + + std::size_t size() const; + + template + std::optional get() const + { + return Accessor{}.get(*this); + } + + template + T get(U &&defaultValue) const + { + return get().value_or(std::forward(defaultValue)); + } + + template + void set(T &&value) + { + return Accessor>{}.set(*this, std::forward(value)); + } + + DictAdapter asDict() const { return DictAdapter{ list_ }; } + ListAdapter asList() const { return ListAdapter{ list_ }; } + + const YamlObject &operator[](std::size_t index) const; + + bool contains(std::string_view key) const; + const YamlObject &operator[](std::string_view key) const; + + YamlObject *add(std::unique_ptr child); + YamlObject *add(std::string key, std::unique_ptr child); + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) + + template + friend struct Accessor; + + enum class Type { + Dictionary, + List, + Value, + Empty, + }; + + template + struct Accessor { + std::optional get(const YamlObject &obj) const; + void set(YamlObject &obj, T value); + }; + + Type type_; + + std::string value_; + ValueContainer list_; + std::map> dictionary_; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index 7b6d16de1a04..e503e83a80da 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -7,221 +7,13 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include -#include +#include "libcamera/internal/yaml_object.h" namespace libcamera { class File; -class YamlParserContext; - -class YamlObject -{ -private: - struct Value { - Value(std::string &&k, std::unique_ptr &&v) - : key(std::move(k)), value(std::move(v)) - { - } - std::string key; - std::unique_ptr value; - }; - - using ValueContainer = std::vector; - -public: -#ifndef __DOXYGEN__ - template - class Iterator - { - public: - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - Iterator(typename ValueContainer::const_iterator it) - : it_(it) - { - } - - Derived &operator++() - { - ++it_; - return *static_cast(this); - } - - Derived operator++(int) - { - Derived it = *static_cast(this); - it_++; - return it; - } - - friend bool operator==(const Iterator &a, const Iterator &b) - { - return a.it_ == b.it_; - } - - friend bool operator!=(const Iterator &a, const Iterator &b) - { - return a.it_ != b.it_; - } - - protected: - ValueContainer::const_iterator it_; - }; - - template - class Adapter - { - public: - Adapter(const ValueContainer &container) - : container_(container) - { - } - - Iterator begin() const - { - return Iterator{ container_.begin() }; - } - - Iterator end() const - { - return Iterator{ container_.end() }; - } - - protected: - const ValueContainer &container_; - }; - - class ListIterator : public Iterator - { - public: - using value_type = const YamlObject &; - using pointer = const YamlObject *; - using reference = value_type; - - value_type operator*() const - { - return *it_->value.get(); - } - - pointer operator->() const - { - return it_->value.get(); - } - }; - - class DictIterator : public Iterator - { - public: - using value_type = std::pair; - using pointer = value_type *; - using reference = value_type &; - - value_type operator*() const - { - return { it_->key, *it_->value.get() }; - } - }; - - class DictAdapter : public Adapter - { - public: - using key_type = std::string; - }; - - class ListAdapter : public Adapter - { - }; -#endif /* __DOXYGEN__ */ - - YamlObject(); - ~YamlObject(); - - bool isValue() const - { - return type_ == Type::Value; - } - bool isList() const - { - return type_ == Type::List; - } - bool isDictionary() const - { - return type_ == Type::Dictionary; - } - bool isEmpty() const - { - return type_ == Type::Empty; - } - explicit operator bool() const - { - return type_ != Type::Empty; - } - - std::size_t size() const; - - template - std::optional get() const - { - return Accessor{}.get(*this); - } - - template - T get(U &&defaultValue) const - { - return get().value_or(std::forward(defaultValue)); - } - - template - void set(T &&value) - { - return Accessor>{}.set(*this, std::forward(value)); - } - - DictAdapter asDict() const { return DictAdapter{ list_ }; } - ListAdapter asList() const { return ListAdapter{ list_ }; } - - const YamlObject &operator[](std::size_t index) const; - - bool contains(std::string_view key) const; - const YamlObject &operator[](std::string_view key) const; - - YamlObject *add(std::unique_ptr child); - YamlObject *add(std::string key, std::unique_ptr child); - -private: - LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) - - template - friend struct Accessor; - - enum class Type { - Dictionary, - List, - Value, - Empty, - }; - - template - struct Accessor { - std::optional get(const YamlObject &obj) const; - void set(YamlObject &obj, T value); - }; - - Type type_; - - std::string value_; - ValueContainer list_; - std::map> dictionary_; -}; class YamlParser final { diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h index 0df97b27332d..dfe1ccbe948b 100644 --- a/src/ipa/libipa/agc_mean_luminance.h +++ b/src/ipa/libipa/agc_mean_luminance.h @@ -16,7 +16,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "exposure_mode_helper.h" #include "histogram.h" diff --git a/src/ipa/libipa/awb.h b/src/ipa/libipa/awb.h index f4a86038635f..3f25d13feaa8 100644 --- a/src/ipa/libipa/awb.h +++ b/src/ipa/libipa/awb.h @@ -14,7 +14,7 @@ #include #include "libcamera/internal/vector.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/src/ipa/libipa/awb_bayes.h b/src/ipa/libipa/awb_bayes.h index 47ef3cce4d58..79334ad3e7a3 100644 --- a/src/ipa/libipa/awb_bayes.h +++ b/src/ipa/libipa/awb_bayes.h @@ -10,7 +10,7 @@ #include #include "libcamera/internal/vector.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "awb.h" #include "interpolator.h" diff --git a/src/ipa/libipa/interpolator.cpp b/src/ipa/libipa/interpolator.cpp index f901a86e4c74..9355802f796a 100644 --- a/src/ipa/libipa/interpolator.cpp +++ b/src/ipa/libipa/interpolator.cpp @@ -11,8 +11,6 @@ #include -#include "libcamera/internal/yaml_parser.h" - #include "interpolator.h" /** diff --git a/src/ipa/libipa/interpolator.h b/src/ipa/libipa/interpolator.h index 7880db6976d1..08003a06dbba 100644 --- a/src/ipa/libipa/interpolator.h +++ b/src/ipa/libipa/interpolator.h @@ -15,7 +15,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h index c71f215de3fc..19da46860849 100644 --- a/src/ipa/libipa/lsc_polynomial.h +++ b/src/ipa/libipa/lsc_polynomial.h @@ -16,7 +16,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/src/ipa/libipa/lux.cpp b/src/ipa/libipa/lux.cpp index 899e88248f04..d79b116a3339 100644 --- a/src/ipa/libipa/lux.cpp +++ b/src/ipa/libipa/lux.cpp @@ -12,7 +12,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "histogram.h" diff --git a/src/ipa/libipa/module.h b/src/ipa/libipa/module.h index c27af7718feb..8e6c658a6b63 100644 --- a/src/ipa/libipa/module.h +++ b/src/ipa/libipa/module.h @@ -15,7 +15,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "algorithm.h" diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp index d099219c3e43..3bdf19141e1d 100644 --- a/src/ipa/mali-c55/algorithms/blc.cpp +++ b/src/ipa/mali-c55/algorithms/blc.cpp @@ -10,7 +10,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" /** * \file blc.h diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp index f75b9cd7b7b8..e32f5a83485e 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -7,7 +7,7 @@ #include "lsc.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" namespace libcamera { diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index 7cc06f91ac2b..ef16a3775056 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -19,7 +19,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "libipa/histogram.h" diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp index 32fc44ffff92..19c262fffa73 100644 --- a/src/ipa/rkisp1/algorithms/blc.cpp +++ b/src/ipa/rkisp1/algorithms/blc.cpp @@ -13,7 +13,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" /** * \file blc.h diff --git a/src/ipa/rkisp1/algorithms/ccm.cpp b/src/ipa/rkisp1/algorithms/ccm.cpp index de2b6fe775aa..3ed307280677 100644 --- a/src/ipa/rkisp1/algorithms/ccm.cpp +++ b/src/ipa/rkisp1/algorithms/ccm.cpp @@ -16,7 +16,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "libipa/fixedpoint.h" #include "libipa/interpolator.h" diff --git a/src/ipa/rkisp1/algorithms/dpcc.cpp b/src/ipa/rkisp1/algorithms/dpcc.cpp index 7894628144f3..c195334750e1 100644 --- a/src/ipa/rkisp1/algorithms/dpcc.cpp +++ b/src/ipa/rkisp1/algorithms/dpcc.cpp @@ -9,7 +9,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "linux/rkisp1-config.h" diff --git a/src/ipa/rkisp1/algorithms/goc.cpp b/src/ipa/rkisp1/algorithms/goc.cpp index a0e7030fe5db..6c07bd8c71e5 100644 --- a/src/ipa/rkisp1/algorithms/goc.cpp +++ b/src/ipa/rkisp1/algorithms/goc.cpp @@ -13,7 +13,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "linux/rkisp1-config.h" diff --git a/src/ipa/rkisp1/algorithms/gsl.cpp b/src/ipa/rkisp1/algorithms/gsl.cpp index 7ac5dc215850..292d0e80dc57 100644 --- a/src/ipa/rkisp1/algorithms/gsl.cpp +++ b/src/ipa/rkisp1/algorithms/gsl.cpp @@ -10,7 +10,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "linux/rkisp1-config.h" diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 429565a0b51f..9c0ed44b3943 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -14,7 +14,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "libipa/lsc_polynomial.h" #include "linux/rkisp1-config.h" diff --git a/src/ipa/rkisp1/algorithms/wdr.cpp b/src/ipa/rkisp1/algorithms/wdr.cpp index ed81628c032c..9e2688a05179 100644 --- a/src/ipa/rkisp1/algorithms/wdr.cpp +++ b/src/ipa/rkisp1/algorithms/wdr.cpp @@ -10,7 +10,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include #include diff --git a/src/ipa/rpi/controller/algorithm.h b/src/ipa/rpi/controller/algorithm.h index 1971bfdcc8ad..8839daa90916 100644 --- a/src/ipa/rpi/controller/algorithm.h +++ b/src/ipa/rpi/controller/algorithm.h @@ -15,7 +15,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "controller.h" diff --git a/src/ipa/rpi/controller/controller.h b/src/ipa/rpi/controller/controller.h index fdb46557de9c..573942886bc0 100644 --- a/src/ipa/rpi/controller/controller.h +++ b/src/ipa/rpi/controller/controller.h @@ -16,7 +16,7 @@ #include #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "camera_mode.h" #include "device_status.h" diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index 2e8e9e33ea78..621008844c74 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -12,7 +12,7 @@ #include -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" /** * \file geometry.h diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6f952bd9832a..da89aa3714c3 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -58,6 +58,7 @@ libcamera_internal_sources = files([ 'v4l2_subdevice.cpp', 'v4l2_videodevice.cpp', 'vector.cpp', + 'yaml_object.cpp', 'yaml_parser.cpp', ]) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 7eb197ce435c..684438bd5fb7 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -21,6 +21,7 @@ #include "libcamera/internal/camera_lens.h" #include "libcamera/internal/v4l2_subdevice.h" +#include "libcamera/internal/yaml_parser.h" using namespace std::chrono_literals; diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h index 6257a93467df..c69a690f580c 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h @@ -26,7 +26,7 @@ #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" #include "libcamera/internal/v4l2_videodevice.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include #include diff --git a/src/libcamera/pipeline/virtual/config_parser.h b/src/libcamera/pipeline/virtual/config_parser.h index d2000de9c12f..f696d8862897 100644 --- a/src/libcamera/pipeline/virtual/config_parser.h +++ b/src/libcamera/pipeline/virtual/config_parser.h @@ -13,7 +13,7 @@ #include #include "libcamera/internal/pipeline_handler.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "virtual.h" diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp index 40c35264c568..b032db54ded4 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -36,7 +36,7 @@ #include "libcamera/internal/framebuffer.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" -#include "libcamera/internal/yaml_parser.h" +#include "libcamera/internal/yaml_object.h" #include "pipeline/virtual/config_parser.h" diff --git a/src/libcamera/yaml_object.cpp b/src/libcamera/yaml_object.cpp new file mode 100644 index 000000000000..5e92189fdb8e --- /dev/null +++ b/src/libcamera/yaml_object.cpp @@ -0,0 +1,477 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * Copyright (C) 2025, Ideas on Board. + * + * libcamera YAML object + */ + +#include "libcamera/internal/yaml_object.h" + +#include +#include +#include +#include + +#include + +/** + * \file yaml_object.h + * \brief YAML objects + */ + +namespace libcamera { + +namespace { + +/* Empty static YamlObject as a safe result for invalid operations */ +static const YamlObject empty; + +} /* namespace */ + +/** + * \class YamlObject + * \brief A class representing the tree structure of the YAML content + * + * The YamlObject class represents the tree structure of YAML content. A + * YamlObject can be empty, a dictionary or list of YamlObjects, or a value if a + * tree leaf. + */ + +YamlObject::YamlObject() + : type_(Type::Empty) +{ +} + +YamlObject::~YamlObject() = default; + +/** + * \fn YamlObject::isValue() + * \brief Return whether the YamlObject is a value + * + * \return True if the YamlObject is a value, false otherwise + */ + +/** + * \fn YamlObject::isList() + * \brief Return whether the YamlObject is a list + * + * \return True if the YamlObject is a list, false otherwise + */ + +/** + * \fn YamlObject::isDictionary() + * \brief Return whether the YamlObject is a dictionary + * + * \return True if the YamlObject is a dictionary, false otherwise + */ + +/** + * \fn YamlObject::isEmpty() + * \brief Return whether the YamlObject is an empty + * + * \return True if the YamlObject is empty, false otherwise + */ + +/** + * \fn YamlObject::operator bool() + * \brief Return whether the YamlObject is a non-empty + * + * \return False if the YamlObject is empty, true otherwise + */ + +/** + * \fn YamlObject::size() + * \brief Retrieve the number of elements in a dictionary or list YamlObject + * + * This function retrieves the size of the YamlObject, defined as the number of + * child elements it contains. Only YamlObject instances of Dictionary or List + * types have a size, calling this function on other types of instances is + * invalid and results in undefined behaviour. + * + * \return The size of the YamlObject + */ +std::size_t YamlObject::size() const +{ + switch (type_) { + case Type::Dictionary: + case Type::List: + return list_.size(); + default: + return 0; + } +} + +/** + * \fn template YamlObject::get() const + * \tparam T Type of the value + * \brief Parse the YamlObject as a \a T value + * + * This function parses the value of the YamlObject as a \a T object, and + * returns the value. If parsing fails (usually because the YamlObject doesn't + * store a \a T value), std::nullopt is returned. + * + * If the type \a T is an std::vector, the YamlObject will be parsed as a list + * of values. + * + * \return The YamlObject value, or std::nullopt if parsing failed + */ + +/** + * \fn template YamlObject::get(U &&defaultValue) const + * \brief Parse the YamlObject as a \a T value + * \param[in] defaultValue The default value when failing to parse + * + * This function parses the value of the YamlObject as a \a T object, and + * returns the value. If parsing fails (usually because the YamlObject doesn't + * store a \a T value), the \a defaultValue is returned. + * + * Unlike the get() function, this overload does not support std::vector for the + * type \a T. + * + * \return The YamlObject value, or \a defaultValue if parsing failed + */ + +/** + * \fn template YamlObject::set(T &&value) + * \brief Set the value of a YamlObject + * \param[in] value The value + * + * This function sets the value stored in a YamlObject to \a value. The value is + * converted to a string in an implementation-specific way that guarantees that + * subsequent calls to get() will return the same value. + * + * Values can only be set on YamlObject of Type::Value type or empty YamlObject. + * Attempting to set a value on an object of type Type::Dict or Type::List does + * not modify the YamlObject. + */ + +#ifndef __DOXYGEN__ + +template<> +std::optional +YamlObject::Accessor::get(const YamlObject &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + if (obj.value_ == "true") + return true; + else if (obj.value_ == "false") + return false; + + return std::nullopt; +} + +template<> +void YamlObject::Accessor::set(YamlObject &obj, bool value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = value ? "true" : "false"; +} + +template +struct YamlObject::Accessor || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> +{ + std::optional get(const YamlObject &obj) const + { + if (obj.type_ != Type::Value) + return std::nullopt; + + const std::string &str = obj.value_; + T value; + + auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), + value); + if (ptr != str.data() + str.size() || ec != std::errc()) + return std::nullopt; + + return value; + } + + void set(YamlObject &obj, T value) + { + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::to_string(value); + } +}; + +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; +template struct YamlObject::Accessor; + +template<> +std::optional +YamlObject::Accessor::get(const YamlObject &obj) const +{ + return obj.get(); +} + +template<> +void YamlObject::Accessor::set(YamlObject &obj, float value) +{ + obj.set(std::forward(value)); +} + +template<> +std::optional +YamlObject::Accessor::get(const YamlObject &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + if (obj.value_.empty()) + return std::nullopt; + + char *end; + + errno = 0; + double value = utils::strtod(obj.value_.c_str(), &end); + + if ('\0' != *end || errno == ERANGE) + return std::nullopt; + + return value; +} + +template<> +void YamlObject::Accessor::set(YamlObject &obj, double value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::to_string(value); +} + +template<> +std::optional +YamlObject::Accessor::get(const YamlObject &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + return obj.value_; +} + +template<> +void YamlObject::Accessor::set(YamlObject &obj, std::string value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::move(value); +} + +template +struct YamlObject::Accessor, std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> +{ + std::optional> get(const YamlObject &obj) const + { + if (obj.type_ != Type::List) + return std::nullopt; + + std::vector values; + values.reserve(obj.list_.size()); + + for (const YamlObject &entry : obj.asList()) { + const auto value = entry.get(); + if (!value) + return std::nullopt; + values.emplace_back(*value); + } + + return values; + } +}; + +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +template struct YamlObject::Accessor>; +#endif /* __DOXYGEN__ */ + +/** + * \fn YamlObject::asDict() const + * \brief Wrap a dictionary YamlObject in an adapter that exposes iterators + * + * The YamlObject class doesn't directly implement iterators, as the iterator + * type depends on whether the object is a Dictionary or List. This function + * wraps a YamlObject of Dictionary type into an adapter that exposes + * iterators, as well as begin() and end() functions, allowing usage of + * range-based for loops with YamlObject. As YAML mappings are not ordered, the + * iteration order is not specified. + * + * The iterator's value_type is a + * std::pair. + * + * If the YamlObject is not of Dictionary type, the returned adapter operates + * as an empty container. + * + * \return An adapter of unspecified type compatible with range-based for loops + */ + +/** + * \fn YamlObject::asList() const + * \brief Wrap a list YamlObject in an adapter that exposes iterators + * + * The YamlObject class doesn't directly implement iterators, as the iterator + * type depends on whether the object is a Dictionary or List. This function + * wraps a YamlObject of List type into an adapter that exposes iterators, as + * well as begin() and end() functions, allowing usage of range-based for loops + * with YamlObject. As YAML lists are ordered, the iteration order is identical + * to the list order in the YAML data. + * + * The iterator's value_type is a const YamlObject &. + * + * If the YamlObject is not of List type, the returned adapter operates as an + * empty container. + * + * \return An adapter of unspecified type compatible with range-based for loops + */ + +/** + * \fn YamlObject::operator[](std::size_t index) const + * \brief Retrieve the element from list YamlObject by index + * + * This function retrieves an element of the YamlObject. Only YamlObject + * instances of List type associate elements with index, calling this function + * on other types of instances or with an invalid index results in an empty + * object. + * + * \return The YamlObject as an element of the list + */ +const YamlObject &YamlObject::operator[](std::size_t index) const +{ + if (type_ != Type::List || index >= size()) + return empty; + + return *list_[index].value; +} + +/** + * \fn YamlObject::contains() + * \brief Check if an element of a dictionary exists + * + * This function check if the YamlObject contains an element. Only YamlObject + * instances of Dictionary type associate elements with names, calling this + * function on other types of instances is invalid and results in undefined + * behaviour. + * + * \return True if an element exists, false otherwise + */ +bool YamlObject::contains(std::string_view key) const +{ + return dictionary_.find(key) != dictionary_.end(); +} + +/** + * \fn YamlObject::operator[](std::string_view key) const + * \brief Retrieve a member by name from the dictionary + * + * This function retrieve a member of a YamlObject by name. Only YamlObject + * instances of Dictionary type associate elements with names, calling this + * function on other types of instances or with a nonexistent key results in an + * empty object. + * + * \return The YamlObject corresponding to the \a key member + */ +const YamlObject &YamlObject::operator[](std::string_view key) const +{ + if (type_ != Type::Dictionary) + return empty; + + auto iter = dictionary_.find(key); + if (iter == dictionary_.end()) + return empty; + + return *iter->second; +} + +/** + * \brief Add a child object to a list + * \param[in] child The child object + * + * Append the \a child node as the last element of this node's children list. + * This node must be empty, in which case it is converted to the Type::List + * type, or be a list. Otherwise, the \a child is discarded and the function + * returns a nullptr. + * + * \return The child object if successfully added, nullptr otherwise + */ +YamlObject *YamlObject::add(std::unique_ptr child) +{ + if (type_ == Type::Empty) + type_ = Type::List; + + if (type_ != Type::List) + return nullptr; + + Value &elem = list_.emplace_back(std::string{}, std::move(child)); + return elem.value.get(); +} + +/** + * \brief Add a child object to a dictionary + * \param[in] key The dictionary key + * \param[in] child The child object + * + * Add the \a child node with the given \a key to this node's children. This + * node must be empty, in which case it is converted to the Type::Dictionary + * type, or be a dictionary. Otherwise, the \a child is discarded and the + * function returns a nullptr. + * + * Keys are unique. If a child with the same \a key already exist, the \a child + * is discarded and the function returns a nullptr. + * + * \return The child object if successfully added, nullptr otherwise + */ +YamlObject *YamlObject::add(std::string key, std::unique_ptr child) +{ + if (type_ == Type::Empty) + type_ = Type::Dictionary; + + if (type_ != Type::Dictionary) + return nullptr; + + if (dictionary_.find(key) != dictionary_.end()) + return nullptr; + + Value &elem = list_.emplace_back(std::move(key), std::move(child)); + dictionary_.emplace(elem.key, elem.value.get()); + return elem.value.get(); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index 0ef1f3ea303b..d83df0fb9597 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -7,11 +7,10 @@ #include "libcamera/internal/yaml_parser.h" -#include #include #include -#include -#include +#include +#include #include #include @@ -27,459 +26,6 @@ namespace libcamera { LOG_DEFINE_CATEGORY(YamlParser) -namespace { - -/* Empty static YamlObject as a safe result for invalid operations */ -static const YamlObject empty; - -} /* namespace */ - -/** - * \class YamlObject - * \brief A class representing the tree structure of the YAML content - * - * The YamlObject class represents the tree structure of YAML content. A - * YamlObject can be empty, a dictionary or list of YamlObjects, or a value if a - * tree leaf. - */ - -YamlObject::YamlObject() - : type_(Type::Empty) -{ -} - -YamlObject::~YamlObject() = default; - -/** - * \fn YamlObject::isValue() - * \brief Return whether the YamlObject is a value - * - * \return True if the YamlObject is a value, false otherwise - */ - -/** - * \fn YamlObject::isList() - * \brief Return whether the YamlObject is a list - * - * \return True if the YamlObject is a list, false otherwise - */ - -/** - * \fn YamlObject::isDictionary() - * \brief Return whether the YamlObject is a dictionary - * - * \return True if the YamlObject is a dictionary, false otherwise - */ - -/** - * \fn YamlObject::isEmpty() - * \brief Return whether the YamlObject is an empty - * - * \return True if the YamlObject is empty, false otherwise - */ - -/** - * \fn YamlObject::operator bool() - * \brief Return whether the YamlObject is a non-empty - * - * \return False if the YamlObject is empty, true otherwise - */ - -/** - * \brief Retrieve the number of elements in a dictionary or list YamlObject - * - * This function retrieves the size of the YamlObject, defined as the number of - * child elements it contains. Only YamlObject instances of Dictionary or List - * types have a size, calling this function on other types of instances is - * invalid and results in undefined behaviour. - * - * \return The size of the YamlObject - */ -std::size_t YamlObject::size() const -{ - switch (type_) { - case Type::Dictionary: - case Type::List: - return list_.size(); - default: - return 0; - } -} - -/** - * \fn template YamlObject::get() const - * \tparam T Type of the value - * \brief Parse the YamlObject as a \a T value - * - * This function parses the value of the YamlObject as a \a T object, and - * returns the value. If parsing fails (usually because the YamlObject doesn't - * store a \a T value), std::nullopt is returned. - * - * If the type \a T is an std::vector, the YamlObject will be parsed as a list - * of values. - * - * \return The YamlObject value, or std::nullopt if parsing failed - */ - -/** - * \fn template YamlObject::get(U &&defaultValue) const - * \brief Parse the YamlObject as a \a T value - * \param[in] defaultValue The default value when failing to parse - * - * This function parses the value of the YamlObject as a \a T object, and - * returns the value. If parsing fails (usually because the YamlObject doesn't - * store a \a T value), the \a defaultValue is returned. - * - * Unlike the get() function, this overload does not support std::vector for the - * type \a T. - * - * \return The YamlObject value, or \a defaultValue if parsing failed - */ - -/** - * \fn template YamlObject::set(T &&value) - * \brief Set the value of a YamlObject - * \param[in] value The value - * - * This function sets the value stored in a YamlObject to \a value. The value is - * converted to a string in an implementation-specific way that guarantees that - * subsequent calls to get() will return the same value. - * - * Values can only be set on YamlObject of Type::Value type or empty YamlObject. - * Attempting to set a value on an object of type Type::Dict or Type::List does - * not modify the YamlObject. - */ - -#ifndef __DOXYGEN__ - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - if (obj.value_ == "true") - return true; - else if (obj.value_ == "false") - return false; - - return std::nullopt; -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, bool value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = value ? "true" : "false"; -} - -template -struct YamlObject::Accessor || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v>> -{ - std::optional get(const YamlObject &obj) const - { - if (obj.type_ != Type::Value) - return std::nullopt; - - const std::string &str = obj.value_; - T value; - - auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), - value); - if (ptr != str.data() + str.size() || ec != std::errc()) - return std::nullopt; - - return value; - } - - void set(YamlObject &obj, T value) - { - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::to_string(value); - } -}; - -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - return obj.get(); -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, float value) -{ - obj.set(std::forward(value)); -} - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - if (obj.value_.empty()) - return std::nullopt; - - char *end; - - errno = 0; - double value = utils::strtod(obj.value_.c_str(), &end); - - if ('\0' != *end || errno == ERANGE) - return std::nullopt; - - return value; -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, double value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::to_string(value); -} - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - return obj.value_; -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, std::string value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::move(value); -} - -template -struct YamlObject::Accessor, std::enable_if_t< - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v>> -{ - std::optional> get(const YamlObject &obj) const - { - if (obj.type_ != Type::List) - return std::nullopt; - - std::vector values; - values.reserve(obj.list_.size()); - - for (const YamlObject &entry : obj.asList()) { - const auto value = entry.get(); - if (!value) - return std::nullopt; - values.emplace_back(*value); - } - - return values; - } -}; - -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -#endif /* __DOXYGEN__ */ - -/** - * \fn YamlObject::asDict() const - * \brief Wrap a dictionary YamlObject in an adapter that exposes iterators - * - * The YamlObject class doesn't directly implement iterators, as the iterator - * type depends on whether the object is a Dictionary or List. This function - * wraps a YamlObject of Dictionary type into an adapter that exposes - * iterators, as well as begin() and end() functions, allowing usage of - * range-based for loops with YamlObject. As YAML mappings are not ordered, the - * iteration order is not specified. - * - * The iterator's value_type is a - * std::pair. - * - * If the YamlObject is not of Dictionary type, the returned adapter operates - * as an empty container. - * - * \return An adapter of unspecified type compatible with range-based for loops - */ - -/** - * \fn YamlObject::asList() const - * \brief Wrap a list YamlObject in an adapter that exposes iterators - * - * The YamlObject class doesn't directly implement iterators, as the iterator - * type depends on whether the object is a Dictionary or List. This function - * wraps a YamlObject of List type into an adapter that exposes iterators, as - * well as begin() and end() functions, allowing usage of range-based for loops - * with YamlObject. As YAML lists are ordered, the iteration order is identical - * to the list order in the YAML data. - * - * The iterator's value_type is a const YamlObject &. - * - * If the YamlObject is not of List type, the returned adapter operates as an - * empty container. - * - * \return An adapter of unspecified type compatible with range-based for loops - */ - -/** - * \fn YamlObject::operator[](std::size_t index) const - * \brief Retrieve the element from list YamlObject by index - * - * This function retrieves an element of the YamlObject. Only YamlObject - * instances of List type associate elements with index, calling this function - * on other types of instances or with an invalid index results in an empty - * object. - * - * \return The YamlObject as an element of the list - */ -const YamlObject &YamlObject::operator[](std::size_t index) const -{ - if (type_ != Type::List || index >= size()) - return empty; - - return *list_[index].value; -} - -/** - * \fn YamlObject::contains() - * \brief Check if an element of a dictionary exists - * - * This function check if the YamlObject contains an element. Only YamlObject - * instances of Dictionary type associate elements with names, calling this - * function on other types of instances is invalid and results in undefined - * behaviour. - * - * \return True if an element exists, false otherwise - */ -bool YamlObject::contains(std::string_view key) const -{ - return dictionary_.find(key) != dictionary_.end(); -} - -/** - * \fn YamlObject::operator[](std::string_view key) const - * \brief Retrieve a member by name from the dictionary - * - * This function retrieve a member of a YamlObject by name. Only YamlObject - * instances of Dictionary type associate elements with names, calling this - * function on other types of instances or with a nonexistent key results in an - * empty object. - * - * \return The YamlObject corresponding to the \a key member - */ -const YamlObject &YamlObject::operator[](std::string_view key) const -{ - if (type_ != Type::Dictionary) - return empty; - - auto iter = dictionary_.find(key); - if (iter == dictionary_.end()) - return empty; - - return *iter->second; -} - -/** - * \brief Add a child object to a list - * \param[in] child The child object - * - * Append the \a child node as the last element of this node's children list. - * This node must be empty, in which case it is converted to the Type::List - * type, or be a list. Otherwise, the \a child is discarded and the function - * returns a nullptr. - * - * \return A pointer to the child object if successfully added, nullptr - * otherwise - */ -YamlObject *YamlObject::add(std::unique_ptr child) -{ - if (type_ == Type::Empty) - type_ = Type::List; - - if (type_ != Type::List) - return nullptr; - - Value &elem = list_.emplace_back(std::string{}, std::move(child)); - return elem.value.get(); -} - -/** - * \brief Add a child object to a dictionary - * \param[in] key The dictionary key - * \param[in] child The child object - * - * Add the \a child node with the given \a key to this node's children. This - * node must be empty, in which case it is converted to the Type::Dictionary - * type, or be a dictionary. Otherwise, the \a child is discarded and the - * function returns a nullptr. - * - * Keys are unique. If a child with the same \a key already exist, the \a child - * is discarded and the function returns a nullptr. - * - * \return A pointer to the child object if successfully added, nullptr - * otherwise - */ -YamlObject *YamlObject::add(std::string key, std::unique_ptr child) -{ - if (type_ == Type::Empty) - type_ = Type::Dictionary; - - if (type_ != Type::Dictionary) - return nullptr; - - if (dictionary_.find(key) != dictionary_.end()) - return nullptr; - - Value &elem = list_.emplace_back(std::move(key), std::move(child)); - dictionary_.emplace(elem.key, elem.value.get()); - return elem.value.get(); -} - #ifndef __DOXYGEN__ class YamlParserContext From patchwork Tue Jan 13 00:07:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25738 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 9FD9BBDCBF for ; Tue, 13 Jan 2026 00:08:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5969E61FC8; Tue, 13 Jan 2026 01:08:59 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="t0ZWsMyl"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2F18061FC8 for ; Tue, 13 Jan 2026 01:08:58 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 4073EBCA for ; Tue, 13 Jan 2026 01:08:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262912; bh=FdsClevNyNQuTBJXJy7gOR1uROX9L0CA1y+LtpZ8j7c=; h=From:To:Subject:Date:In-Reply-To:References:From; b=t0ZWsMylLt5+E0JElhJtncbuVz/R+TsH/YUcgB+jyksANGHJJSwj+b77Bz3W0NdNm GNYQ/+3IubMKy7pPetNSxrDJajlnTnpnrHQObF/ak8npDdc9S6+1PKEhJUrhsSPKNN Oxp4ub/fTgUYknx6lBuRBMeHVWGLBwqXYds2c6DI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 18/36] libcamera: yaml_object: Miscellaneous documentation improvements Date: Tue, 13 Jan 2026 02:07:50 +0200 Message-ID: <20260113000808.15395-19-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" Fix a few documentation issues: - Drop unneeded \fn - Sort \brief and \tparam correctly - Add missing \tparam and \param - Explain the T and U template parameters for get() - Standardize the naming of dictionary keys as "key" - Fix typo Signed-off-by: Laurent Pinchart --- src/libcamera/yaml_object.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/libcamera/yaml_object.cpp b/src/libcamera/yaml_object.cpp index 5e92189fdb8e..4328ccbff8f1 100644 --- a/src/libcamera/yaml_object.cpp +++ b/src/libcamera/yaml_object.cpp @@ -81,7 +81,6 @@ YamlObject::~YamlObject() = default; */ /** - * \fn YamlObject::size() * \brief Retrieve the number of elements in a dictionary or list YamlObject * * This function retrieves the size of the YamlObject, defined as the number of @@ -104,8 +103,8 @@ std::size_t YamlObject::size() const /** * \fn template YamlObject::get() const - * \tparam T Type of the value * \brief Parse the YamlObject as a \a T value + * \tparam T Type of the value * * This function parses the value of the YamlObject as a \a T object, and * returns the value. If parsing fails (usually because the YamlObject doesn't @@ -120,11 +119,14 @@ std::size_t YamlObject::size() const /** * \fn template YamlObject::get(U &&defaultValue) const * \brief Parse the YamlObject as a \a T value + * \tparam T Type of the value + * \tparam U Type of the default value * \param[in] defaultValue The default value when failing to parse * * This function parses the value of the YamlObject as a \a T object, and * returns the value. If parsing fails (usually because the YamlObject doesn't - * store a \a T value), the \a defaultValue is returned. + * store a \a T value), the \a defaultValue is returned. Type \a U must be + * convertible to type \a T. * * Unlike the get() function, this overload does not support std::vector for the * type \a T. @@ -135,6 +137,7 @@ std::size_t YamlObject::size() const /** * \fn template YamlObject::set(T &&value) * \brief Set the value of a YamlObject + * \tparam T Type of the value * \param[in] value The value * * This function sets the value stored in a YamlObject to \a value. The value is @@ -363,8 +366,8 @@ template struct YamlObject::Accessor>; */ /** - * \fn YamlObject::operator[](std::size_t index) const * \brief Retrieve the element from list YamlObject by index + * \param[in] index The element index * * This function retrieves an element of the YamlObject. Only YamlObject * instances of List type associate elements with index, calling this function @@ -382,13 +385,13 @@ const YamlObject &YamlObject::operator[](std::size_t index) const } /** - * \fn YamlObject::contains() * \brief Check if an element of a dictionary exists + * \param[in] key The element key * - * This function check if the YamlObject contains an element. Only YamlObject - * instances of Dictionary type associate elements with names, calling this - * function on other types of instances is invalid and results in undefined - * behaviour. + * This function check if the YamlObject contains an element for the given \a + * key. Only YamlObject instances of Dictionary type associate elements with + * keys, calling this function on other types of instances is invalid and + * results in undefined behaviour. * * \return True if an element exists, false otherwise */ @@ -398,11 +401,11 @@ bool YamlObject::contains(std::string_view key) const } /** - * \fn YamlObject::operator[](std::string_view key) const - * \brief Retrieve a member by name from the dictionary + * \brief Retrieve a member by key from the dictionary + * \param[in] key The element key * - * This function retrieve a member of a YamlObject by name. Only YamlObject - * instances of Dictionary type associate elements with names, calling this + * This function retrieves a member of a YamlObject by \a key. Only YamlObject + * instances of Dictionary type associate elements with keys, calling this * function on other types of instances or with a nonexistent key results in an * empty object. * From patchwork Tue Jan 13 00:07:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25739 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 744E2C32AF for ; Tue, 13 Jan 2026 00:09:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DD76861FD9; Tue, 13 Jan 2026 01:09:02 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FKpua/hy"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A6E8561FD9 for ; Tue, 13 Jan 2026 01:09:00 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id ED2EA66B for ; Tue, 13 Jan 2026 01:08:33 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262915; bh=dyYhf9xaDfjXxreBlvOxZE7847IP273iPLdXgxDJSoI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FKpua/hyzbttqZypu64aAVbKWARnJipMzabaYGr0kZ0kkblPtZK5ArkN/ByMQ08MG 21o5iR+zq4vasAZhzaJ1RNc9FuuH0HywpFos6lKn2TSjJ983ig0a3W1UtRG/S94wfs wKbtdOABt+CuQ0KeEbsk8Xl5pAil47Im0Du1cfto= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 19/36] libcamera: Rename YamlObject to ValueNode Date: Tue, 13 Jan 2026 02:07:51 +0200 Message-ID: <20260113000808.15395-20-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The YamlObject class is now a generic data container to model trees of values. Rename it to ValueNode and expand the class documentation. While at it, drop the unneeded libcamera:: namespace prefix when using the ValueNode class. Signed-off-by: Laurent Pinchart --- .../internal/converter/converter_dw100.h | 2 +- .../libcamera/internal/global_configuration.h | 10 +- include/libcamera/internal/matrix.h | 10 +- include/libcamera/internal/meson.build | 2 +- .../internal/{yaml_object.h => value_node.h} | 34 +- include/libcamera/internal/vector.h | 10 +- include/libcamera/internal/yaml_parser.h | 4 +- src/android/camera_hal_config.cpp | 16 +- src/ipa/ipu3/algorithms/agc.cpp | 4 +- src/ipa/ipu3/algorithms/agc.h | 2 +- src/ipa/ipu3/ipu3.cpp | 2 +- src/ipa/libipa/agc_mean_luminance.cpp | 16 +- src/ipa/libipa/agc_mean_luminance.h | 12 +- src/ipa/libipa/algorithm.cpp | 2 +- src/ipa/libipa/algorithm.h | 4 +- src/ipa/libipa/awb.cpp | 6 +- src/ipa/libipa/awb.h | 6 +- src/ipa/libipa/awb_bayes.cpp | 4 +- src/ipa/libipa/awb_bayes.h | 6 +- src/ipa/libipa/awb_grey.cpp | 2 +- src/ipa/libipa/awb_grey.h | 2 +- src/ipa/libipa/interpolator.cpp | 2 +- src/ipa/libipa/interpolator.h | 4 +- src/ipa/libipa/lsc_polynomial.h | 6 +- src/ipa/libipa/lux.cpp | 6 +- src/ipa/libipa/lux.h | 4 +- src/ipa/libipa/module.cpp | 2 +- src/ipa/libipa/module.h | 6 +- src/ipa/libipa/pwl.cpp | 2 +- src/ipa/mali-c55/algorithms/agc.cpp | 2 +- src/ipa/mali-c55/algorithms/agc.h | 2 +- src/ipa/mali-c55/algorithms/blc.cpp | 4 +- src/ipa/mali-c55/algorithms/blc.h | 2 +- src/ipa/mali-c55/algorithms/lsc.cpp | 6 +- src/ipa/mali-c55/algorithms/lsc.h | 2 +- src/ipa/mali-c55/mali-c55.cpp | 2 +- src/ipa/rkisp1/algorithms/agc.cpp | 10 +- src/ipa/rkisp1/algorithms/agc.h | 4 +- src/ipa/rkisp1/algorithms/awb.cpp | 2 +- src/ipa/rkisp1/algorithms/awb.h | 2 +- src/ipa/rkisp1/algorithms/blc.cpp | 4 +- src/ipa/rkisp1/algorithms/blc.h | 2 +- src/ipa/rkisp1/algorithms/ccm.cpp | 4 +- src/ipa/rkisp1/algorithms/ccm.h | 4 +- src/ipa/rkisp1/algorithms/cproc.cpp | 2 +- src/ipa/rkisp1/algorithms/cproc.h | 2 +- src/ipa/rkisp1/algorithms/dpcc.cpp | 22 +- src/ipa/rkisp1/algorithms/dpcc.h | 2 +- src/ipa/rkisp1/algorithms/dpf.cpp | 8 +- src/ipa/rkisp1/algorithms/dpf.h | 2 +- src/ipa/rkisp1/algorithms/filter.cpp | 2 +- src/ipa/rkisp1/algorithms/filter.h | 2 +- src/ipa/rkisp1/algorithms/goc.cpp | 4 +- src/ipa/rkisp1/algorithms/goc.h | 2 +- src/ipa/rkisp1/algorithms/gsl.cpp | 6 +- src/ipa/rkisp1/algorithms/gsl.h | 2 +- src/ipa/rkisp1/algorithms/lsc.cpp | 14 +- src/ipa/rkisp1/algorithms/lsc.h | 2 +- src/ipa/rkisp1/algorithms/lux.cpp | 2 +- src/ipa/rkisp1/algorithms/lux.h | 2 +- src/ipa/rkisp1/algorithms/wdr.cpp | 4 +- src/ipa/rkisp1/algorithms/wdr.h | 2 +- src/ipa/rkisp1/rkisp1.cpp | 2 +- src/ipa/rpi/controller/algorithm.cpp | 2 +- src/ipa/rpi/controller/algorithm.h | 4 +- src/ipa/rpi/controller/controller.cpp | 4 +- src/ipa/rpi/controller/controller.h | 4 +- src/ipa/rpi/controller/rpi/af.cpp | 10 +- src/ipa/rpi/controller/rpi/af.h | 8 +- src/ipa/rpi/controller/rpi/agc.cpp | 2 +- src/ipa/rpi/controller/rpi/agc.h | 2 +- src/ipa/rpi/controller/rpi/agc_channel.cpp | 24 +- src/ipa/rpi/controller/rpi/agc_channel.h | 12 +- src/ipa/rpi/controller/rpi/alsc.cpp | 10 +- src/ipa/rpi/controller/rpi/alsc.h | 2 +- src/ipa/rpi/controller/rpi/awb.cpp | 10 +- src/ipa/rpi/controller/rpi/awb.h | 8 +- src/ipa/rpi/controller/rpi/black_level.cpp | 2 +- src/ipa/rpi/controller/rpi/black_level.h | 2 +- src/ipa/rpi/controller/rpi/cac.cpp | 4 +- src/ipa/rpi/controller/rpi/cac.h | 2 +- src/ipa/rpi/controller/rpi/ccm.cpp | 2 +- src/ipa/rpi/controller/rpi/ccm.h | 2 +- src/ipa/rpi/controller/rpi/contrast.cpp | 2 +- src/ipa/rpi/controller/rpi/contrast.h | 2 +- src/ipa/rpi/controller/rpi/decompand.cpp | 2 +- src/ipa/rpi/controller/rpi/decompand.h | 2 +- src/ipa/rpi/controller/rpi/denoise.cpp | 4 +- src/ipa/rpi/controller/rpi/denoise.h | 4 +- src/ipa/rpi/controller/rpi/dpc.cpp | 2 +- src/ipa/rpi/controller/rpi/dpc.h | 2 +- src/ipa/rpi/controller/rpi/geq.cpp | 2 +- src/ipa/rpi/controller/rpi/geq.h | 2 +- src/ipa/rpi/controller/rpi/hdr.cpp | 4 +- src/ipa/rpi/controller/rpi/hdr.h | 4 +- src/ipa/rpi/controller/rpi/lux.cpp | 2 +- src/ipa/rpi/controller/rpi/lux.h | 2 +- src/ipa/rpi/controller/rpi/noise.cpp | 2 +- src/ipa/rpi/controller/rpi/noise.h | 2 +- src/ipa/rpi/controller/rpi/saturation.cpp | 2 +- src/ipa/rpi/controller/rpi/saturation.h | 2 +- src/ipa/rpi/controller/rpi/sdn.cpp | 2 +- src/ipa/rpi/controller/rpi/sdn.h | 2 +- src/ipa/rpi/controller/rpi/sharpen.cpp | 2 +- src/ipa/rpi/controller/rpi/sharpen.h | 2 +- src/ipa/rpi/controller/rpi/tonemap.cpp | 2 +- src/ipa/rpi/controller/rpi/tonemap.h | 2 +- src/ipa/simple/algorithms/blc.cpp | 2 +- src/ipa/simple/algorithms/blc.h | 2 +- src/ipa/simple/algorithms/ccm.cpp | 2 +- src/ipa/simple/algorithms/ccm.h | 2 +- src/ipa/simple/algorithms/lut.cpp | 2 +- src/ipa/simple/algorithms/lut.h | 2 +- src/ipa/simple/soft_simple.cpp | 2 +- src/libcamera/converter/converter_dw100.cpp | 2 +- src/libcamera/geometry.cpp | 4 +- src/libcamera/global_configuration.cpp | 8 +- src/libcamera/matrix.cpp | 2 +- src/libcamera/meson.build | 2 +- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 2 +- .../pipeline/rpi/common/pipeline_base.cpp | 4 +- .../pipeline/rpi/common/pipeline_base.h | 4 +- src/libcamera/pipeline/rpi/pisp/pisp.cpp | 6 +- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 6 +- src/libcamera/pipeline/virtual/README.md | 2 +- .../pipeline/virtual/config_parser.cpp | 18 +- .../pipeline/virtual/config_parser.h | 12 +- src/libcamera/pipeline/virtual/virtual.cpp | 2 +- src/libcamera/value_node.cpp | 484 ++++++++++++++++++ src/libcamera/vector.cpp | 2 +- src/libcamera/yaml_object.cpp | 480 ----------------- src/libcamera/yaml_parser.cpp | 54 +- test/yaml-parser.cpp | 6 +- 133 files changed, 807 insertions(+), 803 deletions(-) rename include/libcamera/internal/{yaml_object.h => value_node.h} (81%) create mode 100644 src/libcamera/value_node.cpp delete mode 100644 src/libcamera/yaml_object.cpp diff --git a/include/libcamera/internal/converter/converter_dw100.h b/include/libcamera/internal/converter/converter_dw100.h index d70c8fe76185..054750ef0866 100644 --- a/include/libcamera/internal/converter/converter_dw100.h +++ b/include/libcamera/internal/converter/converter_dw100.h @@ -31,7 +31,7 @@ public: static std::unique_ptr createModule(DeviceEnumerator *enumerator); - int init(const YamlObject ¶ms); + int init(const ValueNode ¶ms); int configure(const StreamConfiguration &inputCfg, const std::vector> diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 16c6a21f2a8a..7ae923977aa6 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -14,14 +14,14 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" namespace libcamera { class GlobalConfiguration { public: - using Configuration = const YamlObject &; + using Configuration = const ValueNode &; GlobalConfiguration(); @@ -32,7 +32,7 @@ public: std::optional option( const std::initializer_list confPath) const { - const YamlObject *c = &configuration(); + const ValueNode *c = &configuration(); for (auto part : confPath) { c = &(*c)[part]; if (!*c) @@ -55,8 +55,8 @@ private: bool loadFile(const std::filesystem::path &fileName); void load(); - std::unique_ptr yamlConfiguration_ = - std::make_unique(); + std::unique_ptr yamlConfiguration_ = + std::make_unique(); }; } /* namespace libcamera */ diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h index 11fccd27547e..0f72263f2536 100644 --- a/include/libcamera/internal/matrix.h +++ b/include/libcamera/internal/matrix.h @@ -14,7 +14,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" namespace libcamera { @@ -188,7 +188,7 @@ constexpr Matrix operator+(const Matrix &m1, const } #ifndef __DOXYGEN__ -bool matrixValidateYaml(const YamlObject &obj, unsigned int size); +bool matrixValidateYaml(const ValueNode &obj, unsigned int size); #endif /* __DOXYGEN__ */ #ifndef __DOXYGEN__ @@ -200,8 +200,8 @@ std::ostream &operator<<(std::ostream &out, const Matrix &m) } template -struct YamlObject::Accessor> { - std::optional> get(const YamlObject &obj) const +struct ValueNode::Accessor> { + std::optional> get(const ValueNode &obj) const { if (!matrixValidateYaml(obj, Rows * Cols)) return std::nullopt; @@ -210,7 +210,7 @@ struct YamlObject::Accessor> { T *data = &matrix[0][0]; unsigned int i = 0; - for (const YamlObject &entry : obj.asList()) { + for (const ValueNode &entry : obj.asList()) { const auto value = entry.get(); if (!value) return std::nullopt; diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index c24c9f062f29..76ab43115768 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -49,8 +49,8 @@ libcamera_internal_headers = files([ 'v4l2_request.h', 'v4l2_subdevice.h', 'v4l2_videodevice.h', + 'value_node.h', 'vector.h', - 'yaml_object.h', 'yaml_parser.h', ]) diff --git a/include/libcamera/internal/yaml_object.h b/include/libcamera/internal/value_node.h similarity index 81% rename from include/libcamera/internal/yaml_object.h rename to include/libcamera/internal/value_node.h index 1771f8821e2e..a336c1d08e1c 100644 --- a/include/libcamera/internal/yaml_object.h +++ b/include/libcamera/internal/value_node.h @@ -3,7 +3,7 @@ * Copyright (C) 2022, Google Inc. * Copyright (C) 2025, Ideas on Board * - * libcamera YAML object + * Data structure to manage tree of values */ #pragma once @@ -22,16 +22,16 @@ namespace libcamera { -class YamlObject +class ValueNode { private: struct Value { - Value(std::string &&k, std::unique_ptr &&v) + Value(std::string &&k, std::unique_ptr &&v) : key(std::move(k)), value(std::move(v)) { } std::string key; - std::unique_ptr value; + std::unique_ptr value; }; using ValueContainer = std::vector; @@ -103,8 +103,8 @@ public: class ListIterator : public Iterator { public: - using value_type = const YamlObject &; - using pointer = const YamlObject *; + using value_type = const ValueNode &; + using pointer = const ValueNode *; using reference = value_type; value_type operator*() const @@ -121,7 +121,7 @@ public: class DictIterator : public Iterator { public: - using value_type = std::pair; + using value_type = std::pair; using pointer = value_type *; using reference = value_type &; @@ -142,8 +142,8 @@ public: }; #endif /* __DOXYGEN__ */ - YamlObject(); - ~YamlObject(); + ValueNode(); + ~ValueNode(); bool isValue() const { @@ -189,16 +189,16 @@ public: DictAdapter asDict() const { return DictAdapter{ list_ }; } ListAdapter asList() const { return ListAdapter{ list_ }; } - const YamlObject &operator[](std::size_t index) const; + const ValueNode &operator[](std::size_t index) const; bool contains(std::string_view key) const; - const YamlObject &operator[](std::string_view key) const; + const ValueNode &operator[](std::string_view key) const; - YamlObject *add(std::unique_ptr child); - YamlObject *add(std::string key, std::unique_ptr child); + ValueNode *add(std::unique_ptr child); + ValueNode *add(std::string key, std::unique_ptr child); private: - LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject) + LIBCAMERA_DISABLE_COPY_AND_MOVE(ValueNode) template friend struct Accessor; @@ -212,15 +212,15 @@ private: template struct Accessor { - std::optional get(const YamlObject &obj) const; - void set(YamlObject &obj, T value); + std::optional get(const ValueNode &obj) const; + void set(ValueNode &obj, T value); }; Type type_; std::string value_; ValueContainer list_; - std::map> dictionary_; + std::map> dictionary_; }; } /* namespace libcamera */ diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h index af24485f3bb1..ed7490e16e9e 100644 --- a/include/libcamera/internal/vector.h +++ b/include/libcamera/internal/vector.h @@ -19,7 +19,7 @@ #include #include "libcamera/internal/matrix.h" -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" namespace libcamera { @@ -329,7 +329,7 @@ bool operator!=(const Vector &lhs, const Vector &rhs) } #ifndef __DOXYGEN__ -bool vectorValidateYaml(const YamlObject &obj, unsigned int size); +bool vectorValidateYaml(const ValueNode &obj, unsigned int size); #endif /* __DOXYGEN__ */ #ifndef __DOXYGEN__ @@ -347,8 +347,8 @@ std::ostream &operator<<(std::ostream &out, const Vector &v) } template -struct YamlObject::Accessor> { - std::optional> get(const YamlObject &obj) const +struct ValueNode::Accessor> { + std::optional> get(const ValueNode &obj) const { if (!vectorValidateYaml(obj, Rows)) return std::nullopt; @@ -356,7 +356,7 @@ struct YamlObject::Accessor> { Vector vector; unsigned int i = 0; - for (const YamlObject &entry : obj.asList()) { + for (const ValueNode &entry : obj.asList()) { const auto value = entry.get(); if (!value) return std::nullopt; diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h index e503e83a80da..9d4ba0a1d0e1 100644 --- a/include/libcamera/internal/yaml_parser.h +++ b/include/libcamera/internal/yaml_parser.h @@ -9,7 +9,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" namespace libcamera { @@ -18,7 +18,7 @@ class File; class YamlParser final { public: - static std::unique_ptr parse(File &file); + static std::unique_ptr parse(File &file); }; } /* namespace libcamera */ diff --git a/src/android/camera_hal_config.cpp b/src/android/camera_hal_config.cpp index 7ef451ef8ab9..4a9c0577a0be 100644 --- a/src/android/camera_hal_config.cpp +++ b/src/android/camera_hal_config.cpp @@ -30,9 +30,9 @@ public: int parseConfigFile(File &file, std::map *cameras); private: - int parseCameraConfigData(const std::string &cameraId, const YamlObject &); - int parseLocation(const YamlObject &, CameraConfigData &cameraConfigData); - int parseRotation(const YamlObject &, CameraConfigData &cameraConfigData); + int parseCameraConfigData(const std::string &cameraId, const ValueNode &); + int parseLocation(const ValueNode &, CameraConfigData &cameraConfigData); + int parseRotation(const ValueNode &, CameraConfigData &cameraConfigData); std::map *cameras_; }; @@ -65,7 +65,7 @@ int CameraHalConfig::Private::parseConfigFile(File &file, cameras_ = cameras; - std::unique_ptr root = YamlParser::parse(file); + std::unique_ptr root = YamlParser::parse(file); if (!root) return -EINVAL; @@ -76,7 +76,7 @@ int CameraHalConfig::Private::parseConfigFile(File &file, if (!root->contains("cameras")) return -EINVAL; - const YamlObject &yamlObjectCameras = (*root)["cameras"]; + const ValueNode &yamlObjectCameras = (*root)["cameras"]; if (!yamlObjectCameras.isDictionary()) return -EINVAL; @@ -90,7 +90,7 @@ int CameraHalConfig::Private::parseConfigFile(File &file, } int CameraHalConfig::Private::parseCameraConfigData(const std::string &cameraId, - const YamlObject &cameraObject) + const ValueNode &cameraObject) { if (!cameraObject.isDictionary()) @@ -109,7 +109,7 @@ int CameraHalConfig::Private::parseCameraConfigData(const std::string &cameraId, return 0; } -int CameraHalConfig::Private::parseLocation(const YamlObject &cameraObject, +int CameraHalConfig::Private::parseLocation(const ValueNode &cameraObject, CameraConfigData &cameraConfigData) { if (!cameraObject.contains("location")) @@ -127,7 +127,7 @@ int CameraHalConfig::Private::parseLocation(const YamlObject &cameraObject, return 0; } -int CameraHalConfig::Private::parseRotation(const YamlObject &cameraObject, +int CameraHalConfig::Private::parseRotation(const ValueNode &cameraObject, CameraConfigData &cameraConfigData) { if (!cameraObject.contains("rotation")) diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp index b0d89541da85..d6a7036c6504 100644 --- a/src/ipa/ipu3/algorithms/agc.cpp +++ b/src/ipa/ipu3/algorithms/agc.cpp @@ -65,14 +65,14 @@ Agc::Agc() /** * \brief Initialise the AGC algorithm from tuning files * \param[in] context The shared IPA context - * \param[in] tuningData The YamlObject containing Agc tuning data + * \param[in] tuningData The ValueNode containing Agc tuning data * * This function calls the base class' tuningData parsers to discover which * control values are supported. * * \return 0 on success or errors from the base class */ -int Agc::init(IPAContext &context, const YamlObject &tuningData) +int Agc::init(IPAContext &context, const ValueNode &tuningData) { int ret; diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h index 890c271b4462..d274a2350485 100644 --- a/src/ipa/ipu3/algorithms/agc.h +++ b/src/ipa/ipu3/algorithms/agc.h @@ -30,7 +30,7 @@ public: Agc(); ~Agc() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPAConfigInfo &configInfo) override; void process(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp index b926f579a9a3..09f6aeb9400d 100644 --- a/src/ipa/ipu3/ipu3.cpp +++ b/src/ipa/ipu3/ipu3.cpp @@ -324,7 +324,7 @@ int IPAIPU3::init(const IPASettings &settings, return ret; } - std::unique_ptr data = YamlParser::parse(file); + std::unique_ptr data = YamlParser::parse(file); if (!data) return -EINVAL; diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp index 72988096d384..1d385551adc6 100644 --- a/src/ipa/libipa/agc_mean_luminance.cpp +++ b/src/ipa/libipa/agc_mean_luminance.cpp @@ -159,7 +159,7 @@ AgcMeanLuminance::AgcMeanLuminance() AgcMeanLuminance::~AgcMeanLuminance() = default; -int AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData) +int AgcMeanLuminance::parseRelativeLuminanceTarget(const ValueNode &tuningData) { auto &target = tuningData["relativeLuminanceTarget"]; if (!target) { @@ -178,7 +178,7 @@ int AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData) return 0; } -int AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id) +int AgcMeanLuminance::parseConstraint(const ValueNode &modeDict, int32_t id) { for (const auto &[boundName, content] : modeDict.asDict()) { if (boundName != "upper" && boundName != "lower") { @@ -212,11 +212,11 @@ int AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id) return 0; } -int AgcMeanLuminance::parseConstraintModes(const YamlObject &tuningData) +int AgcMeanLuminance::parseConstraintModes(const ValueNode &tuningData) { std::vector availableConstraintModes; - const YamlObject &yamlConstraintModes = tuningData[controls::AeConstraintMode.name()]; + const ValueNode &yamlConstraintModes = tuningData[controls::AeConstraintMode.name()]; if (yamlConstraintModes.isDictionary()) { for (const auto &[modeName, modeDict] : yamlConstraintModes.asDict()) { if (AeConstraintModeNameValueMap.find(modeName) == @@ -267,11 +267,11 @@ int AgcMeanLuminance::parseConstraintModes(const YamlObject &tuningData) return 0; } -int AgcMeanLuminance::parseExposureModes(const YamlObject &tuningData) +int AgcMeanLuminance::parseExposureModes(const ValueNode &tuningData) { std::vector availableExposureModes; - const YamlObject &yamlExposureModes = tuningData[controls::AeExposureMode.name()]; + const ValueNode &yamlExposureModes = tuningData[controls::AeExposureMode.name()]; if (yamlExposureModes.isDictionary()) { for (const auto &[modeName, modeValues] : yamlExposureModes.asDict()) { if (AeExposureModeNameValueMap.find(modeName) == @@ -361,7 +361,7 @@ void AgcMeanLuminance::configure(utils::Duration lineDuration, /** * \brief Parse tuning data for AeConstraintMode and AeExposureMode controls - * \param[in] tuningData the YamlObject representing the tuning data + * \param[in] tuningData the ValueNode representing the tuning data * * This function parses tuning data to build the list of allowed values for the * AeConstraintMode and AeExposureMode controls. Those tuning data must provide @@ -414,7 +414,7 @@ void AgcMeanLuminance::configure(utils::Duration lineDuration, * * \return 0 on success or a negative error code */ -int AgcMeanLuminance::parseTuningData(const YamlObject &tuningData) +int AgcMeanLuminance::parseTuningData(const ValueNode &tuningData) { int ret; diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h index dfe1ccbe948b..27e92b6fce7a 100644 --- a/src/ipa/libipa/agc_mean_luminance.h +++ b/src/ipa/libipa/agc_mean_luminance.h @@ -16,7 +16,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "exposure_mode_helper.h" #include "histogram.h" @@ -44,7 +44,7 @@ public: }; void configure(utils::Duration lineDuration, const CameraSensorHelper *sensorHelper); - int parseTuningData(const YamlObject &tuningData); + int parseTuningData(const ValueNode &tuningData); void setExposureCompensation(double gain) { @@ -88,10 +88,10 @@ public: private: virtual double estimateLuminance(const double gain) const = 0; - int parseRelativeLuminanceTarget(const YamlObject &tuningData); - int parseConstraint(const YamlObject &modeDict, int32_t id); - int parseConstraintModes(const YamlObject &tuningData); - int parseExposureModes(const YamlObject &tuningData); + int parseRelativeLuminanceTarget(const ValueNode &tuningData); + int parseConstraint(const ValueNode &modeDict, int32_t id); + int parseConstraintModes(const ValueNode &tuningData); + int parseExposureModes(const ValueNode &tuningData); double estimateInitialGain() const; double constraintClampGain(uint32_t constraintModeIndex, const Histogram &hist, diff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp index 201efdfdba25..757ce3519652 100644 --- a/src/ipa/libipa/algorithm.cpp +++ b/src/ipa/libipa/algorithm.cpp @@ -44,7 +44,7 @@ namespace ipa { * \param[in] tuningData The tuning data for the algorithm * * This function is called once, when the IPA module is initialized, to - * initialize the algorithm. The \a tuningData YamlObject contains the tuning + * initialize the algorithm. The \a tuningData ValueNode contains the tuning * data for algorithm. * * \return 0 if successful, an error code otherwise diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h index 9a19dbd61b31..4ddb16ef3920 100644 --- a/src/ipa/libipa/algorithm.h +++ b/src/ipa/libipa/algorithm.h @@ -14,7 +14,7 @@ namespace libcamera { -class YamlObject; +class ValueNode; namespace ipa { @@ -27,7 +27,7 @@ public: virtual ~Algorithm() {} virtual int init([[maybe_unused]] typename Module::Context &context, - [[maybe_unused]] const YamlObject &tuningData) + [[maybe_unused]] const ValueNode &tuningData) { return 0; } diff --git a/src/ipa/libipa/awb.cpp b/src/ipa/libipa/awb.cpp index 214bac8b56a6..af966f1e007c 100644 --- a/src/ipa/libipa/awb.cpp +++ b/src/ipa/libipa/awb.cpp @@ -132,7 +132,7 @@ namespace ipa { /** * \brief Parse the mode configurations from the tuning data - * \param[in] tuningData the YamlObject representing the tuning data + * \param[in] tuningData the ValueNode representing the tuning data * \param[in] def The default value for the AwbMode control * * Utility function to parse the tuning data for an AwbMode entry and read all @@ -162,12 +162,12 @@ namespace ipa { * \sa controls::AwbModeEnum * \return Zero on success, negative error code otherwise */ -int AwbAlgorithm::parseModeConfigs(const YamlObject &tuningData, +int AwbAlgorithm::parseModeConfigs(const ValueNode &tuningData, const ControlValue &def) { std::vector availableModes; - const YamlObject &yamlModes = tuningData[controls::AwbMode.name()]; + const ValueNode &yamlModes = tuningData[controls::AwbMode.name()]; if (!yamlModes.isDictionary()) { LOG(Awb, Error) << "AwbModes must be a dictionary."; diff --git a/src/ipa/libipa/awb.h b/src/ipa/libipa/awb.h index 3f25d13feaa8..09c00e47d604 100644 --- a/src/ipa/libipa/awb.h +++ b/src/ipa/libipa/awb.h @@ -13,8 +13,8 @@ #include #include +#include "libcamera/internal/value_node.h" #include "libcamera/internal/vector.h" -#include "libcamera/internal/yaml_object.h" namespace libcamera { @@ -38,7 +38,7 @@ class AwbAlgorithm public: virtual ~AwbAlgorithm() = default; - virtual int init(const YamlObject &tuningData) = 0; + virtual int init(const ValueNode &tuningData) = 0; virtual AwbResult calculateAwb(const AwbStats &stats, unsigned int lux) = 0; virtual std::optional> gainsFromColourTemperature(double colourTemperature) = 0; @@ -50,7 +50,7 @@ public: virtual void handleControls([[maybe_unused]] const ControlList &controls) {} protected: - int parseModeConfigs(const YamlObject &tuningData, + int parseModeConfigs(const ValueNode &tuningData, const ControlValue &def = {}); struct ModeConfig { diff --git a/src/ipa/libipa/awb_bayes.cpp b/src/ipa/libipa/awb_bayes.cpp index 595bd0705732..a1412c8bd2b5 100644 --- a/src/ipa/libipa/awb_bayes.cpp +++ b/src/ipa/libipa/awb_bayes.cpp @@ -143,7 +143,7 @@ void Interpolator::interpolate(const Pwl &a, const Pwl &b, Pwl &dest, doubl * \brief The currently selected mode */ -int AwbBayes::init(const YamlObject &tuningData) +int AwbBayes::init(const ValueNode &tuningData) { int ret = colourGainCurve_.readYaml(tuningData["colourGains"], "ct", "gains"); if (ret) { @@ -188,7 +188,7 @@ int AwbBayes::init(const YamlObject &tuningData) return 0; } -int AwbBayes::readPriors(const YamlObject &tuningData) +int AwbBayes::readPriors(const ValueNode &tuningData) { const auto &priorsList = tuningData["priors"]; std::map priors; diff --git a/src/ipa/libipa/awb_bayes.h b/src/ipa/libipa/awb_bayes.h index 79334ad3e7a3..1e3373676bc0 100644 --- a/src/ipa/libipa/awb_bayes.h +++ b/src/ipa/libipa/awb_bayes.h @@ -9,8 +9,8 @@ #include +#include "libcamera/internal/value_node.h" #include "libcamera/internal/vector.h" -#include "libcamera/internal/yaml_object.h" #include "awb.h" #include "interpolator.h" @@ -25,13 +25,13 @@ class AwbBayes : public AwbAlgorithm public: AwbBayes() = default; - int init(const YamlObject &tuningData) override; + int init(const ValueNode &tuningData) override; AwbResult calculateAwb(const AwbStats &stats, unsigned int lux) override; std::optional> gainsFromColourTemperature(double temperatureK) override; void handleControls(const ControlList &controls) override; private: - int readPriors(const YamlObject &tuningData); + int readPriors(const ValueNode &tuningData); void fineSearch(double &t, double &r, double &b, ipa::Pwl const &prior, const AwbStats &stats) const; diff --git a/src/ipa/libipa/awb_grey.cpp b/src/ipa/libipa/awb_grey.cpp index d252edb2b6c6..b14b096810ae 100644 --- a/src/ipa/libipa/awb_grey.cpp +++ b/src/ipa/libipa/awb_grey.cpp @@ -41,7 +41,7 @@ namespace ipa { * * \return 0 on success, a negative error code otherwise */ -int AwbGrey::init(const YamlObject &tuningData) +int AwbGrey::init(const ValueNode &tuningData) { Interpolator> gains; int ret = gains.readYaml(tuningData["colourGains"], "ct", "gains"); diff --git a/src/ipa/libipa/awb_grey.h b/src/ipa/libipa/awb_grey.h index f82a368d11cc..154a2af97f15 100644 --- a/src/ipa/libipa/awb_grey.h +++ b/src/ipa/libipa/awb_grey.h @@ -23,7 +23,7 @@ class AwbGrey : public AwbAlgorithm public: AwbGrey() = default; - int init(const YamlObject &tuningData) override; + int init(const ValueNode &tuningData) override; AwbResult calculateAwb(const AwbStats &stats, unsigned int lux) override; std::optional> gainsFromColourTemperature(double colourTemperature) override; diff --git a/src/ipa/libipa/interpolator.cpp b/src/ipa/libipa/interpolator.cpp index 9355802f796a..6bd83849262e 100644 --- a/src/ipa/libipa/interpolator.cpp +++ b/src/ipa/libipa/interpolator.cpp @@ -53,7 +53,7 @@ namespace ipa { */ /** - * \fn int Interpolator::readYaml(const libcamera::YamlObject &yaml, + * \fn int Interpolator::readYaml(const ValueNode &yaml, const std::string &key_name, const std::string &value_name) * \brief Initialize an Interpolator instance from yaml diff --git a/src/ipa/libipa/interpolator.h b/src/ipa/libipa/interpolator.h index 08003a06dbba..c67091e21ca6 100644 --- a/src/ipa/libipa/interpolator.h +++ b/src/ipa/libipa/interpolator.h @@ -15,7 +15,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" namespace libcamera { @@ -39,7 +39,7 @@ public: ~Interpolator() = default; - int readYaml(const libcamera::YamlObject &yaml, + int readYaml(const ValueNode &yaml, const std::string &key_name, const std::string &value_name) { diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h index 19da46860849..d7d9ae42e360 100644 --- a/src/ipa/libipa/lsc_polynomial.h +++ b/src/ipa/libipa/lsc_polynomial.h @@ -16,7 +16,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" namespace libcamera { @@ -83,8 +83,8 @@ private: #ifndef __DOXYGEN__ template<> -struct YamlObject::Accessor { - std::optional get(const YamlObject &obj) const +struct ValueNode::Accessor { + std::optional get(const ValueNode &obj) const { std::optional cx = obj["cx"].get(); std::optional cy = obj["cy"].get(); diff --git a/src/ipa/libipa/lux.cpp b/src/ipa/libipa/lux.cpp index d79b116a3339..46cc63a115b5 100644 --- a/src/ipa/libipa/lux.cpp +++ b/src/ipa/libipa/lux.cpp @@ -12,7 +12,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "histogram.h" @@ -78,7 +78,7 @@ Lux::Lux() /** * \brief Parse tuning data - * \param[in] tuningData The YamlObject representing the tuning data + * \param[in] tuningData The ValueNode representing the tuning data * * This function parses yaml tuning data for the common Lux module. It requires * reference exposure time, analogue gain, digital gain, and lux values. @@ -95,7 +95,7 @@ Lux::Lux() * * \return 0 on success or a negative error code */ -int Lux::parseTuningData(const YamlObject &tuningData) +int Lux::parseTuningData(const ValueNode &tuningData) { auto value = tuningData["referenceExposureTime"].get(); if (!value) { diff --git a/src/ipa/libipa/lux.h b/src/ipa/libipa/lux.h index d95bcdafcfcd..b6837ab729de 100644 --- a/src/ipa/libipa/lux.h +++ b/src/ipa/libipa/lux.h @@ -12,7 +12,7 @@ namespace libcamera { -class YamlObject; +class ValueNode; namespace ipa { @@ -23,7 +23,7 @@ class Lux public: Lux(); - int parseTuningData(const YamlObject &tuningData); + int parseTuningData(const ValueNode &tuningData); double estimateLux(utils::Duration exposureTime, double aGain, double dGain, const Histogram &yHist) const; diff --git a/src/ipa/libipa/module.cpp b/src/ipa/libipa/module.cpp index a95dca696adf..76e10e250b73 100644 --- a/src/ipa/libipa/module.cpp +++ b/src/ipa/libipa/module.cpp @@ -87,7 +87,7 @@ namespace ipa { * \fn Module::createAlgorithms() * \brief Create algorithms from YAML configuration data * \param[in] context The IPA context - * \param[in] algorithms Algorithms configuration data as a parsed YamlObject + * \param[in] algorithms Algorithms configuration data as a parsed ValueNode * * This function iterates over the list of \a algorithms parsed from the YAML * configuration file, and instantiates and initializes the corresponding diff --git a/src/ipa/libipa/module.h b/src/ipa/libipa/module.h index 8e6c658a6b63..3e2408ca30b6 100644 --- a/src/ipa/libipa/module.h +++ b/src/ipa/libipa/module.h @@ -15,7 +15,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "algorithm.h" @@ -43,7 +43,7 @@ public: return algorithms_; } - int createAlgorithms(Context &context, const YamlObject &algorithms) + int createAlgorithms(Context &context, const ValueNode &algorithms) { const auto &list = algorithms.asList(); @@ -71,7 +71,7 @@ public: } private: - int createAlgorithm(Context &context, const YamlObject &data) + int createAlgorithm(Context &context, const ValueNode &data) { const auto &[name, algoData] = *data.asDict().begin(); diff --git a/src/ipa/libipa/pwl.cpp b/src/ipa/libipa/pwl.cpp index f38573e69c13..9fddd5bf70e2 100644 --- a/src/ipa/libipa/pwl.cpp +++ b/src/ipa/libipa/pwl.cpp @@ -435,7 +435,7 @@ std::string Pwl::toString() const */ template<> std::optional -YamlObject::Accessor::get(const YamlObject &obj) const +ValueNode::Accessor::get(const ValueNode &obj) const { /* Treat a single value as single point PWL. */ if (obj.isValue()) { diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp index 014fd12452ac..e4ac735ccabc 100644 --- a/src/ipa/mali-c55/algorithms/agc.cpp +++ b/src/ipa/mali-c55/algorithms/agc.cpp @@ -131,7 +131,7 @@ Agc::Agc() { } -int Agc::init(IPAContext &context, const YamlObject &tuningData) +int Agc::init(IPAContext &context, const ValueNode &tuningData) { int ret = parseTuningData(tuningData); if (ret) diff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h index 9684fff664bc..ee913de2b2e2 100644 --- a/src/ipa/mali-c55/algorithms/agc.h +++ b/src/ipa/mali-c55/algorithms/agc.h @@ -49,7 +49,7 @@ public: Agc(); ~Agc() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void queueRequest(IPAContext &context, const uint32_t frame, diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp index 3bdf19141e1d..591a5eaf2dc8 100644 --- a/src/ipa/mali-c55/algorithms/blc.cpp +++ b/src/ipa/mali-c55/algorithms/blc.cpp @@ -10,7 +10,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" /** * \file blc.h @@ -36,7 +36,7 @@ BlackLevelCorrection::BlackLevelCorrection() * \copydoc libcamera::ipa::Algorithm::init */ int BlackLevelCorrection::init([[maybe_unused]] IPAContext &context, - const YamlObject &tuningData) + const ValueNode &tuningData) { offset00 = tuningData["offset00"].get(0); offset01 = tuningData["offset01"].get(0); diff --git a/src/ipa/mali-c55/algorithms/blc.h b/src/ipa/mali-c55/algorithms/blc.h index fc5a7ea310cb..bce343e20c55 100644 --- a/src/ipa/mali-c55/algorithms/blc.h +++ b/src/ipa/mali-c55/algorithms/blc.h @@ -18,7 +18,7 @@ public: BlackLevelCorrection(); ~BlackLevelCorrection() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp index e32f5a83485e..fe230fdff418 100644 --- a/src/ipa/mali-c55/algorithms/lsc.cpp +++ b/src/ipa/mali-c55/algorithms/lsc.cpp @@ -7,7 +7,7 @@ #include "lsc.h" -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" namespace libcamera { @@ -15,7 +15,7 @@ namespace ipa::mali_c55::algorithms { LOG_DEFINE_CATEGORY(MaliC55Lsc) -int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) +int Lsc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) { if (!tuningData.contains("meshScale")) { LOG(MaliC55Lsc, Error) << "meshScale missing from tuningData"; @@ -24,7 +24,7 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData meshScale_ = tuningData["meshScale"].get(0); - const YamlObject &yamlSets = tuningData["sets"]; + const ValueNode &yamlSets = tuningData["sets"]; if (!yamlSets.isList()) { LOG(MaliC55Lsc, Error) << "LSC tables missing or invalid"; return -EINVAL; diff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h index e7092bc74a0b..3d35fd72bfa8 100644 --- a/src/ipa/mali-c55/algorithms/lsc.h +++ b/src/ipa/mali-c55/algorithms/lsc.h @@ -20,7 +20,7 @@ public: Lsc() = default; ~Lsc() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, MaliC55Params *params) override; diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp index 1d2a4f75cf8c..e4637548ac4d 100644 --- a/src/ipa/mali-c55/mali-c55.cpp +++ b/src/ipa/mali-c55/mali-c55.cpp @@ -118,7 +118,7 @@ int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig return ret; } - std::unique_ptr data = YamlParser::parse(file); + std::unique_ptr data = YamlParser::parse(file); if (!data) return -EINVAL; diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp index ef16a3775056..523930488a3b 100644 --- a/src/ipa/rkisp1/algorithms/agc.cpp +++ b/src/ipa/rkisp1/algorithms/agc.cpp @@ -19,7 +19,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "libipa/histogram.h" @@ -40,7 +40,7 @@ namespace ipa::rkisp1::algorithms { LOG_DEFINE_CATEGORY(RkISP1Agc) -int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData) +int Agc::parseMeteringModes(IPAContext &context, const ValueNode &tuningData) { if (!tuningData.isDictionary()) LOG(RkISP1Agc, Warning) @@ -127,14 +127,14 @@ Agc::Agc() /** * \brief Initialise the AGC algorithm from tuning files * \param[in] context The shared IPA context - * \param[in] tuningData The YamlObject containing Agc tuning data + * \param[in] tuningData The ValueNode containing Agc tuning data * * This function calls the base class' tuningData parsers to discover which * control values are supported. * * \return 0 on success or errors from the base class */ -int Agc::init(IPAContext &context, const YamlObject &tuningData) +int Agc::init(IPAContext &context, const ValueNode &tuningData) { int ret; @@ -142,7 +142,7 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData) if (ret) return ret; - const YamlObject &yamlMeteringModes = tuningData["AeMeteringMode"]; + const ValueNode &yamlMeteringModes = tuningData["AeMeteringMode"]; ret = parseMeteringModes(context, yamlMeteringModes); if (ret) return ret; diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h index 7867eed9c4e3..dec79f2f399c 100644 --- a/src/ipa/rkisp1/algorithms/agc.h +++ b/src/ipa/rkisp1/algorithms/agc.h @@ -28,7 +28,7 @@ public: Agc(); ~Agc() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void queueRequest(IPAContext &context, const uint32_t frame, @@ -43,7 +43,7 @@ public: ControlList &metadata) override; private: - int parseMeteringModes(IPAContext &context, const YamlObject &tuningData); + int parseMeteringModes(IPAContext &context, const ValueNode &tuningData); uint8_t computeHistogramPredivider(const Size &size, enum rkisp1_cif_isp_histogram_mode mode); diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp index e8da7974a1d6..1d248beba61f 100644 --- a/src/ipa/rkisp1/algorithms/awb.cpp +++ b/src/ipa/rkisp1/algorithms/awb.cpp @@ -84,7 +84,7 @@ Awb::Awb() /** * \copydoc libcamera::ipa::Algorithm::init */ -int Awb::init(IPAContext &context, const YamlObject &tuningData) +int Awb::init(IPAContext &context, const ValueNode &tuningData) { auto &cmap = context.ctrlMap; cmap[&controls::ColourTemperature] = ControlInfo(kMinColourTemperature, diff --git a/src/ipa/rkisp1/algorithms/awb.h b/src/ipa/rkisp1/algorithms/awb.h index 02651cc732bf..60d9ef111495 100644 --- a/src/ipa/rkisp1/algorithms/awb.h +++ b/src/ipa/rkisp1/algorithms/awb.h @@ -24,7 +24,7 @@ public: Awb(); ~Awb() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void queueRequest(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp index 19c262fffa73..1ed700a205c8 100644 --- a/src/ipa/rkisp1/algorithms/blc.cpp +++ b/src/ipa/rkisp1/algorithms/blc.cpp @@ -13,7 +13,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" /** * \file blc.h @@ -53,7 +53,7 @@ BlackLevelCorrection::BlackLevelCorrection() /** * \copydoc libcamera::ipa::Algorithm::init */ -int BlackLevelCorrection::init(IPAContext &context, const YamlObject &tuningData) +int BlackLevelCorrection::init(IPAContext &context, const ValueNode &tuningData) { std::optional levelRed = tuningData["R"].get(); std::optional levelGreenR = tuningData["Gr"].get(); diff --git a/src/ipa/rkisp1/algorithms/blc.h b/src/ipa/rkisp1/algorithms/blc.h index f797ae44d639..3b2b0ce6e2a8 100644 --- a/src/ipa/rkisp1/algorithms/blc.h +++ b/src/ipa/rkisp1/algorithms/blc.h @@ -19,7 +19,7 @@ public: BlackLevelCorrection(); ~BlackLevelCorrection() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, diff --git a/src/ipa/rkisp1/algorithms/ccm.cpp b/src/ipa/rkisp1/algorithms/ccm.cpp index 3ed307280677..710989de1d74 100644 --- a/src/ipa/rkisp1/algorithms/ccm.cpp +++ b/src/ipa/rkisp1/algorithms/ccm.cpp @@ -16,7 +16,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "libipa/fixedpoint.h" #include "libipa/interpolator.h" @@ -41,7 +41,7 @@ constexpr Matrix kIdentity3x3 = Matrix::identity(); /** * \copydoc libcamera::ipa::Algorithm::init */ -int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) +int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) { auto &cmap = context.ctrlMap; cmap[&controls::ColourCorrectionMatrix] = ControlInfo( diff --git a/src/ipa/rkisp1/algorithms/ccm.h b/src/ipa/rkisp1/algorithms/ccm.h index c301e6e531c8..9ac537426d16 100644 --- a/src/ipa/rkisp1/algorithms/ccm.h +++ b/src/ipa/rkisp1/algorithms/ccm.h @@ -25,7 +25,7 @@ public: Ccm() {} ~Ccm() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void queueRequest(IPAContext &context, @@ -41,7 +41,7 @@ public: ControlList &metadata) override; private: - void parseYaml(const YamlObject &tuningData); + void parseYaml(const ValueNode &tuningData); void setParameters(struct rkisp1_cif_isp_ctk_config &config, const Matrix &matrix, const Matrix &offsets); diff --git a/src/ipa/rkisp1/algorithms/cproc.cpp b/src/ipa/rkisp1/algorithms/cproc.cpp index d1fff6990d37..ae3effacd359 100644 --- a/src/ipa/rkisp1/algorithms/cproc.cpp +++ b/src/ipa/rkisp1/algorithms/cproc.cpp @@ -55,7 +55,7 @@ int convertContrastOrSaturation(const float v) * \copydoc libcamera::ipa::Algorithm::init */ int ColorProcessing::init(IPAContext &context, - [[maybe_unused]] const YamlObject &tuningData) + [[maybe_unused]] const ValueNode &tuningData) { auto &cmap = context.ctrlMap; diff --git a/src/ipa/rkisp1/algorithms/cproc.h b/src/ipa/rkisp1/algorithms/cproc.h index fd38fd17e8bb..a3863b94fb6e 100644 --- a/src/ipa/rkisp1/algorithms/cproc.h +++ b/src/ipa/rkisp1/algorithms/cproc.h @@ -21,7 +21,7 @@ public: ColorProcessing() = default; ~ColorProcessing() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void queueRequest(IPAContext &context, const uint32_t frame, diff --git a/src/ipa/rkisp1/algorithms/dpcc.cpp b/src/ipa/rkisp1/algorithms/dpcc.cpp index c195334750e1..eb8cbf2049c5 100644 --- a/src/ipa/rkisp1/algorithms/dpcc.cpp +++ b/src/ipa/rkisp1/algorithms/dpcc.cpp @@ -9,7 +9,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "linux/rkisp1-config.h" @@ -45,7 +45,7 @@ DefectPixelClusterCorrection::DefectPixelClusterCorrection() * \copydoc libcamera::ipa::Algorithm::init */ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, - const YamlObject &tuningData) + const ValueNode &tuningData) { config_.mode = RKISP1_CIF_ISP_DPCC_MODE_STAGE1_ENABLE; config_.output_mode = RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_STAGE1_INCL_G_CENTER @@ -55,7 +55,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, ? RKISP1_CIF_ISP_DPCC_SET_USE_STAGE1_USE_FIX_SET : 0; /* Get all defined sets to apply (up to 3). */ - const YamlObject &setsObject = tuningData["sets"]; + const ValueNode &setsObject = tuningData["sets"]; if (!setsObject.isList()) { LOG(RkISP1Dpcc, Error) << "'sets' parameter not found in tuning file"; @@ -71,14 +71,14 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, for (std::size_t i = 0; i < setsObject.size(); ++i) { struct rkisp1_cif_isp_dpcc_methods_config &method = config_.methods[i]; - const YamlObject &set = setsObject[i]; + const ValueNode &set = setsObject[i]; uint16_t value; /* Enable set if described in YAML tuning file. */ config_.set_use |= 1 << i; /* PG Method */ - const YamlObject &pgObject = set["pg-factor"]; + const ValueNode &pgObject = set["pg-factor"]; if (pgObject.contains("green")) { method.method |= @@ -97,7 +97,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, } /* RO Method */ - const YamlObject &roObject = set["ro-limits"]; + const ValueNode &roObject = set["ro-limits"]; if (roObject.contains("green")) { method.method |= @@ -118,7 +118,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, } /* RG Method */ - const YamlObject &rgObject = set["rg-factor"]; + const ValueNode &rgObject = set["rg-factor"]; method.rg_fac = 0; if (rgObject.contains("green")) { @@ -138,7 +138,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, } /* RND Method */ - const YamlObject &rndOffsetsObject = set["rnd-offsets"]; + const ValueNode &rndOffsetsObject = set["rnd-offsets"]; if (rndOffsetsObject.contains("green")) { method.method |= @@ -158,7 +158,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, RKISP1_CIF_ISP_DPCC_RND_OFFS_n_RB(i, value); } - const YamlObject &rndThresholdObject = set["rnd-threshold"]; + const ValueNode &rndThresholdObject = set["rnd-threshold"]; method.rnd_thresh = 0; if (rndThresholdObject.contains("green")) { @@ -180,7 +180,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, } /* LC Method */ - const YamlObject &lcThresholdObject = set["line-threshold"]; + const ValueNode &lcThresholdObject = set["line-threshold"]; method.line_thresh = 0; if (lcThresholdObject.contains("green")) { @@ -201,7 +201,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, RKISP1_CIF_ISP_DPCC_LINE_THRESH_RB(value); } - const YamlObject &lcTMadFactorObject = set["line-mad-factor"]; + const ValueNode &lcTMadFactorObject = set["line-mad-factor"]; method.line_mad_fac = 0; if (lcTMadFactorObject.contains("green")) { diff --git a/src/ipa/rkisp1/algorithms/dpcc.h b/src/ipa/rkisp1/algorithms/dpcc.h index b77766c300fb..50b62e9bab3f 100644 --- a/src/ipa/rkisp1/algorithms/dpcc.h +++ b/src/ipa/rkisp1/algorithms/dpcc.h @@ -19,7 +19,7 @@ public: DefectPixelClusterCorrection(); ~DefectPixelClusterCorrection() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index ec989bc2421f..b681ddeb96df 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -45,7 +45,7 @@ Dpf::Dpf() * \copydoc libcamera::ipa::Algorithm::init */ int Dpf::init([[maybe_unused]] IPAContext &context, - const YamlObject &tuningData) + const ValueNode &tuningData) { std::vector values; @@ -53,7 +53,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, * The domain kernel is configured with a 9x9 kernel for the green * pixels, and a 13x9 or 9x9 kernel for red and blue pixels. */ - const YamlObject &dFObject = tuningData["DomainFilter"]; + const ValueNode &dFObject = tuningData["DomainFilter"]; /* * For the green component, we have the 9x9 kernel specified @@ -134,7 +134,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, * which stores a piecewise linear function that characterizes the * sensor noise profile as a noise level function curve (NLF). */ - const YamlObject &rFObject = tuningData["NoiseLevelFunction"]; + const ValueNode &rFObject = tuningData["NoiseLevelFunction"]; std::vector nllValues; nllValues = rFObject["coeff"].get>().value_or(std::vector{}); @@ -162,7 +162,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context, return -EINVAL; } - const YamlObject &fSObject = tuningData["FilterStrength"]; + const ValueNode &fSObject = tuningData["FilterStrength"]; strengthConfig_.r = fSObject["r"].get(64); strengthConfig_.g = fSObject["g"].get(64); diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 2dd8cd362624..b07067cec0a5 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -21,7 +21,7 @@ public: Dpf(); ~Dpf() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; void queueRequest(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const ControlList &controls) override; diff --git a/src/ipa/rkisp1/algorithms/filter.cpp b/src/ipa/rkisp1/algorithms/filter.cpp index 8ad79801792f..2e9b4e285503 100644 --- a/src/ipa/rkisp1/algorithms/filter.cpp +++ b/src/ipa/rkisp1/algorithms/filter.cpp @@ -43,7 +43,7 @@ static constexpr uint32_t kFiltModeDefault = 0x000004f2; * \copydoc libcamera::ipa::Algorithm::init */ int Filter::init(IPAContext &context, - [[maybe_unused]] const YamlObject &tuningData) + [[maybe_unused]] const ValueNode &tuningData) { auto &cmap = context.ctrlMap; cmap[&controls::Sharpness] = ControlInfo(0.0f, 10.0f, 1.0f); diff --git a/src/ipa/rkisp1/algorithms/filter.h b/src/ipa/rkisp1/algorithms/filter.h index 37d8938d37bd..9f0188da7880 100644 --- a/src/ipa/rkisp1/algorithms/filter.h +++ b/src/ipa/rkisp1/algorithms/filter.h @@ -21,7 +21,7 @@ public: Filter() = default; ~Filter() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; void queueRequest(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, const ControlList &controls) override; diff --git a/src/ipa/rkisp1/algorithms/goc.cpp b/src/ipa/rkisp1/algorithms/goc.cpp index 6c07bd8c71e5..e8f64bf3d5e0 100644 --- a/src/ipa/rkisp1/algorithms/goc.cpp +++ b/src/ipa/rkisp1/algorithms/goc.cpp @@ -13,7 +13,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "linux/rkisp1-config.h" @@ -48,7 +48,7 @@ const float kDefaultGamma = 2.2f; /** * \copydoc libcamera::ipa::Algorithm::init */ -int GammaOutCorrection::init(IPAContext &context, const YamlObject &tuningData) +int GammaOutCorrection::init(IPAContext &context, const ValueNode &tuningData) { if (context.hw.numGammaOutSamples != RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10) { diff --git a/src/ipa/rkisp1/algorithms/goc.h b/src/ipa/rkisp1/algorithms/goc.h index bb2ddfc92375..bd79fe19cc86 100644 --- a/src/ipa/rkisp1/algorithms/goc.h +++ b/src/ipa/rkisp1/algorithms/goc.h @@ -19,7 +19,7 @@ public: GammaOutCorrection() = default; ~GammaOutCorrection() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void queueRequest(IPAContext &context, diff --git a/src/ipa/rkisp1/algorithms/gsl.cpp b/src/ipa/rkisp1/algorithms/gsl.cpp index 292d0e80dc57..d6272f3a39ef 100644 --- a/src/ipa/rkisp1/algorithms/gsl.cpp +++ b/src/ipa/rkisp1/algorithms/gsl.cpp @@ -10,7 +10,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "linux/rkisp1-config.h" @@ -56,7 +56,7 @@ GammaSensorLinearization::GammaSensorLinearization() * \copydoc libcamera::ipa::Algorithm::init */ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, - const YamlObject &tuningData) + const ValueNode &tuningData) { std::vector xIntervals = tuningData["x-intervals"].get>().value_or(std::vector{}); @@ -75,7 +75,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context, for (unsigned int i = 0; i < kDegammaXIntervals; ++i) gammaDx_[i / 8] |= (xIntervals[i] & 0x07) << ((i % 8) * 4); - const YamlObject &yObject = tuningData["y"]; + const ValueNode &yObject = tuningData["y"]; if (!yObject.isDictionary()) { LOG(RkISP1Gsl, Error) << "Issue while parsing 'y' in tuning file: " diff --git a/src/ipa/rkisp1/algorithms/gsl.h b/src/ipa/rkisp1/algorithms/gsl.h index 91cf6efa7925..3ef5630713ab 100644 --- a/src/ipa/rkisp1/algorithms/gsl.h +++ b/src/ipa/rkisp1/algorithms/gsl.h @@ -19,7 +19,7 @@ public: GammaSensorLinearization(); ~GammaSensorLinearization() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp index 9c0ed44b3943..78618f65c591 100644 --- a/src/ipa/rkisp1/algorithms/lsc.cpp +++ b/src/ipa/rkisp1/algorithms/lsc.cpp @@ -14,7 +14,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "libipa/lsc_polynomial.h" #include "linux/rkisp1-config.h" @@ -85,7 +85,7 @@ public: { } - int parseLscData(const YamlObject &yamlSets, + int parseLscData(const ValueNode &yamlSets, std::map &lscData) { const auto &sets = yamlSets.asList(); @@ -204,7 +204,7 @@ private: class LscTableLoader { public: - int parseLscData(const YamlObject &yamlSets, + int parseLscData(const ValueNode &yamlSets, std::map &lscData) { const auto &sets = yamlSets.asList(); @@ -245,7 +245,7 @@ public: } private: - std::vector parseTable(const YamlObject &tuningData, + std::vector parseTable(const ValueNode &tuningData, const char *prop) { static constexpr unsigned int kLscNumSamples = @@ -265,7 +265,7 @@ private: } }; -static std::vector parseSizes(const YamlObject &tuningData, +static std::vector parseSizes(const ValueNode &tuningData, const char *prop) { std::vector sizes = @@ -305,7 +305,7 @@ LensShadingCorrection::LensShadingCorrection() * \copydoc libcamera::ipa::Algorithm::init */ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, - const YamlObject &tuningData) + const ValueNode &tuningData) { xSize_ = parseSizes(tuningData, "x-size"); ySize_ = parseSizes(tuningData, "y-size"); @@ -314,7 +314,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context, return -EINVAL; /* Get all defined sets to apply. */ - const YamlObject &yamlSets = tuningData["sets"]; + const ValueNode &yamlSets = tuningData["sets"]; if (!yamlSets.isList()) { LOG(RkISP1Lsc, Error) << "'sets' parameter not found in tuning file"; diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h index 5a0824e36dd5..6e0ebad11dc0 100644 --- a/src/ipa/rkisp1/algorithms/lsc.h +++ b/src/ipa/rkisp1/algorithms/lsc.h @@ -23,7 +23,7 @@ public: LensShadingCorrection(); ~LensShadingCorrection() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, diff --git a/src/ipa/rkisp1/algorithms/lux.cpp b/src/ipa/rkisp1/algorithms/lux.cpp index e9717bb3bf66..86e46c492f04 100644 --- a/src/ipa/rkisp1/algorithms/lux.cpp +++ b/src/ipa/rkisp1/algorithms/lux.cpp @@ -41,7 +41,7 @@ Lux::Lux() /** * \copydoc libcamera::ipa::Algorithm::init */ -int Lux::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) +int Lux::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) { return lux_.parseTuningData(tuningData); } diff --git a/src/ipa/rkisp1/algorithms/lux.h b/src/ipa/rkisp1/algorithms/lux.h index e0239848e252..8cb35cbae20d 100644 --- a/src/ipa/rkisp1/algorithms/lux.h +++ b/src/ipa/rkisp1/algorithms/lux.h @@ -22,7 +22,7 @@ class Lux : public Algorithm public: Lux(); - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; void prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) override; diff --git a/src/ipa/rkisp1/algorithms/wdr.cpp b/src/ipa/rkisp1/algorithms/wdr.cpp index 9e2688a05179..c3d73da2c5b2 100644 --- a/src/ipa/rkisp1/algorithms/wdr.cpp +++ b/src/ipa/rkisp1/algorithms/wdr.cpp @@ -10,7 +10,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include #include @@ -110,7 +110,7 @@ WideDynamicRange::WideDynamicRange() * \copydoc libcamera::ipa::Algorithm::init */ int WideDynamicRange::init([[maybe_unused]] IPAContext &context, - [[maybe_unused]] const YamlObject &tuningData) + [[maybe_unused]] const ValueNode &tuningData) { if (!(context.hw.supportedBlocks & 1 << RKISP1_EXT_PARAMS_BLOCK_TYPE_WDR)) { LOG(RkISP1Wdr, Error) diff --git a/src/ipa/rkisp1/algorithms/wdr.h b/src/ipa/rkisp1/algorithms/wdr.h index 46f7cdeea69d..f79de66fe73b 100644 --- a/src/ipa/rkisp1/algorithms/wdr.h +++ b/src/ipa/rkisp1/algorithms/wdr.h @@ -23,7 +23,7 @@ public: WideDynamicRange(); ~WideDynamicRange() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override; void queueRequest(IPAContext &context, const uint32_t frame, diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp index fbcc39103d4b..3230823f3a28 100644 --- a/src/ipa/rkisp1/rkisp1.cpp +++ b/src/ipa/rkisp1/rkisp1.cpp @@ -185,7 +185,7 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision, return ret; } - std::unique_ptr data = YamlParser::parse(file); + std::unique_ptr data = YamlParser::parse(file); if (!data) return -EINVAL; diff --git a/src/ipa/rpi/controller/algorithm.cpp b/src/ipa/rpi/controller/algorithm.cpp index beed47a1e1c4..82bc0302fd12 100644 --- a/src/ipa/rpi/controller/algorithm.cpp +++ b/src/ipa/rpi/controller/algorithm.cpp @@ -9,7 +9,7 @@ using namespace RPiController; -int Algorithm::read([[maybe_unused]] const libcamera::YamlObject ¶ms) +int Algorithm::read([[maybe_unused]] const libcamera::ValueNode ¶ms) { return 0; } diff --git a/src/ipa/rpi/controller/algorithm.h b/src/ipa/rpi/controller/algorithm.h index 8839daa90916..214b06576bbf 100644 --- a/src/ipa/rpi/controller/algorithm.h +++ b/src/ipa/rpi/controller/algorithm.h @@ -15,7 +15,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "controller.h" @@ -32,7 +32,7 @@ public: } virtual ~Algorithm() = default; virtual char const *name() const = 0; - virtual int read(const libcamera::YamlObject ¶ms); + virtual int read(const libcamera::ValueNode ¶ms); virtual void initialise(); virtual void switchMode(CameraMode const &cameraMode, Metadata *metadata); virtual void prepare(Metadata *imageMetadata); diff --git a/src/ipa/rpi/controller/controller.cpp b/src/ipa/rpi/controller/controller.cpp index df45dcd345b7..162c75d8848f 100644 --- a/src/ipa/rpi/controller/controller.cpp +++ b/src/ipa/rpi/controller/controller.cpp @@ -102,7 +102,7 @@ int Controller::read(char const *filename) return -EINVAL; } - std::unique_ptr root = YamlParser::parse(file); + std::unique_ptr root = YamlParser::parse(file); if (!root) return -EINVAL; @@ -143,7 +143,7 @@ int Controller::read(char const *filename) return 0; } -int Controller::createAlgorithm(const std::string &name, const YamlObject ¶ms) +int Controller::createAlgorithm(const std::string &name, const ValueNode ¶ms) { auto it = getAlgorithms().find(name); if (it == getAlgorithms().end()) { diff --git a/src/ipa/rpi/controller/controller.h b/src/ipa/rpi/controller/controller.h index 573942886bc0..094917b08b6a 100644 --- a/src/ipa/rpi/controller/controller.h +++ b/src/ipa/rpi/controller/controller.h @@ -16,7 +16,7 @@ #include #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "camera_mode.h" #include "device_status.h" @@ -65,7 +65,7 @@ public: const HardwareConfig &getHardwareConfig() const; protected: - int createAlgorithm(const std::string &name, const libcamera::YamlObject ¶ms); + int createAlgorithm(const std::string &name, const libcamera::ValueNode ¶ms); Metadata globalMetadata_; std::vector algorithms_; diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index 26e599303f24..47c2bf935835 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -68,7 +68,7 @@ Af::CfgParams::CfgParams() } template -static void readNumber(T &dest, const libcamera::YamlObject ¶ms, char const *name) +static void readNumber(T &dest, const libcamera::ValueNode ¶ms, char const *name) { auto value = params[name].get(); if (value) @@ -77,7 +77,7 @@ static void readNumber(T &dest, const libcamera::YamlObject ¶ms, char const LOG(RPiAf, Warning) << "Missing parameter \"" << name << "\""; } -void Af::RangeDependentParams::read(const libcamera::YamlObject ¶ms) +void Af::RangeDependentParams::read(const libcamera::ValueNode ¶ms) { readNumber(focusMin, params, "min"); @@ -85,7 +85,7 @@ void Af::RangeDependentParams::read(const libcamera::YamlObject ¶ms) readNumber(focusDefault, params, "default"); } -void Af::SpeedDependentParams::read(const libcamera::YamlObject ¶ms) +void Af::SpeedDependentParams::read(const libcamera::ValueNode ¶ms) { readNumber(stepCoarse, params, "step_coarse"); readNumber(stepFine, params, "step_fine"); @@ -100,7 +100,7 @@ void Af::SpeedDependentParams::read(const libcamera::YamlObject ¶ms) readNumber(stepFrames, params, "step_frames"); } -int Af::CfgParams::read(const libcamera::YamlObject ¶ms) +int Af::CfgParams::read(const libcamera::ValueNode ¶ms) { if (params.contains("ranges")) { auto &rr = params["ranges"]; @@ -226,7 +226,7 @@ char const *Af::name() const return NAME; } -int Af::read(const libcamera::YamlObject ¶ms) +int Af::read(const libcamera::ValueNode ¶ms) { return cfg_.read(params); } diff --git a/src/ipa/rpi/controller/rpi/af.h b/src/ipa/rpi/controller/rpi/af.h index d35a39d12049..b464927ba92b 100644 --- a/src/ipa/rpi/controller/rpi/af.h +++ b/src/ipa/rpi/controller/rpi/af.h @@ -47,7 +47,7 @@ public: Af(Controller *controller = NULL); ~Af(); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void initialise() override; /* IPA calls */ @@ -87,7 +87,7 @@ private: double focusDefault; /* default setting ("hyperfocal") */ RangeDependentParams(); - void read(const libcamera::YamlObject ¶ms); + void read(const libcamera::ValueNode ¶ms); }; struct SpeedDependentParams { @@ -104,7 +104,7 @@ private: uint32_t stepFrames; /* frames to skip in between steps of a scan */ SpeedDependentParams(); - void read(const libcamera::YamlObject ¶ms); + void read(const libcamera::ValueNode ¶ms); }; struct CfgParams { @@ -118,7 +118,7 @@ private: libcamera::ipa::Pwl map; /* converts dioptres -> lens driver position */ CfgParams(); - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); void initialise(); }; diff --git a/src/ipa/rpi/controller/rpi/agc.cpp b/src/ipa/rpi/controller/rpi/agc.cpp index afda2e364f64..830b26174df2 100644 --- a/src/ipa/rpi/controller/rpi/agc.cpp +++ b/src/ipa/rpi/controller/rpi/agc.cpp @@ -31,7 +31,7 @@ char const *Agc::name() const return NAME; } -int Agc::read(const libcamera::YamlObject ¶ms) +int Agc::read(const libcamera::ValueNode ¶ms) { /* * When there is only a single channel we can read the old style syntax. diff --git a/src/ipa/rpi/controller/rpi/agc.h b/src/ipa/rpi/controller/rpi/agc.h index 966630a26303..5189ad2a2bf8 100644 --- a/src/ipa/rpi/controller/rpi/agc.h +++ b/src/ipa/rpi/controller/rpi/agc.h @@ -27,7 +27,7 @@ class Agc : public AgcAlgorithm public: Agc(Controller *controller); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; unsigned int getConvergenceFrames() const override; std::vector const &getWeights() const override; void setEv(unsigned int channel, double ev) override; diff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp index c6cf1f8903f1..c0ac76c569af 100644 --- a/src/ipa/rpi/controller/rpi/agc_channel.cpp +++ b/src/ipa/rpi/controller/rpi/agc_channel.cpp @@ -29,9 +29,9 @@ using namespace std::literals::chrono_literals; LOG_DECLARE_CATEGORY(RPiAgc) -int AgcMeteringMode::read(const libcamera::YamlObject ¶ms) +int AgcMeteringMode::read(const libcamera::ValueNode ¶ms) { - const YamlObject &yamlWeights = params["weights"]; + const ValueNode &yamlWeights = params["weights"]; for (const auto &p : yamlWeights.asList()) { auto value = p.get(); @@ -45,7 +45,7 @@ int AgcMeteringMode::read(const libcamera::YamlObject ¶ms) static std::tuple readMeteringModes(std::map &metering_modes, - const libcamera::YamlObject ¶ms) + const libcamera::ValueNode ¶ms) { std::string first; int ret; @@ -64,7 +64,7 @@ readMeteringModes(std::map &metering_modes, return { 0, first }; } -int AgcExposureMode::read(const libcamera::YamlObject ¶ms) +int AgcExposureMode::read(const libcamera::ValueNode ¶ms) { auto value = params["shutter"].get>(); if (!value) @@ -94,7 +94,7 @@ int AgcExposureMode::read(const libcamera::YamlObject ¶ms) static std::tuple readExposureModes(std::map &exposureModes, - const libcamera::YamlObject ¶ms) + const libcamera::ValueNode ¶ms) { std::string first; int ret; @@ -113,7 +113,7 @@ readExposureModes(std::map &exposureModes, return { 0, first }; } -int AgcConstraint::read(const libcamera::YamlObject ¶ms) +int AgcConstraint::read(const libcamera::ValueNode ¶ms) { std::string boundString = params["bound"].get(""); transform(boundString.begin(), boundString.end(), @@ -139,7 +139,7 @@ int AgcConstraint::read(const libcamera::YamlObject ¶ms) } static std::tuple -readConstraintMode(const libcamera::YamlObject ¶ms) +readConstraintMode(const libcamera::ValueNode ¶ms) { AgcConstraintMode mode; int ret; @@ -158,7 +158,7 @@ readConstraintMode(const libcamera::YamlObject ¶ms) static std::tuple readConstraintModes(std::map &constraintModes, - const libcamera::YamlObject ¶ms) + const libcamera::ValueNode ¶ms) { std::string first; int ret; @@ -175,7 +175,7 @@ readConstraintModes(std::map &constraintModes, return { 0, first }; } -int AgcChannelConstraint::read(const libcamera::YamlObject ¶ms) +int AgcChannelConstraint::read(const libcamera::ValueNode ¶ms) { auto channelValue = params["channel"].get(); if (!channelValue) { @@ -204,7 +204,7 @@ int AgcChannelConstraint::read(const libcamera::YamlObject ¶ms) } static int readChannelConstraints(std::vector &channelConstraints, - const libcamera::YamlObject ¶ms) + const libcamera::ValueNode ¶ms) { for (const auto &p : params.asList()) { AgcChannelConstraint constraint; @@ -218,7 +218,7 @@ static int readChannelConstraints(std::vector &channelCons return 0; } -int AgcConfig::read(const libcamera::YamlObject ¶ms) +int AgcConfig::read(const libcamera::ValueNode ¶ms) { LOG(RPiAgc, Debug) << "AgcConfig"; int ret; @@ -290,7 +290,7 @@ AgcChannel::AgcChannel() status_.ev = ev_; } -int AgcChannel::read(const libcamera::YamlObject ¶ms, +int AgcChannel::read(const libcamera::ValueNode ¶ms, const Controller::HardwareConfig &hardwareConfig) { int ret = config_.read(params); diff --git a/src/ipa/rpi/controller/rpi/agc_channel.h b/src/ipa/rpi/controller/rpi/agc_channel.h index 42d85ec15e8d..90e540a8a18d 100644 --- a/src/ipa/rpi/controller/rpi/agc_channel.h +++ b/src/ipa/rpi/controller/rpi/agc_channel.h @@ -26,13 +26,13 @@ using AgcChannelTotalExposures = std::vector; struct AgcMeteringMode { std::vector weights; - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); }; struct AgcExposureMode { std::vector exposureTime; std::vector gain; - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); }; struct AgcConstraint { @@ -42,7 +42,7 @@ struct AgcConstraint { double qLo; double qHi; libcamera::ipa::Pwl yTarget; - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); }; typedef std::vector AgcConstraintMode; @@ -53,11 +53,11 @@ struct AgcChannelConstraint { Bound bound; unsigned int channel; double factor; - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); }; struct AgcConfig { - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); std::map meteringModes; std::map exposureModes; std::map constraintModes; @@ -85,7 +85,7 @@ class AgcChannel { public: AgcChannel(); - int read(const libcamera::YamlObject ¶ms, + int read(const libcamera::ValueNode ¶ms, const Controller::HardwareConfig &hardwareConfig); unsigned int getConvergenceFrames() const; std::vector const &getWeights() const; diff --git a/src/ipa/rpi/controller/rpi/alsc.cpp b/src/ipa/rpi/controller/rpi/alsc.cpp index 21edb819ad1c..4c852db04f7f 100644 --- a/src/ipa/rpi/controller/rpi/alsc.cpp +++ b/src/ipa/rpi/controller/rpi/alsc.cpp @@ -50,7 +50,7 @@ char const *Alsc::name() const return NAME; } -static int generateLut(Array2D &lut, const libcamera::YamlObject ¶ms) +static int generateLut(Array2D &lut, const libcamera::ValueNode ¶ms) { /* These must be signed ints for the co-ordinate calculations below. */ int X = lut.dimensions().width, Y = lut.dimensions().height; @@ -82,7 +82,7 @@ static int generateLut(Array2D &lut, const libcamera::YamlObject ¶ms return 0; } -static int readLut(Array2D &lut, const libcamera::YamlObject ¶ms) +static int readLut(Array2D &lut, const libcamera::ValueNode ¶ms) { if (params.size() != lut.size()) { LOG(RPiAlsc, Error) << "Invalid number of entries in LSC table"; @@ -101,7 +101,7 @@ static int readLut(Array2D &lut, const libcamera::YamlObject ¶ms) } static int readCalibrations(std::vector &calibrations, - const libcamera::YamlObject ¶ms, + const libcamera::ValueNode ¶ms, std::string const &name, const Size &size) { if (params.contains(name)) { @@ -119,7 +119,7 @@ static int readCalibrations(std::vector &calibrations, AlscCalibration calibration; calibration.ct = lastCt = ct; - const libcamera::YamlObject &table = p["table"]; + const libcamera::ValueNode &table = p["table"]; if (table.size() != size.width * size.height) { LOG(RPiAlsc, Error) << "Incorrect number of values for ct " @@ -144,7 +144,7 @@ static int readCalibrations(std::vector &calibrations, return 0; } -int Alsc::read(const libcamera::YamlObject ¶ms) +int Alsc::read(const libcamera::ValueNode ¶ms) { config_.tableSize = getHardwareConfig().awbRegions; config_.framePeriod = params["frame_period"].get(12); diff --git a/src/ipa/rpi/controller/rpi/alsc.h b/src/ipa/rpi/controller/rpi/alsc.h index 310879820fba..0952ae8358c6 100644 --- a/src/ipa/rpi/controller/rpi/alsc.h +++ b/src/ipa/rpi/controller/rpi/alsc.h @@ -112,7 +112,7 @@ public: char const *name() const override; void initialise() override; void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void prepare(Metadata *imageMetadata) override; void process(StatisticsPtr &stats, Metadata *imageMetadata) override; diff --git a/src/ipa/rpi/controller/rpi/awb.cpp b/src/ipa/rpi/controller/rpi/awb.cpp index 365b595ff9b4..1ccac36e5b4f 100644 --- a/src/ipa/rpi/controller/rpi/awb.cpp +++ b/src/ipa/rpi/controller/rpi/awb.cpp @@ -30,7 +30,7 @@ constexpr double kDefaultCT = 4500.0; * elsewhere (ALSC and AGC). */ -int AwbMode::read(const libcamera::YamlObject ¶ms) +int AwbMode::read(const libcamera::ValueNode ¶ms) { auto value = params["lo"].get(); if (!value) @@ -45,7 +45,7 @@ int AwbMode::read(const libcamera::YamlObject ¶ms) return 0; } -int AwbPrior::read(const libcamera::YamlObject ¶ms) +int AwbPrior::read(const libcamera::ValueNode ¶ms) { auto value = params["lux"].get(); if (!value) @@ -56,7 +56,7 @@ int AwbPrior::read(const libcamera::YamlObject ¶ms) return prior.empty() ? -EINVAL : 0; } -static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::YamlObject ¶ms) +static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::ValueNode ¶ms) { if (params.size() % 3) { LOG(RPiAwb, Error) << "AwbConfig: incomplete CT curve entry"; @@ -92,7 +92,7 @@ static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::YamlObject return 0; } -int AwbConfig::read(const libcamera::YamlObject ¶ms) +int AwbConfig::read(const libcamera::ValueNode ¶ms) { int ret; @@ -204,7 +204,7 @@ char const *Awb::name() const return NAME; } -int Awb::read(const libcamera::YamlObject ¶ms) +int Awb::read(const libcamera::ValueNode ¶ms) { return config_.read(params); } diff --git a/src/ipa/rpi/controller/rpi/awb.h b/src/ipa/rpi/controller/rpi/awb.h index 2fb912541a2b..ac73105113fb 100644 --- a/src/ipa/rpi/controller/rpi/awb.h +++ b/src/ipa/rpi/controller/rpi/awb.h @@ -23,20 +23,20 @@ namespace RPiController { /* Control algorithm to perform AWB calculations. */ struct AwbMode { - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); double ctLo; /* low CT value for search */ double ctHi; /* high CT value for search */ }; struct AwbPrior { - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); double lux; /* lux level */ libcamera::ipa::Pwl prior; /* maps CT to prior log likelihood for this lux level */ }; struct AwbConfig { AwbConfig() : defaultMode(nullptr) {} - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); /* Only repeat the AWB calculation every "this many" frames */ uint16_t framePeriod; /* number of initial frames for which speed taken as 1.0 (maximum) */ @@ -99,7 +99,7 @@ public: ~Awb(); char const *name() const override; void initialise() override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; unsigned int getConvergenceFrames() const override; void initialValues(double &gainR, double &gainB) override; void setMode(std::string const &name) override; diff --git a/src/ipa/rpi/controller/rpi/black_level.cpp b/src/ipa/rpi/controller/rpi/black_level.cpp index 4c968f14a1ca..42ea1505014f 100644 --- a/src/ipa/rpi/controller/rpi/black_level.cpp +++ b/src/ipa/rpi/controller/rpi/black_level.cpp @@ -30,7 +30,7 @@ char const *BlackLevel::name() const return NAME; } -int BlackLevel::read(const libcamera::YamlObject ¶ms) +int BlackLevel::read(const libcamera::ValueNode ¶ms) { /* 64 in 10 bits scaled to 16 bits */ uint16_t blackLevel = params["black_level"].get(4096); diff --git a/src/ipa/rpi/controller/rpi/black_level.h b/src/ipa/rpi/controller/rpi/black_level.h index f50729dbc1e3..dbf29b282e4c 100644 --- a/src/ipa/rpi/controller/rpi/black_level.h +++ b/src/ipa/rpi/controller/rpi/black_level.h @@ -18,7 +18,7 @@ class BlackLevel : public BlackLevelAlgorithm public: BlackLevel(Controller *controller); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void initialValues(uint16_t &blackLevelR, uint16_t &blackLevelG, uint16_t &blackLevelB) override; void prepare(Metadata *imageMetadata) override; diff --git a/src/ipa/rpi/controller/rpi/cac.cpp b/src/ipa/rpi/controller/rpi/cac.cpp index 17779ad5469b..ddc848f21f3f 100644 --- a/src/ipa/rpi/controller/rpi/cac.cpp +++ b/src/ipa/rpi/controller/rpi/cac.cpp @@ -27,7 +27,7 @@ char const *Cac::name() const return NAME; } -static bool arrayToSet(const libcamera::YamlObject ¶ms, std::vector &inputArray, const Size &size) +static bool arrayToSet(const libcamera::ValueNode ¶ms, std::vector &inputArray, const Size &size) { int num = 0; int max_num = (size.width + 1) * (size.height + 1); @@ -51,7 +51,7 @@ static void setStrength(std::vector &inputArray, std::vector &ou } } -int Cac::read(const libcamera::YamlObject ¶ms) +int Cac::read(const libcamera::ValueNode ¶ms) { config_.enabled = params.contains("lut_rx") && params.contains("lut_ry") && params.contains("lut_bx") && params.contains("lut_by"); diff --git a/src/ipa/rpi/controller/rpi/cac.h b/src/ipa/rpi/controller/rpi/cac.h index 533cca44424b..11c47a7c4323 100644 --- a/src/ipa/rpi/controller/rpi/cac.h +++ b/src/ipa/rpi/controller/rpi/cac.h @@ -24,7 +24,7 @@ class Cac : public Algorithm public: Cac(Controller *controller = NULL); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void prepare(Metadata *imageMetadata) override; private: diff --git a/src/ipa/rpi/controller/rpi/ccm.cpp b/src/ipa/rpi/controller/rpi/ccm.cpp index 2806b4967158..d3231182913d 100644 --- a/src/ipa/rpi/controller/rpi/ccm.cpp +++ b/src/ipa/rpi/controller/rpi/ccm.cpp @@ -40,7 +40,7 @@ char const *Ccm::name() const return NAME; } -int Ccm::read(const libcamera::YamlObject ¶ms) +int Ccm::read(const libcamera::ValueNode ¶ms) { if (params.contains("saturation")) { config_.saturation = params["saturation"].get(ipa::Pwl{}); diff --git a/src/ipa/rpi/controller/rpi/ccm.h b/src/ipa/rpi/controller/rpi/ccm.h index 70f28ed33d5e..a0f5b698db9b 100644 --- a/src/ipa/rpi/controller/rpi/ccm.h +++ b/src/ipa/rpi/controller/rpi/ccm.h @@ -31,7 +31,7 @@ class Ccm : public CcmAlgorithm public: Ccm(Controller *controller = NULL); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void enableAuto() override; void setSaturation(double saturation) override; void setCcm(Matrix3x3 const &matrix) override; diff --git a/src/ipa/rpi/controller/rpi/contrast.cpp b/src/ipa/rpi/controller/rpi/contrast.cpp index fe866a544293..3457e04002e0 100644 --- a/src/ipa/rpi/controller/rpi/contrast.cpp +++ b/src/ipa/rpi/controller/rpi/contrast.cpp @@ -38,7 +38,7 @@ char const *Contrast::name() const return NAME; } -int Contrast::read(const libcamera::YamlObject ¶ms) +int Contrast::read(const libcamera::ValueNode ¶ms) { // enable adaptive enhancement by default config_.ceEnable = params["ce_enable"].get(1); diff --git a/src/ipa/rpi/controller/rpi/contrast.h b/src/ipa/rpi/controller/rpi/contrast.h index c0f7db981c7d..3571626d8623 100644 --- a/src/ipa/rpi/controller/rpi/contrast.h +++ b/src/ipa/rpi/controller/rpi/contrast.h @@ -35,7 +35,7 @@ class Contrast : public ContrastAlgorithm public: Contrast(Controller *controller = NULL); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void setBrightness(double brightness) override; void setContrast(double contrast) override; void enableCe(bool enable) override; diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp b/src/ipa/rpi/controller/rpi/decompand.cpp index 2d457926c060..5646984132f6 100644 --- a/src/ipa/rpi/controller/rpi/decompand.cpp +++ b/src/ipa/rpi/controller/rpi/decompand.cpp @@ -22,7 +22,7 @@ char const *Decompand::name() const return NAME; } -int Decompand::read(const libcamera::YamlObject ¶ms) +int Decompand::read(const libcamera::ValueNode ¶ms) { config_.bitdepth = params["bitdepth"].get(0); config_.decompandCurve = params["decompand_curve"].get(ipa::Pwl{}); diff --git a/src/ipa/rpi/controller/rpi/decompand.h b/src/ipa/rpi/controller/rpi/decompand.h index 6db779c359a8..847769af4338 100644 --- a/src/ipa/rpi/controller/rpi/decompand.h +++ b/src/ipa/rpi/controller/rpi/decompand.h @@ -17,7 +17,7 @@ class Decompand : public DecompandAlgorithm public: Decompand(Controller *controller = nullptr); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void initialise() override; void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; void initialValues(libcamera::ipa::Pwl &decompandCurve) override; diff --git a/src/ipa/rpi/controller/rpi/denoise.cpp b/src/ipa/rpi/controller/rpi/denoise.cpp index cabe3e2a08aa..0cd0dd53fe97 100644 --- a/src/ipa/rpi/controller/rpi/denoise.cpp +++ b/src/ipa/rpi/controller/rpi/denoise.cpp @@ -21,7 +21,7 @@ LOG_DEFINE_CATEGORY(RPiDenoise) #define NAME "rpi.denoise" -int DenoiseConfig::read(const libcamera::YamlObject ¶ms) +int DenoiseConfig::read(const libcamera::ValueNode ¶ms) { sdnEnable = params.contains("sdn"); if (sdnEnable) { @@ -82,7 +82,7 @@ char const *Denoise::name() const return NAME; } -int Denoise::read(const libcamera::YamlObject ¶ms) +int Denoise::read(const libcamera::ValueNode ¶ms) { if (!params.contains("normal")) { configs_["normal"].read(params); diff --git a/src/ipa/rpi/controller/rpi/denoise.h b/src/ipa/rpi/controller/rpi/denoise.h index e23a2e8ff525..499b2ab74749 100644 --- a/src/ipa/rpi/controller/rpi/denoise.h +++ b/src/ipa/rpi/controller/rpi/denoise.h @@ -31,7 +31,7 @@ struct DenoiseConfig { bool tdnEnable; bool sdnEnable; bool cdnEnable; - int read(const libcamera::YamlObject ¶ms); + int read(const libcamera::ValueNode ¶ms); }; class Denoise : public DenoiseAlgorithm @@ -39,7 +39,7 @@ class Denoise : public DenoiseAlgorithm public: Denoise(Controller *controller); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void initialise() override; void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; void prepare(Metadata *imageMetadata) override; diff --git a/src/ipa/rpi/controller/rpi/dpc.cpp b/src/ipa/rpi/controller/rpi/dpc.cpp index 8aac03f794fc..a92207999fab 100644 --- a/src/ipa/rpi/controller/rpi/dpc.cpp +++ b/src/ipa/rpi/controller/rpi/dpc.cpp @@ -31,7 +31,7 @@ char const *Dpc::name() const return NAME; } -int Dpc::read(const libcamera::YamlObject ¶ms) +int Dpc::read(const libcamera::ValueNode ¶ms) { config_.strength = params["strength"].get(1); if (config_.strength < 0 || config_.strength > 2) { diff --git a/src/ipa/rpi/controller/rpi/dpc.h b/src/ipa/rpi/controller/rpi/dpc.h index 9cefb06d4a7c..a1a02af59cbc 100644 --- a/src/ipa/rpi/controller/rpi/dpc.h +++ b/src/ipa/rpi/controller/rpi/dpc.h @@ -22,7 +22,7 @@ class Dpc : public Algorithm public: Dpc(Controller *controller); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void prepare(Metadata *imageMetadata) override; private: diff --git a/src/ipa/rpi/controller/rpi/geq.cpp b/src/ipa/rpi/controller/rpi/geq.cpp index 40e7191ba16a..9382a033f055 100644 --- a/src/ipa/rpi/controller/rpi/geq.cpp +++ b/src/ipa/rpi/controller/rpi/geq.cpp @@ -34,7 +34,7 @@ char const *Geq::name() const return NAME; } -int Geq::read(const libcamera::YamlObject ¶ms) +int Geq::read(const libcamera::ValueNode ¶ms) { config_.offset = params["offset"].get(0); config_.slope = params["slope"].get(0.0); diff --git a/src/ipa/rpi/controller/rpi/geq.h b/src/ipa/rpi/controller/rpi/geq.h index e8b9f42708c0..4827051b4f46 100644 --- a/src/ipa/rpi/controller/rpi/geq.h +++ b/src/ipa/rpi/controller/rpi/geq.h @@ -26,7 +26,7 @@ class Geq : public Algorithm public: Geq(Controller *controller); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void prepare(Metadata *imageMetadata) override; private: diff --git a/src/ipa/rpi/controller/rpi/hdr.cpp b/src/ipa/rpi/controller/rpi/hdr.cpp index 06400ea79a95..c256f7485f77 100644 --- a/src/ipa/rpi/controller/rpi/hdr.cpp +++ b/src/ipa/rpi/controller/rpi/hdr.cpp @@ -23,7 +23,7 @@ LOG_DEFINE_CATEGORY(RPiHdr) #define NAME "rpi.hdr" -void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &modeName) +void HdrConfig::read(const libcamera::ValueNode ¶ms, const std::string &modeName) { name = modeName; @@ -111,7 +111,7 @@ char const *Hdr::name() const return NAME; } -int Hdr::read(const libcamera::YamlObject ¶ms) +int Hdr::read(const libcamera::ValueNode ¶ms) { /* Make an "HDR off" mode by default so that tuning files don't have to. */ HdrConfig &offMode = config_["Off"]; diff --git a/src/ipa/rpi/controller/rpi/hdr.h b/src/ipa/rpi/controller/rpi/hdr.h index 5c2f3988d789..58ff5ba83d2e 100644 --- a/src/ipa/rpi/controller/rpi/hdr.h +++ b/src/ipa/rpi/controller/rpi/hdr.h @@ -52,7 +52,7 @@ struct HdrConfig { uint8_t diffPower; double motionThreshold; - void read(const libcamera::YamlObject ¶ms, const std::string &name); + void read(const libcamera::ValueNode ¶ms, const std::string &name); }; class Hdr : public HdrAlgorithm @@ -61,7 +61,7 @@ public: Hdr(Controller *controller); char const *name() const override; void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void prepare(Metadata *imageMetadata) override; void process(StatisticsPtr &stats, Metadata *imageMetadata) override; int setMode(std::string const &mode) override; diff --git a/src/ipa/rpi/controller/rpi/lux.cpp b/src/ipa/rpi/controller/rpi/lux.cpp index 7dab27cc0a90..2047a240bad5 100644 --- a/src/ipa/rpi/controller/rpi/lux.cpp +++ b/src/ipa/rpi/controller/rpi/lux.cpp @@ -35,7 +35,7 @@ char const *Lux::name() const return NAME; } -int Lux::read(const libcamera::YamlObject ¶ms) +int Lux::read(const libcamera::ValueNode ¶ms) { auto value = params["reference_shutter_speed"].get(); if (!value) diff --git a/src/ipa/rpi/controller/rpi/lux.h b/src/ipa/rpi/controller/rpi/lux.h index db2227e41455..c9ffe38b69db 100644 --- a/src/ipa/rpi/controller/rpi/lux.h +++ b/src/ipa/rpi/controller/rpi/lux.h @@ -23,7 +23,7 @@ class Lux : public Algorithm public: Lux(Controller *controller); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; void prepare(Metadata *imageMetadata) override; void process(StatisticsPtr &stats, Metadata *imageMetadata) override; diff --git a/src/ipa/rpi/controller/rpi/noise.cpp b/src/ipa/rpi/controller/rpi/noise.cpp index 145175fb4940..d6e01c2cfe4e 100644 --- a/src/ipa/rpi/controller/rpi/noise.cpp +++ b/src/ipa/rpi/controller/rpi/noise.cpp @@ -41,7 +41,7 @@ void Noise::switchMode(CameraMode const &cameraMode, modeFactor_ = std::max(1.0, cameraMode.noiseFactor); } -int Noise::read(const libcamera::YamlObject ¶ms) +int Noise::read(const libcamera::ValueNode ¶ms) { auto value = params["reference_constant"].get(); if (!value) diff --git a/src/ipa/rpi/controller/rpi/noise.h b/src/ipa/rpi/controller/rpi/noise.h index 6deae1f0282e..c449fa52ffd2 100644 --- a/src/ipa/rpi/controller/rpi/noise.h +++ b/src/ipa/rpi/controller/rpi/noise.h @@ -19,7 +19,7 @@ public: Noise(Controller *controller); char const *name() const override; void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void prepare(Metadata *imageMetadata) override; private: diff --git a/src/ipa/rpi/controller/rpi/saturation.cpp b/src/ipa/rpi/controller/rpi/saturation.cpp index b83c5887c02e..5001f930a1ec 100644 --- a/src/ipa/rpi/controller/rpi/saturation.cpp +++ b/src/ipa/rpi/controller/rpi/saturation.cpp @@ -27,7 +27,7 @@ char const *Saturation::name() const return NAME; } -int Saturation::read(const libcamera::YamlObject ¶ms) +int Saturation::read(const libcamera::ValueNode ¶ms) { config_.shiftR = params["shift_r"].get(0); config_.shiftG = params["shift_g"].get(0); diff --git a/src/ipa/rpi/controller/rpi/saturation.h b/src/ipa/rpi/controller/rpi/saturation.h index c67d496ef065..e6a22c8bb94d 100644 --- a/src/ipa/rpi/controller/rpi/saturation.h +++ b/src/ipa/rpi/controller/rpi/saturation.h @@ -21,7 +21,7 @@ class Saturation : public Algorithm public: Saturation(Controller *controller = NULL); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void initialise() override; void prepare(Metadata *imageMetadata) override; diff --git a/src/ipa/rpi/controller/rpi/sdn.cpp b/src/ipa/rpi/controller/rpi/sdn.cpp index 594ea70133ac..13dfad02068c 100644 --- a/src/ipa/rpi/controller/rpi/sdn.cpp +++ b/src/ipa/rpi/controller/rpi/sdn.cpp @@ -35,7 +35,7 @@ char const *Sdn::name() const return NAME; } -int Sdn::read(const libcamera::YamlObject ¶ms) +int Sdn::read(const libcamera::ValueNode ¶ms) { deviation_ = params["deviation"].get(3.2); strength_ = params["strength"].get(0.75); diff --git a/src/ipa/rpi/controller/rpi/sdn.h b/src/ipa/rpi/controller/rpi/sdn.h index cb226de88c3c..20d847f0cefa 100644 --- a/src/ipa/rpi/controller/rpi/sdn.h +++ b/src/ipa/rpi/controller/rpi/sdn.h @@ -18,7 +18,7 @@ class Sdn : public DenoiseAlgorithm public: Sdn(Controller *controller = NULL); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void initialise() override; void prepare(Metadata *imageMetadata) override; void setMode(DenoiseMode mode) override; diff --git a/src/ipa/rpi/controller/rpi/sharpen.cpp b/src/ipa/rpi/controller/rpi/sharpen.cpp index 1d143ff53287..e8723916c965 100644 --- a/src/ipa/rpi/controller/rpi/sharpen.cpp +++ b/src/ipa/rpi/controller/rpi/sharpen.cpp @@ -37,7 +37,7 @@ void Sharpen::switchMode(CameraMode const &cameraMode, modeFactor_ = std::max(1.0, cameraMode.noiseFactor); } -int Sharpen::read(const libcamera::YamlObject ¶ms) +int Sharpen::read(const libcamera::ValueNode ¶ms) { threshold_ = params["threshold"].get(1.0); strength_ = params["strength"].get(1.0); diff --git a/src/ipa/rpi/controller/rpi/sharpen.h b/src/ipa/rpi/controller/rpi/sharpen.h index 96ccd60934f8..2814ec85fef1 100644 --- a/src/ipa/rpi/controller/rpi/sharpen.h +++ b/src/ipa/rpi/controller/rpi/sharpen.h @@ -19,7 +19,7 @@ public: Sharpen(Controller *controller); char const *name() const override; void switchMode(CameraMode const &cameraMode, Metadata *metadata) override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void setStrength(double strength) override; void prepare(Metadata *imageMetadata) override; diff --git a/src/ipa/rpi/controller/rpi/tonemap.cpp b/src/ipa/rpi/controller/rpi/tonemap.cpp index 3422adfe7dee..3cbecf5379ac 100644 --- a/src/ipa/rpi/controller/rpi/tonemap.cpp +++ b/src/ipa/rpi/controller/rpi/tonemap.cpp @@ -27,7 +27,7 @@ char const *Tonemap::name() const return NAME; } -int Tonemap::read(const libcamera::YamlObject ¶ms) +int Tonemap::read(const libcamera::ValueNode ¶ms) { config_.detailConstant = params["detail_constant"].get(0); config_.detailSlope = params["detail_slope"].get(0.1); diff --git a/src/ipa/rpi/controller/rpi/tonemap.h b/src/ipa/rpi/controller/rpi/tonemap.h index 4e513b1d00da..4d486d136499 100644 --- a/src/ipa/rpi/controller/rpi/tonemap.h +++ b/src/ipa/rpi/controller/rpi/tonemap.h @@ -25,7 +25,7 @@ class Tonemap : public Algorithm public: Tonemap(Controller *controller = NULL); char const *name() const override; - int read(const libcamera::YamlObject ¶ms) override; + int read(const libcamera::ValueNode ¶ms) override; void initialise() override; void prepare(Metadata *imageMetadata) override; diff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp index 464e43c278f3..677be56ed669 100644 --- a/src/ipa/simple/algorithms/blc.cpp +++ b/src/ipa/simple/algorithms/blc.cpp @@ -24,7 +24,7 @@ BlackLevel::BlackLevel() } int BlackLevel::init([[maybe_unused]] IPAContext &context, - const YamlObject &tuningData) + const ValueNode &tuningData) { auto blackLevel = tuningData["blackLevel"].get(); if (blackLevel.has_value()) { diff --git a/src/ipa/simple/algorithms/blc.h b/src/ipa/simple/algorithms/blc.h index a5592d08740f..2933ff1fffe7 100644 --- a/src/ipa/simple/algorithms/blc.h +++ b/src/ipa/simple/algorithms/blc.h @@ -22,7 +22,7 @@ public: BlackLevel(); ~BlackLevel() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPAConfigInfo &configInfo) override; void prepare(IPAContext &context, const uint32_t frame, diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp index 0a98406c1a3a..ec66f0193478 100644 --- a/src/ipa/simple/algorithms/ccm.cpp +++ b/src/ipa/simple/algorithms/ccm.cpp @@ -27,7 +27,7 @@ namespace ipa::soft::algorithms { LOG_DEFINE_CATEGORY(IPASoftCcm) -int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) +int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData) { int ret = ccm_.readYaml(tuningData["ccms"], "ct", "ccm"); if (ret < 0) { diff --git a/src/ipa/simple/algorithms/ccm.h b/src/ipa/simple/algorithms/ccm.h index 8279a3d5967e..3e3755165c03 100644 --- a/src/ipa/simple/algorithms/ccm.h +++ b/src/ipa/simple/algorithms/ccm.h @@ -25,7 +25,7 @@ public: Ccm() = default; ~Ccm() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPAConfigInfo &configInfo) override; void queueRequest(typename Module::Context &context, diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp index 54cb804e7822..5e09bce79ee1 100644 --- a/src/ipa/simple/algorithms/lut.cpp +++ b/src/ipa/simple/algorithms/lut.cpp @@ -25,7 +25,7 @@ LOG_DEFINE_CATEGORY(IPASoftLut) namespace ipa::soft::algorithms { int Lut::init(IPAContext &context, - [[maybe_unused]] const YamlObject &tuningData) + [[maybe_unused]] const ValueNode &tuningData) { context.ctrlMap[&controls::Contrast] = ControlInfo(0.0f, 2.0f, 1.0f); return 0; diff --git a/src/ipa/simple/algorithms/lut.h b/src/ipa/simple/algorithms/lut.h index ba8b9021b37e..a3f8fac23b19 100644 --- a/src/ipa/simple/algorithms/lut.h +++ b/src/ipa/simple/algorithms/lut.h @@ -19,7 +19,7 @@ public: Lut() = default; ~Lut() = default; - int init(IPAContext &context, const YamlObject &tuningData) override; + int init(IPAContext &context, const ValueNode &tuningData) override; int configure(IPAContext &context, const IPAConfigInfo &configInfo) override; void queueRequest(typename Module::Context &context, const uint32_t frame, diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp index 57836c73ccfa..6200072b9268 100644 --- a/src/ipa/simple/soft_simple.cpp +++ b/src/ipa/simple/soft_simple.cpp @@ -120,7 +120,7 @@ int IPASoftSimple::init(const IPASettings &settings, return ret; } - std::unique_ptr data = YamlParser::parse(file); + std::unique_ptr data = YamlParser::parse(file); if (!data) return -EINVAL; diff --git a/src/libcamera/converter/converter_dw100.cpp b/src/libcamera/converter/converter_dw100.cpp index 5782cd0b21b7..86b530c13f96 100644 --- a/src/libcamera/converter/converter_dw100.cpp +++ b/src/libcamera/converter/converter_dw100.cpp @@ -97,7 +97,7 @@ ConverterDW100Module::createModule(DeviceEnumerator *enumerator) * \sa Dw100VertexMap::setDewarpParams() * \return 0 if successful, an error code otherwise */ -int ConverterDW100Module::init(const YamlObject ¶ms) +int ConverterDW100Module::init(const ValueNode ¶ms) { DewarpParms dp; diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index 621008844c74..010c1d8c35d9 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -12,7 +12,7 @@ #include -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" /** * \file geometry.h @@ -933,7 +933,7 @@ std::ostream &operator<<(std::ostream &out, const Rectangle &r) */ template<> std::optional -YamlObject::Accessor::get(const YamlObject &obj) const +ValueNode::Accessor::get(const ValueNode &obj) const { if (obj.type_ != Type::List) return std::nullopt; diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 99d16e7c38c6..c4999d32d7c7 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -65,7 +65,7 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) return true; } - std::unique_ptr configuration = YamlParser::parse(file); + std::unique_ptr configuration = YamlParser::parse(file); if (!configuration) { LOG(Configuration, Error) << "Failed to parse configuration file " << fileName; @@ -146,7 +146,7 @@ GlobalConfiguration::GlobalConfiguration() std::optional> GlobalConfiguration::listOption( const std::initializer_list confPath) const { - const YamlObject *c = &configuration(); + const ValueNode *c = &configuration(); for (auto part : confPath) { c = &(*c)[part]; if (!*c) @@ -237,10 +237,10 @@ unsigned int GlobalConfiguration::version() const * This returns the whole configuration stored in the top-level section * `%configuration` of the YAML configuration file. * - * The requested part of the configuration can be accessed using \a YamlObject + * The requested part of the configuration can be accessed using \a ValueNode * methods. * - * \note \a YamlObject type itself shouldn't be used in type declarations to + * \note \a ValueNode type itself shouldn't be used in type declarations to * avoid trouble if we decide to change the underlying data objects in future. * * \return The whole configuration section diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp index b7c07e896538..4fe210830421 100644 --- a/src/libcamera/matrix.cpp +++ b/src/libcamera/matrix.cpp @@ -314,7 +314,7 @@ template bool matrixInvert(Span data, Span dataOut * to the product of the number of rows and columns of the matrix (Rows x * Cols). The values shall be stored in row-major order. */ -bool matrixValidateYaml(const YamlObject &obj, unsigned int size) +bool matrixValidateYaml(const ValueNode &obj, unsigned int size) { if (!obj.isList()) return false; diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index da89aa3714c3..a24c1ec63c96 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -57,8 +57,8 @@ libcamera_internal_sources = files([ 'v4l2_request.cpp', 'v4l2_subdevice.cpp', 'v4l2_videodevice.cpp', + 'value_node.cpp', 'vector.cpp', - 'yaml_object.cpp', 'yaml_parser.cpp', ]) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index c7e3b185f89b..b2cfcf7395ca 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -443,7 +443,7 @@ int RkISP1CameraData::loadTuningFile(const std::string &path) return ret; } - std::unique_ptr data = YamlParser::parse(file); + std::unique_ptr data = YamlParser::parse(file); if (!data) return -EINVAL; diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 684438bd5fb7..a2929bca2a03 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -1116,7 +1116,7 @@ int CameraData::loadPipelineConfiguration() LOG(RPI, Info) << "Using configuration file '" << filename << "'"; - std::unique_ptr root = YamlParser::parse(file); + std::unique_ptr root = YamlParser::parse(file); if (!root) { LOG(RPI, Warning) << "Failed to parse configuration file, using defaults"; return 0; @@ -1129,7 +1129,7 @@ int CameraData::loadPipelineConfiguration() return 0; } - const YamlObject &phConfig = (*root)["pipeline_handler"]; + const ValueNode &phConfig = (*root)["pipeline_handler"]; if (phConfig.contains("disable_startup_frame_drops")) LOG(RPI, Warning) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h index c69a690f580c..d959f27705ef 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h @@ -26,7 +26,7 @@ #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" #include "libcamera/internal/v4l2_videodevice.h" -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include #include @@ -96,7 +96,7 @@ public: virtual V4L2VideoDevice::Formats rawFormats() const = 0; virtual V4L2VideoDevice *frontendDevice() = 0; - virtual int platformPipelineConfigure(const std::unique_ptr &root) = 0; + virtual int platformPipelineConfigure(const std::unique_ptr &root) = 0; std::unique_ptr ipa_; diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp index 7bcba32b9b58..f4133de47f23 100644 --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -743,7 +743,7 @@ public: CameraConfiguration::Status platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const override; - int platformPipelineConfigure(const std::unique_ptr &root) override; + int platformPipelineConfigure(const std::unique_ptr &root) override; void platformStart() override; void platformStop() override; @@ -1333,7 +1333,7 @@ PiSPCameraData::platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const return status; } -int PiSPCameraData::platformPipelineConfigure(const std::unique_ptr &root) +int PiSPCameraData::platformPipelineConfigure(const std::unique_ptr &root) { config_ = { .numCfeConfigStatsBuffers = 12, @@ -1358,7 +1358,7 @@ int PiSPCameraData::platformPipelineConfigure(const std::unique_ptr return -EINVAL; } - const YamlObject &phConfig = (*root)["pipeline_handler"]; + const ValueNode &phConfig = (*root)["pipeline_handler"]; config_.numCfeConfigStatsBuffers = phConfig["num_cfe_config_stats_buffers"].get(config_.numCfeConfigStatsBuffers); config_.numCfeConfigQueue = diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index 8a80439e9082..b5d4a2f670a9 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -69,7 +69,7 @@ public: CameraConfiguration::Status platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const override; - int platformPipelineConfigure(const std::unique_ptr &root) override; + int platformPipelineConfigure(const std::unique_ptr &root) override; void platformStart() override; void platformStop() override; @@ -498,7 +498,7 @@ CameraConfiguration::Status Vc4CameraData::platformValidate(RPi::RPiCameraConfig return status; } -int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr &root) +int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr &root) { config_ = { .minUnicamBuffers = 2, @@ -521,7 +521,7 @@ int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr & return -EINVAL; } - const YamlObject &phConfig = (*root)["pipeline_handler"]; + const ValueNode &phConfig = (*root)["pipeline_handler"]; config_.minUnicamBuffers = phConfig["min_unicam_buffers"].get(config_.minUnicamBuffers); config_.minTotalUnicamBuffers = diff --git a/src/libcamera/pipeline/virtual/README.md b/src/libcamera/pipeline/virtual/README.md index a9f39c15172b..0a02a9ea44b3 100644 --- a/src/libcamera/pipeline/virtual/README.md +++ b/src/libcamera/pipeline/virtual/README.md @@ -48,7 +48,7 @@ in Virtual Pipeline Handler. `parseConfigFile()` is exposed to use in Virtual Pipeline Handler. This is the procedure of the Parser class: -1. `parseConfigFile()` parses the config file to `YamlObject` using `YamlParser::parse()`. +1. `parseConfigFile()` parses the config file to `ValueNode` using `YamlParser::parse()`. - Parse the top level of config file which are the camera ids and look into each camera properties. 2. For each camera, `parseCameraConfigData()` returns a camera with the configuration. diff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp index fdc729509371..5169fd39bc38 100644 --- a/src/libcamera/pipeline/virtual/config_parser.cpp +++ b/src/libcamera/pipeline/virtual/config_parser.cpp @@ -29,7 +29,7 @@ ConfigParser::parseConfigFile(File &file, PipelineHandler *pipe) { std::vector> configurations; - std::unique_ptr cameras = YamlParser::parse(file); + std::unique_ptr cameras = YamlParser::parse(file); if (!cameras) { LOG(Virtual, Error) << "Failed to parse config file."; return configurations; @@ -72,7 +72,7 @@ ConfigParser::parseConfigFile(File &file, PipelineHandler *pipe) } std::unique_ptr -ConfigParser::parseCameraConfigData(const YamlObject &cameraConfigData, +ConfigParser::parseCameraConfigData(const ValueNode &cameraConfigData, PipelineHandler *pipe) { std::vector resolutions; @@ -94,13 +94,13 @@ ConfigParser::parseCameraConfigData(const YamlObject &cameraConfigData, return data; } -int ConfigParser::parseSupportedFormats(const YamlObject &cameraConfigData, +int ConfigParser::parseSupportedFormats(const ValueNode &cameraConfigData, std::vector *resolutions) { if (cameraConfigData.contains("supported_formats")) { - const YamlObject &supportedResolutions = cameraConfigData["supported_formats"]; + const ValueNode &supportedResolutions = cameraConfigData["supported_formats"]; - for (const YamlObject &supportedResolution : supportedResolutions.asList()) { + for (const ValueNode &supportedResolution : supportedResolutions.asList()) { unsigned int width = supportedResolution["width"].get(1920); unsigned int height = supportedResolution["height"].get(1080); if (width == 0 || height == 0) { @@ -152,7 +152,7 @@ int ConfigParser::parseSupportedFormats(const YamlObject &cameraConfigData, return 0; } -int ConfigParser::parseFrameGenerator(const YamlObject &cameraConfigData, VirtualCameraData *data) +int ConfigParser::parseFrameGenerator(const ValueNode &cameraConfigData, VirtualCameraData *data) { const std::string testPatternKey = "test_pattern"; const std::string framesKey = "frames"; @@ -178,7 +178,7 @@ int ConfigParser::parseFrameGenerator(const YamlObject &cameraConfigData, Virtua return 0; } - const YamlObject &frames = cameraConfigData[framesKey]; + const ValueNode &frames = cameraConfigData[framesKey]; /* When there is no frames provided in the config file, use color bar test pattern */ if (!frames) { @@ -231,7 +231,7 @@ int ConfigParser::parseFrameGenerator(const YamlObject &cameraConfigData, Virtua return 0; } -int ConfigParser::parseLocation(const YamlObject &cameraConfigData, VirtualCameraData *data) +int ConfigParser::parseLocation(const ValueNode &cameraConfigData, VirtualCameraData *data) { /* Default value is properties::CameraLocationFront */ int32_t location = properties::CameraLocationFront; @@ -252,7 +252,7 @@ int ConfigParser::parseLocation(const YamlObject &cameraConfigData, VirtualCamer return 0; } -int ConfigParser::parseModel(const YamlObject &cameraConfigData, VirtualCameraData *data) +int ConfigParser::parseModel(const ValueNode &cameraConfigData, VirtualCameraData *data) { std::string model = cameraConfigData["model"].get("Unknown"); diff --git a/src/libcamera/pipeline/virtual/config_parser.h b/src/libcamera/pipeline/virtual/config_parser.h index f696d8862897..97d6dffa31ec 100644 --- a/src/libcamera/pipeline/virtual/config_parser.h +++ b/src/libcamera/pipeline/virtual/config_parser.h @@ -13,7 +13,7 @@ #include #include "libcamera/internal/pipeline_handler.h" -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "virtual.h" @@ -27,13 +27,13 @@ public: private: std::unique_ptr - parseCameraConfigData(const YamlObject &cameraConfigData, PipelineHandler *pipe); + parseCameraConfigData(const ValueNode &cameraConfigData, PipelineHandler *pipe); - int parseSupportedFormats(const YamlObject &cameraConfigData, + int parseSupportedFormats(const ValueNode &cameraConfigData, std::vector *resolutions); - int parseFrameGenerator(const YamlObject &cameraConfigData, VirtualCameraData *data); - int parseLocation(const YamlObject &cameraConfigData, VirtualCameraData *data); - int parseModel(const YamlObject &cameraConfigData, VirtualCameraData *data); + int parseFrameGenerator(const ValueNode &cameraConfigData, VirtualCameraData *data); + int parseLocation(const ValueNode &cameraConfigData, VirtualCameraData *data); + int parseModel(const ValueNode &cameraConfigData, VirtualCameraData *data); }; } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp index b032db54ded4..90f2110ade8c 100644 --- a/src/libcamera/pipeline/virtual/virtual.cpp +++ b/src/libcamera/pipeline/virtual/virtual.cpp @@ -36,7 +36,7 @@ #include "libcamera/internal/framebuffer.h" #include "libcamera/internal/pipeline_handler.h" #include "libcamera/internal/request.h" -#include "libcamera/internal/yaml_object.h" +#include "libcamera/internal/value_node.h" #include "pipeline/virtual/config_parser.h" diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp new file mode 100644 index 000000000000..7374e7bdde8c --- /dev/null +++ b/src/libcamera/value_node.cpp @@ -0,0 +1,484 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Google Inc. + * Copyright (C) 2025, Ideas on Board. + * + * Data structure to manage tree of values + */ + +#include "libcamera/internal/value_node.h" + +#include +#include +#include +#include + +#include + +/** + * \file value_node.h + * \brief Data structure to manage tree of values + */ + +namespace libcamera { + +namespace { + +/* Empty static ValueNode as a safe result for invalid operations */ +static const ValueNode empty; + +} /* namespace */ + +/** + * \class ValueNode + * \brief A class representing a tree structure of values + * + * The ValueNode class is designed to model a tree of values. Each node in the + * tree is represented by a ValueNode instance. Intermediate nodes store + * children either as an ordered list (sequence) or a string-indexed dictionary + * (mapping). Leaf nodes can be empty or store a string value. + */ + +ValueNode::ValueNode() + : type_(Type::Empty) +{ +} + +ValueNode::~ValueNode() = default; + +/** + * \fn ValueNode::isValue() + * \brief Return whether the ValueNode is a value + * + * \return True if the ValueNode is a value, false otherwise + */ + +/** + * \fn ValueNode::isList() + * \brief Return whether the ValueNode is a list + * + * \return True if the ValueNode is a list, false otherwise + */ + +/** + * \fn ValueNode::isDictionary() + * \brief Return whether the ValueNode is a dictionary + * + * \return True if the ValueNode is a dictionary, false otherwise + */ + +/** + * \fn ValueNode::isEmpty() + * \brief Return whether the ValueNode is an empty + * + * \return True if the ValueNode is empty, false otherwise + */ + +/** + * \fn ValueNode::operator bool() + * \brief Return whether the ValueNode is a non-empty + * + * \return False if the ValueNode is empty, true otherwise + */ + +/** + * \fn ValueNode::size() + * \brief Retrieve the number of elements in a dictionary or list ValueNode + * + * This function retrieves the size of the ValueNode, defined as the number of + * child elements it contains. Only ValueNode instances of Dictionary or List + * types have a size, calling this function on other types of instances is + * invalid and results in undefined behaviour. + * + * \return The size of the ValueNode + */ +std::size_t ValueNode::size() const +{ + switch (type_) { + case Type::Dictionary: + case Type::List: + return list_.size(); + default: + return 0; + } +} + +/** + * \fn template ValueNode::get() const + * \brief Parse the ValueNode as a \a T value + * \tparam T Type of the value + * + * This function parses the value of the ValueNode as a \a T object, and + * returns the value. If parsing fails (usually because the ValueNode doesn't + * store a \a T value), std::nullopt is returned. + * + * If the type \a T is an std::vector, the ValueNode will be parsed as a list + * of values. + * + * \return The ValueNode value, or std::nullopt if parsing failed + */ + +/** + * \fn template ValueNode::get(U &&defaultValue) const + * \brief Parse the ValueNode as a \a T value + * \tparam T Type of the value + * \tparam U Type of the default value + * \param[in] defaultValue The default value when failing to parse + * + * This function parses the value of the ValueNode as a \a T object, and + * returns the value. If parsing fails (usually because the ValueNode doesn't + * store a \a T value), the \a defaultValue is returned. Type \a U must be + * convertible to type \a T. + * + * Unlike the get() function, this overload does not support std::vector for the + * type \a T. + * + * \return The ValueNode value, or \a defaultValue if parsing failed + */ + +/** + * \fn template ValueNode::set(T &&value) + * \brief Set the value of a ValueNode + * \tparam T Type of the value + * \param[in] value The value + * + * This function sets the value stored in a ValueNode to \a value. The value is + * converted to a string in an implementation-specific way that guarantees that + * subsequent calls to get() will return the same value. + * + * Values can only be set on ValueNode of Type::Value type or empty ValueNode. + * Attempting to set a value on a node of type Type::Dict or Type::List does not + * modify the ValueNode. + */ + +#ifndef __DOXYGEN__ + +template<> +std::optional +ValueNode::Accessor::get(const ValueNode &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + if (obj.value_ == "true") + return true; + else if (obj.value_ == "false") + return false; + + return std::nullopt; +} + +template<> +void ValueNode::Accessor::set(ValueNode &obj, bool value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = value ? "true" : "false"; +} + +template +struct ValueNode::Accessor || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> +{ + std::optional get(const ValueNode &obj) const + { + if (obj.type_ != Type::Value) + return std::nullopt; + + const std::string &str = obj.value_; + T value; + + auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), + value); + if (ptr != str.data() + str.size() || ec != std::errc()) + return std::nullopt; + + return value; + } + + void set(ValueNode &obj, T value) + { + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::to_string(value); + } +}; + +template struct ValueNode::Accessor; +template struct ValueNode::Accessor; +template struct ValueNode::Accessor; +template struct ValueNode::Accessor; +template struct ValueNode::Accessor; +template struct ValueNode::Accessor; + +template<> +std::optional +ValueNode::Accessor::get(const ValueNode &obj) const +{ + return obj.get(); +} + +template<> +void ValueNode::Accessor::set(ValueNode &obj, float value) +{ + obj.set(std::forward(value)); +} + +template<> +std::optional +ValueNode::Accessor::get(const ValueNode &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + if (obj.value_.empty()) + return std::nullopt; + + char *end; + + errno = 0; + double value = utils::strtod(obj.value_.c_str(), &end); + + if ('\0' != *end || errno == ERANGE) + return std::nullopt; + + return value; +} + +template<> +void ValueNode::Accessor::set(ValueNode &obj, double value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::to_string(value); +} + +template<> +std::optional +ValueNode::Accessor::get(const ValueNode &obj) const +{ + if (obj.type_ != Type::Value) + return std::nullopt; + + return obj.value_; +} + +template<> +void ValueNode::Accessor::set(ValueNode &obj, std::string value) +{ + if (obj.type_ != Type::Empty && obj.type_ != Type::Value) + return; + + obj.type_ = Type::Value; + obj.value_ = std::move(value); +} + +template +struct ValueNode::Accessor, std::enable_if_t< + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v>> +{ + std::optional> get(const ValueNode &obj) const + { + if (obj.type_ != Type::List) + return std::nullopt; + + std::vector values; + values.reserve(obj.list_.size()); + + for (const ValueNode &entry : obj.asList()) { + const auto value = entry.get(); + if (!value) + return std::nullopt; + values.emplace_back(*value); + } + + return values; + } +}; + +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +template struct ValueNode::Accessor>; +#endif /* __DOXYGEN__ */ + +/** + * \fn ValueNode::asDict() const + * \brief Wrap a dictionary ValueNode in an adapter that exposes iterators + * + * The ValueNode class doesn't directly implement iterators, as the iterator + * type depends on whether the node is a Dictionary or List. This function wraps + * a ValueNode of Dictionary type into an adapter that exposes iterators, as + * well as begin() and end() functions, allowing usage of range-based for loops + * with ValueNode. As mappings are not ordered, the iteration order is not + * specified. + * + * The iterator's value_type is a + * std::pair. + * + * If the ValueNode is not of Dictionary type, the returned adapter operates + * as an empty container. + * + * \return An adapter of unspecified type compatible with range-based for loops + */ + +/** + * \fn ValueNode::asList() const + * \brief Wrap a list ValueNode in an adapter that exposes iterators + * + * The ValueNode class doesn't directly implement iterators, as the iterator + * type depends on whether the node is a Dictionary or List. This function wraps + * a ValueNode of List type into an adapter that exposes iterators, as well as + * begin() and end() functions, allowing usage of range-based for loops with + * ValueNode. As lists are ordered, the iteration order is matches the order in + * which child nodes have been added. + * + * The iterator's value_type is a const ValueNode &. + * + * If the ValueNode is not of List type, the returned adapter operates as an + * empty container. + * + * \return An adapter of unspecified type compatible with range-based for loops + */ + +/** + * \brief Retrieve the element from list ValueNode by index + * \param[in] index The element index + * + * This function retrieves an element of the ValueNode. Only ValueNode + * instances of List type associate elements with index, calling this function + * on other types of instances or with an invalid index results in an empty + * node. + * + * \return The ValueNode as an element of the list + */ +const ValueNode &ValueNode::operator[](std::size_t index) const +{ + if (type_ != Type::List || index >= size()) + return empty; + + return *list_[index].value; +} + +/** + * \brief Check if an element of a dictionary exists + * \param[in] key The element key + * + * This function check if the ValueNode contains an element for the given \a + * key. Only ValueNode instances of Dictionary type associate elements with + * keys, calling this function on other types of instances is invalid and + * results in undefined behaviour. + * + * \return True if an element exists, false otherwise + */ +bool ValueNode::contains(std::string_view key) const +{ + return dictionary_.find(key) != dictionary_.end(); +} + +/** + * \brief Retrieve a member by key from the dictionary + * \param[in] key The element key + * + * This function retrieves a member of a ValueNode by \a key. Only ValueNode + * instances of Dictionary type associate elements with keys, calling this + * function on other types of instances or with a nonexistent key results in an + * empty node. + * + * \return The ValueNode corresponding to the \a key member + */ +const ValueNode &ValueNode::operator[](std::string_view key) const +{ + if (type_ != Type::Dictionary) + return empty; + + auto iter = dictionary_.find(key); + if (iter == dictionary_.end()) + return empty; + + return *iter->second; +} + +/** + * \brief Add a child node to a list + * \param[in] child The child node + * + * Append the \a child node as the last element of this node's children list. + * This node must be empty, in which case it is converted to the Type::List + * type, or be a list. Otherwise, the \a child is discarded and the function + * returns a nullptr. + * + * \return A pointer to the \a child node if successfully added, nullptr + * otherwise + */ +ValueNode *ValueNode::add(std::unique_ptr child) +{ + if (type_ == Type::Empty) + type_ = Type::List; + + if (type_ != Type::List) + return nullptr; + + Value &elem = list_.emplace_back(std::string{}, std::move(child)); + return elem.value.get(); +} + +/** + * \brief Add a child node to a dictionary + * \param[in] key The dictionary key + * \param[in] child The child node + * + * Add the \a child node with the given \a key to this node's children. This + * node must be empty, in which case it is converted to the Type::Dictionary + * type, or be a dictionary. Otherwise, the \a child is discarded and the + * function returns a nullptr. + * + * Keys are unique. If a child with the same \a key already exist, the \a child + * is discarded and the function returns a nullptr. + * + * \return A pointer to the \a child node if successfully added, nullptr + * otherwise + */ +ValueNode *ValueNode::add(std::string key, std::unique_ptr child) +{ + if (type_ == Type::Empty) + type_ = Type::Dictionary; + + if (type_ != Type::Dictionary) + return nullptr; + + if (dictionary_.find(key) != dictionary_.end()) + return nullptr; + + Value &elem = list_.emplace_back(std::move(key), std::move(child)); + dictionary_.emplace(elem.key, elem.value.get()); + return elem.value.get(); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/vector.cpp b/src/libcamera/vector.cpp index 4dad1b9001c5..86b9f9bb6d5e 100644 --- a/src/libcamera/vector.cpp +++ b/src/libcamera/vector.cpp @@ -337,7 +337,7 @@ LOG_DEFINE_CATEGORY(Vector) */ #ifndef __DOXYGEN__ -bool vectorValidateYaml(const YamlObject &obj, unsigned int size) +bool vectorValidateYaml(const ValueNode &obj, unsigned int size) { if (!obj.isList()) return false; diff --git a/src/libcamera/yaml_object.cpp b/src/libcamera/yaml_object.cpp deleted file mode 100644 index 4328ccbff8f1..000000000000 --- a/src/libcamera/yaml_object.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2022, Google Inc. - * Copyright (C) 2025, Ideas on Board. - * - * libcamera YAML object - */ - -#include "libcamera/internal/yaml_object.h" - -#include -#include -#include -#include - -#include - -/** - * \file yaml_object.h - * \brief YAML objects - */ - -namespace libcamera { - -namespace { - -/* Empty static YamlObject as a safe result for invalid operations */ -static const YamlObject empty; - -} /* namespace */ - -/** - * \class YamlObject - * \brief A class representing the tree structure of the YAML content - * - * The YamlObject class represents the tree structure of YAML content. A - * YamlObject can be empty, a dictionary or list of YamlObjects, or a value if a - * tree leaf. - */ - -YamlObject::YamlObject() - : type_(Type::Empty) -{ -} - -YamlObject::~YamlObject() = default; - -/** - * \fn YamlObject::isValue() - * \brief Return whether the YamlObject is a value - * - * \return True if the YamlObject is a value, false otherwise - */ - -/** - * \fn YamlObject::isList() - * \brief Return whether the YamlObject is a list - * - * \return True if the YamlObject is a list, false otherwise - */ - -/** - * \fn YamlObject::isDictionary() - * \brief Return whether the YamlObject is a dictionary - * - * \return True if the YamlObject is a dictionary, false otherwise - */ - -/** - * \fn YamlObject::isEmpty() - * \brief Return whether the YamlObject is an empty - * - * \return True if the YamlObject is empty, false otherwise - */ - -/** - * \fn YamlObject::operator bool() - * \brief Return whether the YamlObject is a non-empty - * - * \return False if the YamlObject is empty, true otherwise - */ - -/** - * \brief Retrieve the number of elements in a dictionary or list YamlObject - * - * This function retrieves the size of the YamlObject, defined as the number of - * child elements it contains. Only YamlObject instances of Dictionary or List - * types have a size, calling this function on other types of instances is - * invalid and results in undefined behaviour. - * - * \return The size of the YamlObject - */ -std::size_t YamlObject::size() const -{ - switch (type_) { - case Type::Dictionary: - case Type::List: - return list_.size(); - default: - return 0; - } -} - -/** - * \fn template YamlObject::get() const - * \brief Parse the YamlObject as a \a T value - * \tparam T Type of the value - * - * This function parses the value of the YamlObject as a \a T object, and - * returns the value. If parsing fails (usually because the YamlObject doesn't - * store a \a T value), std::nullopt is returned. - * - * If the type \a T is an std::vector, the YamlObject will be parsed as a list - * of values. - * - * \return The YamlObject value, or std::nullopt if parsing failed - */ - -/** - * \fn template YamlObject::get(U &&defaultValue) const - * \brief Parse the YamlObject as a \a T value - * \tparam T Type of the value - * \tparam U Type of the default value - * \param[in] defaultValue The default value when failing to parse - * - * This function parses the value of the YamlObject as a \a T object, and - * returns the value. If parsing fails (usually because the YamlObject doesn't - * store a \a T value), the \a defaultValue is returned. Type \a U must be - * convertible to type \a T. - * - * Unlike the get() function, this overload does not support std::vector for the - * type \a T. - * - * \return The YamlObject value, or \a defaultValue if parsing failed - */ - -/** - * \fn template YamlObject::set(T &&value) - * \brief Set the value of a YamlObject - * \tparam T Type of the value - * \param[in] value The value - * - * This function sets the value stored in a YamlObject to \a value. The value is - * converted to a string in an implementation-specific way that guarantees that - * subsequent calls to get() will return the same value. - * - * Values can only be set on YamlObject of Type::Value type or empty YamlObject. - * Attempting to set a value on an object of type Type::Dict or Type::List does - * not modify the YamlObject. - */ - -#ifndef __DOXYGEN__ - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - if (obj.value_ == "true") - return true; - else if (obj.value_ == "false") - return false; - - return std::nullopt; -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, bool value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = value ? "true" : "false"; -} - -template -struct YamlObject::Accessor || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v>> -{ - std::optional get(const YamlObject &obj) const - { - if (obj.type_ != Type::Value) - return std::nullopt; - - const std::string &str = obj.value_; - T value; - - auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), - value); - if (ptr != str.data() + str.size() || ec != std::errc()) - return std::nullopt; - - return value; - } - - void set(YamlObject &obj, T value) - { - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::to_string(value); - } -}; - -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; -template struct YamlObject::Accessor; - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - return obj.get(); -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, float value) -{ - obj.set(std::forward(value)); -} - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - if (obj.value_.empty()) - return std::nullopt; - - char *end; - - errno = 0; - double value = utils::strtod(obj.value_.c_str(), &end); - - if ('\0' != *end || errno == ERANGE) - return std::nullopt; - - return value; -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, double value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::to_string(value); -} - -template<> -std::optional -YamlObject::Accessor::get(const YamlObject &obj) const -{ - if (obj.type_ != Type::Value) - return std::nullopt; - - return obj.value_; -} - -template<> -void YamlObject::Accessor::set(YamlObject &obj, std::string value) -{ - if (obj.type_ != Type::Empty && obj.type_ != Type::Value) - return; - - obj.type_ = Type::Value; - obj.value_ = std::move(value); -} - -template -struct YamlObject::Accessor, std::enable_if_t< - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v>> -{ - std::optional> get(const YamlObject &obj) const - { - if (obj.type_ != Type::List) - return std::nullopt; - - std::vector values; - values.reserve(obj.list_.size()); - - for (const YamlObject &entry : obj.asList()) { - const auto value = entry.get(); - if (!value) - return std::nullopt; - values.emplace_back(*value); - } - - return values; - } -}; - -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -template struct YamlObject::Accessor>; -#endif /* __DOXYGEN__ */ - -/** - * \fn YamlObject::asDict() const - * \brief Wrap a dictionary YamlObject in an adapter that exposes iterators - * - * The YamlObject class doesn't directly implement iterators, as the iterator - * type depends on whether the object is a Dictionary or List. This function - * wraps a YamlObject of Dictionary type into an adapter that exposes - * iterators, as well as begin() and end() functions, allowing usage of - * range-based for loops with YamlObject. As YAML mappings are not ordered, the - * iteration order is not specified. - * - * The iterator's value_type is a - * std::pair. - * - * If the YamlObject is not of Dictionary type, the returned adapter operates - * as an empty container. - * - * \return An adapter of unspecified type compatible with range-based for loops - */ - -/** - * \fn YamlObject::asList() const - * \brief Wrap a list YamlObject in an adapter that exposes iterators - * - * The YamlObject class doesn't directly implement iterators, as the iterator - * type depends on whether the object is a Dictionary or List. This function - * wraps a YamlObject of List type into an adapter that exposes iterators, as - * well as begin() and end() functions, allowing usage of range-based for loops - * with YamlObject. As YAML lists are ordered, the iteration order is identical - * to the list order in the YAML data. - * - * The iterator's value_type is a const YamlObject &. - * - * If the YamlObject is not of List type, the returned adapter operates as an - * empty container. - * - * \return An adapter of unspecified type compatible with range-based for loops - */ - -/** - * \brief Retrieve the element from list YamlObject by index - * \param[in] index The element index - * - * This function retrieves an element of the YamlObject. Only YamlObject - * instances of List type associate elements with index, calling this function - * on other types of instances or with an invalid index results in an empty - * object. - * - * \return The YamlObject as an element of the list - */ -const YamlObject &YamlObject::operator[](std::size_t index) const -{ - if (type_ != Type::List || index >= size()) - return empty; - - return *list_[index].value; -} - -/** - * \brief Check if an element of a dictionary exists - * \param[in] key The element key - * - * This function check if the YamlObject contains an element for the given \a - * key. Only YamlObject instances of Dictionary type associate elements with - * keys, calling this function on other types of instances is invalid and - * results in undefined behaviour. - * - * \return True if an element exists, false otherwise - */ -bool YamlObject::contains(std::string_view key) const -{ - return dictionary_.find(key) != dictionary_.end(); -} - -/** - * \brief Retrieve a member by key from the dictionary - * \param[in] key The element key - * - * This function retrieves a member of a YamlObject by \a key. Only YamlObject - * instances of Dictionary type associate elements with keys, calling this - * function on other types of instances or with a nonexistent key results in an - * empty object. - * - * \return The YamlObject corresponding to the \a key member - */ -const YamlObject &YamlObject::operator[](std::string_view key) const -{ - if (type_ != Type::Dictionary) - return empty; - - auto iter = dictionary_.find(key); - if (iter == dictionary_.end()) - return empty; - - return *iter->second; -} - -/** - * \brief Add a child object to a list - * \param[in] child The child object - * - * Append the \a child node as the last element of this node's children list. - * This node must be empty, in which case it is converted to the Type::List - * type, or be a list. Otherwise, the \a child is discarded and the function - * returns a nullptr. - * - * \return The child object if successfully added, nullptr otherwise - */ -YamlObject *YamlObject::add(std::unique_ptr child) -{ - if (type_ == Type::Empty) - type_ = Type::List; - - if (type_ != Type::List) - return nullptr; - - Value &elem = list_.emplace_back(std::string{}, std::move(child)); - return elem.value.get(); -} - -/** - * \brief Add a child object to a dictionary - * \param[in] key The dictionary key - * \param[in] child The child object - * - * Add the \a child node with the given \a key to this node's children. This - * node must be empty, in which case it is converted to the Type::Dictionary - * type, or be a dictionary. Otherwise, the \a child is discarded and the - * function returns a nullptr. - * - * Keys are unique. If a child with the same \a key already exist, the \a child - * is discarded and the function returns a nullptr. - * - * \return The child object if successfully added, nullptr otherwise - */ -YamlObject *YamlObject::add(std::string key, std::unique_ptr child) -{ - if (type_ == Type::Empty) - type_ = Type::Dictionary; - - if (type_ != Type::Dictionary) - return nullptr; - - if (dictionary_.find(key) != dictionary_.end()) - return nullptr; - - Value &elem = list_.emplace_back(std::move(key), std::move(child)); - dictionary_.emplace(elem.key, elem.value.get()); - return elem.value.get(); -} - -} /* namespace libcamera */ diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index d83df0fb9597..b44818319845 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -35,7 +35,7 @@ public: ~YamlParserContext(); int init(File &file); - int parseContent(YamlObject &yamlObject); + int parseContent(ValueNode &valueNode); private: struct EventDeleter { @@ -55,7 +55,7 @@ private: std::string readValue(EventPtr event); int parseDictionaryOrList(yaml_event_type_t endEventType, const std::function &parseItem); - int parseNextYamlObject(YamlObject &yamlObject, EventPtr event); + int parseNextNode(ValueNode &valueNode, EventPtr event); bool parserValid_; yaml_parser_t parser_; @@ -153,15 +153,15 @@ YamlParserContext::EventPtr YamlParserContext::nextEvent() /** * \brief Parse the content of a YAML document - * \param[in] yamlObject The result of YamlObject + * \param[in] valueNode The result of ValueNode * * Check YAML start and end events of a YAML document, and parse the root object - * of the YAML document into a YamlObject. + * of the YAML document into a ValueNode. * * \return 0 on success or a negative error code otherwise * \retval -EINVAL The parser has failed to validate end of a YAML file */ -int YamlParserContext::parseContent(YamlObject &yamlObject) +int YamlParserContext::parseContent(ValueNode &valueNode) { /* Check start of the YAML file. */ EventPtr event = nextEvent(); @@ -174,7 +174,7 @@ int YamlParserContext::parseContent(YamlObject &yamlObject) /* Parse the root object. */ event = nextEvent(); - if (parseNextYamlObject(yamlObject, std::move(event))) + if (parseNextNode(valueNode, std::move(event))) return -EINVAL; /* Check end of the YAML file. */ @@ -247,8 +247,8 @@ int YamlParserContext::parseDictionaryOrList(yaml_event_type_t endEventType, } /** - * \brief Parse next YAML event and read it as a YamlObject - * \param[in] yamlObject The result of YamlObject + * \brief Parse next YAML event and read it as a ValueNode + * \param[in] valueNode The result of ValueNode * \param[in] event The leading event of the object * * Parse next YAML object separately as a value, list or dictionary. @@ -256,26 +256,26 @@ int YamlParserContext::parseDictionaryOrList(yaml_event_type_t endEventType, * \return 0 on success or a negative error code otherwise * \retval -EINVAL Fail to parse the YAML file. */ -int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr event) +int YamlParserContext::parseNextNode(ValueNode &valueNode, EventPtr event) { if (!event) return -EINVAL; switch (event->type) { case YAML_SCALAR_EVENT: - yamlObject.set(readValue(std::move(event))); + valueNode.set(readValue(std::move(event))); return 0; case YAML_SEQUENCE_START_EVENT: { - auto handler = [this, &yamlObject](EventPtr evt) { - YamlObject *child = yamlObject.add(std::make_unique()); - return parseNextYamlObject(*child, std::move(evt)); + auto handler = [this, &valueNode](EventPtr evt) { + ValueNode *child = valueNode.add(std::make_unique()); + return parseNextNode(*child, std::move(evt)); }; return parseDictionaryOrList(YAML_SEQUENCE_END_EVENT, handler); } case YAML_MAPPING_START_EVENT: { - auto handler = [this, &yamlObject](EventPtr evtKey) { + auto handler = [this, &valueNode](EventPtr evtKey) { /* Parse key */ if (evtKey->type != YAML_SCALAR_EVENT) { LOG(YamlParser, Error) << "Expect key at line: " @@ -292,9 +292,9 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even if (!evtValue) return -EINVAL; - YamlObject *child = yamlObject.add(std::move(key), - std::make_unique()); - return parseNextYamlObject(*child, std::move(evtValue)); + ValueNode *child = valueNode.add(std::move(key), + std::make_unique()); + return parseNextNode(*child, std::move(evtValue)); }; int ret = parseDictionaryOrList(YAML_MAPPING_END_EVENT, handler); if (ret) @@ -316,7 +316,7 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even * \brief A helper class for parsing a YAML file * * The YamlParser class provides an easy interface to parse the contents of a - * YAML file into a tree of YamlObject instances. + * YAML file into a tree of ValueNode instances. * * Example usage: * @@ -334,17 +334,17 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even * * \code{.cpp} * - * std::unique_ptr root = YamlParser::parse(fh); + * std::unique_ptr root = YamlParser::parse(fh); * if (!root) * return; * * if (!root->isDictionary()) * return; * - * const YamlObject &name = (*root)["name"]; + * const ValueNode &name = (*root)["name"]; * std::cout << name.get("") << std::endl; * - * const YamlObject &numbers = (*root)["numbers"]; + * const ValueNode &numbers = (*root)["numbers"]; * if (!numbers.isList()) * return; * @@ -354,7 +354,7 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even * \endcode * * The YamlParser::parse() function takes an open FILE, parses its contents, and - * returns a pointer to a YamlObject corresponding to the root node of the YAML + * returns a pointer to a ValueNode corresponding to the root node of the YAML * document. * * The parser preserves the order of items in the YAML file, for both lists and @@ -362,23 +362,23 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even */ /** - * \brief Parse a YAML file as a YamlObject + * \brief Parse a YAML file as a ValueNode * \param[in] file The YAML file to parse * * The YamlParser::parse() function takes a file, parses its contents, and - * returns a pointer to a YamlObject corresponding to the root node of the YAML + * returns a pointer to a ValueNode corresponding to the root node of the YAML * document. * - * \return Pointer to result YamlObject on success or nullptr otherwise + * \return Pointer to result ValueNode on success or nullptr otherwise */ -std::unique_ptr YamlParser::parse(File &file) +std::unique_ptr YamlParser::parse(File &file) { YamlParserContext context; if (context.init(file)) return nullptr; - std::unique_ptr root = std::make_unique(); + std::unique_ptr root = std::make_unique(); if (context.parseContent(*root)) { LOG(YamlParser, Error) diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp index 01e734d23059..8c5826f4885b 100644 --- a/test/yaml-parser.cpp +++ b/test/yaml-parser.cpp @@ -94,7 +94,7 @@ protected: Dictionary, }; - int testObjectType(const YamlObject &obj, const char *name, Type type) + int testObjectType(const ValueNode &obj, const char *name, Type type) { bool isList = type == Type::List || type == Type::Size; bool isScalar = !isList && type != Type::Dictionary; @@ -194,7 +194,7 @@ protected: return TestPass; } - int testIntegerObject(const YamlObject &obj, const char *name, Type type, + int testIntegerObject(const ValueNode &obj, const char *name, Type type, int64_t value) { uint64_t unsignedValue = static_cast(value); @@ -292,7 +292,7 @@ protected: return TestFail; } - std::unique_ptr root = YamlParser::parse(file); + std::unique_ptr root = YamlParser::parse(file); if (root) { cerr << "Invalid YAML file parse successfully" << std::endl; return TestFail; From patchwork Tue Jan 13 00:07:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25740 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 175D5C3284 for ; Tue, 13 Jan 2026 00:09:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 94CF761FF7; Tue, 13 Jan 2026 01:09:04 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="coEqiA28"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BCF4B61FC8 for ; Tue, 13 Jan 2026 01:09:02 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 1777766B for ; Tue, 13 Jan 2026 01:08:37 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262917; bh=N+SQTlzT52P3/T/dWz/8VUAWdOXbf87LopEJX+BEAls=; h=From:To:Subject:Date:In-Reply-To:References:From; b=coEqiA28kGsOUEYlhqLDHXGnRXETxQ/NVRPj1wYypOWxUiklkgjBtL2N/XJYEPX01 efOCIus4ZQE1HMmP8Akl5FKphS0hPu/NoRo43XJzwm8+nafTo2rGFkDqbYZZgnUwoN wewzAfINqpQqzJOgxpJ0OqUJlBEqWISRAQEKjWXo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 20/36] libcamera: Pass CameraManager around instead of GlobalConfiguration Date: Tue, 13 Jan 2026 02:07:52 +0200 Message-ID: <20260113000808.15395-21-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The GlobalConfiguration is explicitly passed around through constructors of various objects that need access to the configuration. This ad-hoc solution works for the specific use cases it was meant to support, but isn't very generic. We have a top-level object in libcamera, the CameraManager, that also needs to be accessed from various locations and is passed to object constructors. Standardize on passing the CameraManager everywhere, and access the global configuration through it. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/ipa_manager.h | 10 +++++----- include/libcamera/internal/ipa_proxy.h | 4 ++-- .../libcamera/internal/software_isp/benchmark.h | 6 +++--- .../internal/software_isp/swstats_cpu.h | 6 +++--- src/libcamera/camera_manager.cpp | 3 ++- src/libcamera/ipa_manager.cpp | 7 +++++-- src/libcamera/ipa_proxy.cpp | 16 +++++++++++----- src/libcamera/software_isp/benchmark.cpp | 7 ++++++- src/libcamera/software_isp/debayer.cpp | 13 ++++++------- src/libcamera/software_isp/debayer.h | 4 ++-- src/libcamera/software_isp/debayer_cpu.cpp | 7 ++++--- src/libcamera/software_isp/debayer_cpu.h | 3 ++- src/libcamera/software_isp/debayer_egl.cpp | 7 +++---- src/libcamera/software_isp/debayer_egl.h | 4 +++- src/libcamera/software_isp/software_isp.cpp | 9 +++++---- src/libcamera/software_isp/swstats_cpu.cpp | 8 ++++---- test/ipa/ipa_interface_test.cpp | 5 +---- .../module_ipa_proxy.cpp.tmpl | 8 ++++---- .../libcamera_templates/module_ipa_proxy.h.tmpl | 4 ++-- 19 files changed, 73 insertions(+), 58 deletions(-) diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h index ecb6ae896e0c..aaa3ca37c493 100644 --- a/include/libcamera/internal/ipa_manager.h +++ b/include/libcamera/internal/ipa_manager.h @@ -16,13 +16,13 @@ #include #include -#include "libcamera/internal/camera_manager.h" #include "libcamera/internal/pub_key.h" namespace libcamera { LOG_DECLARE_CATEGORY(IPAManager) +class CameraManager; class GlobalConfiguration; class IPAModule; class PipelineHandler; @@ -30,7 +30,7 @@ class PipelineHandler; class IPAManager { public: - IPAManager(const GlobalConfiguration &configuration); + IPAManager(const CameraManager &cm); ~IPAManager(); template @@ -43,9 +43,9 @@ public: auto proxy = [&]() -> std::unique_ptr { if (isSignatureValid(m)) - return std::make_unique(m, configuration_); + return std::make_unique(m, cm_); else - return std::make_unique(m, configuration_); + return std::make_unique(m, cm_); }(); if (!proxy->isValid()) { @@ -73,7 +73,7 @@ private: bool isSignatureValid(IPAModule *ipa) const; - const GlobalConfiguration &configuration_; + const CameraManager &cm_; std::vector> modules_; #if HAVE_IPA_PUBKEY diff --git a/include/libcamera/internal/ipa_proxy.h b/include/libcamera/internal/ipa_proxy.h index f1865d67e8d3..723978426950 100644 --- a/include/libcamera/internal/ipa_proxy.h +++ b/include/libcamera/internal/ipa_proxy.h @@ -13,7 +13,7 @@ #include -#include "libcamera/internal/global_configuration.h" +#include "libcamera/internal/camera_manager.h" namespace libcamera { @@ -28,7 +28,7 @@ public: ProxyRunning, }; - IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration); + IPAProxy(IPAModule *ipam, const CameraManager &cm); ~IPAProxy(); bool isValid() const { return valid_; } diff --git a/include/libcamera/internal/software_isp/benchmark.h b/include/libcamera/internal/software_isp/benchmark.h index 0680d6cd9595..29980ef0712f 100644 --- a/include/libcamera/internal/software_isp/benchmark.h +++ b/include/libcamera/internal/software_isp/benchmark.h @@ -12,15 +12,15 @@ #include #include -#include -#include "libcamera/internal/global_configuration.h" namespace libcamera { +class CameraManager; + class Benchmark { public: - Benchmark(const GlobalConfiguration &configuration); + Benchmark(const CameraManager &cm); ~Benchmark(); void startFrame(void); diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h index 64b3e23f5bf9..0ef50caf4c6b 100644 --- a/include/libcamera/internal/software_isp/swstats_cpu.h +++ b/include/libcamera/internal/software_isp/swstats_cpu.h @@ -19,7 +19,6 @@ #include "libcamera/internal/bayer_format.h" #include "libcamera/internal/framebuffer.h" -#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/shared_mem_object.h" #include "libcamera/internal/software_isp/swisp_stats.h" @@ -27,14 +26,15 @@ namespace libcamera { -class PixelFormat; +class CameraManager; class MappedFrameBuffer; +class PixelFormat; struct StreamConfiguration; class SwStatsCpu { public: - SwStatsCpu(const GlobalConfiguration &configuration); + SwStatsCpu(const CameraManager &cm); ~SwStatsCpu() = default; /* diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 5762c210ffc2..f774bd84291b 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -93,7 +93,8 @@ void CameraManager::Private::run() int CameraManager::Private::init() { - ipaManager_ = std::make_unique(configuration()); + CameraManager *const o = LIBCAMERA_O_PTR(); + ipaManager_ = std::make_unique(*o); enumerator_ = DeviceEnumerator::create(); if (!enumerator_ || enumerator_->enumerate()) diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 1e905e8b82e8..dd1f483beec3 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -100,13 +100,16 @@ LOG_DEFINE_CATEGORY(IPAManager) /** * \brief Construct an IPAManager instance + * \param[in] cm The camera manager * * The IPAManager class is meant to only be instantiated once, by the * CameraManager. */ -IPAManager::IPAManager(const GlobalConfiguration &configuration) - : configuration_(configuration) +IPAManager::IPAManager(const CameraManager &cm) + : cm_(cm) { + const GlobalConfiguration &configuration = cm._d()->configuration(); + #if HAVE_IPA_PUBKEY if (!pubKey_.isValid()) LOG(IPAManager, Warning) << "Public key not valid"; diff --git a/src/libcamera/ipa_proxy.cpp b/src/libcamera/ipa_proxy.cpp index a3ccfa6035e1..6c8780a012d5 100644 --- a/src/libcamera/ipa_proxy.cpp +++ b/src/libcamera/ipa_proxy.cpp @@ -117,13 +117,19 @@ std::string ipaConfigurationFile(const std::string &ipaName, const std::string & /** * \brief Construct an IPAProxy instance * \param[in] ipam The IPA module - * \param[in] configuration The global configuration + * \param[in] cm The camera manager */ -IPAProxy::IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration) - : valid_(false), state_(ProxyStopped), ipam_(ipam), - configPaths_(configuration.envListOption("LIBCAMERA_IPA_CONFIG_PATH", { "ipa", "config_paths" }).value_or(std::vector())), - execPaths_(configuration.envListOption("LIBCAMERA_IPA_PROXY_PATH", { "ipa", "proxy_paths" }).value_or(std::vector())) +IPAProxy::IPAProxy(IPAModule *ipam, const CameraManager &cm) + : valid_(false), state_(ProxyStopped), ipam_(ipam) { + const GlobalConfiguration &configuration = cm._d()->configuration(); + + configPaths_ = configuration.envListOption("LIBCAMERA_IPA_CONFIG_PATH", + { "ipa", "config_paths" }) + .value_or(std::vector()); + execPaths_ = configuration.envListOption("LIBCAMERA_IPA_PROXY_PATH", + { "ipa", "proxy_paths" }) + .value_or(std::vector()); } IPAProxy::~IPAProxy() diff --git a/src/libcamera/software_isp/benchmark.cpp b/src/libcamera/software_isp/benchmark.cpp index 1a00ae569aab..b15ddd66e26f 100644 --- a/src/libcamera/software_isp/benchmark.cpp +++ b/src/libcamera/software_isp/benchmark.cpp @@ -12,6 +12,9 @@ #include +#include "libcamera/internal/camera_manager.h" +#include "libcamera/internal/global_configuration.h" + namespace libcamera { LOG_DEFINE_CATEGORY(Benchmark) @@ -26,8 +29,10 @@ LOG_DEFINE_CATEGORY(Benchmark) /** * \brief Constructs a Benchmark object */ -Benchmark::Benchmark(const GlobalConfiguration &configuration) +Benchmark::Benchmark(const CameraManager &cm) { + const GlobalConfiguration &configuration = cm._d()->configuration(); + skipBeforeMeasure_ = configuration.option( { "software_isp", "measure", "skip" }) .value_or(skipBeforeMeasure_); diff --git a/src/libcamera/software_isp/debayer.cpp b/src/libcamera/software_isp/debayer.cpp index 65a1762ddc35..edd0edda82be 100644 --- a/src/libcamera/software_isp/debayer.cpp +++ b/src/libcamera/software_isp/debayer.cpp @@ -18,12 +18,6 @@ namespace libcamera { * \brief Struct to hold the debayer parameters. */ -/** - * \fn Debayer::Debayer(const GlobalConfiguration &configuration) - * \brief Construct a Debayer object - * \param[in] configuration Global configuration reference - */ - /** * \var DebayerParams::kRGBLookupSize * \brief Size of a color lookup table @@ -129,7 +123,12 @@ namespace libcamera { LOG_DEFINE_CATEGORY(Debayer) -Debayer::Debayer(const GlobalConfiguration &configuration) : bench_(configuration) +/** + * \brief Construct a Debayer object + * \param[in] cm The camera manager + */ +Debayer::Debayer(const CameraManager &cm) + : bench_(cm) { /* Initialize color lookup tables */ for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) { diff --git a/src/libcamera/software_isp/debayer.h b/src/libcamera/software_isp/debayer.h index cd2db9930988..427758c812e6 100644 --- a/src/libcamera/software_isp/debayer.h +++ b/src/libcamera/software_isp/debayer.h @@ -22,12 +22,12 @@ #include "libcamera/internal/bayer_format.h" #include "libcamera/internal/dma_buf_allocator.h" -#include "libcamera/internal/global_configuration.h" #include "libcamera/internal/software_isp/benchmark.h" #include "libcamera/internal/software_isp/debayer_params.h" namespace libcamera { +class CameraManager; class FrameBuffer; LOG_DECLARE_CATEGORY(Debayer) @@ -35,7 +35,7 @@ LOG_DECLARE_CATEGORY(Debayer) class Debayer : public Object { public: - Debayer(const GlobalConfiguration &configuration); + Debayer(const CameraManager &cm); virtual ~Debayer() = 0; virtual int configure(const StreamConfiguration &inputCfg, diff --git a/src/libcamera/software_isp/debayer_cpu.cpp b/src/libcamera/software_isp/debayer_cpu.cpp index 00738c56b30e..556c2a062b92 100644 --- a/src/libcamera/software_isp/debayer_cpu.cpp +++ b/src/libcamera/software_isp/debayer_cpu.cpp @@ -38,10 +38,10 @@ namespace libcamera { /** * \brief Constructs a DebayerCpu object * \param[in] stats Pointer to the stats object to use - * \param[in] configuration The global configuration + * \param[in] cm The camera manager */ -DebayerCpu::DebayerCpu(std::unique_ptr stats, const GlobalConfiguration &configuration) - : Debayer(configuration), stats_(std::move(stats)) +DebayerCpu::DebayerCpu(std::unique_ptr stats, const CameraManager &cm) + : Debayer(cm), stats_(std::move(stats)) { /* * Reading from uncached buffers may be very slow. @@ -54,6 +54,7 @@ DebayerCpu::DebayerCpu(std::unique_ptr stats, const GlobalConfigurat * \todo Make memcpy automatic based on runtime detection of platform * capabilities. */ + const GlobalConfiguration &configuration = cm._d()->configuration(); enableInputMemcpy_ = configuration.option({ "software_isp", "copy_input_buffer" }).value_or(true); } diff --git a/src/libcamera/software_isp/debayer_cpu.h b/src/libcamera/software_isp/debayer_cpu.h index 67df2b93a0e6..d96c536c9022 100644 --- a/src/libcamera/software_isp/debayer_cpu.h +++ b/src/libcamera/software_isp/debayer_cpu.h @@ -18,6 +18,7 @@ #include #include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/camera_manager.h" #include "libcamera/internal/software_isp/swstats_cpu.h" #include "debayer.h" @@ -27,7 +28,7 @@ namespace libcamera { class DebayerCpu : public Debayer { public: - DebayerCpu(std::unique_ptr stats, const GlobalConfiguration &configuration); + DebayerCpu(std::unique_ptr stats, const CameraManager &cm); ~DebayerCpu(); int configure(const StreamConfiguration &inputCfg, diff --git a/src/libcamera/software_isp/debayer_egl.cpp b/src/libcamera/software_isp/debayer_egl.cpp index 8e089032371f..4a4db77cdc5b 100644 --- a/src/libcamera/software_isp/debayer_egl.cpp +++ b/src/libcamera/software_isp/debayer_egl.cpp @@ -29,13 +29,12 @@ namespace libcamera { */ /** - * \fn DebayerEGL::DebayerEGL(std::unique_ptr stats, const GlobalConfiguration &configuration) * \brief Construct a DebayerEGL object * \param[in] stats Statistics processing object - * \param[in] configuration Global configuration reference + * \param[in] cm The camera manager */ -DebayerEGL::DebayerEGL(std::unique_ptr stats, const GlobalConfiguration &configuration) - : Debayer(configuration), stats_(std::move(stats)) +DebayerEGL::DebayerEGL(std::unique_ptr stats, const CameraManager &cm) + : Debayer(cm), stats_(std::move(stats)) { } diff --git a/src/libcamera/software_isp/debayer_egl.h b/src/libcamera/software_isp/debayer_egl.h index a5033bc63a73..92782f80cd4c 100644 --- a/src/libcamera/software_isp/debayer_egl.h +++ b/src/libcamera/software_isp/debayer_egl.h @@ -35,10 +35,12 @@ namespace libcamera { #define DEBAYER_EGL_MIN_SIMPLE_RGB_GAIN_TEXTURE_UNITS 4 #define DEBAYER_OPENGL_COORDS 4 +class CameraManager; + class DebayerEGL : public Debayer { public: - DebayerEGL(std::unique_ptr stats, const GlobalConfiguration &configuration); + DebayerEGL(std::unique_ptr stats, const CameraManager &cm); ~DebayerEGL(); int configure(const StreamConfiguration &inputCfg, diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index aa62257340d8..d8ef69644e71 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -111,9 +111,9 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, return; } - const GlobalConfiguration &configuration = pipe->cameraManager()->_d()->configuration(); + const CameraManager &cm = *pipe->cameraManager(); - auto stats = std::make_unique(configuration); + auto stats = std::make_unique(cm); if (!stats->isValid()) { LOG(SoftwareIsp, Error) << "Failed to create SwStatsCpu object"; return; @@ -123,6 +123,7 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, bool gpuIspEnabled; #if HAVE_DEBAYER_EGL + const GlobalConfiguration &configuration = cm._d()->configuration(); std::optional softISPMode = configuration.envOption("LIBCAMERA_SOFTISP_MODE", { "software_isp", "mode" }); if (softISPMode) { if (softISPMode != "gpu" && softISPMode != "cpu") { @@ -133,12 +134,12 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, } if (!softISPMode || softISPMode == "gpu") { - debayer_ = std::make_unique(std::move(stats), configuration); + debayer_ = std::make_unique(std::move(stats), cm); gpuIspEnabled = true; } #endif if (!debayer_) { - debayer_ = std::make_unique(std::move(stats), configuration); + debayer_ = std::make_unique(std::move(stats), cm); gpuIspEnabled = false; } diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index c931edb412b4..cbcec40f323d 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -36,9 +36,9 @@ namespace libcamera { */ /** - * \fn SwStatsCpu::SwStatsCpu(const GlobalConfiguration &configuration) + * \fn SwStatsCpu::SwStatsCpu(const CameraManager &cm) * \brief Construct a SwStatsCpu object - * \param[in] configuration Global configuration reference + * \param[in] cm The camera manager * * Creates a SwStatsCpu object and initialises shared memory for statistics * exchange. @@ -154,8 +154,8 @@ namespace libcamera { LOG_DEFINE_CATEGORY(SwStatsCpu) -SwStatsCpu::SwStatsCpu(const GlobalConfiguration &configuration) - : sharedStats_("softIsp_stats"), bench_(configuration) +SwStatsCpu::SwStatsCpu(const CameraManager &cm) + : sharedStats_("softIsp_stats"), bench_(cm) { if (!sharedStats_) LOG(SwStatsCpu, Error) diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp index c1fe2267cc6e..271c4e2c9dc2 100644 --- a/test/ipa/ipa_interface_test.cpp +++ b/test/ipa/ipa_interface_test.cpp @@ -47,7 +47,6 @@ public: notifier_.reset(); ipa_.reset(); ipaManager_.reset(); - config_.reset(); cameraManager_.reset(); } @@ -90,8 +89,7 @@ protected: notifier_->activated.connect(this, &IPAInterfaceTest::readTrace); /* Create the IPA manager. */ - config_ = std::make_unique(); - ipaManager_ = std::make_unique(*config_); + ipaManager_ = std::make_unique(*cameraManager_); return TestPass; } @@ -169,7 +167,6 @@ private: std::shared_ptr pipe_; std::unique_ptr ipa_; std::unique_ptr cameraManager_; - std::unique_ptr config_; std::unique_ptr ipaManager_; enum ipa::vimc::IPAOperationCode trace_; std::unique_ptr notifier_; diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl index e6e19b3030b9..0d0a16147edd 100644 --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl @@ -45,8 +45,8 @@ namespace {{ns}} { {% endfor %} {%- endif %} -{{proxy_name}}Threaded::{{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration) - : {{proxy_name}}(ipam, configuration), thread_("{{proxy_name}}") +{{proxy_name}}Threaded::{{proxy_name}}Threaded(IPAModule *ipam, const CameraManager &cm) + : {{proxy_name}}(ipam, cm), thread_("{{proxy_name}}") { LOG(IPAProxy, Debug) << "initializing {{module_name}} proxy in thread: loading IPA from " @@ -127,8 +127,8 @@ namespace {{ns}} { /* ========================================================================== */ -{{proxy_name}}Isolated::{{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration) - : {{proxy_name}}(ipam, configuration), +{{proxy_name}}Isolated::{{proxy_name}}Isolated(IPAModule *ipam, const CameraManager &cm) + : {{proxy_name}}(ipam, cm), controlSerializer_(ControlSerializer::Role::Proxy), seq_(0) { LOG(IPAProxy, Debug) diff --git a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl index ef280ca423f6..d48b90dcfa41 100644 --- a/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl +++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl @@ -50,7 +50,7 @@ protected: class {{proxy_name}}Threaded : public {{proxy_name}} { public: - {{proxy_name}}Threaded(IPAModule *ipam, const GlobalConfiguration &configuration); + {{proxy_name}}Threaded(IPAModule *ipam, const CameraManager &cm); ~{{proxy_name}}Threaded(); {% for method in interface_main.methods %} @@ -112,7 +112,7 @@ private: class {{proxy_name}}Isolated : public {{proxy_name}} { public: - {{proxy_name}}Isolated(IPAModule *ipam, const GlobalConfiguration &configuration); + {{proxy_name}}Isolated(IPAModule *ipam, const CameraManager &cm); ~{{proxy_name}}Isolated(); {% for method in interface_main.methods %} From patchwork Tue Jan 13 00:07:53 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25741 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 1BB72C32E0 for ; Tue, 13 Jan 2026 00:09:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A4D6461FC8; Tue, 13 Jan 2026 01:09:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="lT91nOu1"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5519E61FD7 for ; Tue, 13 Jan 2026 01:09:04 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id ABA5E66B for ; Tue, 13 Jan 2026 01:08:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262918; bh=xAOfLR3namUexCO9dQWb16Jb+d6ytgSbp861prCGnus=; h=From:To:Subject:Date:In-Reply-To:References:From; b=lT91nOu1/XfO2W70ZP1ST6m0LNDSVxqDnLrZ1Uq2T0+jo+7UUTcPMOuhqYnAMjOVL 12i4TAZLtR+qOC+qFKngIC4WQGA0ezcP2sBep4TIn6BeH+1K9BTAfvjiC8a1+s7xQX k1Xu/1hqvqA58sz0O9esZpe3IMVNL0Tt74P+il/0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 21/36] libcamera: global_configuration: Reorder functions Date: Tue, 13 Jan 2026 02:07:53 +0200 Message-ID: <20260113000808.15395-22-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" Member functions should be implemented in the .cpp file in the same order as in the class definition, within each access group. Move them to the right location. While at it, move load() before loadFile() in the class definition to match execution order, making the code easier to read. Signed-off-by: Laurent Pinchart --- .../libcamera/internal/global_configuration.h | 2 +- src/libcamera/global_configuration.cpp | 144 +++++++++--------- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 7ae923977aa6..84bdf90244d9 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -52,8 +52,8 @@ public: const std::string delimiter = ":") const; private: - bool loadFile(const std::filesystem::path &fileName); void load(); + bool loadFile(const std::filesystem::path &fileName); std::unique_ptr yamlConfiguration_ = std::make_unique(); diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index c4999d32d7c7..c853a028c91d 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -53,6 +53,48 @@ LOG_DEFINE_CATEGORY(Configuration) * options, or configuration() to access the whole configuration. */ +/** + * \typedef GlobalConfiguration::Configuration + * \brief Type representing global libcamera configuration + * + * All code outside GlobalConfiguration must use this type declaration and not + * the underlying type. + */ + +/** + * \brief Initialize the global configuration + */ +GlobalConfiguration::GlobalConfiguration() +{ + load(); +} + +void GlobalConfiguration::load() +{ + std::filesystem::path userConfigurationDirectory; + const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); + if (xdgConfigHome) { + userConfigurationDirectory = xdgConfigHome; + } else { + const char *home = utils::secure_getenv("HOME"); + if (home) + userConfigurationDirectory = + std::filesystem::path(home) / ".config"; + } + + if (!userConfigurationDirectory.empty()) { + std::filesystem::path user_configuration_file = + userConfigurationDirectory / "libcamera" / "configuration.yaml"; + if (loadFile(user_configuration_file)) + return; + } + + for (const auto &path : globalConfigurationFiles) { + if (loadFile(path)) + return; + } +} + bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) { File file(fileName); @@ -85,47 +127,39 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) return true; } -void GlobalConfiguration::load() -{ - std::filesystem::path userConfigurationDirectory; - const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); - if (xdgConfigHome) { - userConfigurationDirectory = xdgConfigHome; - } else { - const char *home = utils::secure_getenv("HOME"); - if (home) - userConfigurationDirectory = - std::filesystem::path(home) / ".config"; - } - - if (!userConfigurationDirectory.empty()) { - std::filesystem::path user_configuration_file = - userConfigurationDirectory / "libcamera" / "configuration.yaml"; - if (loadFile(user_configuration_file)) - return; - } - - for (const auto &path : globalConfigurationFiles) { - if (loadFile(path)) - return; - } -} - /** - * \brief Initialize the global configuration - */ -GlobalConfiguration::GlobalConfiguration() -{ - load(); -} - -/** - * \typedef GlobalConfiguration::Configuration - * \brief Type representing global libcamera configuration + * \brief Retrieve the configuration version * - * All code outside GlobalConfiguration must use this type declaration and not - * the underlying type. + * The version is declared in the configuration file in the top-level `%version` + * element, alongside `%configuration`. This has currently no real use but may be + * needed in future if configuration incompatibilities occur. + * + * \return Configuration version as declared in the configuration file or 0 if + * no global configuration is available */ +unsigned int GlobalConfiguration::version() const +{ + return (*yamlConfiguration_)["version"].get().value_or(0); +} + +/** + * \brief Retrieve the libcamera global configuration + * + * This returns the whole configuration stored in the top-level section + * `%configuration` of the YAML configuration file. + * + * The requested part of the configuration can be accessed using \a ValueNode + * methods. + * + * \note \a ValueNode type itself shouldn't be used in type declarations to + * avoid trouble if we decide to change the underlying data objects in future. + * + * \return The whole configuration section + */ +GlobalConfiguration::Configuration GlobalConfiguration::configuration() const +{ + return (*yamlConfiguration_)["configuration"]; +} /** * \fn std::optional GlobalConfiguration::option(const std::initializer_list &confPath) const @@ -216,38 +250,4 @@ std::optional> GlobalConfiguration::envListOption( return listOption(confPath); } -/** - * \brief Retrieve the configuration version - * - * The version is declared in the configuration file in the top-level `%version` - * element, alongside `%configuration`. This has currently no real use but may be - * needed in future if configuration incompatibilities occur. - * - * \return Configuration version as declared in the configuration file or 0 if - * no global configuration is available - */ -unsigned int GlobalConfiguration::version() const -{ - return (*yamlConfiguration_)["version"].get().value_or(0); -} - -/** - * \brief Retrieve the libcamera global configuration - * - * This returns the whole configuration stored in the top-level section - * `%configuration` of the YAML configuration file. - * - * The requested part of the configuration can be accessed using \a ValueNode - * methods. - * - * \note \a ValueNode type itself shouldn't be used in type declarations to - * avoid trouble if we decide to change the underlying data objects in future. - * - * \return The whole configuration section - */ -GlobalConfiguration::Configuration GlobalConfiguration::configuration() const -{ - return (*yamlConfiguration_)["configuration"]; -} - } /* namespace libcamera */ From patchwork Tue Jan 13 00:07:54 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25742 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 9DA10C3285 for ; Tue, 13 Jan 2026 00:09:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4D95161FFB; Tue, 13 Jan 2026 01:09:08 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="lDgLf5pV"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5F84461FFF for ; Tue, 13 Jan 2026 01:09:06 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B7D4666B for ; Tue, 13 Jan 2026 01:08:40 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262920; bh=YTpeizXjkfouLVWgUHFYDSUKALWuq5yLvVyGBtLxDCc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=lDgLf5pVyuTHvScrcITpsqfMV3Wb/IAmtxl14a3RJC0Qry49QSacXx4mSuQ94m0W3 fyR9GXj/0GJg6Cp6zxFmQ30rfEexCN7okd4MIlSb05yKWnOvWxE3o7cxbeo8tzkjWl 9g53SfCb3TQ2M5WjXunxqfh1a8DdvEsEiR0weyY4= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 22/36] libcamera: global_configuration: Add missing include and comment Date: Tue, 13 Jan 2026 02:07:54 +0200 Message-ID: <20260113000808.15395-23-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" global_configuration.h uses std::initializer_list, include the corresponding header. Add a comment in global_configuration.cpp to close an anonymous namespace, as mandated by the coding style. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/global_configuration.h | 1 + src/libcamera/global_configuration.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 84bdf90244d9..80b57b38ba03 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index c853a028c91d..44ed206de78f 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -24,11 +24,13 @@ namespace libcamera { namespace { + const std::vector globalConfigurationFiles = { std::filesystem::path(LIBCAMERA_SYSCONF_DIR) / "configuration.yaml", std::filesystem::path(LIBCAMERA_DATA_DIR) / "configuration.yaml", }; -} + +} /* namespace */ LOG_DEFINE_CATEGORY(Configuration) From patchwork Tue Jan 13 00:07:55 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25743 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 4D6F5C32C1 for ; Tue, 13 Jan 2026 00:09:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0644761FFF; Tue, 13 Jan 2026 01:09:10 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="mmsD5+Lv"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DCE6F61FFB for ; Tue, 13 Jan 2026 01:09:07 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 3699A66B for ; Tue, 13 Jan 2026 01:08:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262922; bh=QS/ejGv2+4tMwSD3Jl6b3tK5qdQ/xT7e+v/yuetD8vw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=mmsD5+Lv0JgbqiV7iibzy75ko8oNcrd9dlhpLtOG9f+jSxgugbLhYSImTJrlKMUZ5 4wEuyHtwJxh+b1iV2gxFbZBK2bAxg3i+4BIwzbYQKrF28eJcurKtTix9xcQEURSlpr 6qYZ50PHZZ0mUjeWrZGDUlEAxHbsaony26kiyqLY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 23/36] libcamera: global_configuration: Rename yamlConfiguration_ Date: Tue, 13 Jan 2026 02:07:55 +0200 Message-ID: <20260113000808.15395-24-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" Once parsed, the global configuration isn't a YAML file anymore. Rename the yamlConfiguration_ to configuration_. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/global_configuration.h | 2 +- src/libcamera/global_configuration.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 80b57b38ba03..5c907ee92bfe 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -56,7 +56,7 @@ private: void load(); bool loadFile(const std::filesystem::path &fileName); - std::unique_ptr yamlConfiguration_ = + std::unique_ptr configuration_ = std::make_unique(); }; diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 44ed206de78f..ee7d9c185b80 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -125,7 +125,7 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) return true; } - yamlConfiguration_ = std::move(configuration); + configuration_ = std::move(configuration); return true; } @@ -141,7 +141,7 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) */ unsigned int GlobalConfiguration::version() const { - return (*yamlConfiguration_)["version"].get().value_or(0); + return (*configuration_)["version"].get().value_or(0); } /** @@ -160,7 +160,7 @@ unsigned int GlobalConfiguration::version() const */ GlobalConfiguration::Configuration GlobalConfiguration::configuration() const { - return (*yamlConfiguration_)["configuration"]; + return (*configuration_)["configuration"]; } /** From patchwork Tue Jan 13 00:07:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25744 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 2692EC32E7 for ; Tue, 13 Jan 2026 00:09:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C038E61FFE; Tue, 13 Jan 2026 01:09:10 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="f5gtUNvK"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7991061FF4 for ; Tue, 13 Jan 2026 01:09:09 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B8B2ABCA for ; Tue, 13 Jan 2026 01:08:43 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262923; bh=X9kirumTMtE66ZYFuT/Z9ToZS2MjYkwFNNYolZ9KKuI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=f5gtUNvKhk6VxLP5/Pises8u1ktSENVQcT2frfq+NKl9BJQn5JEmc5LbY+3JhNUIq SvH7EDxdtRc/bxfOzusqweD6/7TKQeFTNo74IHilZ5sG9qatnTi6cQp/7sdrRRMU4Z d7QtDqJYc4++9Rld/H1/iJcbNHiwPqTDZPpJ7wuI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 24/36] libcamera: global_configuration: Rename Configuration to Option Date: Tue, 13 Jan 2026 02:07:56 +0200 Message-ID: <20260113000808.15395-25-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The GlobalConfiguration::Configuration type represent a configuration option. Rename it to Option to make this clearer. This shortens lines as an added bonus. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/global_configuration.h | 4 ++-- src/libcamera/global_configuration.cpp | 8 ++++---- src/libcamera/pipeline/simple/simple.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 5c907ee92bfe..2c0bfadb4676 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -22,12 +22,12 @@ namespace libcamera { class GlobalConfiguration { public: - using Configuration = const ValueNode &; + using Option = const ValueNode &; GlobalConfiguration(); unsigned int version() const; - Configuration configuration() const; + Option configuration() const; template std::optional option( diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index ee7d9c185b80..4d154c026e44 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -56,8 +56,8 @@ LOG_DEFINE_CATEGORY(Configuration) */ /** - * \typedef GlobalConfiguration::Configuration - * \brief Type representing global libcamera configuration + * \typedef GlobalConfiguration::Option + * \brief Type representing a configuration option * * All code outside GlobalConfiguration must use this type declaration and not * the underlying type. @@ -156,9 +156,9 @@ unsigned int GlobalConfiguration::version() const * \note \a ValueNode type itself shouldn't be used in type declarations to * avoid trouble if we decide to change the underlying data objects in future. * - * \return The whole configuration section + * \return The top-level configuration option */ -GlobalConfiguration::Configuration GlobalConfiguration::configuration() const +GlobalConfiguration::Option GlobalConfiguration::configuration() const { return (*configuration_)["configuration"]; } diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index b30b0a122e6e..bdc87d39ef0b 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -1880,7 +1880,7 @@ bool SimplePipelineHandler::matchDevice(std::shared_ptr media, swIspEnabled_ = info.swIspEnabled; const GlobalConfiguration &configuration = cameraManager()->_d()->configuration(); - for (GlobalConfiguration::Configuration entry : + for (GlobalConfiguration::Option entry : configuration.configuration()["pipelines"]["simple"]["supported_devices"] .asList()) { auto name = entry["driver"].get(); From patchwork Tue Jan 13 00:07:57 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25745 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 94DE6C323E for ; Tue, 13 Jan 2026 00:09:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5286261FD9; Tue, 13 Jan 2026 01:09:13 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="C7FFapPo"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 07ACD62006 for ; Tue, 13 Jan 2026 01:09:11 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 51FC866B for ; Tue, 13 Jan 2026 01:08:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262925; bh=cIzixro/MPWtfKkZikxXAehRwwzE4X4fcRkdRO8pZFQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=C7FFapPoY3WsVgC1N7a/5P6TzwFixFJ3qogetpl14PE7rXmfDURooY9vKwZfuqOXD zSBB9PRPb0auqXUVh8HOf6tMsu0zlfjri4s1aKJXzy12FEza8QUF9AIezQsGGzDZXb UPN/FrO4q128UNbMfMMMCvG58yEWQ0pQroZd88K0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 25/36] libcamera: value_node: Add constructor with value Date: Tue, 13 Jan 2026 02:07:57 +0200 Message-ID: <20260113000808.15395-26-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The new constructor takes a value, allowing creation of a leaf ValueNode with a value in a single operation instead of having to call set() on an empty node. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/value_node.h | 7 +++++++ src/libcamera/value_node.cpp | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h index a336c1d08e1c..eb509d855810 100644 --- a/include/libcamera/internal/value_node.h +++ b/include/libcamera/internal/value_node.h @@ -143,6 +143,13 @@ public: #endif /* __DOXYGEN__ */ ValueNode(); + + template + ValueNode(T &&value) + { + set(std::forward(value)); + } + ~ValueNode(); bool isValue() const diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp index 7374e7bdde8c..b8f0c6d5cbc4 100644 --- a/src/libcamera/value_node.cpp +++ b/src/libcamera/value_node.cpp @@ -44,6 +44,13 @@ ValueNode::ValueNode() { } +/** + * \fn template ValueNode::ValueNode(T &&value) + * \brief Construct a ValueNode instance with a value + * \tparam T Type of the value + * \param[in] value The value + */ + ValueNode::~ValueNode() = default; /** From patchwork Tue Jan 13 00:07:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25746 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 321D3C32EA for ; Tue, 13 Jan 2026 00:09:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CD7E961FFC; Tue, 13 Jan 2026 01:09:13 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="bJnY2hW0"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 811B161FD9 for ; Tue, 13 Jan 2026 01:09:12 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id D5618BCA for ; Tue, 13 Jan 2026 01:08:46 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262927; bh=G5F6ILJj2jySIS86YLqqeBaHY9/JGqHNy0/Rhw+qV38=; h=From:To:Subject:Date:In-Reply-To:References:From; b=bJnY2hW0MO1Kk45/JcTmkGaPeP+EX+Xc2h9wci6sXJK95Z2xqZtymzQEKDN1ARxvH OIR0kkIPi2YkbCEi0fJL6/q2KBW6iDqIrS6LPO5YRXJUDGZd4KOBq4b8jWP8EYsJvn LjmpsTSjrXtXz1sjA3yNaqm0d9SPgbSnyBoJJ+vM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 26/36] libcamera: value_node: Rework templates to prepare for mutable views Date: Tue, 13 Jan 2026 02:07:58 +0200 Message-ID: <20260113000808.15395-27-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" ValueNode provides adapter classes to expose the object as an iteratable list or dictionary. The Iterator and Adapter classes hardcode the assumption that the ValueNode is const. To prepare for mutable views, move the const specifier to the top-level DictAdapter and ListAdapter class templates. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/value_node.h | 54 ++++++++++++++++--------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h index eb509d855810..dd45859f3501 100644 --- a/include/libcamera/internal/value_node.h +++ b/include/libcamera/internal/value_node.h @@ -38,14 +38,14 @@ private: public: #ifndef __DOXYGEN__ - template + template class Iterator { public: using difference_type = std::ptrdiff_t; using iterator_category = std::forward_iterator_tag; - Iterator(typename ValueContainer::const_iterator it) + Iterator(ContainerIterator it) : it_(it) { } @@ -74,14 +74,14 @@ public: } protected: - ValueContainer::const_iterator it_; + ContainerIterator it_; }; - template + template class Adapter { public: - Adapter(const ValueContainer &container) + Adapter(Container &container) : container_(container) { } @@ -97,47 +97,63 @@ public: } protected: - const ValueContainer &container_; + Container &container_; }; - class ListIterator : public Iterator + template + class ListIterator : public Iterator, + ContainerIterator> { - public: - using value_type = const ValueNode &; - using pointer = const ValueNode *; - using reference = value_type; + private: + using Base = Iterator, + ContainerIterator>; - value_type operator*() const + public: + using value_type = Value; + using pointer = value_type *; + using reference = value_type &; + + reference operator*() const { - return *it_->value.get(); + return *Base::it_->value.get(); } pointer operator->() const { - return it_->value.get(); + return Base::it_->value.get(); } }; - class DictIterator : public Iterator + template + class DictIterator : public Iterator, + ContainerIterator> { + private: + using Base = Iterator, + ContainerIterator>; + public: - using value_type = std::pair; + using value_type = std::pair; using pointer = value_type *; using reference = value_type &; value_type operator*() const { - return { it_->key, *it_->value.get() }; + return { Base::it_->key, *Base::it_->value.get() }; } }; - class DictAdapter : public Adapter + class DictAdapter : public Adapter, + const ValueContainer> { public: using key_type = std::string; }; - class ListAdapter : public Adapter + class ListAdapter : public Adapter, + const ValueContainer> { }; #endif /* __DOXYGEN__ */ From patchwork Tue Jan 13 00:07:59 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25747 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 0715CC3274 for ; Tue, 13 Jan 2026 00:09:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AFF616200C; Tue, 13 Jan 2026 01:09:16 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Rl4CkRIw"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A2E261FC8 for ; Tue, 13 Jan 2026 01:09:14 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 4DC1050A for ; Tue, 13 Jan 2026 01:08:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262928; bh=W/yPyHKX2bBnhl5b348E0xIqiMmpbsmhk4DhPgru5Bw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Rl4CkRIwBVWeJAb/K8EGSRk19uYAxmGARjsd8lsMkd1gwjPY6tgHupCUXNo5PvnMo MUeO0Q465VFQ5prCkABhP2YgtD7WYEKJCXpUMJoldW9TJiER6NmpGZrf9VEiDuWmxM RE3G7napZ6Vy9/vCkSITr8qlCjN3KyHmE3TCFW9U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 27/36] libcamera: value_node: Add mutable adapters Date: Tue, 13 Jan 2026 02:07:59 +0200 Message-ID: <20260113000808.15395-28-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The ValueNode class was initially designed to store read-only property trees. It is useful to also provide mutable access. Add non-const adapters and iterators and adapters. This allows obtaining a mutable ValueNode instance when traversing a tree. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/value_node.h | 32 ++++++++++++++++++------- src/libcamera/value_node.cpp | 10 ++++++++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h index dd45859f3501..56d200e1cf27 100644 --- a/include/libcamera/internal/value_node.h +++ b/include/libcamera/internal/value_node.h @@ -143,17 +143,31 @@ public: } }; - class DictAdapter : public Adapter, - const ValueContainer> + class DictAdapter : public Adapter, + ValueContainer> { public: using key_type = std::string; }; - class ListAdapter : public Adapter, - const ValueContainer> + class ListAdapter : public Adapter, + ValueContainer> + { + }; + + class ConstDictAdapter : public Adapter, + const ValueContainer> + { + public: + using key_type = std::string; + }; + + class ConstListAdapter : public Adapter, + const ValueContainer> { }; #endif /* __DOXYGEN__ */ @@ -209,8 +223,10 @@ public: return Accessor>{}.set(*this, std::forward(value)); } - DictAdapter asDict() const { return DictAdapter{ list_ }; } - ListAdapter asList() const { return ListAdapter{ list_ }; } + DictAdapter asDict() { return DictAdapter{ list_ }; } + ListAdapter asList() { return ListAdapter{ list_ }; } + ConstDictAdapter asDict() const { return ConstDictAdapter{ list_ }; } + ConstListAdapter asList() const { return ConstListAdapter{ list_ }; } const ValueNode &operator[](std::size_t index) const; diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp index b8f0c6d5cbc4..3c56b47bf79d 100644 --- a/src/libcamera/value_node.cpp +++ b/src/libcamera/value_node.cpp @@ -335,6 +335,11 @@ template struct ValueNode::Accessor>; template struct ValueNode::Accessor>; #endif /* __DOXYGEN__ */ +/** + * \fn ValueNode::asDict() + * \copydoc ValueNode::asDict() const + */ + /** * \fn ValueNode::asDict() const * \brief Wrap a dictionary ValueNode in an adapter that exposes iterators @@ -355,6 +360,11 @@ template struct ValueNode::Accessor>; * \return An adapter of unspecified type compatible with range-based for loops */ +/** + * \fn ValueNode::asList() + * \copydoc ValueNode::asList() const + */ + /** * \fn ValueNode::asList() const * \brief Wrap a list ValueNode in an adapter that exposes iterators From patchwork Tue Jan 13 00:08:00 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25748 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 A33A4C32DE for ; Tue, 13 Jan 2026 00:09:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3A8AB61FFB; Tue, 13 Jan 2026 01:09:18 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="C75crtFw"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 90CF161FBB for ; Tue, 13 Jan 2026 01:09:15 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id E3F8EBCA for ; Tue, 13 Jan 2026 01:08:49 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262930; bh=3Lf3x50+ATkUhpAAFRKWHCsJniBHxNzC3uzR9CcRQOM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=C75crtFwKFBv5F/cXEKgkJt52KmVafxKyjw50/IcEgK2IWlZwY99jvmQqaMt87NAR 2+I5qR6eudt1mi2wdv8awDjz/++COVQOVcx+XpKFQQuzOgCBoGyPTI8n2rw4TaYiAO NLoHIeDO/9NKbc0tlGokT5QlG2KL23pl7lvE6wNc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 28/36] libcamera: value_node: Add mutable children accessors Date: Tue, 13 Jan 2026 02:08:00 +0200 Message-ID: <20260113000808.15395-29-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" At two at() functions that return mutable pointer to child nodes, based on an index for lists and a key for dictionaries. The API differs from const children accessors that use operator[] and return a reference in order to allow better error handling: while the const accessors return a reference to a global instance of an empty ValueNode when the requested child doesn't exist, a mutable accessor can't do the same without allowing modifying the empty global instance. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/value_node.h | 2 ++ src/libcamera/value_node.cpp | 41 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h index 56d200e1cf27..c285be4957ed 100644 --- a/include/libcamera/internal/value_node.h +++ b/include/libcamera/internal/value_node.h @@ -228,9 +228,11 @@ public: ConstDictAdapter asDict() const { return ConstDictAdapter{ list_ }; } ConstListAdapter asList() const { return ConstListAdapter{ list_ }; } + ValueNode *at(std::size_t index); const ValueNode &operator[](std::size_t index) const; bool contains(std::string_view key) const; + ValueNode *at(std::string_view key); const ValueNode &operator[](std::string_view key) const; ValueNode *add(std::unique_ptr child); diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp index 3c56b47bf79d..50b23284f930 100644 --- a/src/libcamera/value_node.cpp +++ b/src/libcamera/value_node.cpp @@ -384,6 +384,24 @@ template struct ValueNode::Accessor>; * \return An adapter of unspecified type compatible with range-based for loops */ +/** + * \brief Retrieve the element from list ValueNode by index + * \param[in] index The element index + * + * This function retrieves an element of the ValueNode. Only ValueNode + * instances of List type associate elements with index, calling this function + * on other types of instances or with an invalid index returns a null pointer. + * + * \return The ValueNode as an element of the list + */ +ValueNode *ValueNode::at(std::size_t index) +{ + if (type_ != Type::List || index >= size()) + return nullptr; + + return list_[index].value.get(); +} + /** * \brief Retrieve the element from list ValueNode by index * \param[in] index The element index @@ -419,6 +437,29 @@ bool ValueNode::contains(std::string_view key) const return dictionary_.find(key) != dictionary_.end(); } +/** + * \brief Retrieve a member by key from the dictionary + * \param[in] key The element key + * + * This function retrieves a member of a ValueNode by \a key. Only ValueNode + * instances of Dictionary type associate elements with keys, calling this + * function on other types of instances or with a nonexistent key returns a null + * pointer. + * + * \return The ValueNode corresponding to the \a key member + */ +ValueNode *ValueNode::at(std::string_view key) +{ + if (type_ != Type::Dictionary) + return nullptr; + + auto iter = dictionary_.find(key); + if (iter == dictionary_.end()) + return nullptr; + + return iter->second; +} + /** * \brief Retrieve a member by key from the dictionary * \param[in] key The element key From patchwork Tue Jan 13 00:08:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25749 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 22310BDCBF for ; Tue, 13 Jan 2026 00:09:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C021E61FFE; Tue, 13 Jan 2026 01:09:18 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="UfmjG6Is"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2EAF361FFF for ; Tue, 13 Jan 2026 01:09:17 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 88A9FBCA for ; Tue, 13 Jan 2026 01:08:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262931; bh=Q4PkQX2DZj9WDuWPR7gu+NRUWPoKvmBZtKuMRMRT0t8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=UfmjG6IsxRLXq81G2OIOs01e7XHMTzInC9eDRS2yUkLb7RuS5JtHXyMUAYYYHTHG9 dTxMvXD6QxRIEolPAR5CerNv+KJhho5/EgziCbm/F6ums26jTtRIXjOQumdKUZDK5W hOI+kQEXBcKM62G1x5vui2yUwKy53tUPox4HCB+o= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 29/36] libcamera: value_node: Support adding nested children in one operation Date: Tue, 13 Jan 2026 02:08:01 +0200 Message-ID: <20260113000808.15395-30-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The GlobalConfiguration class will need to add nested children to a ValueNode. Add a new overload to the add() function for this purpose. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/value_node.h | 3 ++ src/libcamera/value_node.cpp | 56 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h index c285be4957ed..abb0991fd87e 100644 --- a/include/libcamera/internal/value_node.h +++ b/include/libcamera/internal/value_node.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -237,6 +238,8 @@ public: ValueNode *add(std::unique_ptr child); ValueNode *add(std::string key, std::unique_ptr child); + ValueNode *add(std::initializer_list path, + std::unique_ptr child); private: LIBCAMERA_DISABLE_COPY_AND_MOVE(ValueNode) diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp index 50b23284f930..1256adf8361d 100644 --- a/src/libcamera/value_node.cpp +++ b/src/libcamera/value_node.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include /** @@ -22,6 +24,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(ValueNode) + namespace { /* Empty static ValueNode as a safe result for invalid operations */ @@ -539,4 +543,56 @@ ValueNode *ValueNode::add(std::string key, std::unique_ptr child) return elem.value.get(); } +/** + * \brief Add a child node at the given path + * \param[in] path The path + * \param[in] child The child node + * + * Add the \a child node at the given \a path starting at this node. Missing + * nodes are created along the path. Nodes along the path must be empty, in + * which case they are converted to the Type::Dictionary type, be a dictionary, + * or be missing. Otherwise, the \a child is discarded and the function returns + * a nullptr. + * + * Path elements are unique in the context of a parent node. If a child with the + * same \a key already exist at the end of the path, the \a child is discarded + * and the function returns a nullptr. + * + * \return A pointer to the \a child node if successfully added, nullptr + * otherwise + */ +ValueNode *ValueNode::add(std::initializer_list path, + std::unique_ptr child) +{ + if (!path.size()) + return NULL; + + ValueNode *node = this; + + for (const auto [i, name] : utils::enumerate(path)) { + auto iter = node->dictionary_.find(name); + if (iter == node->dictionary_.end()) { + std::unique_ptr obj; + + if (i < path.size() - 1) + obj = std::make_unique(); + else + obj = std::move(child); + + node = node->add(std::string{ name }, std::move(obj)); + if (!node) { + Span pathName{ std::data(path), i + 1 }; + LOG(ValueNode, Error) + << "Failed to populate '" + << utils::join(pathName, "/") << "'"; + return nullptr; + } + } else { + node = iter->second; + } + } + + return node; +} + } /* namespace libcamera */ From patchwork Tue Jan 13 00:08:02 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25750 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 5610BC32AF for ; Tue, 13 Jan 2026 00:09:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E2E4762013; Tue, 13 Jan 2026 01:09:20 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="N4h9ifE9"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CC00561FF4 for ; Tue, 13 Jan 2026 01:09:18 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 2FE73BCA for ; Tue, 13 Jan 2026 01:08:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262933; bh=swlUtzW82ngKAGHFFUN5/TSMXj/Bxv99B2kP9bfB6Bc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=N4h9ifE9ssQ79ggYRQbWYozyLs/TB+ivjdEJuYaq3kAbvAJ18gSFOE2zsal1renRT qX75JYZTqD8rGFzayGAwiZJlJj/+gRgN5yjGGq+7c6eRvii/Jxk5Yd9kLTv2b0/DEH 3i0C8W/2kg+kEwqVfeIWY0vUMJi3we/O0MQpwdWo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 30/36] libcamera: value_node: Support looking up nested children in one operation Date: Tue, 13 Jan 2026 02:08:02 +0200 Message-ID: <20260113000808.15395-31-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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: Laurent Pinchart --- include/libcamera/internal/value_node.h | 1 + src/libcamera/value_node.cpp | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h index abb0991fd87e..da72651d2161 100644 --- a/include/libcamera/internal/value_node.h +++ b/include/libcamera/internal/value_node.h @@ -235,6 +235,7 @@ public: bool contains(std::string_view key) const; ValueNode *at(std::string_view key); const ValueNode &operator[](std::string_view key) const; + const ValueNode &operator[](std::initializer_list path) const; ValueNode *add(std::unique_ptr child); ValueNode *add(std::string key, std::unique_ptr child); diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp index 1256adf8361d..55d5a1a29991 100644 --- a/src/libcamera/value_node.cpp +++ b/src/libcamera/value_node.cpp @@ -487,6 +487,29 @@ const ValueNode &ValueNode::operator[](std::string_view key) const return *iter->second; } +/** + * \brief Retrieve a descendant node by path + * \param[in] path The path + * + * This function retrieves a descendant of a ValueNode by following a \a path. + * The path is a list of keys that index nested dictionary nodes. If any node + * along the path is not a Dictionary node, an empty node is returned. + * + * \return The ValueNode corresponding to the \a path + */ +const ValueNode &ValueNode::operator[](std::initializer_list path) const +{ + const ValueNode *node = this; + + for (const auto part : path) { + node = &(*node)[part]; + if (!*node) + return empty; + } + + return *node; +} + /** * \brief Add a child node to a list * \param[in] child The child node From patchwork Tue Jan 13 00:08:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25751 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 D392FC32EF for ; Tue, 13 Jan 2026 00:09:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7D23F62008; Tue, 13 Jan 2026 01:09:21 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="KzOQdluJ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6BCA961FFF for ; Tue, 13 Jan 2026 01:09:20 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id BC84FBCA for ; Tue, 13 Jan 2026 01:08:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262934; bh=biwNcX9AnvvKMmo/+haG0inazJgkeTFZD9a4Agd8dPY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=KzOQdluJPirccR4kWidkHStr1i+R4lh/oKpbAuFDwtfcjds+B0rplYC8PGpT//x8K NTSfl6gi6n3W3EaqUNZjVngYNF/tUdzMDGYq+SHkR+2x8fmnAQRnU3svDQe5stJwF4 Z2MA05SbouvUEEBVqv0r2rnHU1hc5L3QYMyTfXPY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 31/36] libcamera: global_configuration: Populate empty configuration Date: Tue, 13 Jan 2026 02:08:03 +0200 Message-ID: <20260113000808.15395-32-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" If no configuration file can be parsed, populate an empty configuration. This will serve as a base to store the configuration options set through environment variables. Signed-off-by: Laurent Pinchart --- src/libcamera/global_configuration.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index 4d154c026e44..a759a086b9a4 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -93,7 +93,12 @@ void GlobalConfiguration::load() for (const auto &path : globalConfigurationFiles) { if (loadFile(path)) - return; + break; + } + + if (configuration_->isEmpty()) { + configuration_->add("version", std::make_unique(1)); + configuration_->add("configuration", std::make_unique()); } } From patchwork Tue Jan 13 00:08:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25752 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 80ACEC3284 for ; Tue, 13 Jan 2026 00:09:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 22D4261FFB; Tue, 13 Jan 2026 01:09:24 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="OoY4aOrB"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 16BB96200D for ; Tue, 13 Jan 2026 01:09:22 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 3E9C9BCA for ; Tue, 13 Jan 2026 01:08:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262936; bh=ikivyvlfwDk5I1JCn7mMHuX+aBfqq+1heOxM507x0Jc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=OoY4aOrBzWO9UaUBcUbx/w3fSG/GPCChdZpb1Rdc9AsdJTl/IcScvLsMG3xRhGgc1 xTFMmTG3AiE4VCxt4IlUvrgq0nSnsBeO7ehnaGBFewiC/uO2valRnekXZbnWNjdBLy 0PRZAZnj/r0x61/bMeCeiN0pNXFJGtLJYeyQIURs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 32/36] libcamera: global_configuration: Override options with environment variables Date: Tue, 13 Jan 2026 02:08:04 +0200 Message-ID: <20260113000808.15395-33-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" libcamera supports several environment variables that can override configuration options. This requires components that use such overrides to call the special envOption() and envListOption() functions, spreading knowledge of the overrides through the code base. This will hinder future enhancements to the global configuration, such as implementing per-camera options that will override pipeline handler-level options. To prepare for that, move handling of the environment variables to the GlobalConfiguration class. Signed-off-by: Laurent Pinchart --- .../libcamera/internal/global_configuration.h | 7 - src/libcamera/camera_manager.cpp | 4 +- src/libcamera/global_configuration.cpp | 182 ++++++++++++------ src/libcamera/ipa_manager.cpp | 9 +- src/libcamera/ipa_proxy.cpp | 6 +- src/libcamera/software_isp/software_isp.cpp | 6 +- 6 files changed, 127 insertions(+), 87 deletions(-) diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h index 2c0bfadb4676..f537a9417d23 100644 --- a/include/libcamera/internal/global_configuration.h +++ b/include/libcamera/internal/global_configuration.h @@ -44,13 +44,6 @@ public: std::optional> listOption( const std::initializer_list confPath) const; - std::optional envOption( - const char *const envVariable, - const std::initializer_list confPath) const; - std::optional> envListOption( - const char *const envVariable, - const std::initializer_list confPath, - const std::string delimiter = ":") const; private: void load(); diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index f774bd84291b..0dd4e0c590a1 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -114,9 +114,7 @@ void CameraManager::Private::createPipelineHandlers() * there is no configuration file. */ const auto pipesList = - configuration().envListOption("LIBCAMERA_PIPELINES_MATCH_LIST", - { "pipelines_match_list" }, - ","); + configuration().listOption({ "pipelines_match_list" }); if (pipesList.has_value()) { /* * When a list of preferred pipelines is defined, iterate diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp index a759a086b9a4..06dfac016c33 100644 --- a/src/libcamera/global_configuration.cpp +++ b/src/libcamera/global_configuration.cpp @@ -7,6 +7,7 @@ #include "libcamera/internal/global_configuration.h" +#include #include #include #include @@ -30,6 +31,103 @@ const std::vector globalConfigurationFiles = { std::filesystem::path(LIBCAMERA_DATA_DIR) / "configuration.yaml", }; +class EnvironmentProcessor +{ +public: + virtual ~EnvironmentProcessor() = default; + + virtual void process(ValueNode &node, const char *env) = 0; +}; + +/* A processor that sets a fixed value. */ +template +class EnvironmentFixedProcessor : public EnvironmentProcessor +{ +public: + EnvironmentFixedProcessor(const T &value) + : value_(value) + { + } + + void process(ValueNode &node, [[maybe_unused]] const char *env) override + { + node.set(value_); + } + +private: + T value_; +}; + +/* + * A processor that parses the environment variable as a list of strings with a + * custom delimiter. + */ +class EnvironmentListProcessor : public EnvironmentProcessor +{ +public: + EnvironmentListProcessor(const char *delimiter) + : delimiter_(delimiter) + { + } + + void process(ValueNode &node, const char *env) override + { + for (auto value : utils::split(env, delimiter_)) + node.add(std::make_unique(value)); + } + +private: + const std::string delimiter_; +}; + +/* A processor that copies the value of the environment variable. */ +class EnvironmentValueProcessor : public EnvironmentProcessor +{ +public: + EnvironmentValueProcessor() + { + } + + void process(ValueNode &node, const char *env) override + { + node.set(std::string{ env }); + } +}; + +struct EnvironmentOverride { + const char *variable; + std::initializer_list path; + std::unique_ptr processor; +}; + +const std::array environmentOverrides{ { + { + "LIBCAMERA_IPA_CONFIG_PATH", + { "ipa", "config_paths" }, + std::make_unique(":"), + }, { + "LIBCAMERA_IPA_FORCE_ISOLATION", + { "ipa", "force_isolation" }, + std::make_unique>(true), + }, { + "LIBCAMERA_IPA_MODULE_PATH", + { "ipa", "module_paths" }, + std::make_unique(":"), + }, { + "LIBCAMERA_IPA_PROXY_PATH", + { "ipa", "proxy_paths" }, + std::make_unique(":"), + }, { + "LIBCAMERA_PIPELINES_MATCH_LIST", + { "pipelines_match_list" }, + std::make_unique(","), + }, { + "LIBCAMERA_SOFTISP_MODE", + { "software_isp", "mode" }, + std::make_unique(), + }, +} }; + } /* namespace */ LOG_DEFINE_CATEGORY(Configuration) @@ -50,9 +148,9 @@ LOG_DEFINE_CATEGORY(Configuration) * reported and no configuration file is used. This is to prevent libcamera from * using an unintended configuration file. * - * The configuration can be accessed using the provided helpers, namely - * option(), envOption(), listOption() and envListOption() to access individual - * options, or configuration() to access the whole configuration. + * The configuration can be accessed using the provided helpers, namely option() + * and listOption() to access individual options, or configuration() to access + * the whole configuration. */ /** @@ -100,6 +198,23 @@ void GlobalConfiguration::load() configuration_->add("version", std::make_unique(1)); configuration_->add("configuration", std::make_unique()); } + + /* Process environment variables that override configuration options. */ + ValueNode *cfg = configuration_->at("configuration"); + + for (const EnvironmentOverride &envOverride : environmentOverrides) { + const char *envValue = utils::secure_getenv(envOverride.variable); + if (!envValue || !envValue[0]) + continue; + + std::unique_ptr node = std::make_unique(); + envOverride.processor->process(*node.get(), envValue); + + if (!cfg->add(envOverride.path, std::move(node))) + LOG(Configuration, Error) + << "Failed to override " + << utils::join(envOverride.path, "/"); + } } bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) @@ -196,65 +311,4 @@ std::optional> GlobalConfiguration::listOption( return c->get>(); } -/** - * \brief Retrieve the value of environment variable with a fallback on the configuration file - * \param[in] envVariable Environment variable to get the value from - * \param[in] confPath The sequence of YAML section names to fall back on when - * \a envVariable is unavailable - * - * This helper looks first at the given environment variable and if it is - * defined then it returns its value (even if it is empty). Otherwise it looks - * for \a confPath the same way as in GlobalConfiguration::option. Only string - * values are supported. - * - * \note Support for using environment variables to configure libcamera behavior - * is provided here mostly for backward compatibility reasons. Introducing new - * configuration environment variables is discouraged. - * - * \return The value retrieved from the given environment if it is set, - * otherwise the value from the configuration file if it exists, or no value if - * it does not - */ -std::optional GlobalConfiguration::envOption( - const char *envVariable, - const std::initializer_list confPath) const -{ - const char *envValue = utils::secure_getenv(envVariable); - if (envValue) - return std::optional{ std::string{ envValue } }; - return option(confPath); -} - -/** - * \brief Retrieve the value of the configuration option from a file or environment - * \param[in] envVariable Environment variable to get the value from - * \param[in] confPath The same as in GlobalConfiguration::option - * \param[in] delimiter Items separator in the environment variable - * - * This helper looks first at the given environment variable and if it is - * defined (even if it is empty) then it splits its value by semicolons and - * returns the resulting list of strings. Otherwise it looks for \a confPath the - * same way as in GlobalConfiguration::option, value of which must be a list of - * strings. - * - * \note Support for using environment variables to configure libcamera behavior - * is provided here mostly for backward compatibility reasons. Introducing new - * configuration environment variables is discouraged. - * - * \return A vector of strings retrieved from the given environment option or - * configuration file or no value if not found; the vector may be empty - */ -std::optional> GlobalConfiguration::envListOption( - const char *const envVariable, - const std::initializer_list confPath, - const std::string delimiter) const -{ - const char *envValue = utils::secure_getenv(envVariable); - if (envValue) { - auto items = utils::split(envValue, delimiter); - return std::vector(items.begin(), items.end()); - } - return listOption(confPath); -} - } /* namespace libcamera */ diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index dd1f483beec3..a351f4f7b581 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -114,18 +114,15 @@ IPAManager::IPAManager(const CameraManager &cm) if (!pubKey_.isValid()) LOG(IPAManager, Warning) << "Public key not valid"; - char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION"); - forceIsolation_ = (force && force[0] != '\0') || - (!force && configuration.option({ "ipa", "force_isolation" }) - .value_or(false)); + forceIsolation_ = configuration.option({ "ipa", "force_isolation" }) + .value_or(false); #endif unsigned int ipaCount = 0; /* User-specified paths take precedence. */ const auto modulePaths = - configuration.envListOption( - "LIBCAMERA_IPA_MODULE_PATH", { "ipa", "module_paths" }) + configuration.listOption({ "ipa", "module_paths" }) .value_or(std::vector()); for (const auto &dir : modulePaths) { if (dir.empty()) diff --git a/src/libcamera/ipa_proxy.cpp b/src/libcamera/ipa_proxy.cpp index 6c8780a012d5..bc8ff090fa86 100644 --- a/src/libcamera/ipa_proxy.cpp +++ b/src/libcamera/ipa_proxy.cpp @@ -124,11 +124,9 @@ IPAProxy::IPAProxy(IPAModule *ipam, const CameraManager &cm) { const GlobalConfiguration &configuration = cm._d()->configuration(); - configPaths_ = configuration.envListOption("LIBCAMERA_IPA_CONFIG_PATH", - { "ipa", "config_paths" }) + configPaths_ = configuration.listOption({ "ipa", "config_paths" }) .value_or(std::vector()); - execPaths_ = configuration.envListOption("LIBCAMERA_IPA_PROXY_PATH", - { "ipa", "proxy_paths" }) + execPaths_ = configuration.listOption({ "ipa", "proxy_paths" }) .value_or(std::vector()); } diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp index d8ef69644e71..57d3a830df54 100644 --- a/src/libcamera/software_isp/software_isp.cpp +++ b/src/libcamera/software_isp/software_isp.cpp @@ -124,11 +124,11 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor, #if HAVE_DEBAYER_EGL const GlobalConfiguration &configuration = cm._d()->configuration(); - std::optional softISPMode = configuration.envOption("LIBCAMERA_SOFTISP_MODE", { "software_isp", "mode" }); + std::optional softISPMode = configuration.option({ "software_isp", "mode" }); if (softISPMode) { if (softISPMode != "gpu" && softISPMode != "cpu") { - LOG(SoftwareIsp, Error) << "LIBCAMERA_SOFISP_MODE " << softISPMode.value() << " invalid " - << "must be \"cpu\" or \"gpu\""; + LOG(SoftwareIsp, Error) << "Software ISP mode " << softISPMode.value() + << " invalid, must be \"cpu\" or \"gpu\""; return; } } From patchwork Tue Jan 13 00:08:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25753 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 2C78DC32E0 for ; Tue, 13 Jan 2026 00:09:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B7C9B62016; Tue, 13 Jan 2026 01:09:24 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vNL6pq3U"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C89F161FFB for ; Tue, 13 Jan 2026 01:09:23 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 2F653BCA for ; Tue, 13 Jan 2026 01:08:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262938; bh=gxLhejTzWeC+7kPLBlg3RXhKrwQbhQQyfajMIcFntak=; h=From:To:Subject:Date:In-Reply-To:References:From; b=vNL6pq3UYtyYxfPHJrvK4To3p7B+1wWAimVgmesaYBU1g6d4IqfDlGdTYkb2AcY8a WVDlaliFbvKtqtVDO+htkaChBZ6CZBtHhNoLkBAudWcjenWIoQzZYMql+LzW8tHDxC Gi1dAx3idWpCv4IV00+WiRRfqJ1n5Wu12x6puFAo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 33/36] Documentation: Rename runtime configuration title Date: Tue, 13 Jan 2026 02:08:05 +0200 Message-ID: <20260113000808.15395-34-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The Documentation/runtime_configuration.rst file has a title that mentions "variables" to refer to environment variables. Spell it out fully for clarity. Signed-off-by: Laurent Pinchart Reviewed-by: Barnabás Pőcze --- Documentation/runtime_configuration.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index e99ef2fb9561..b4386cd2ef4b 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -85,8 +85,8 @@ Configuration file example skip: 50 number: 30 -List of variables and configuration options -------------------------------------------- +List of environment variables and configuration options +------------------------------------------------------- LIBCAMERA_LOG_FILE The custom destination for log output. From patchwork Tue Jan 13 00:08:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25754 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 E44A0C3285 for ; Tue, 13 Jan 2026 00:09:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8128C61FBF; Tue, 13 Jan 2026 01:09:27 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="WDNaBwD/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6DBE661FBF for ; Tue, 13 Jan 2026 01:09:25 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id B51F766B for ; Tue, 13 Jan 2026 01:08:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262939; bh=8/sokydaSp9DC91XqA2Wrrga4MkaoJf/swqM7LXZYFQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=WDNaBwD/OWbULLr1d2jnbTsy6pLMh9gWtKjkr0b4e8/GgRU3pHaYbt8I266rxVB9O zQgxYi/u+LpqW0R1I8WP3Hb7iIm2fWNTdK0QYiz5fr1BOaBO9zyUMDz+DUPb9mE2XA cRYZ41T0Sjz6fD+NvQqyxta/N5KwNqIzGuMI1Mkc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 34/36] libcamera: software_isp: Rename "measure" option to "benchmark" Date: Tue, 13 Jan 2026 02:08:06 +0200 Message-ID: <20260113000808.15395-35-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The software ISP "measure" configuration option doesn't clearly indicate what it measures. Rename it to "benchmark" to match the name of the class that handles it and make it self-explicit. While at it, improve the documentation slightly by replacing "per-frame time measurement" with "performance measurement". Signed-off-by: Laurent Pinchart --- Documentation/runtime_configuration.rst | 10 +++++----- src/libcamera/software_isp/benchmark.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index b4386cd2ef4b..8c920978648d 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -48,7 +48,7 @@ file structure: software_isp: # true/false software_isp: copy_input_buffer: # true/false - measure: + benchmark: skip: # non-negative integer, frames to skip initially number: # non-negative integer, frames to measure @@ -81,7 +81,7 @@ Configuration file example software_isp: true software_isp: copy_input_buffer: false - measure: + benchmark: skip: 50 number: 30 @@ -155,13 +155,13 @@ software_isp.copy_input_buffer Example value: ``false`` -software_isp.measure.skip, software_isp.measure.number - Define per-frame time measurement parameters in software ISP. `skip` +software_isp.benchmark.skip, software_isp.benchmark.number + Define performance measurement parameters for the software ISP. `skip` defines how many initial frames are skipped before starting the measurement; `number` defines how many frames then participate in the measurement. - Set `software_isp.measure.number` to 0 to disable the measurement. + Set `software_isp.benchmark.number` to 0 to disable the measurement. Example `skip` value: ``50`` diff --git a/src/libcamera/software_isp/benchmark.cpp b/src/libcamera/software_isp/benchmark.cpp index b15ddd66e26f..47bd58727ac3 100644 --- a/src/libcamera/software_isp/benchmark.cpp +++ b/src/libcamera/software_isp/benchmark.cpp @@ -34,11 +34,11 @@ Benchmark::Benchmark(const CameraManager &cm) const GlobalConfiguration &configuration = cm._d()->configuration(); skipBeforeMeasure_ = configuration.option( - { "software_isp", "measure", "skip" }) - .value_or(skipBeforeMeasure_); - framesToMeasure_ = configuration.option( - { "software_isp", "measure", "number" }) - .value_or(framesToMeasure_); + { "software_isp", "benchmark", "skip" }) + .value_or(skipBeforeMeasure_); + framesToMeasure_ = configuration.option( + { "software_isp", "benchmark", "number" }) + .value_or(framesToMeasure_); } Benchmark::~Benchmark() From patchwork Tue Jan 13 00:08:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25755 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 6FA93C32F0 for ; Tue, 13 Jan 2026 00:09:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 125C862015; Tue, 13 Jan 2026 01:09:28 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rczyoQvI"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F3CA762008 for ; Tue, 13 Jan 2026 01:09:26 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 55D1912D6 for ; Tue, 13 Jan 2026 01:09:01 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262941; bh=aNoMaVmQCckXyR5NQCh2+FMzgF7Lwlv6SmpfRTabAds=; h=From:To:Subject:Date:In-Reply-To:References:From; b=rczyoQvID7GqjLBJFhUx85ktc40bERTeXVEhweuPsI8V/FifBpLaDuihDZjo+O0on w9KWuXjYxlIFoPyJm66ZL2clTria9R5cKImLMye5kbol+neVKcjJomBHYm+GV7W0M9 MA3pB5aGylutg+suUBnYAIhNO9WuuLfYH5gZyhsM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 35/36] pipeline: simple: Rename supported_devices configuration option to devices Date: Tue, 13 Jan 2026 02:08:07 +0200 Message-ID: <20260113000808.15395-36-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The pipelines.simple.supported_devices configuration entry list per-device options for the simple pipeline handler. Rename "supported_devices" to "devices" to indicate its role more clearly. Signed-off-by: Laurent Pinchart --- Documentation/runtime_configuration.rst | 6 +++--- src/libcamera/pipeline/simple/simple.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 8c920978648d..19c2309ac94f 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -43,7 +43,7 @@ file structure: - ... # pipeline name pipelines: simple: - supported_devices: + devices: - driver: # driver name, e.g. `mxc-isi` software_isp: # true/false software_isp: @@ -76,7 +76,7 @@ Configuration file example - simple pipelines: simple: - supported_devices: + devices: - driver: mxc-isi software_isp: true software_isp: @@ -139,7 +139,7 @@ LIBCAMERA__TUNING_FILE Example value: ``/usr/local/share/libcamera/ipa/rpi/vc4/custom_sensor.json`` -pipelines.simple.supported_devices.driver, pipelines.simple.supported_devices.software_isp +pipelines.simple.devices.driver, pipelines.simple.devices.software_isp Override whether software ISP is enabled for the given driver. Example `driver` value: ``mxc-isi`` diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index bdc87d39ef0b..0ae9e081f01a 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -1881,7 +1881,7 @@ bool SimplePipelineHandler::matchDevice(std::shared_ptr media, swIspEnabled_ = info.swIspEnabled; const GlobalConfiguration &configuration = cameraManager()->_d()->configuration(); for (GlobalConfiguration::Option entry : - configuration.configuration()["pipelines"]["simple"]["supported_devices"] + configuration.configuration()["pipelines"]["simple"]["devices"] .asList()) { auto name = entry["driver"].get(); if (name == info.driver) { From patchwork Tue Jan 13 00:08:08 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 25756 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 3E3BBC32C1 for ; Tue, 13 Jan 2026 00:09:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D68DC62016; Tue, 13 Jan 2026 01:09:29 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="qxmDYvT6"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7DAC26201E for ; Tue, 13 Jan 2026 01:09:28 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi [81.175.209.152]) by perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id CF60C50A for ; Tue, 13 Jan 2026 01:09:02 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1768262942; bh=W3sHbbdsGvkaqkKeqXqBvjANtmmt7NHoaPtTLcdrprU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=qxmDYvT6IG1zyLHgDPm4ZjHTIwNEQQOiQh7kO91JfWjs1q8/AuYykglCjDhfeCvWJ j15FoJoT4756Il5eMBr2P+lrmlxMno5N8FO4wda63ddHKu3FF/YuCKe1g4wwfgLpRk IY/wpjD311C2nuM/X+xfqCdJzLMGZmVekus6SPWI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH 36/36] pipeline: simple: Turn devices configuration option into dictionary Date: Tue, 13 Jan 2026 02:08:08 +0200 Message-ID: <20260113000808.15395-37-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20260113000808.15395-1-laurent.pinchart@ideasonboard.com> References: <20260113000808.15395-1-laurent.pinchart@ideasonboard.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" The pipelines.simple.devices configuration option contains a list of devices, each of them being a dictionary with a "driver" element that acts as a unique key to index the list. Turn it into a YAML dictionary to ensure uniqueness of the key, and simplify access in the pipeline handler. Signed-off-by: Laurent Pinchart --- This simplification will preclude indexing the list of devices with a compound key. For instance, if we were to extend the simple pipeline handler to match not only on a driver name but on a (driver, driver version) pair, the current configuration file structure would allow expressing this with pipelines: simple: devices: - driver: mxc-isi driver_version: 1 software_isp: true - driver: mxc-isi driver_version: 2 software_isp: false The new structure would conceptually allow us to write pipelines: simple: devices: ? driver: mxc-isi driver_version: 1 : software_isp: true ? driver: mxc-isi driver_version: 2 : software_isp: false For those not familiar with the explicit syntax for mappings, this would translate to the following Python data if dict objects were hashable in Python: { 'pipelines': { 'simple': { 'devices': { { 'driver': 'mxc-isi', 'driver_version': 1 }: { 'software_isp': True, }, { 'driver': 'mxc-isi', 'driver_version': 2 }: { 'software_isp': False, }, }, }, }, } Yes, YAML can use complex data as keys in mappings. I would really not want to have to support that in libcamera though. Opinions will be appreciated. --- Documentation/runtime_configuration.rst | 6 +++--- src/libcamera/pipeline/simple/simple.cpp | 20 +++++++++----------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst index 19c2309ac94f..a904b09a1d35 100644 --- a/Documentation/runtime_configuration.rst +++ b/Documentation/runtime_configuration.rst @@ -44,7 +44,7 @@ file structure: pipelines: simple: devices: - - driver: # driver name, e.g. `mxc-isi` + # driver name, e.g. `mxc-isi`: software_isp: # true/false software_isp: copy_input_buffer: # true/false @@ -77,7 +77,7 @@ Configuration file example pipelines: simple: devices: - - driver: mxc-isi + mxc-isi: software_isp: true software_isp: copy_input_buffer: false @@ -139,7 +139,7 @@ LIBCAMERA__TUNING_FILE Example value: ``/usr/local/share/libcamera/ipa/rpi/vc4/custom_sensor.json`` -pipelines.simple.devices.driver, pipelines.simple.devices.software_isp +pipelines.simple.devices..software_isp Override whether software ISP is enabled for the given driver. Example `driver` value: ``mxc-isi`` diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 0ae9e081f01a..c949f3a69d16 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -1879,18 +1879,16 @@ bool SimplePipelineHandler::matchDevice(std::shared_ptr media, } swIspEnabled_ = info.swIspEnabled; + const GlobalConfiguration &configuration = cameraManager()->_d()->configuration(); - for (GlobalConfiguration::Option entry : - configuration.configuration()["pipelines"]["simple"]["devices"] - .asList()) { - auto name = entry["driver"].get(); - if (name == info.driver) { - swIspEnabled_ = entry["software_isp"].get().value_or(swIspEnabled_); - LOG(SimplePipeline, Debug) - << "Configuration file overrides software ISP for " - << info.driver << " to " << swIspEnabled_; - break; - } + GlobalConfiguration::Option &cfg = + configuration.configuration()["pipelines"]["simple"]["devices"][info.driver]; + + if (cfg) { + swIspEnabled_ = cfg["software_isp"].get().value_or(swIspEnabled_); + LOG(SimplePipeline, Debug) + << "Configuration file overrides software ISP for " + << info.driver << " to " << swIspEnabled_; } /* Locate the sensors. */