Patch Detail
Show a patch.
GET /api/patches/25739/?format=api
{ "id": 25739, "url": "https://patchwork.libcamera.org/api/patches/25739/?format=api", "web_url": "https://patchwork.libcamera.org/patch/25739/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20260113000808.15395-20-laurent.pinchart@ideasonboard.com>", "date": "2026-01-13T00:07:51", "name": "[19/36] libcamera: Rename YamlObject to ValueNode", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "27efa1c5f6a41fc0e7dec153b5d03d0e3b28bca4", "submitter": { "id": 2, "url": "https://patchwork.libcamera.org/api/people/2/?format=api", "name": "Laurent Pinchart", "email": "laurent.pinchart@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/25739/mbox/", "series": [ { "id": 5703, "url": "https://patchwork.libcamera.org/api/series/5703/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5703", "date": "2026-01-13T00:07:32", "name": "libcamera: Global configuration file improvements", "version": 1, "mbox": "https://patchwork.libcamera.org/series/5703/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/25739/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/25739/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 744E2C32AF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 13 Jan 2026 00:09:03 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DD76861FD9;\n\tTue, 13 Jan 2026 01:09:02 +0100 (CET)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A6E8561FD9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 13 Jan 2026 01:09:00 +0100 (CET)", "from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi\n\t[81.175.209.152])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id ED2EA66B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 13 Jan 2026 01:08:33 +0100 (CET)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"FKpua/hy\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1768262915;\n\tbh=dyYhf9xaDfjXxreBlvOxZE7847IP273iPLdXgxDJSoI=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=FKpua/hyzbttqZypu64aAVbKWARnJipMzabaYGr0kZ0kkblPtZK5ArkN/ByMQ08MG\n\t21o5iR+zq4vasAZhzaJ1RNc9FuuH0HywpFos6lKn2TSjJ983ig0a3W1UtRG/S94wfs\n\twKbtdOABt+CuQ0KeEbsk8Xl5pAil47Im0Du1cfto=", "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>", "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", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "The YamlObject class is now a generic data container to model trees of\nvalues. Rename it to ValueNode and expand the class documentation.\n\nWhile at it, drop the unneeded libcamera:: namespace prefix when using\nthe ValueNode class.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n .../internal/converter/converter_dw100.h | 2 +-\n .../libcamera/internal/global_configuration.h | 10 +-\n include/libcamera/internal/matrix.h | 10 +-\n include/libcamera/internal/meson.build | 2 +-\n .../internal/{yaml_object.h => value_node.h} | 34 +-\n include/libcamera/internal/vector.h | 10 +-\n include/libcamera/internal/yaml_parser.h | 4 +-\n src/android/camera_hal_config.cpp | 16 +-\n src/ipa/ipu3/algorithms/agc.cpp | 4 +-\n src/ipa/ipu3/algorithms/agc.h | 2 +-\n src/ipa/ipu3/ipu3.cpp | 2 +-\n src/ipa/libipa/agc_mean_luminance.cpp | 16 +-\n src/ipa/libipa/agc_mean_luminance.h | 12 +-\n src/ipa/libipa/algorithm.cpp | 2 +-\n src/ipa/libipa/algorithm.h | 4 +-\n src/ipa/libipa/awb.cpp | 6 +-\n src/ipa/libipa/awb.h | 6 +-\n src/ipa/libipa/awb_bayes.cpp | 4 +-\n src/ipa/libipa/awb_bayes.h | 6 +-\n src/ipa/libipa/awb_grey.cpp | 2 +-\n src/ipa/libipa/awb_grey.h | 2 +-\n src/ipa/libipa/interpolator.cpp | 2 +-\n src/ipa/libipa/interpolator.h | 4 +-\n src/ipa/libipa/lsc_polynomial.h | 6 +-\n src/ipa/libipa/lux.cpp | 6 +-\n src/ipa/libipa/lux.h | 4 +-\n src/ipa/libipa/module.cpp | 2 +-\n src/ipa/libipa/module.h | 6 +-\n src/ipa/libipa/pwl.cpp | 2 +-\n src/ipa/mali-c55/algorithms/agc.cpp | 2 +-\n src/ipa/mali-c55/algorithms/agc.h | 2 +-\n src/ipa/mali-c55/algorithms/blc.cpp | 4 +-\n src/ipa/mali-c55/algorithms/blc.h | 2 +-\n src/ipa/mali-c55/algorithms/lsc.cpp | 6 +-\n src/ipa/mali-c55/algorithms/lsc.h | 2 +-\n src/ipa/mali-c55/mali-c55.cpp | 2 +-\n src/ipa/rkisp1/algorithms/agc.cpp | 10 +-\n src/ipa/rkisp1/algorithms/agc.h | 4 +-\n src/ipa/rkisp1/algorithms/awb.cpp | 2 +-\n src/ipa/rkisp1/algorithms/awb.h | 2 +-\n src/ipa/rkisp1/algorithms/blc.cpp | 4 +-\n src/ipa/rkisp1/algorithms/blc.h | 2 +-\n src/ipa/rkisp1/algorithms/ccm.cpp | 4 +-\n src/ipa/rkisp1/algorithms/ccm.h | 4 +-\n src/ipa/rkisp1/algorithms/cproc.cpp | 2 +-\n src/ipa/rkisp1/algorithms/cproc.h | 2 +-\n src/ipa/rkisp1/algorithms/dpcc.cpp | 22 +-\n src/ipa/rkisp1/algorithms/dpcc.h | 2 +-\n src/ipa/rkisp1/algorithms/dpf.cpp | 8 +-\n src/ipa/rkisp1/algorithms/dpf.h | 2 +-\n src/ipa/rkisp1/algorithms/filter.cpp | 2 +-\n src/ipa/rkisp1/algorithms/filter.h | 2 +-\n src/ipa/rkisp1/algorithms/goc.cpp | 4 +-\n src/ipa/rkisp1/algorithms/goc.h | 2 +-\n src/ipa/rkisp1/algorithms/gsl.cpp | 6 +-\n src/ipa/rkisp1/algorithms/gsl.h | 2 +-\n src/ipa/rkisp1/algorithms/lsc.cpp | 14 +-\n src/ipa/rkisp1/algorithms/lsc.h | 2 +-\n src/ipa/rkisp1/algorithms/lux.cpp | 2 +-\n src/ipa/rkisp1/algorithms/lux.h | 2 +-\n src/ipa/rkisp1/algorithms/wdr.cpp | 4 +-\n src/ipa/rkisp1/algorithms/wdr.h | 2 +-\n src/ipa/rkisp1/rkisp1.cpp | 2 +-\n src/ipa/rpi/controller/algorithm.cpp | 2 +-\n src/ipa/rpi/controller/algorithm.h | 4 +-\n src/ipa/rpi/controller/controller.cpp | 4 +-\n src/ipa/rpi/controller/controller.h | 4 +-\n src/ipa/rpi/controller/rpi/af.cpp | 10 +-\n src/ipa/rpi/controller/rpi/af.h | 8 +-\n src/ipa/rpi/controller/rpi/agc.cpp | 2 +-\n src/ipa/rpi/controller/rpi/agc.h | 2 +-\n src/ipa/rpi/controller/rpi/agc_channel.cpp | 24 +-\n src/ipa/rpi/controller/rpi/agc_channel.h | 12 +-\n src/ipa/rpi/controller/rpi/alsc.cpp | 10 +-\n src/ipa/rpi/controller/rpi/alsc.h | 2 +-\n src/ipa/rpi/controller/rpi/awb.cpp | 10 +-\n src/ipa/rpi/controller/rpi/awb.h | 8 +-\n src/ipa/rpi/controller/rpi/black_level.cpp | 2 +-\n src/ipa/rpi/controller/rpi/black_level.h | 2 +-\n src/ipa/rpi/controller/rpi/cac.cpp | 4 +-\n src/ipa/rpi/controller/rpi/cac.h | 2 +-\n src/ipa/rpi/controller/rpi/ccm.cpp | 2 +-\n src/ipa/rpi/controller/rpi/ccm.h | 2 +-\n src/ipa/rpi/controller/rpi/contrast.cpp | 2 +-\n src/ipa/rpi/controller/rpi/contrast.h | 2 +-\n src/ipa/rpi/controller/rpi/decompand.cpp | 2 +-\n src/ipa/rpi/controller/rpi/decompand.h | 2 +-\n src/ipa/rpi/controller/rpi/denoise.cpp | 4 +-\n src/ipa/rpi/controller/rpi/denoise.h | 4 +-\n src/ipa/rpi/controller/rpi/dpc.cpp | 2 +-\n src/ipa/rpi/controller/rpi/dpc.h | 2 +-\n src/ipa/rpi/controller/rpi/geq.cpp | 2 +-\n src/ipa/rpi/controller/rpi/geq.h | 2 +-\n src/ipa/rpi/controller/rpi/hdr.cpp | 4 +-\n src/ipa/rpi/controller/rpi/hdr.h | 4 +-\n src/ipa/rpi/controller/rpi/lux.cpp | 2 +-\n src/ipa/rpi/controller/rpi/lux.h | 2 +-\n src/ipa/rpi/controller/rpi/noise.cpp | 2 +-\n src/ipa/rpi/controller/rpi/noise.h | 2 +-\n src/ipa/rpi/controller/rpi/saturation.cpp | 2 +-\n src/ipa/rpi/controller/rpi/saturation.h | 2 +-\n src/ipa/rpi/controller/rpi/sdn.cpp | 2 +-\n src/ipa/rpi/controller/rpi/sdn.h | 2 +-\n src/ipa/rpi/controller/rpi/sharpen.cpp | 2 +-\n src/ipa/rpi/controller/rpi/sharpen.h | 2 +-\n src/ipa/rpi/controller/rpi/tonemap.cpp | 2 +-\n src/ipa/rpi/controller/rpi/tonemap.h | 2 +-\n src/ipa/simple/algorithms/blc.cpp | 2 +-\n src/ipa/simple/algorithms/blc.h | 2 +-\n src/ipa/simple/algorithms/ccm.cpp | 2 +-\n src/ipa/simple/algorithms/ccm.h | 2 +-\n src/ipa/simple/algorithms/lut.cpp | 2 +-\n src/ipa/simple/algorithms/lut.h | 2 +-\n src/ipa/simple/soft_simple.cpp | 2 +-\n src/libcamera/converter/converter_dw100.cpp | 2 +-\n src/libcamera/geometry.cpp | 4 +-\n src/libcamera/global_configuration.cpp | 8 +-\n src/libcamera/matrix.cpp | 2 +-\n src/libcamera/meson.build | 2 +-\n src/libcamera/pipeline/rkisp1/rkisp1.cpp | 2 +-\n .../pipeline/rpi/common/pipeline_base.cpp | 4 +-\n .../pipeline/rpi/common/pipeline_base.h | 4 +-\n src/libcamera/pipeline/rpi/pisp/pisp.cpp | 6 +-\n src/libcamera/pipeline/rpi/vc4/vc4.cpp | 6 +-\n src/libcamera/pipeline/virtual/README.md | 2 +-\n .../pipeline/virtual/config_parser.cpp | 18 +-\n .../pipeline/virtual/config_parser.h | 12 +-\n src/libcamera/pipeline/virtual/virtual.cpp | 2 +-\n src/libcamera/value_node.cpp | 484 ++++++++++++++++++\n src/libcamera/vector.cpp | 2 +-\n src/libcamera/yaml_object.cpp | 480 -----------------\n src/libcamera/yaml_parser.cpp | 54 +-\n test/yaml-parser.cpp | 6 +-\n 133 files changed, 807 insertions(+), 803 deletions(-)\n rename include/libcamera/internal/{yaml_object.h => value_node.h} (81%)\n create mode 100644 src/libcamera/value_node.cpp\n delete mode 100644 src/libcamera/yaml_object.cpp", "diff": "diff --git a/include/libcamera/internal/converter/converter_dw100.h b/include/libcamera/internal/converter/converter_dw100.h\nindex d70c8fe76185..054750ef0866 100644\n--- a/include/libcamera/internal/converter/converter_dw100.h\n+++ b/include/libcamera/internal/converter/converter_dw100.h\n@@ -31,7 +31,7 @@ public:\n \n \tstatic std::unique_ptr<ConverterDW100Module> createModule(DeviceEnumerator *enumerator);\n \n-\tint init(const YamlObject ¶ms);\n+\tint init(const ValueNode ¶ms);\n \n \tint configure(const StreamConfiguration &inputCfg,\n \t\t const std::vector<std::reference_wrapper<StreamConfiguration>>\ndiff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h\nindex 16c6a21f2a8a..7ae923977aa6 100644\n--- a/include/libcamera/internal/global_configuration.h\n+++ b/include/libcamera/internal/global_configuration.h\n@@ -14,14 +14,14 @@\n \n #include <libcamera/base/utils.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n namespace libcamera {\n \n class GlobalConfiguration\n {\n public:\n-\tusing Configuration = const YamlObject &;\n+\tusing Configuration = const ValueNode &;\n \n \tGlobalConfiguration();\n \n@@ -32,7 +32,7 @@ public:\n \tstd::optional<T> option(\n \t\tconst std::initializer_list<std::string_view> confPath) const\n \t{\n-\t\tconst YamlObject *c = &configuration();\n+\t\tconst ValueNode *c = &configuration();\n \t\tfor (auto part : confPath) {\n \t\t\tc = &(*c)[part];\n \t\t\tif (!*c)\n@@ -55,8 +55,8 @@ private:\n \tbool loadFile(const std::filesystem::path &fileName);\n \tvoid load();\n \n-\tstd::unique_ptr<YamlObject> yamlConfiguration_ =\n-\t\tstd::make_unique<YamlObject>();\n+\tstd::unique_ptr<ValueNode> yamlConfiguration_ =\n+\t\tstd::make_unique<ValueNode>();\n };\n \n } /* namespace libcamera */\ndiff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h\nindex 11fccd27547e..0f72263f2536 100644\n--- a/include/libcamera/internal/matrix.h\n+++ b/include/libcamera/internal/matrix.h\n@@ -14,7 +14,7 @@\n #include <libcamera/base/log.h>\n #include <libcamera/base/span.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n namespace libcamera {\n \n@@ -188,7 +188,7 @@ constexpr Matrix<T, Rows, Cols> operator+(const Matrix<T, Rows, Cols> &m1, const\n }\n \n #ifndef __DOXYGEN__\n-bool matrixValidateYaml(const YamlObject &obj, unsigned int size);\n+bool matrixValidateYaml(const ValueNode &obj, unsigned int size);\n #endif /* __DOXYGEN__ */\n \n #ifndef __DOXYGEN__\n@@ -200,8 +200,8 @@ std::ostream &operator<<(std::ostream &out, const Matrix<T, Rows, Cols> &m)\n }\n \n template<typename T, unsigned int Rows, unsigned int Cols>\n-struct YamlObject::Accessor<Matrix<T, Rows, Cols>> {\n-\tstd::optional<Matrix<T, Rows, Cols>> get(const YamlObject &obj) const\n+struct ValueNode::Accessor<Matrix<T, Rows, Cols>> {\n+\tstd::optional<Matrix<T, Rows, Cols>> get(const ValueNode &obj) const\n \t{\n \t\tif (!matrixValidateYaml(obj, Rows * Cols))\n \t\t\treturn std::nullopt;\n@@ -210,7 +210,7 @@ struct YamlObject::Accessor<Matrix<T, Rows, Cols>> {\n \t\tT *data = &matrix[0][0];\n \n \t\tunsigned int i = 0;\n-\t\tfor (const YamlObject &entry : obj.asList()) {\n+\t\tfor (const ValueNode &entry : obj.asList()) {\n \t\t\tconst auto value = entry.get<T>();\n \t\t\tif (!value)\n \t\t\t\treturn std::nullopt;\ndiff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\nindex c24c9f062f29..76ab43115768 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -49,8 +49,8 @@ libcamera_internal_headers = files([\n 'v4l2_request.h',\n 'v4l2_subdevice.h',\n 'v4l2_videodevice.h',\n+ 'value_node.h',\n 'vector.h',\n- 'yaml_object.h',\n 'yaml_parser.h',\n ])\n \ndiff --git a/include/libcamera/internal/yaml_object.h b/include/libcamera/internal/value_node.h\nsimilarity index 81%\nrename from include/libcamera/internal/yaml_object.h\nrename to include/libcamera/internal/value_node.h\nindex 1771f8821e2e..a336c1d08e1c 100644\n--- a/include/libcamera/internal/yaml_object.h\n+++ b/include/libcamera/internal/value_node.h\n@@ -3,7 +3,7 @@\n * Copyright (C) 2022, Google Inc.\n * Copyright (C) 2025, Ideas on Board\n *\n- * libcamera YAML object\n+ * Data structure to manage tree of values\n */\n \n #pragma once\n@@ -22,16 +22,16 @@\n \n namespace libcamera {\n \n-class YamlObject\n+class ValueNode\n {\n private:\n \tstruct Value {\n-\t\tValue(std::string &&k, std::unique_ptr<YamlObject> &&v)\n+\t\tValue(std::string &&k, std::unique_ptr<ValueNode> &&v)\n \t\t\t: key(std::move(k)), value(std::move(v))\n \t\t{\n \t\t}\n \t\tstd::string key;\n-\t\tstd::unique_ptr<YamlObject> value;\n+\t\tstd::unique_ptr<ValueNode> value;\n \t};\n \n \tusing ValueContainer = std::vector<Value>;\n@@ -103,8 +103,8 @@ public:\n \tclass ListIterator : public Iterator<ListIterator>\n \t{\n \tpublic:\n-\t\tusing value_type = const YamlObject &;\n-\t\tusing pointer = const YamlObject *;\n+\t\tusing value_type = const ValueNode &;\n+\t\tusing pointer = const ValueNode *;\n \t\tusing reference = value_type;\n \n \t\tvalue_type operator*() const\n@@ -121,7 +121,7 @@ public:\n \tclass DictIterator : public Iterator<DictIterator>\n \t{\n \tpublic:\n-\t\tusing value_type = std::pair<const std::string &, const YamlObject &>;\n+\t\tusing value_type = std::pair<const std::string &, const ValueNode &>;\n \t\tusing pointer = value_type *;\n \t\tusing reference = value_type &;\n \n@@ -142,8 +142,8 @@ public:\n \t};\n #endif /* __DOXYGEN__ */\n \n-\tYamlObject();\n-\t~YamlObject();\n+\tValueNode();\n+\t~ValueNode();\n \n \tbool isValue() const\n \t{\n@@ -189,16 +189,16 @@ public:\n \tDictAdapter asDict() const { return DictAdapter{ list_ }; }\n \tListAdapter asList() const { return ListAdapter{ list_ }; }\n \n-\tconst YamlObject &operator[](std::size_t index) const;\n+\tconst ValueNode &operator[](std::size_t index) const;\n \n \tbool contains(std::string_view key) const;\n-\tconst YamlObject &operator[](std::string_view key) const;\n+\tconst ValueNode &operator[](std::string_view key) const;\n \n-\tYamlObject *add(std::unique_ptr<YamlObject> child);\n-\tYamlObject *add(std::string key, std::unique_ptr<YamlObject> child);\n+\tValueNode *add(std::unique_ptr<ValueNode> child);\n+\tValueNode *add(std::string key, std::unique_ptr<ValueNode> child);\n \n private:\n-\tLIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject)\n+\tLIBCAMERA_DISABLE_COPY_AND_MOVE(ValueNode)\n \n \ttemplate<typename T>\n \tfriend struct Accessor;\n@@ -212,15 +212,15 @@ private:\n \n \ttemplate<typename T, typename Enable = void>\n \tstruct Accessor {\n-\t\tstd::optional<T> get(const YamlObject &obj) const;\n-\t\tvoid set(YamlObject &obj, T value);\n+\t\tstd::optional<T> get(const ValueNode &obj) const;\n+\t\tvoid set(ValueNode &obj, T value);\n \t};\n \n \tType type_;\n \n \tstd::string value_;\n \tValueContainer list_;\n-\tstd::map<std::string, YamlObject *, std::less<>> dictionary_;\n+\tstd::map<std::string, ValueNode *, std::less<>> dictionary_;\n };\n \n } /* namespace libcamera */\ndiff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h\nindex af24485f3bb1..ed7490e16e9e 100644\n--- a/include/libcamera/internal/vector.h\n+++ b/include/libcamera/internal/vector.h\n@@ -19,7 +19,7 @@\n #include <libcamera/base/span.h>\n \n #include \"libcamera/internal/matrix.h\"\n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n namespace libcamera {\n \n@@ -329,7 +329,7 @@ bool operator!=(const Vector<T, Rows> &lhs, const Vector<T, Rows> &rhs)\n }\n \n #ifndef __DOXYGEN__\n-bool vectorValidateYaml(const YamlObject &obj, unsigned int size);\n+bool vectorValidateYaml(const ValueNode &obj, unsigned int size);\n #endif /* __DOXYGEN__ */\n \n #ifndef __DOXYGEN__\n@@ -347,8 +347,8 @@ std::ostream &operator<<(std::ostream &out, const Vector<T, Rows> &v)\n }\n \n template<typename T, unsigned int Rows>\n-struct YamlObject::Accessor<Vector<T, Rows>> {\n-\tstd::optional<Vector<T, Rows>> get(const YamlObject &obj) const\n+struct ValueNode::Accessor<Vector<T, Rows>> {\n+\tstd::optional<Vector<T, Rows>> get(const ValueNode &obj) const\n \t{\n \t\tif (!vectorValidateYaml(obj, Rows))\n \t\t\treturn std::nullopt;\n@@ -356,7 +356,7 @@ struct YamlObject::Accessor<Vector<T, Rows>> {\n \t\tVector<T, Rows> vector;\n \n \t\tunsigned int i = 0;\n-\t\tfor (const YamlObject &entry : obj.asList()) {\n+\t\tfor (const ValueNode &entry : obj.asList()) {\n \t\t\tconst auto value = entry.get<T>();\n \t\t\tif (!value)\n \t\t\t\treturn std::nullopt;\ndiff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\nindex e503e83a80da..9d4ba0a1d0e1 100644\n--- a/include/libcamera/internal/yaml_parser.h\n+++ b/include/libcamera/internal/yaml_parser.h\n@@ -9,7 +9,7 @@\n \n #include <memory>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n namespace libcamera {\n \n@@ -18,7 +18,7 @@ class File;\n class YamlParser final\n {\n public:\n-\tstatic std::unique_ptr<YamlObject> parse(File &file);\n+\tstatic std::unique_ptr<ValueNode> parse(File &file);\n };\n \n } /* namespace libcamera */\ndiff --git a/src/android/camera_hal_config.cpp b/src/android/camera_hal_config.cpp\nindex 7ef451ef8ab9..4a9c0577a0be 100644\n--- a/src/android/camera_hal_config.cpp\n+++ b/src/android/camera_hal_config.cpp\n@@ -30,9 +30,9 @@ public:\n \tint parseConfigFile(File &file, std::map<std::string, CameraConfigData> *cameras);\n \n private:\n-\tint parseCameraConfigData(const std::string &cameraId, const YamlObject &);\n-\tint parseLocation(const YamlObject &, CameraConfigData &cameraConfigData);\n-\tint parseRotation(const YamlObject &, CameraConfigData &cameraConfigData);\n+\tint parseCameraConfigData(const std::string &cameraId, const ValueNode &);\n+\tint parseLocation(const ValueNode &, CameraConfigData &cameraConfigData);\n+\tint parseRotation(const ValueNode &, CameraConfigData &cameraConfigData);\n \n \tstd::map<std::string, CameraConfigData> *cameras_;\n };\n@@ -65,7 +65,7 @@ int CameraHalConfig::Private::parseConfigFile(File &file,\n \n \tcameras_ = cameras;\n \n-\tstd::unique_ptr<YamlObject> root = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> root = YamlParser::parse(file);\n \tif (!root)\n \t\treturn -EINVAL;\n \n@@ -76,7 +76,7 @@ int CameraHalConfig::Private::parseConfigFile(File &file,\n \tif (!root->contains(\"cameras\"))\n \t\treturn -EINVAL;\n \n-\tconst YamlObject &yamlObjectCameras = (*root)[\"cameras\"];\n+\tconst ValueNode &yamlObjectCameras = (*root)[\"cameras\"];\n \n \tif (!yamlObjectCameras.isDictionary())\n \t\treturn -EINVAL;\n@@ -90,7 +90,7 @@ int CameraHalConfig::Private::parseConfigFile(File &file,\n }\n \n int CameraHalConfig::Private::parseCameraConfigData(const std::string &cameraId,\n-\t\t\t\t\t\t const YamlObject &cameraObject)\n+\t\t\t\t\t\t const ValueNode &cameraObject)\n \n {\n \tif (!cameraObject.isDictionary())\n@@ -109,7 +109,7 @@ int CameraHalConfig::Private::parseCameraConfigData(const std::string &cameraId,\n \treturn 0;\n }\n \n-int CameraHalConfig::Private::parseLocation(const YamlObject &cameraObject,\n+int CameraHalConfig::Private::parseLocation(const ValueNode &cameraObject,\n \t\t\t\t\t CameraConfigData &cameraConfigData)\n {\n \tif (!cameraObject.contains(\"location\"))\n@@ -127,7 +127,7 @@ int CameraHalConfig::Private::parseLocation(const YamlObject &cameraObject,\n \treturn 0;\n }\n \n-int CameraHalConfig::Private::parseRotation(const YamlObject &cameraObject,\n+int CameraHalConfig::Private::parseRotation(const ValueNode &cameraObject,\n \t\t\t\t\t CameraConfigData &cameraConfigData)\n {\n \tif (!cameraObject.contains(\"rotation\"))\ndiff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\nindex b0d89541da85..d6a7036c6504 100644\n--- a/src/ipa/ipu3/algorithms/agc.cpp\n+++ b/src/ipa/ipu3/algorithms/agc.cpp\n@@ -65,14 +65,14 @@ Agc::Agc()\n /**\n * \\brief Initialise the AGC algorithm from tuning files\n * \\param[in] context The shared IPA context\n- * \\param[in] tuningData The YamlObject containing Agc tuning data\n+ * \\param[in] tuningData The ValueNode containing Agc tuning data\n *\n * This function calls the base class' tuningData parsers to discover which\n * control values are supported.\n *\n * \\return 0 on success or errors from the base class\n */\n-int Agc::init(IPAContext &context, const YamlObject &tuningData)\n+int Agc::init(IPAContext &context, const ValueNode &tuningData)\n {\n \tint ret;\n \ndiff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h\nindex 890c271b4462..d274a2350485 100644\n--- a/src/ipa/ipu3/algorithms/agc.h\n+++ b/src/ipa/ipu3/algorithms/agc.h\n@@ -30,7 +30,7 @@ public:\n \tAgc();\n \t~Agc() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n \tvoid process(IPAContext &context, const uint32_t frame,\n \t\t IPAFrameContext &frameContext,\ndiff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\nindex b926f579a9a3..09f6aeb9400d 100644\n--- a/src/ipa/ipu3/ipu3.cpp\n+++ b/src/ipa/ipu3/ipu3.cpp\n@@ -324,7 +324,7 @@ int IPAIPU3::init(const IPASettings &settings,\n \t\treturn ret;\n \t}\n \n-\tstd::unique_ptr<libcamera::YamlObject> data = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> data = YamlParser::parse(file);\n \tif (!data)\n \t\treturn -EINVAL;\n \ndiff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp\nindex 72988096d384..1d385551adc6 100644\n--- a/src/ipa/libipa/agc_mean_luminance.cpp\n+++ b/src/ipa/libipa/agc_mean_luminance.cpp\n@@ -159,7 +159,7 @@ AgcMeanLuminance::AgcMeanLuminance()\n \n AgcMeanLuminance::~AgcMeanLuminance() = default;\n \n-int AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData)\n+int AgcMeanLuminance::parseRelativeLuminanceTarget(const ValueNode &tuningData)\n {\n \tauto &target = tuningData[\"relativeLuminanceTarget\"];\n \tif (!target) {\n@@ -178,7 +178,7 @@ int AgcMeanLuminance::parseRelativeLuminanceTarget(const YamlObject &tuningData)\n \treturn 0;\n }\n \n-int AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id)\n+int AgcMeanLuminance::parseConstraint(const ValueNode &modeDict, int32_t id)\n {\n \tfor (const auto &[boundName, content] : modeDict.asDict()) {\n \t\tif (boundName != \"upper\" && boundName != \"lower\") {\n@@ -212,11 +212,11 @@ int AgcMeanLuminance::parseConstraint(const YamlObject &modeDict, int32_t id)\n \treturn 0;\n }\n \n-int AgcMeanLuminance::parseConstraintModes(const YamlObject &tuningData)\n+int AgcMeanLuminance::parseConstraintModes(const ValueNode &tuningData)\n {\n \tstd::vector<ControlValue> availableConstraintModes;\n \n-\tconst YamlObject &yamlConstraintModes = tuningData[controls::AeConstraintMode.name()];\n+\tconst ValueNode &yamlConstraintModes = tuningData[controls::AeConstraintMode.name()];\n \tif (yamlConstraintModes.isDictionary()) {\n \t\tfor (const auto &[modeName, modeDict] : yamlConstraintModes.asDict()) {\n \t\t\tif (AeConstraintModeNameValueMap.find(modeName) ==\n@@ -267,11 +267,11 @@ int AgcMeanLuminance::parseConstraintModes(const YamlObject &tuningData)\n \treturn 0;\n }\n \n-int AgcMeanLuminance::parseExposureModes(const YamlObject &tuningData)\n+int AgcMeanLuminance::parseExposureModes(const ValueNode &tuningData)\n {\n \tstd::vector<ControlValue> availableExposureModes;\n \n-\tconst YamlObject &yamlExposureModes = tuningData[controls::AeExposureMode.name()];\n+\tconst ValueNode &yamlExposureModes = tuningData[controls::AeExposureMode.name()];\n \tif (yamlExposureModes.isDictionary()) {\n \t\tfor (const auto &[modeName, modeValues] : yamlExposureModes.asDict()) {\n \t\t\tif (AeExposureModeNameValueMap.find(modeName) ==\n@@ -361,7 +361,7 @@ void AgcMeanLuminance::configure(utils::Duration lineDuration,\n \n /**\n * \\brief Parse tuning data for AeConstraintMode and AeExposureMode controls\n- * \\param[in] tuningData the YamlObject representing the tuning data\n+ * \\param[in] tuningData the ValueNode representing the tuning data\n *\n * This function parses tuning data to build the list of allowed values for the\n * AeConstraintMode and AeExposureMode controls. Those tuning data must provide\n@@ -414,7 +414,7 @@ void AgcMeanLuminance::configure(utils::Duration lineDuration,\n *\n * \\return 0 on success or a negative error code\n */\n-int AgcMeanLuminance::parseTuningData(const YamlObject &tuningData)\n+int AgcMeanLuminance::parseTuningData(const ValueNode &tuningData)\n {\n \tint ret;\n \ndiff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h\nindex dfe1ccbe948b..27e92b6fce7a 100644\n--- a/src/ipa/libipa/agc_mean_luminance.h\n+++ b/src/ipa/libipa/agc_mean_luminance.h\n@@ -16,7 +16,7 @@\n \n #include <libcamera/controls.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"exposure_mode_helper.h\"\n #include \"histogram.h\"\n@@ -44,7 +44,7 @@ public:\n \t};\n \n \tvoid configure(utils::Duration lineDuration, const CameraSensorHelper *sensorHelper);\n-\tint parseTuningData(const YamlObject &tuningData);\n+\tint parseTuningData(const ValueNode &tuningData);\n \n \tvoid setExposureCompensation(double gain)\n \t{\n@@ -88,10 +88,10 @@ public:\n private:\n \tvirtual double estimateLuminance(const double gain) const = 0;\n \n-\tint parseRelativeLuminanceTarget(const YamlObject &tuningData);\n-\tint parseConstraint(const YamlObject &modeDict, int32_t id);\n-\tint parseConstraintModes(const YamlObject &tuningData);\n-\tint parseExposureModes(const YamlObject &tuningData);\n+\tint parseRelativeLuminanceTarget(const ValueNode &tuningData);\n+\tint parseConstraint(const ValueNode &modeDict, int32_t id);\n+\tint parseConstraintModes(const ValueNode &tuningData);\n+\tint parseExposureModes(const ValueNode &tuningData);\n \tdouble estimateInitialGain() const;\n \tdouble constraintClampGain(uint32_t constraintModeIndex,\n \t\t\t\t const Histogram &hist,\ndiff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp\nindex 201efdfdba25..757ce3519652 100644\n--- a/src/ipa/libipa/algorithm.cpp\n+++ b/src/ipa/libipa/algorithm.cpp\n@@ -44,7 +44,7 @@ namespace ipa {\n * \\param[in] tuningData The tuning data for the algorithm\n *\n * This function is called once, when the IPA module is initialized, to\n- * initialize the algorithm. The \\a tuningData YamlObject contains the tuning\n+ * initialize the algorithm. The \\a tuningData ValueNode contains the tuning\n * data for algorithm.\n *\n * \\return 0 if successful, an error code otherwise\ndiff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h\nindex 9a19dbd61b31..4ddb16ef3920 100644\n--- a/src/ipa/libipa/algorithm.h\n+++ b/src/ipa/libipa/algorithm.h\n@@ -14,7 +14,7 @@\n \n namespace libcamera {\n \n-class YamlObject;\n+class ValueNode;\n \n namespace ipa {\n \n@@ -27,7 +27,7 @@ public:\n \tvirtual ~Algorithm() {}\n \n \tvirtual int init([[maybe_unused]] typename Module::Context &context,\n-\t\t\t [[maybe_unused]] const YamlObject &tuningData)\n+\t\t\t [[maybe_unused]] const ValueNode &tuningData)\n \t{\n \t\treturn 0;\n \t}\ndiff --git a/src/ipa/libipa/awb.cpp b/src/ipa/libipa/awb.cpp\nindex 214bac8b56a6..af966f1e007c 100644\n--- a/src/ipa/libipa/awb.cpp\n+++ b/src/ipa/libipa/awb.cpp\n@@ -132,7 +132,7 @@ namespace ipa {\n \n /**\n * \\brief Parse the mode configurations from the tuning data\n- * \\param[in] tuningData the YamlObject representing the tuning data\n+ * \\param[in] tuningData the ValueNode representing the tuning data\n * \\param[in] def The default value for the AwbMode control\n *\n * Utility function to parse the tuning data for an AwbMode entry and read all\n@@ -162,12 +162,12 @@ namespace ipa {\n * \\sa controls::AwbModeEnum\n * \\return Zero on success, negative error code otherwise\n */\n-int AwbAlgorithm::parseModeConfigs(const YamlObject &tuningData,\n+int AwbAlgorithm::parseModeConfigs(const ValueNode &tuningData,\n \t\t\t\t const ControlValue &def)\n {\n \tstd::vector<ControlValue> availableModes;\n \n-\tconst YamlObject &yamlModes = tuningData[controls::AwbMode.name()];\n+\tconst ValueNode &yamlModes = tuningData[controls::AwbMode.name()];\n \tif (!yamlModes.isDictionary()) {\n \t\tLOG(Awb, Error)\n \t\t\t<< \"AwbModes must be a dictionary.\";\ndiff --git a/src/ipa/libipa/awb.h b/src/ipa/libipa/awb.h\nindex 3f25d13feaa8..09c00e47d604 100644\n--- a/src/ipa/libipa/awb.h\n+++ b/src/ipa/libipa/awb.h\n@@ -13,8 +13,8 @@\n #include <libcamera/control_ids.h>\n #include <libcamera/controls.h>\n \n+#include \"libcamera/internal/value_node.h\"\n #include \"libcamera/internal/vector.h\"\n-#include \"libcamera/internal/yaml_object.h\"\n \n namespace libcamera {\n \n@@ -38,7 +38,7 @@ class AwbAlgorithm\n public:\n \tvirtual ~AwbAlgorithm() = default;\n \n-\tvirtual int init(const YamlObject &tuningData) = 0;\n+\tvirtual int init(const ValueNode &tuningData) = 0;\n \tvirtual AwbResult calculateAwb(const AwbStats &stats, unsigned int lux) = 0;\n \tvirtual std::optional<RGB<double>> gainsFromColourTemperature(double colourTemperature) = 0;\n \n@@ -50,7 +50,7 @@ public:\n \tvirtual void handleControls([[maybe_unused]] const ControlList &controls) {}\n \n protected:\n-\tint parseModeConfigs(const YamlObject &tuningData,\n+\tint parseModeConfigs(const ValueNode &tuningData,\n \t\t\t const ControlValue &def = {});\n \n \tstruct ModeConfig {\ndiff --git a/src/ipa/libipa/awb_bayes.cpp b/src/ipa/libipa/awb_bayes.cpp\nindex 595bd0705732..a1412c8bd2b5 100644\n--- a/src/ipa/libipa/awb_bayes.cpp\n+++ b/src/ipa/libipa/awb_bayes.cpp\n@@ -143,7 +143,7 @@ void Interpolator<Pwl>::interpolate(const Pwl &a, const Pwl &b, Pwl &dest, doubl\n * \\brief The currently selected mode\n */\n \n-int AwbBayes::init(const YamlObject &tuningData)\n+int AwbBayes::init(const ValueNode &tuningData)\n {\n \tint ret = colourGainCurve_.readYaml(tuningData[\"colourGains\"], \"ct\", \"gains\");\n \tif (ret) {\n@@ -188,7 +188,7 @@ int AwbBayes::init(const YamlObject &tuningData)\n \treturn 0;\n }\n \n-int AwbBayes::readPriors(const YamlObject &tuningData)\n+int AwbBayes::readPriors(const ValueNode &tuningData)\n {\n \tconst auto &priorsList = tuningData[\"priors\"];\n \tstd::map<uint32_t, Pwl> priors;\ndiff --git a/src/ipa/libipa/awb_bayes.h b/src/ipa/libipa/awb_bayes.h\nindex 79334ad3e7a3..1e3373676bc0 100644\n--- a/src/ipa/libipa/awb_bayes.h\n+++ b/src/ipa/libipa/awb_bayes.h\n@@ -9,8 +9,8 @@\n \n #include <libcamera/controls.h>\n \n+#include \"libcamera/internal/value_node.h\"\n #include \"libcamera/internal/vector.h\"\n-#include \"libcamera/internal/yaml_object.h\"\n \n #include \"awb.h\"\n #include \"interpolator.h\"\n@@ -25,13 +25,13 @@ class AwbBayes : public AwbAlgorithm\n public:\n \tAwbBayes() = default;\n \n-\tint init(const YamlObject &tuningData) override;\n+\tint init(const ValueNode &tuningData) override;\n \tAwbResult calculateAwb(const AwbStats &stats, unsigned int lux) override;\n \tstd::optional<RGB<double>> gainsFromColourTemperature(double temperatureK) override;\n \tvoid handleControls(const ControlList &controls) override;\n \n private:\n-\tint readPriors(const YamlObject &tuningData);\n+\tint readPriors(const ValueNode &tuningData);\n \n \tvoid fineSearch(double &t, double &r, double &b, ipa::Pwl const &prior,\n \t\t\tconst AwbStats &stats) const;\ndiff --git a/src/ipa/libipa/awb_grey.cpp b/src/ipa/libipa/awb_grey.cpp\nindex d252edb2b6c6..b14b096810ae 100644\n--- a/src/ipa/libipa/awb_grey.cpp\n+++ b/src/ipa/libipa/awb_grey.cpp\n@@ -41,7 +41,7 @@ namespace ipa {\n *\n * \\return 0 on success, a negative error code otherwise\n */\n-int AwbGrey::init(const YamlObject &tuningData)\n+int AwbGrey::init(const ValueNode &tuningData)\n {\n \tInterpolator<Vector<double, 2>> gains;\n \tint ret = gains.readYaml(tuningData[\"colourGains\"], \"ct\", \"gains\");\ndiff --git a/src/ipa/libipa/awb_grey.h b/src/ipa/libipa/awb_grey.h\nindex f82a368d11cc..154a2af97f15 100644\n--- a/src/ipa/libipa/awb_grey.h\n+++ b/src/ipa/libipa/awb_grey.h\n@@ -23,7 +23,7 @@ class AwbGrey : public AwbAlgorithm\n public:\n \tAwbGrey() = default;\n \n-\tint init(const YamlObject &tuningData) override;\n+\tint init(const ValueNode &tuningData) override;\n \tAwbResult calculateAwb(const AwbStats &stats, unsigned int lux) override;\n \tstd::optional<RGB<double>> gainsFromColourTemperature(double colourTemperature) override;\n \ndiff --git a/src/ipa/libipa/interpolator.cpp b/src/ipa/libipa/interpolator.cpp\nindex 9355802f796a..6bd83849262e 100644\n--- a/src/ipa/libipa/interpolator.cpp\n+++ b/src/ipa/libipa/interpolator.cpp\n@@ -53,7 +53,7 @@ namespace ipa {\n */\n \n /**\n- * \\fn int Interpolator<T>::readYaml(const libcamera::YamlObject &yaml,\n+ * \\fn int Interpolator<T>::readYaml(const ValueNode &yaml,\n \t\t const std::string &key_name,\n \t\t const std::string &value_name)\n * \\brief Initialize an Interpolator instance from yaml\ndiff --git a/src/ipa/libipa/interpolator.h b/src/ipa/libipa/interpolator.h\nindex 08003a06dbba..c67091e21ca6 100644\n--- a/src/ipa/libipa/interpolator.h\n+++ b/src/ipa/libipa/interpolator.h\n@@ -15,7 +15,7 @@\n \n #include <libcamera/base/log.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n namespace libcamera {\n \n@@ -39,7 +39,7 @@ public:\n \n \t~Interpolator() = default;\n \n-\tint readYaml(const libcamera::YamlObject &yaml,\n+\tint readYaml(const ValueNode &yaml,\n \t\t const std::string &key_name,\n \t\t const std::string &value_name)\n \t{\ndiff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h\nindex 19da46860849..d7d9ae42e360 100644\n--- a/src/ipa/libipa/lsc_polynomial.h\n+++ b/src/ipa/libipa/lsc_polynomial.h\n@@ -16,7 +16,7 @@\n \n #include <libcamera/geometry.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n namespace libcamera {\n \n@@ -83,8 +83,8 @@ private:\n #ifndef __DOXYGEN__\n \n template<>\n-struct YamlObject::Accessor<ipa::LscPolynomial> {\n-\tstd::optional<ipa::LscPolynomial> get(const YamlObject &obj) const\n+struct ValueNode::Accessor<ipa::LscPolynomial> {\n+\tstd::optional<ipa::LscPolynomial> get(const ValueNode &obj) const\n \t{\n \t\tstd::optional<double> cx = obj[\"cx\"].get<double>();\n \t\tstd::optional<double> cy = obj[\"cy\"].get<double>();\ndiff --git a/src/ipa/libipa/lux.cpp b/src/ipa/libipa/lux.cpp\nindex d79b116a3339..46cc63a115b5 100644\n--- a/src/ipa/libipa/lux.cpp\n+++ b/src/ipa/libipa/lux.cpp\n@@ -12,7 +12,7 @@\n \n #include <libcamera/base/log.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"histogram.h\"\n \n@@ -78,7 +78,7 @@ Lux::Lux()\n \n /**\n * \\brief Parse tuning data\n- * \\param[in] tuningData The YamlObject representing the tuning data\n+ * \\param[in] tuningData The ValueNode representing the tuning data\n *\n * This function parses yaml tuning data for the common Lux module. It requires\n * reference exposure time, analogue gain, digital gain, and lux values.\n@@ -95,7 +95,7 @@ Lux::Lux()\n *\n * \\return 0 on success or a negative error code\n */\n-int Lux::parseTuningData(const YamlObject &tuningData)\n+int Lux::parseTuningData(const ValueNode &tuningData)\n {\n \tauto value = tuningData[\"referenceExposureTime\"].get<double>();\n \tif (!value) {\ndiff --git a/src/ipa/libipa/lux.h b/src/ipa/libipa/lux.h\nindex d95bcdafcfcd..b6837ab729de 100644\n--- a/src/ipa/libipa/lux.h\n+++ b/src/ipa/libipa/lux.h\n@@ -12,7 +12,7 @@\n \n namespace libcamera {\n \n-class YamlObject;\n+class ValueNode;\n \n namespace ipa {\n \n@@ -23,7 +23,7 @@ class Lux\n public:\n \tLux();\n \n-\tint parseTuningData(const YamlObject &tuningData);\n+\tint parseTuningData(const ValueNode &tuningData);\n \tdouble estimateLux(utils::Duration exposureTime,\n \t\t\t double aGain, double dGain,\n \t\t\t const Histogram &yHist) const;\ndiff --git a/src/ipa/libipa/module.cpp b/src/ipa/libipa/module.cpp\nindex a95dca696adf..76e10e250b73 100644\n--- a/src/ipa/libipa/module.cpp\n+++ b/src/ipa/libipa/module.cpp\n@@ -87,7 +87,7 @@ namespace ipa {\n * \\fn Module::createAlgorithms()\n * \\brief Create algorithms from YAML configuration data\n * \\param[in] context The IPA context\n- * \\param[in] algorithms Algorithms configuration data as a parsed YamlObject\n+ * \\param[in] algorithms Algorithms configuration data as a parsed ValueNode\n *\n * This function iterates over the list of \\a algorithms parsed from the YAML\n * configuration file, and instantiates and initializes the corresponding\ndiff --git a/src/ipa/libipa/module.h b/src/ipa/libipa/module.h\nindex 8e6c658a6b63..3e2408ca30b6 100644\n--- a/src/ipa/libipa/module.h\n+++ b/src/ipa/libipa/module.h\n@@ -15,7 +15,7 @@\n #include <libcamera/base/log.h>\n #include <libcamera/base/utils.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"algorithm.h\"\n \n@@ -43,7 +43,7 @@ public:\n \t\treturn algorithms_;\n \t}\n \n-\tint createAlgorithms(Context &context, const YamlObject &algorithms)\n+\tint createAlgorithms(Context &context, const ValueNode &algorithms)\n \t{\n \t\tconst auto &list = algorithms.asList();\n \n@@ -71,7 +71,7 @@ public:\n \t}\n \n private:\n-\tint createAlgorithm(Context &context, const YamlObject &data)\n+\tint createAlgorithm(Context &context, const ValueNode &data)\n \t{\n \t\tconst auto &[name, algoData] = *data.asDict().begin();\n \ndiff --git a/src/ipa/libipa/pwl.cpp b/src/ipa/libipa/pwl.cpp\nindex f38573e69c13..9fddd5bf70e2 100644\n--- a/src/ipa/libipa/pwl.cpp\n+++ b/src/ipa/libipa/pwl.cpp\n@@ -435,7 +435,7 @@ std::string Pwl::toString() const\n */\n template<>\n std::optional<ipa::Pwl>\n-YamlObject::Accessor<ipa::Pwl>::get(const YamlObject &obj) const\n+ValueNode::Accessor<ipa::Pwl>::get(const ValueNode &obj) const\n {\n \t/* Treat a single value as single point PWL. */\n \tif (obj.isValue()) {\ndiff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp\nindex 014fd12452ac..e4ac735ccabc 100644\n--- a/src/ipa/mali-c55/algorithms/agc.cpp\n+++ b/src/ipa/mali-c55/algorithms/agc.cpp\n@@ -131,7 +131,7 @@ Agc::Agc()\n {\n }\n \n-int Agc::init(IPAContext &context, const YamlObject &tuningData)\n+int Agc::init(IPAContext &context, const ValueNode &tuningData)\n {\n \tint ret = parseTuningData(tuningData);\n \tif (ret)\ndiff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h\nindex 9684fff664bc..ee913de2b2e2 100644\n--- a/src/ipa/mali-c55/algorithms/agc.h\n+++ b/src/ipa/mali-c55/algorithms/agc.h\n@@ -49,7 +49,7 @@ public:\n \tAgc();\n \t~Agc() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t const IPACameraSensorInfo &configInfo) override;\n \tvoid queueRequest(IPAContext &context, const uint32_t frame,\ndiff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp\nindex 3bdf19141e1d..591a5eaf2dc8 100644\n--- a/src/ipa/mali-c55/algorithms/blc.cpp\n+++ b/src/ipa/mali-c55/algorithms/blc.cpp\n@@ -10,7 +10,7 @@\n #include <libcamera/base/log.h>\n #include <libcamera/control_ids.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n /**\n * \\file blc.h\n@@ -36,7 +36,7 @@ BlackLevelCorrection::BlackLevelCorrection()\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n int BlackLevelCorrection::init([[maybe_unused]] IPAContext &context,\n-\t\t\t const YamlObject &tuningData)\n+\t\t\t const ValueNode &tuningData)\n {\n \toffset00 = tuningData[\"offset00\"].get<uint32_t>(0);\n \toffset01 = tuningData[\"offset01\"].get<uint32_t>(0);\ndiff --git a/src/ipa/mali-c55/algorithms/blc.h b/src/ipa/mali-c55/algorithms/blc.h\nindex fc5a7ea310cb..bce343e20c55 100644\n--- a/src/ipa/mali-c55/algorithms/blc.h\n+++ b/src/ipa/mali-c55/algorithms/blc.h\n@@ -18,7 +18,7 @@ public:\n \tBlackLevelCorrection();\n \t~BlackLevelCorrection() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t const IPACameraSensorInfo &configInfo) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\ndiff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp\nindex e32f5a83485e..fe230fdff418 100644\n--- a/src/ipa/mali-c55/algorithms/lsc.cpp\n+++ b/src/ipa/mali-c55/algorithms/lsc.cpp\n@@ -7,7 +7,7 @@\n \n #include \"lsc.h\"\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n namespace libcamera {\n \n@@ -15,7 +15,7 @@ namespace ipa::mali_c55::algorithms {\n \n LOG_DEFINE_CATEGORY(MaliC55Lsc)\n \n-int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)\n+int Lsc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData)\n {\n \tif (!tuningData.contains(\"meshScale\")) {\n \t\tLOG(MaliC55Lsc, Error) << \"meshScale missing from tuningData\";\n@@ -24,7 +24,7 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData\n \n \tmeshScale_ = tuningData[\"meshScale\"].get<uint32_t>(0);\n \n-\tconst YamlObject &yamlSets = tuningData[\"sets\"];\n+\tconst ValueNode &yamlSets = tuningData[\"sets\"];\n \tif (!yamlSets.isList()) {\n \t\tLOG(MaliC55Lsc, Error) << \"LSC tables missing or invalid\";\n \t\treturn -EINVAL;\ndiff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h\nindex e7092bc74a0b..3d35fd72bfa8 100644\n--- a/src/ipa/mali-c55/algorithms/lsc.h\n+++ b/src/ipa/mali-c55/algorithms/lsc.h\n@@ -20,7 +20,7 @@ public:\n \tLsc() = default;\n \t~Lsc() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t IPAFrameContext &frameContext,\n \t\t MaliC55Params *params) override;\ndiff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp\nindex 1d2a4f75cf8c..e4637548ac4d 100644\n--- a/src/ipa/mali-c55/mali-c55.cpp\n+++ b/src/ipa/mali-c55/mali-c55.cpp\n@@ -118,7 +118,7 @@ int IPAMaliC55::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig\n \t\treturn ret;\n \t}\n \n-\tstd::unique_ptr<libcamera::YamlObject> data = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> data = YamlParser::parse(file);\n \tif (!data)\n \t\treturn -EINVAL;\n \ndiff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\nindex ef16a3775056..523930488a3b 100644\n--- a/src/ipa/rkisp1/algorithms/agc.cpp\n+++ b/src/ipa/rkisp1/algorithms/agc.cpp\n@@ -19,7 +19,7 @@\n #include <libcamera/control_ids.h>\n #include <libcamera/ipa/core_ipa_interface.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"libipa/histogram.h\"\n \n@@ -40,7 +40,7 @@ namespace ipa::rkisp1::algorithms {\n \n LOG_DEFINE_CATEGORY(RkISP1Agc)\n \n-int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData)\n+int Agc::parseMeteringModes(IPAContext &context, const ValueNode &tuningData)\n {\n \tif (!tuningData.isDictionary())\n \t\tLOG(RkISP1Agc, Warning)\n@@ -127,14 +127,14 @@ Agc::Agc()\n /**\n * \\brief Initialise the AGC algorithm from tuning files\n * \\param[in] context The shared IPA context\n- * \\param[in] tuningData The YamlObject containing Agc tuning data\n+ * \\param[in] tuningData The ValueNode containing Agc tuning data\n *\n * This function calls the base class' tuningData parsers to discover which\n * control values are supported.\n *\n * \\return 0 on success or errors from the base class\n */\n-int Agc::init(IPAContext &context, const YamlObject &tuningData)\n+int Agc::init(IPAContext &context, const ValueNode &tuningData)\n {\n \tint ret;\n \n@@ -142,7 +142,7 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)\n \tif (ret)\n \t\treturn ret;\n \n-\tconst YamlObject &yamlMeteringModes = tuningData[\"AeMeteringMode\"];\n+\tconst ValueNode &yamlMeteringModes = tuningData[\"AeMeteringMode\"];\n \tret = parseMeteringModes(context, yamlMeteringModes);\n \tif (ret)\n \t\treturn ret;\ndiff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\nindex 7867eed9c4e3..dec79f2f399c 100644\n--- a/src/ipa/rkisp1/algorithms/agc.h\n+++ b/src/ipa/rkisp1/algorithms/agc.h\n@@ -28,7 +28,7 @@ public:\n \tAgc();\n \t~Agc() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override;\n \tvoid queueRequest(IPAContext &context,\n \t\t\t const uint32_t frame,\n@@ -43,7 +43,7 @@ public:\n \t\t ControlList &metadata) override;\n \n private:\n-\tint parseMeteringModes(IPAContext &context, const YamlObject &tuningData);\n+\tint parseMeteringModes(IPAContext &context, const ValueNode &tuningData);\n \tuint8_t computeHistogramPredivider(const Size &size,\n \t\t\t\t\t enum rkisp1_cif_isp_histogram_mode mode);\n \ndiff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\nindex e8da7974a1d6..1d248beba61f 100644\n--- a/src/ipa/rkisp1/algorithms/awb.cpp\n+++ b/src/ipa/rkisp1/algorithms/awb.cpp\n@@ -84,7 +84,7 @@ Awb::Awb()\n /**\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n-int Awb::init(IPAContext &context, const YamlObject &tuningData)\n+int Awb::init(IPAContext &context, const ValueNode &tuningData)\n {\n \tauto &cmap = context.ctrlMap;\n \tcmap[&controls::ColourTemperature] = ControlInfo(kMinColourTemperature,\ndiff --git a/src/ipa/rkisp1/algorithms/awb.h b/src/ipa/rkisp1/algorithms/awb.h\nindex 02651cc732bf..60d9ef111495 100644\n--- a/src/ipa/rkisp1/algorithms/awb.h\n+++ b/src/ipa/rkisp1/algorithms/awb.h\n@@ -24,7 +24,7 @@ public:\n \tAwb();\n \t~Awb() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override;\n \tvoid queueRequest(IPAContext &context, const uint32_t frame,\n \t\t\t IPAFrameContext &frameContext,\ndiff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp\nindex 19c262fffa73..1ed700a205c8 100644\n--- a/src/ipa/rkisp1/algorithms/blc.cpp\n+++ b/src/ipa/rkisp1/algorithms/blc.cpp\n@@ -13,7 +13,7 @@\n \n #include <libcamera/control_ids.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n /**\n * \\file blc.h\n@@ -53,7 +53,7 @@ BlackLevelCorrection::BlackLevelCorrection()\n /**\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n-int BlackLevelCorrection::init(IPAContext &context, const YamlObject &tuningData)\n+int BlackLevelCorrection::init(IPAContext &context, const ValueNode &tuningData)\n {\n \tstd::optional<int16_t> levelRed = tuningData[\"R\"].get<int16_t>();\n \tstd::optional<int16_t> levelGreenR = tuningData[\"Gr\"].get<int16_t>();\ndiff --git a/src/ipa/rkisp1/algorithms/blc.h b/src/ipa/rkisp1/algorithms/blc.h\nindex f797ae44d639..3b2b0ce6e2a8 100644\n--- a/src/ipa/rkisp1/algorithms/blc.h\n+++ b/src/ipa/rkisp1/algorithms/blc.h\n@@ -19,7 +19,7 @@ public:\n \tBlackLevelCorrection();\n \t~BlackLevelCorrection() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t const IPACameraSensorInfo &configInfo) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\ndiff --git a/src/ipa/rkisp1/algorithms/ccm.cpp b/src/ipa/rkisp1/algorithms/ccm.cpp\nindex 3ed307280677..710989de1d74 100644\n--- a/src/ipa/rkisp1/algorithms/ccm.cpp\n+++ b/src/ipa/rkisp1/algorithms/ccm.cpp\n@@ -16,7 +16,7 @@\n \n #include <libcamera/ipa/core_ipa_interface.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"libipa/fixedpoint.h\"\n #include \"libipa/interpolator.h\"\n@@ -41,7 +41,7 @@ constexpr Matrix<float, 3, 3> kIdentity3x3 = Matrix<float, 3, 3>::identity();\n /**\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n-int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)\n+int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData)\n {\n \tauto &cmap = context.ctrlMap;\n \tcmap[&controls::ColourCorrectionMatrix] = ControlInfo(\ndiff --git a/src/ipa/rkisp1/algorithms/ccm.h b/src/ipa/rkisp1/algorithms/ccm.h\nindex c301e6e531c8..9ac537426d16 100644\n--- a/src/ipa/rkisp1/algorithms/ccm.h\n+++ b/src/ipa/rkisp1/algorithms/ccm.h\n@@ -25,7 +25,7 @@ public:\n \tCcm() {}\n \t~Ccm() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t const IPACameraSensorInfo &configInfo) override;\n \tvoid queueRequest(IPAContext &context,\n@@ -41,7 +41,7 @@ public:\n \t\t ControlList &metadata) override;\n \n private:\n-\tvoid parseYaml(const YamlObject &tuningData);\n+\tvoid parseYaml(const ValueNode &tuningData);\n \tvoid setParameters(struct rkisp1_cif_isp_ctk_config &config,\n \t\t\t const Matrix<float, 3, 3> &matrix,\n \t\t\t const Matrix<int16_t, 3, 1> &offsets);\ndiff --git a/src/ipa/rkisp1/algorithms/cproc.cpp b/src/ipa/rkisp1/algorithms/cproc.cpp\nindex d1fff6990d37..ae3effacd359 100644\n--- a/src/ipa/rkisp1/algorithms/cproc.cpp\n+++ b/src/ipa/rkisp1/algorithms/cproc.cpp\n@@ -55,7 +55,7 @@ int convertContrastOrSaturation(const float v)\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n int ColorProcessing::init(IPAContext &context,\n-\t\t\t [[maybe_unused]] const YamlObject &tuningData)\n+\t\t\t [[maybe_unused]] const ValueNode &tuningData)\n {\n \tauto &cmap = context.ctrlMap;\n \ndiff --git a/src/ipa/rkisp1/algorithms/cproc.h b/src/ipa/rkisp1/algorithms/cproc.h\nindex fd38fd17e8bb..a3863b94fb6e 100644\n--- a/src/ipa/rkisp1/algorithms/cproc.h\n+++ b/src/ipa/rkisp1/algorithms/cproc.h\n@@ -21,7 +21,7 @@ public:\n \tColorProcessing() = default;\n \t~ColorProcessing() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t const IPACameraSensorInfo &configInfo) override;\n \tvoid queueRequest(IPAContext &context, const uint32_t frame,\ndiff --git a/src/ipa/rkisp1/algorithms/dpcc.cpp b/src/ipa/rkisp1/algorithms/dpcc.cpp\nindex c195334750e1..eb8cbf2049c5 100644\n--- a/src/ipa/rkisp1/algorithms/dpcc.cpp\n+++ b/src/ipa/rkisp1/algorithms/dpcc.cpp\n@@ -9,7 +9,7 @@\n \n #include <libcamera/base/log.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"linux/rkisp1-config.h\"\n \n@@ -45,7 +45,7 @@ DefectPixelClusterCorrection::DefectPixelClusterCorrection()\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n-\t\t\t\t const YamlObject &tuningData)\n+\t\t\t\t const ValueNode &tuningData)\n {\n \tconfig_.mode = RKISP1_CIF_ISP_DPCC_MODE_STAGE1_ENABLE;\n \tconfig_.output_mode = RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_STAGE1_INCL_G_CENTER\n@@ -55,7 +55,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n \t\t\t? RKISP1_CIF_ISP_DPCC_SET_USE_STAGE1_USE_FIX_SET : 0;\n \n \t/* Get all defined sets to apply (up to 3). */\n-\tconst YamlObject &setsObject = tuningData[\"sets\"];\n+\tconst ValueNode &setsObject = tuningData[\"sets\"];\n \tif (!setsObject.isList()) {\n \t\tLOG(RkISP1Dpcc, Error)\n \t\t\t<< \"'sets' parameter not found in tuning file\";\n@@ -71,14 +71,14 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n \n \tfor (std::size_t i = 0; i < setsObject.size(); ++i) {\n \t\tstruct rkisp1_cif_isp_dpcc_methods_config &method = config_.methods[i];\n-\t\tconst YamlObject &set = setsObject[i];\n+\t\tconst ValueNode &set = setsObject[i];\n \t\tuint16_t value;\n \n \t\t/* Enable set if described in YAML tuning file. */\n \t\tconfig_.set_use |= 1 << i;\n \n \t\t/* PG Method */\n-\t\tconst YamlObject &pgObject = set[\"pg-factor\"];\n+\t\tconst ValueNode &pgObject = set[\"pg-factor\"];\n \n \t\tif (pgObject.contains(\"green\")) {\n \t\t\tmethod.method |=\n@@ -97,7 +97,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n \t\t}\n \n \t\t/* RO Method */\n-\t\tconst YamlObject &roObject = set[\"ro-limits\"];\n+\t\tconst ValueNode &roObject = set[\"ro-limits\"];\n \n \t\tif (roObject.contains(\"green\")) {\n \t\t\tmethod.method |=\n@@ -118,7 +118,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n \t\t}\n \n \t\t/* RG Method */\n-\t\tconst YamlObject &rgObject = set[\"rg-factor\"];\n+\t\tconst ValueNode &rgObject = set[\"rg-factor\"];\n \t\tmethod.rg_fac = 0;\n \n \t\tif (rgObject.contains(\"green\")) {\n@@ -138,7 +138,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n \t\t}\n \n \t\t/* RND Method */\n-\t\tconst YamlObject &rndOffsetsObject = set[\"rnd-offsets\"];\n+\t\tconst ValueNode &rndOffsetsObject = set[\"rnd-offsets\"];\n \n \t\tif (rndOffsetsObject.contains(\"green\")) {\n \t\t\tmethod.method |=\n@@ -158,7 +158,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n \t\t\t\tRKISP1_CIF_ISP_DPCC_RND_OFFS_n_RB(i, value);\n \t\t}\n \n-\t\tconst YamlObject &rndThresholdObject = set[\"rnd-threshold\"];\n+\t\tconst ValueNode &rndThresholdObject = set[\"rnd-threshold\"];\n \t\tmethod.rnd_thresh = 0;\n \n \t\tif (rndThresholdObject.contains(\"green\")) {\n@@ -180,7 +180,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n \t\t}\n \n \t\t/* LC Method */\n-\t\tconst YamlObject &lcThresholdObject = set[\"line-threshold\"];\n+\t\tconst ValueNode &lcThresholdObject = set[\"line-threshold\"];\n \t\tmethod.line_thresh = 0;\n \n \t\tif (lcThresholdObject.contains(\"green\")) {\n@@ -201,7 +201,7 @@ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context,\n \t\t\t\tRKISP1_CIF_ISP_DPCC_LINE_THRESH_RB(value);\n \t\t}\n \n-\t\tconst YamlObject &lcTMadFactorObject = set[\"line-mad-factor\"];\n+\t\tconst ValueNode &lcTMadFactorObject = set[\"line-mad-factor\"];\n \t\tmethod.line_mad_fac = 0;\n \n \t\tif (lcTMadFactorObject.contains(\"green\")) {\ndiff --git a/src/ipa/rkisp1/algorithms/dpcc.h b/src/ipa/rkisp1/algorithms/dpcc.h\nindex b77766c300fb..50b62e9bab3f 100644\n--- a/src/ipa/rkisp1/algorithms/dpcc.h\n+++ b/src/ipa/rkisp1/algorithms/dpcc.h\n@@ -19,7 +19,7 @@ public:\n \tDefectPixelClusterCorrection();\n \t~DefectPixelClusterCorrection() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t IPAFrameContext &frameContext,\n \t\t RkISP1Params *params) override;\ndiff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp\nindex ec989bc2421f..b681ddeb96df 100644\n--- a/src/ipa/rkisp1/algorithms/dpf.cpp\n+++ b/src/ipa/rkisp1/algorithms/dpf.cpp\n@@ -45,7 +45,7 @@ Dpf::Dpf()\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n int Dpf::init([[maybe_unused]] IPAContext &context,\n-\t const YamlObject &tuningData)\n+\t const ValueNode &tuningData)\n {\n \tstd::vector<uint8_t> values;\n \n@@ -53,7 +53,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context,\n \t * The domain kernel is configured with a 9x9 kernel for the green\n \t * pixels, and a 13x9 or 9x9 kernel for red and blue pixels.\n \t */\n-\tconst YamlObject &dFObject = tuningData[\"DomainFilter\"];\n+\tconst ValueNode &dFObject = tuningData[\"DomainFilter\"];\n \n \t/*\n \t * For the green component, we have the 9x9 kernel specified\n@@ -134,7 +134,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context,\n \t * which stores a piecewise linear function that characterizes the\n \t * sensor noise profile as a noise level function curve (NLF).\n \t */\n-\tconst YamlObject &rFObject = tuningData[\"NoiseLevelFunction\"];\n+\tconst ValueNode &rFObject = tuningData[\"NoiseLevelFunction\"];\n \n \tstd::vector<uint16_t> nllValues;\n \tnllValues = rFObject[\"coeff\"].get<std::vector<uint16_t>>().value_or(std::vector<uint16_t>{});\n@@ -162,7 +162,7 @@ int Dpf::init([[maybe_unused]] IPAContext &context,\n \t\treturn -EINVAL;\n \t}\n \n-\tconst YamlObject &fSObject = tuningData[\"FilterStrength\"];\n+\tconst ValueNode &fSObject = tuningData[\"FilterStrength\"];\n \n \tstrengthConfig_.r = fSObject[\"r\"].get<uint16_t>(64);\n \tstrengthConfig_.g = fSObject[\"g\"].get<uint16_t>(64);\ndiff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h\nindex 2dd8cd362624..b07067cec0a5 100644\n--- a/src/ipa/rkisp1/algorithms/dpf.h\n+++ b/src/ipa/rkisp1/algorithms/dpf.h\n@@ -21,7 +21,7 @@ public:\n \tDpf();\n \t~Dpf() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tvoid queueRequest(IPAContext &context, const uint32_t frame,\n \t\t\t IPAFrameContext &frameContext,\n \t\t\t const ControlList &controls) override;\ndiff --git a/src/ipa/rkisp1/algorithms/filter.cpp b/src/ipa/rkisp1/algorithms/filter.cpp\nindex 8ad79801792f..2e9b4e285503 100644\n--- a/src/ipa/rkisp1/algorithms/filter.cpp\n+++ b/src/ipa/rkisp1/algorithms/filter.cpp\n@@ -43,7 +43,7 @@ static constexpr uint32_t kFiltModeDefault = 0x000004f2;\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n int Filter::init(IPAContext &context,\n-\t\t [[maybe_unused]] const YamlObject &tuningData)\n+\t\t [[maybe_unused]] const ValueNode &tuningData)\n {\n \tauto &cmap = context.ctrlMap;\n \tcmap[&controls::Sharpness] = ControlInfo(0.0f, 10.0f, 1.0f);\ndiff --git a/src/ipa/rkisp1/algorithms/filter.h b/src/ipa/rkisp1/algorithms/filter.h\nindex 37d8938d37bd..9f0188da7880 100644\n--- a/src/ipa/rkisp1/algorithms/filter.h\n+++ b/src/ipa/rkisp1/algorithms/filter.h\n@@ -21,7 +21,7 @@ public:\n \tFilter() = default;\n \t~Filter() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tvoid queueRequest(IPAContext &context, const uint32_t frame,\n \t\t\t IPAFrameContext &frameContext,\n \t\t\t const ControlList &controls) override;\ndiff --git a/src/ipa/rkisp1/algorithms/goc.cpp b/src/ipa/rkisp1/algorithms/goc.cpp\nindex 6c07bd8c71e5..e8f64bf3d5e0 100644\n--- a/src/ipa/rkisp1/algorithms/goc.cpp\n+++ b/src/ipa/rkisp1/algorithms/goc.cpp\n@@ -13,7 +13,7 @@\n \n #include <libcamera/control_ids.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"linux/rkisp1-config.h\"\n \n@@ -48,7 +48,7 @@ const float kDefaultGamma = 2.2f;\n /**\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n-int GammaOutCorrection::init(IPAContext &context, const YamlObject &tuningData)\n+int GammaOutCorrection::init(IPAContext &context, const ValueNode &tuningData)\n {\n \tif (context.hw.numGammaOutSamples !=\n \t RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10) {\ndiff --git a/src/ipa/rkisp1/algorithms/goc.h b/src/ipa/rkisp1/algorithms/goc.h\nindex bb2ddfc92375..bd79fe19cc86 100644\n--- a/src/ipa/rkisp1/algorithms/goc.h\n+++ b/src/ipa/rkisp1/algorithms/goc.h\n@@ -19,7 +19,7 @@ public:\n \tGammaOutCorrection() = default;\n \t~GammaOutCorrection() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t const IPACameraSensorInfo &configInfo) override;\n \tvoid queueRequest(IPAContext &context,\ndiff --git a/src/ipa/rkisp1/algorithms/gsl.cpp b/src/ipa/rkisp1/algorithms/gsl.cpp\nindex 292d0e80dc57..d6272f3a39ef 100644\n--- a/src/ipa/rkisp1/algorithms/gsl.cpp\n+++ b/src/ipa/rkisp1/algorithms/gsl.cpp\n@@ -10,7 +10,7 @@\n #include <libcamera/base/log.h>\n #include <libcamera/base/utils.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"linux/rkisp1-config.h\"\n \n@@ -56,7 +56,7 @@ GammaSensorLinearization::GammaSensorLinearization()\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context,\n-\t\t\t\t const YamlObject &tuningData)\n+\t\t\t\t const ValueNode &tuningData)\n {\n \tstd::vector<uint16_t> xIntervals =\n \t\ttuningData[\"x-intervals\"].get<std::vector<uint16_t>>().value_or(std::vector<uint16_t>{});\n@@ -75,7 +75,7 @@ int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context,\n \tfor (unsigned int i = 0; i < kDegammaXIntervals; ++i)\n \t\tgammaDx_[i / 8] |= (xIntervals[i] & 0x07) << ((i % 8) * 4);\n \n-\tconst YamlObject &yObject = tuningData[\"y\"];\n+\tconst ValueNode &yObject = tuningData[\"y\"];\n \tif (!yObject.isDictionary()) {\n \t\tLOG(RkISP1Gsl, Error)\n \t\t\t<< \"Issue while parsing 'y' in tuning file: \"\ndiff --git a/src/ipa/rkisp1/algorithms/gsl.h b/src/ipa/rkisp1/algorithms/gsl.h\nindex 91cf6efa7925..3ef5630713ab 100644\n--- a/src/ipa/rkisp1/algorithms/gsl.h\n+++ b/src/ipa/rkisp1/algorithms/gsl.h\n@@ -19,7 +19,7 @@ public:\n \tGammaSensorLinearization();\n \t~GammaSensorLinearization() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t IPAFrameContext &frameContext,\n \t\t RkISP1Params *params) override;\ndiff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\nindex 9c0ed44b3943..78618f65c591 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.cpp\n+++ b/src/ipa/rkisp1/algorithms/lsc.cpp\n@@ -14,7 +14,7 @@\n #include <libcamera/base/log.h>\n #include <libcamera/base/utils.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"libipa/lsc_polynomial.h\"\n #include \"linux/rkisp1-config.h\"\n@@ -85,7 +85,7 @@ public:\n \t{\n \t}\n \n-\tint parseLscData(const YamlObject &yamlSets,\n+\tint parseLscData(const ValueNode &yamlSets,\n \t\t\t std::map<unsigned int, LensShadingCorrection::Components> &lscData)\n \t{\n \t\tconst auto &sets = yamlSets.asList();\n@@ -204,7 +204,7 @@ private:\n class LscTableLoader\n {\n public:\n-\tint parseLscData(const YamlObject &yamlSets,\n+\tint parseLscData(const ValueNode &yamlSets,\n \t\t\t std::map<unsigned int, LensShadingCorrection::Components> &lscData)\n \t{\n \t\tconst auto &sets = yamlSets.asList();\n@@ -245,7 +245,7 @@ public:\n \t}\n \n private:\n-\tstd::vector<uint16_t> parseTable(const YamlObject &tuningData,\n+\tstd::vector<uint16_t> parseTable(const ValueNode &tuningData,\n \t\t\t\t\t const char *prop)\n \t{\n \t\tstatic constexpr unsigned int kLscNumSamples =\n@@ -265,7 +265,7 @@ private:\n \t}\n };\n \n-static std::vector<double> parseSizes(const YamlObject &tuningData,\n+static std::vector<double> parseSizes(const ValueNode &tuningData,\n \t\t\t\t const char *prop)\n {\n \tstd::vector<double> sizes =\n@@ -305,7 +305,7 @@ LensShadingCorrection::LensShadingCorrection()\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,\n-\t\t\t\tconst YamlObject &tuningData)\n+\t\t\t\tconst ValueNode &tuningData)\n {\n \txSize_ = parseSizes(tuningData, \"x-size\");\n \tySize_ = parseSizes(tuningData, \"y-size\");\n@@ -314,7 +314,7 @@ int LensShadingCorrection::init([[maybe_unused]] IPAContext &context,\n \t\treturn -EINVAL;\n \n \t/* Get all defined sets to apply. */\n-\tconst YamlObject &yamlSets = tuningData[\"sets\"];\n+\tconst ValueNode &yamlSets = tuningData[\"sets\"];\n \tif (!yamlSets.isList()) {\n \t\tLOG(RkISP1Lsc, Error)\n \t\t\t<< \"'sets' parameter not found in tuning file\";\ndiff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h\nindex 5a0824e36dd5..6e0ebad11dc0 100644\n--- a/src/ipa/rkisp1/algorithms/lsc.h\n+++ b/src/ipa/rkisp1/algorithms/lsc.h\n@@ -23,7 +23,7 @@ public:\n \tLensShadingCorrection();\n \t~LensShadingCorrection() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t IPAFrameContext &frameContext,\ndiff --git a/src/ipa/rkisp1/algorithms/lux.cpp b/src/ipa/rkisp1/algorithms/lux.cpp\nindex e9717bb3bf66..86e46c492f04 100644\n--- a/src/ipa/rkisp1/algorithms/lux.cpp\n+++ b/src/ipa/rkisp1/algorithms/lux.cpp\n@@ -41,7 +41,7 @@ Lux::Lux()\n /**\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n-int Lux::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)\n+int Lux::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData)\n {\n \treturn lux_.parseTuningData(tuningData);\n }\ndiff --git a/src/ipa/rkisp1/algorithms/lux.h b/src/ipa/rkisp1/algorithms/lux.h\nindex e0239848e252..8cb35cbae20d 100644\n--- a/src/ipa/rkisp1/algorithms/lux.h\n+++ b/src/ipa/rkisp1/algorithms/lux.h\n@@ -22,7 +22,7 @@ class Lux : public Algorithm\n public:\n \tLux();\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tvoid prepare(IPAContext &context, const uint32_t frame,\n \t\t IPAFrameContext &frameContext,\n \t\t RkISP1Params *params) override;\ndiff --git a/src/ipa/rkisp1/algorithms/wdr.cpp b/src/ipa/rkisp1/algorithms/wdr.cpp\nindex 9e2688a05179..c3d73da2c5b2 100644\n--- a/src/ipa/rkisp1/algorithms/wdr.cpp\n+++ b/src/ipa/rkisp1/algorithms/wdr.cpp\n@@ -10,7 +10,7 @@\n #include <libcamera/base/log.h>\n #include <libcamera/base/utils.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include <libipa/agc_mean_luminance.h>\n #include <libipa/histogram.h>\n@@ -110,7 +110,7 @@ WideDynamicRange::WideDynamicRange()\n * \\copydoc libcamera::ipa::Algorithm::init\n */\n int WideDynamicRange::init([[maybe_unused]] IPAContext &context,\n-\t\t\t [[maybe_unused]] const YamlObject &tuningData)\n+\t\t\t [[maybe_unused]] const ValueNode &tuningData)\n {\n \tif (!(context.hw.supportedBlocks & 1 << RKISP1_EXT_PARAMS_BLOCK_TYPE_WDR)) {\n \t\tLOG(RkISP1Wdr, Error)\ndiff --git a/src/ipa/rkisp1/algorithms/wdr.h b/src/ipa/rkisp1/algorithms/wdr.h\nindex 46f7cdeea69d..f79de66fe73b 100644\n--- a/src/ipa/rkisp1/algorithms/wdr.h\n+++ b/src/ipa/rkisp1/algorithms/wdr.h\n@@ -23,7 +23,7 @@ public:\n \tWideDynamicRange();\n \t~WideDynamicRange() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context, const IPACameraSensorInfo &configInfo) override;\n \n \tvoid queueRequest(IPAContext &context, const uint32_t frame,\ndiff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\nindex fbcc39103d4b..3230823f3a28 100644\n--- a/src/ipa/rkisp1/rkisp1.cpp\n+++ b/src/ipa/rkisp1/rkisp1.cpp\n@@ -185,7 +185,7 @@ int IPARkISP1::init(const IPASettings &settings, unsigned int hwRevision,\n \t\treturn ret;\n \t}\n \n-\tstd::unique_ptr<libcamera::YamlObject> data = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> data = YamlParser::parse(file);\n \tif (!data)\n \t\treturn -EINVAL;\n \ndiff --git a/src/ipa/rpi/controller/algorithm.cpp b/src/ipa/rpi/controller/algorithm.cpp\nindex beed47a1e1c4..82bc0302fd12 100644\n--- a/src/ipa/rpi/controller/algorithm.cpp\n+++ b/src/ipa/rpi/controller/algorithm.cpp\n@@ -9,7 +9,7 @@\n \n using namespace RPiController;\n \n-int Algorithm::read([[maybe_unused]] const libcamera::YamlObject ¶ms)\n+int Algorithm::read([[maybe_unused]] const libcamera::ValueNode ¶ms)\n {\n \treturn 0;\n }\ndiff --git a/src/ipa/rpi/controller/algorithm.h b/src/ipa/rpi/controller/algorithm.h\nindex 8839daa90916..214b06576bbf 100644\n--- a/src/ipa/rpi/controller/algorithm.h\n+++ b/src/ipa/rpi/controller/algorithm.h\n@@ -15,7 +15,7 @@\n #include <memory>\n #include <map>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"controller.h\"\n \n@@ -32,7 +32,7 @@ public:\n \t}\n \tvirtual ~Algorithm() = default;\n \tvirtual char const *name() const = 0;\n-\tvirtual int read(const libcamera::YamlObject ¶ms);\n+\tvirtual int read(const libcamera::ValueNode ¶ms);\n \tvirtual void initialise();\n \tvirtual void switchMode(CameraMode const &cameraMode, Metadata *metadata);\n \tvirtual void prepare(Metadata *imageMetadata);\ndiff --git a/src/ipa/rpi/controller/controller.cpp b/src/ipa/rpi/controller/controller.cpp\nindex df45dcd345b7..162c75d8848f 100644\n--- a/src/ipa/rpi/controller/controller.cpp\n+++ b/src/ipa/rpi/controller/controller.cpp\n@@ -102,7 +102,7 @@ int Controller::read(char const *filename)\n \t\treturn -EINVAL;\n \t}\n \n-\tstd::unique_ptr<YamlObject> root = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> root = YamlParser::parse(file);\n \tif (!root)\n \t\treturn -EINVAL;\n \n@@ -143,7 +143,7 @@ int Controller::read(char const *filename)\n \treturn 0;\n }\n \n-int Controller::createAlgorithm(const std::string &name, const YamlObject ¶ms)\n+int Controller::createAlgorithm(const std::string &name, const ValueNode ¶ms)\n {\n \tauto it = getAlgorithms().find(name);\n \tif (it == getAlgorithms().end()) {\ndiff --git a/src/ipa/rpi/controller/controller.h b/src/ipa/rpi/controller/controller.h\nindex 573942886bc0..094917b08b6a 100644\n--- a/src/ipa/rpi/controller/controller.h\n+++ b/src/ipa/rpi/controller/controller.h\n@@ -16,7 +16,7 @@\n #include <string>\n \n #include <libcamera/base/utils.h>\n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"camera_mode.h\"\n #include \"device_status.h\"\n@@ -65,7 +65,7 @@ public:\n \tconst HardwareConfig &getHardwareConfig() const;\n \n protected:\n-\tint createAlgorithm(const std::string &name, const libcamera::YamlObject ¶ms);\n+\tint createAlgorithm(const std::string &name, const libcamera::ValueNode ¶ms);\n \n \tMetadata globalMetadata_;\n \tstd::vector<AlgorithmPtr> algorithms_;\ndiff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp\nindex 26e599303f24..47c2bf935835 100644\n--- a/src/ipa/rpi/controller/rpi/af.cpp\n+++ b/src/ipa/rpi/controller/rpi/af.cpp\n@@ -68,7 +68,7 @@ Af::CfgParams::CfgParams()\n }\n \n template<typename T>\n-static void readNumber(T &dest, const libcamera::YamlObject ¶ms, char const *name)\n+static void readNumber(T &dest, const libcamera::ValueNode ¶ms, char const *name)\n {\n \tauto value = params[name].get<T>();\n \tif (value)\n@@ -77,7 +77,7 @@ static void readNumber(T &dest, const libcamera::YamlObject ¶ms, char const\n \t\tLOG(RPiAf, Warning) << \"Missing parameter \\\"\" << name << \"\\\"\";\n }\n \n-void Af::RangeDependentParams::read(const libcamera::YamlObject ¶ms)\n+void Af::RangeDependentParams::read(const libcamera::ValueNode ¶ms)\n {\n \n \treadNumber<double>(focusMin, params, \"min\");\n@@ -85,7 +85,7 @@ void Af::RangeDependentParams::read(const libcamera::YamlObject ¶ms)\n \treadNumber<double>(focusDefault, params, \"default\");\n }\n \n-void Af::SpeedDependentParams::read(const libcamera::YamlObject ¶ms)\n+void Af::SpeedDependentParams::read(const libcamera::ValueNode ¶ms)\n {\n \treadNumber<double>(stepCoarse, params, \"step_coarse\");\n \treadNumber<double>(stepFine, params, \"step_fine\");\n@@ -100,7 +100,7 @@ void Af::SpeedDependentParams::read(const libcamera::YamlObject ¶ms)\n \treadNumber<uint32_t>(stepFrames, params, \"step_frames\");\n }\n \n-int Af::CfgParams::read(const libcamera::YamlObject ¶ms)\n+int Af::CfgParams::read(const libcamera::ValueNode ¶ms)\n {\n \tif (params.contains(\"ranges\")) {\n \t\tauto &rr = params[\"ranges\"];\n@@ -226,7 +226,7 @@ char const *Af::name() const\n \treturn NAME;\n }\n \n-int Af::read(const libcamera::YamlObject ¶ms)\n+int Af::read(const libcamera::ValueNode ¶ms)\n {\n \treturn cfg_.read(params);\n }\ndiff --git a/src/ipa/rpi/controller/rpi/af.h b/src/ipa/rpi/controller/rpi/af.h\nindex d35a39d12049..b464927ba92b 100644\n--- a/src/ipa/rpi/controller/rpi/af.h\n+++ b/src/ipa/rpi/controller/rpi/af.h\n@@ -47,7 +47,7 @@ public:\n \tAf(Controller *controller = NULL);\n \t~Af();\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid initialise() override;\n \n \t/* IPA calls */\n@@ -87,7 +87,7 @@ private:\n \t\tdouble focusDefault;\t\t/* default setting (\"hyperfocal\") */\n \n \t\tRangeDependentParams();\n-\t\tvoid read(const libcamera::YamlObject ¶ms);\n+\t\tvoid read(const libcamera::ValueNode ¶ms);\n \t};\n \n \tstruct SpeedDependentParams {\n@@ -104,7 +104,7 @@ private:\n \t\tuint32_t stepFrames;\t\t/* frames to skip in between steps of a scan */\n \n \t\tSpeedDependentParams();\n-\t\tvoid read(const libcamera::YamlObject ¶ms);\n+\t\tvoid read(const libcamera::ValueNode ¶ms);\n \t};\n \n \tstruct CfgParams {\n@@ -118,7 +118,7 @@ private:\n \t\tlibcamera::ipa::Pwl map; \t/* converts dioptres -> lens driver position */\n \n \t\tCfgParams();\n-\t\tint read(const libcamera::YamlObject ¶ms);\n+\t\tint read(const libcamera::ValueNode ¶ms);\n \t\tvoid initialise();\n \t};\n \ndiff --git a/src/ipa/rpi/controller/rpi/agc.cpp b/src/ipa/rpi/controller/rpi/agc.cpp\nindex afda2e364f64..830b26174df2 100644\n--- a/src/ipa/rpi/controller/rpi/agc.cpp\n+++ b/src/ipa/rpi/controller/rpi/agc.cpp\n@@ -31,7 +31,7 @@ char const *Agc::name() const\n \treturn NAME;\n }\n \n-int Agc::read(const libcamera::YamlObject ¶ms)\n+int Agc::read(const libcamera::ValueNode ¶ms)\n {\n \t/*\n \t * When there is only a single channel we can read the old style syntax.\ndiff --git a/src/ipa/rpi/controller/rpi/agc.h b/src/ipa/rpi/controller/rpi/agc.h\nindex 966630a26303..5189ad2a2bf8 100644\n--- a/src/ipa/rpi/controller/rpi/agc.h\n+++ b/src/ipa/rpi/controller/rpi/agc.h\n@@ -27,7 +27,7 @@ class Agc : public AgcAlgorithm\n public:\n \tAgc(Controller *controller);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tunsigned int getConvergenceFrames() const override;\n \tstd::vector<double> const &getWeights() const override;\n \tvoid setEv(unsigned int channel, double ev) override;\ndiff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp\nindex c6cf1f8903f1..c0ac76c569af 100644\n--- a/src/ipa/rpi/controller/rpi/agc_channel.cpp\n+++ b/src/ipa/rpi/controller/rpi/agc_channel.cpp\n@@ -29,9 +29,9 @@ using namespace std::literals::chrono_literals;\n \n LOG_DECLARE_CATEGORY(RPiAgc)\n \n-int AgcMeteringMode::read(const libcamera::YamlObject ¶ms)\n+int AgcMeteringMode::read(const libcamera::ValueNode ¶ms)\n {\n-\tconst YamlObject &yamlWeights = params[\"weights\"];\n+\tconst ValueNode &yamlWeights = params[\"weights\"];\n \n \tfor (const auto &p : yamlWeights.asList()) {\n \t\tauto value = p.get<double>();\n@@ -45,7 +45,7 @@ int AgcMeteringMode::read(const libcamera::YamlObject ¶ms)\n \n static std::tuple<int, std::string>\n readMeteringModes(std::map<std::string, AgcMeteringMode> &metering_modes,\n-\t\t const libcamera::YamlObject ¶ms)\n+\t\t const libcamera::ValueNode ¶ms)\n {\n \tstd::string first;\n \tint ret;\n@@ -64,7 +64,7 @@ readMeteringModes(std::map<std::string, AgcMeteringMode> &metering_modes,\n \treturn { 0, first };\n }\n \n-int AgcExposureMode::read(const libcamera::YamlObject ¶ms)\n+int AgcExposureMode::read(const libcamera::ValueNode ¶ms)\n {\n \tauto value = params[\"shutter\"].get<std::vector<double>>();\n \tif (!value)\n@@ -94,7 +94,7 @@ int AgcExposureMode::read(const libcamera::YamlObject ¶ms)\n \n static std::tuple<int, std::string>\n readExposureModes(std::map<std::string, AgcExposureMode> &exposureModes,\n-\t\t const libcamera::YamlObject ¶ms)\n+\t\t const libcamera::ValueNode ¶ms)\n {\n \tstd::string first;\n \tint ret;\n@@ -113,7 +113,7 @@ readExposureModes(std::map<std::string, AgcExposureMode> &exposureModes,\n \treturn { 0, first };\n }\n \n-int AgcConstraint::read(const libcamera::YamlObject ¶ms)\n+int AgcConstraint::read(const libcamera::ValueNode ¶ms)\n {\n \tstd::string boundString = params[\"bound\"].get<std::string>(\"\");\n \ttransform(boundString.begin(), boundString.end(),\n@@ -139,7 +139,7 @@ int AgcConstraint::read(const libcamera::YamlObject ¶ms)\n }\n \n static std::tuple<int, AgcConstraintMode>\n-readConstraintMode(const libcamera::YamlObject ¶ms)\n+readConstraintMode(const libcamera::ValueNode ¶ms)\n {\n \tAgcConstraintMode mode;\n \tint ret;\n@@ -158,7 +158,7 @@ readConstraintMode(const libcamera::YamlObject ¶ms)\n \n static std::tuple<int, std::string>\n readConstraintModes(std::map<std::string, AgcConstraintMode> &constraintModes,\n-\t\t const libcamera::YamlObject ¶ms)\n+\t\t const libcamera::ValueNode ¶ms)\n {\n \tstd::string first;\n \tint ret;\n@@ -175,7 +175,7 @@ readConstraintModes(std::map<std::string, AgcConstraintMode> &constraintModes,\n \treturn { 0, first };\n }\n \n-int AgcChannelConstraint::read(const libcamera::YamlObject ¶ms)\n+int AgcChannelConstraint::read(const libcamera::ValueNode ¶ms)\n {\n \tauto channelValue = params[\"channel\"].get<unsigned int>();\n \tif (!channelValue) {\n@@ -204,7 +204,7 @@ int AgcChannelConstraint::read(const libcamera::YamlObject ¶ms)\n }\n \n static int readChannelConstraints(std::vector<AgcChannelConstraint> &channelConstraints,\n-\t\t\t\t const libcamera::YamlObject ¶ms)\n+\t\t\t\t const libcamera::ValueNode ¶ms)\n {\n \tfor (const auto &p : params.asList()) {\n \t\tAgcChannelConstraint constraint;\n@@ -218,7 +218,7 @@ static int readChannelConstraints(std::vector<AgcChannelConstraint> &channelCons\n \treturn 0;\n }\n \n-int AgcConfig::read(const libcamera::YamlObject ¶ms)\n+int AgcConfig::read(const libcamera::ValueNode ¶ms)\n {\n \tLOG(RPiAgc, Debug) << \"AgcConfig\";\n \tint ret;\n@@ -290,7 +290,7 @@ AgcChannel::AgcChannel()\n \tstatus_.ev = ev_;\n }\n \n-int AgcChannel::read(const libcamera::YamlObject ¶ms,\n+int AgcChannel::read(const libcamera::ValueNode ¶ms,\n \t\t const Controller::HardwareConfig &hardwareConfig)\n {\n \tint ret = config_.read(params);\ndiff --git a/src/ipa/rpi/controller/rpi/agc_channel.h b/src/ipa/rpi/controller/rpi/agc_channel.h\nindex 42d85ec15e8d..90e540a8a18d 100644\n--- a/src/ipa/rpi/controller/rpi/agc_channel.h\n+++ b/src/ipa/rpi/controller/rpi/agc_channel.h\n@@ -26,13 +26,13 @@ using AgcChannelTotalExposures = std::vector<libcamera::utils::Duration>;\n \n struct AgcMeteringMode {\n \tstd::vector<double> weights;\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n };\n \n struct AgcExposureMode {\n \tstd::vector<libcamera::utils::Duration> exposureTime;\n \tstd::vector<double> gain;\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n };\n \n struct AgcConstraint {\n@@ -42,7 +42,7 @@ struct AgcConstraint {\n \tdouble qLo;\n \tdouble qHi;\n \tlibcamera::ipa::Pwl yTarget;\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n };\n \n typedef std::vector<AgcConstraint> AgcConstraintMode;\n@@ -53,11 +53,11 @@ struct AgcChannelConstraint {\n \tBound bound;\n \tunsigned int channel;\n \tdouble factor;\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n };\n \n struct AgcConfig {\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n \tstd::map<std::string, AgcMeteringMode> meteringModes;\n \tstd::map<std::string, AgcExposureMode> exposureModes;\n \tstd::map<std::string, AgcConstraintMode> constraintModes;\n@@ -85,7 +85,7 @@ class AgcChannel\n {\n public:\n \tAgcChannel();\n-\tint read(const libcamera::YamlObject ¶ms,\n+\tint read(const libcamera::ValueNode ¶ms,\n \t\t const Controller::HardwareConfig &hardwareConfig);\n \tunsigned int getConvergenceFrames() const;\n \tstd::vector<double> const &getWeights() const;\ndiff --git a/src/ipa/rpi/controller/rpi/alsc.cpp b/src/ipa/rpi/controller/rpi/alsc.cpp\nindex 21edb819ad1c..4c852db04f7f 100644\n--- a/src/ipa/rpi/controller/rpi/alsc.cpp\n+++ b/src/ipa/rpi/controller/rpi/alsc.cpp\n@@ -50,7 +50,7 @@ char const *Alsc::name() const\n \treturn NAME;\n }\n \n-static int generateLut(Array2D<double> &lut, const libcamera::YamlObject ¶ms)\n+static int generateLut(Array2D<double> &lut, const libcamera::ValueNode ¶ms)\n {\n \t/* These must be signed ints for the co-ordinate calculations below. */\n \tint X = lut.dimensions().width, Y = lut.dimensions().height;\n@@ -82,7 +82,7 @@ static int generateLut(Array2D<double> &lut, const libcamera::YamlObject ¶ms\n \treturn 0;\n }\n \n-static int readLut(Array2D<double> &lut, const libcamera::YamlObject ¶ms)\n+static int readLut(Array2D<double> &lut, const libcamera::ValueNode ¶ms)\n {\n \tif (params.size() != lut.size()) {\n \t\tLOG(RPiAlsc, Error) << \"Invalid number of entries in LSC table\";\n@@ -101,7 +101,7 @@ static int readLut(Array2D<double> &lut, const libcamera::YamlObject ¶ms)\n }\n \n static int readCalibrations(std::vector<AlscCalibration> &calibrations,\n-\t\t\t const libcamera::YamlObject ¶ms,\n+\t\t\t const libcamera::ValueNode ¶ms,\n \t\t\t std::string const &name, const Size &size)\n {\n \tif (params.contains(name)) {\n@@ -119,7 +119,7 @@ static int readCalibrations(std::vector<AlscCalibration> &calibrations,\n \t\t\tAlscCalibration calibration;\n \t\t\tcalibration.ct = lastCt = ct;\n \n-\t\t\tconst libcamera::YamlObject &table = p[\"table\"];\n+\t\t\tconst libcamera::ValueNode &table = p[\"table\"];\n \t\t\tif (table.size() != size.width * size.height) {\n \t\t\t\tLOG(RPiAlsc, Error)\n \t\t\t\t\t<< \"Incorrect number of values for ct \"\n@@ -144,7 +144,7 @@ static int readCalibrations(std::vector<AlscCalibration> &calibrations,\n \treturn 0;\n }\n \n-int Alsc::read(const libcamera::YamlObject ¶ms)\n+int Alsc::read(const libcamera::ValueNode ¶ms)\n {\n \tconfig_.tableSize = getHardwareConfig().awbRegions;\n \tconfig_.framePeriod = params[\"frame_period\"].get<uint16_t>(12);\ndiff --git a/src/ipa/rpi/controller/rpi/alsc.h b/src/ipa/rpi/controller/rpi/alsc.h\nindex 310879820fba..0952ae8358c6 100644\n--- a/src/ipa/rpi/controller/rpi/alsc.h\n+++ b/src/ipa/rpi/controller/rpi/alsc.h\n@@ -112,7 +112,7 @@ public:\n \tchar const *name() const override;\n \tvoid initialise() override;\n \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \tvoid process(StatisticsPtr &stats, Metadata *imageMetadata) override;\n \ndiff --git a/src/ipa/rpi/controller/rpi/awb.cpp b/src/ipa/rpi/controller/rpi/awb.cpp\nindex 365b595ff9b4..1ccac36e5b4f 100644\n--- a/src/ipa/rpi/controller/rpi/awb.cpp\n+++ b/src/ipa/rpi/controller/rpi/awb.cpp\n@@ -30,7 +30,7 @@ constexpr double kDefaultCT = 4500.0;\n * elsewhere (ALSC and AGC).\n */\n \n-int AwbMode::read(const libcamera::YamlObject ¶ms)\n+int AwbMode::read(const libcamera::ValueNode ¶ms)\n {\n \tauto value = params[\"lo\"].get<double>();\n \tif (!value)\n@@ -45,7 +45,7 @@ int AwbMode::read(const libcamera::YamlObject ¶ms)\n \treturn 0;\n }\n \n-int AwbPrior::read(const libcamera::YamlObject ¶ms)\n+int AwbPrior::read(const libcamera::ValueNode ¶ms)\n {\n \tauto value = params[\"lux\"].get<double>();\n \tif (!value)\n@@ -56,7 +56,7 @@ int AwbPrior::read(const libcamera::YamlObject ¶ms)\n \treturn prior.empty() ? -EINVAL : 0;\n }\n \n-static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::YamlObject ¶ms)\n+static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::ValueNode ¶ms)\n {\n \tif (params.size() % 3) {\n \t\tLOG(RPiAwb, Error) << \"AwbConfig: incomplete CT curve entry\";\n@@ -92,7 +92,7 @@ static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::YamlObject\n \treturn 0;\n }\n \n-int AwbConfig::read(const libcamera::YamlObject ¶ms)\n+int AwbConfig::read(const libcamera::ValueNode ¶ms)\n {\n \tint ret;\n \n@@ -204,7 +204,7 @@ char const *Awb::name() const\n \treturn NAME;\n }\n \n-int Awb::read(const libcamera::YamlObject ¶ms)\n+int Awb::read(const libcamera::ValueNode ¶ms)\n {\n \treturn config_.read(params);\n }\ndiff --git a/src/ipa/rpi/controller/rpi/awb.h b/src/ipa/rpi/controller/rpi/awb.h\nindex 2fb912541a2b..ac73105113fb 100644\n--- a/src/ipa/rpi/controller/rpi/awb.h\n+++ b/src/ipa/rpi/controller/rpi/awb.h\n@@ -23,20 +23,20 @@ namespace RPiController {\n /* Control algorithm to perform AWB calculations. */\n \n struct AwbMode {\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n \tdouble ctLo; /* low CT value for search */\n \tdouble ctHi; /* high CT value for search */\n };\n \n struct AwbPrior {\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n \tdouble lux; /* lux level */\n \tlibcamera::ipa::Pwl prior; /* maps CT to prior log likelihood for this lux level */\n };\n \n struct AwbConfig {\n \tAwbConfig() : defaultMode(nullptr) {}\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n \t/* Only repeat the AWB calculation every \"this many\" frames */\n \tuint16_t framePeriod;\n \t/* number of initial frames for which speed taken as 1.0 (maximum) */\n@@ -99,7 +99,7 @@ public:\n \t~Awb();\n \tchar const *name() const override;\n \tvoid initialise() override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tunsigned int getConvergenceFrames() const override;\n \tvoid initialValues(double &gainR, double &gainB) override;\n \tvoid setMode(std::string const &name) override;\ndiff --git a/src/ipa/rpi/controller/rpi/black_level.cpp b/src/ipa/rpi/controller/rpi/black_level.cpp\nindex 4c968f14a1ca..42ea1505014f 100644\n--- a/src/ipa/rpi/controller/rpi/black_level.cpp\n+++ b/src/ipa/rpi/controller/rpi/black_level.cpp\n@@ -30,7 +30,7 @@ char const *BlackLevel::name() const\n \treturn NAME;\n }\n \n-int BlackLevel::read(const libcamera::YamlObject ¶ms)\n+int BlackLevel::read(const libcamera::ValueNode ¶ms)\n {\n \t/* 64 in 10 bits scaled to 16 bits */\n \tuint16_t blackLevel = params[\"black_level\"].get<uint16_t>(4096);\ndiff --git a/src/ipa/rpi/controller/rpi/black_level.h b/src/ipa/rpi/controller/rpi/black_level.h\nindex f50729dbc1e3..dbf29b282e4c 100644\n--- a/src/ipa/rpi/controller/rpi/black_level.h\n+++ b/src/ipa/rpi/controller/rpi/black_level.h\n@@ -18,7 +18,7 @@ class BlackLevel : public BlackLevelAlgorithm\n public:\n \tBlackLevel(Controller *controller);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid initialValues(uint16_t &blackLevelR, uint16_t &blackLevelG,\n \t\t\t uint16_t &blackLevelB) override;\n \tvoid prepare(Metadata *imageMetadata) override;\ndiff --git a/src/ipa/rpi/controller/rpi/cac.cpp b/src/ipa/rpi/controller/rpi/cac.cpp\nindex 17779ad5469b..ddc848f21f3f 100644\n--- a/src/ipa/rpi/controller/rpi/cac.cpp\n+++ b/src/ipa/rpi/controller/rpi/cac.cpp\n@@ -27,7 +27,7 @@ char const *Cac::name() const\n \treturn NAME;\n }\n \n-static bool arrayToSet(const libcamera::YamlObject ¶ms, std::vector<double> &inputArray, const Size &size)\n+static bool arrayToSet(const libcamera::ValueNode ¶ms, std::vector<double> &inputArray, const Size &size)\n {\n \tint num = 0;\n \tint max_num = (size.width + 1) * (size.height + 1);\n@@ -51,7 +51,7 @@ static void setStrength(std::vector<double> &inputArray, std::vector<double> &ou\n \t}\n }\n \n-int Cac::read(const libcamera::YamlObject ¶ms)\n+int Cac::read(const libcamera::ValueNode ¶ms)\n {\n \tconfig_.enabled = params.contains(\"lut_rx\") && params.contains(\"lut_ry\") &&\n \t\t\t params.contains(\"lut_bx\") && params.contains(\"lut_by\");\ndiff --git a/src/ipa/rpi/controller/rpi/cac.h b/src/ipa/rpi/controller/rpi/cac.h\nindex 533cca44424b..11c47a7c4323 100644\n--- a/src/ipa/rpi/controller/rpi/cac.h\n+++ b/src/ipa/rpi/controller/rpi/cac.h\n@@ -24,7 +24,7 @@ class Cac : public Algorithm\n public:\n \tCac(Controller *controller = NULL);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \n private:\ndiff --git a/src/ipa/rpi/controller/rpi/ccm.cpp b/src/ipa/rpi/controller/rpi/ccm.cpp\nindex 2806b4967158..d3231182913d 100644\n--- a/src/ipa/rpi/controller/rpi/ccm.cpp\n+++ b/src/ipa/rpi/controller/rpi/ccm.cpp\n@@ -40,7 +40,7 @@ char const *Ccm::name() const\n \treturn NAME;\n }\n \n-int Ccm::read(const libcamera::YamlObject ¶ms)\n+int Ccm::read(const libcamera::ValueNode ¶ms)\n {\n \tif (params.contains(\"saturation\")) {\n \t\tconfig_.saturation = params[\"saturation\"].get<ipa::Pwl>(ipa::Pwl{});\ndiff --git a/src/ipa/rpi/controller/rpi/ccm.h b/src/ipa/rpi/controller/rpi/ccm.h\nindex 70f28ed33d5e..a0f5b698db9b 100644\n--- a/src/ipa/rpi/controller/rpi/ccm.h\n+++ b/src/ipa/rpi/controller/rpi/ccm.h\n@@ -31,7 +31,7 @@ class Ccm : public CcmAlgorithm\n public:\n \tCcm(Controller *controller = NULL);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid enableAuto() override;\n \tvoid setSaturation(double saturation) override;\n \tvoid setCcm(Matrix3x3 const &matrix) override;\ndiff --git a/src/ipa/rpi/controller/rpi/contrast.cpp b/src/ipa/rpi/controller/rpi/contrast.cpp\nindex fe866a544293..3457e04002e0 100644\n--- a/src/ipa/rpi/controller/rpi/contrast.cpp\n+++ b/src/ipa/rpi/controller/rpi/contrast.cpp\n@@ -38,7 +38,7 @@ char const *Contrast::name() const\n \treturn NAME;\n }\n \n-int Contrast::read(const libcamera::YamlObject ¶ms)\n+int Contrast::read(const libcamera::ValueNode ¶ms)\n {\n \t// enable adaptive enhancement by default\n \tconfig_.ceEnable = params[\"ce_enable\"].get<int>(1);\ndiff --git a/src/ipa/rpi/controller/rpi/contrast.h b/src/ipa/rpi/controller/rpi/contrast.h\nindex c0f7db981c7d..3571626d8623 100644\n--- a/src/ipa/rpi/controller/rpi/contrast.h\n+++ b/src/ipa/rpi/controller/rpi/contrast.h\n@@ -35,7 +35,7 @@ class Contrast : public ContrastAlgorithm\n public:\n \tContrast(Controller *controller = NULL);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid setBrightness(double brightness) override;\n \tvoid setContrast(double contrast) override;\n \tvoid enableCe(bool enable) override;\ndiff --git a/src/ipa/rpi/controller/rpi/decompand.cpp b/src/ipa/rpi/controller/rpi/decompand.cpp\nindex 2d457926c060..5646984132f6 100644\n--- a/src/ipa/rpi/controller/rpi/decompand.cpp\n+++ b/src/ipa/rpi/controller/rpi/decompand.cpp\n@@ -22,7 +22,7 @@ char const *Decompand::name() const\n \treturn NAME;\n }\n \n-int Decompand::read(const libcamera::YamlObject ¶ms)\n+int Decompand::read(const libcamera::ValueNode ¶ms)\n {\n \tconfig_.bitdepth = params[\"bitdepth\"].get<uint32_t>(0);\n \tconfig_.decompandCurve = params[\"decompand_curve\"].get<ipa::Pwl>(ipa::Pwl{});\ndiff --git a/src/ipa/rpi/controller/rpi/decompand.h b/src/ipa/rpi/controller/rpi/decompand.h\nindex 6db779c359a8..847769af4338 100644\n--- a/src/ipa/rpi/controller/rpi/decompand.h\n+++ b/src/ipa/rpi/controller/rpi/decompand.h\n@@ -17,7 +17,7 @@ class Decompand : public DecompandAlgorithm\n public:\n \tDecompand(Controller *controller = nullptr);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid initialise() override;\n \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n \tvoid initialValues(libcamera::ipa::Pwl &decompandCurve) override;\ndiff --git a/src/ipa/rpi/controller/rpi/denoise.cpp b/src/ipa/rpi/controller/rpi/denoise.cpp\nindex cabe3e2a08aa..0cd0dd53fe97 100644\n--- a/src/ipa/rpi/controller/rpi/denoise.cpp\n+++ b/src/ipa/rpi/controller/rpi/denoise.cpp\n@@ -21,7 +21,7 @@ LOG_DEFINE_CATEGORY(RPiDenoise)\n \n #define NAME \"rpi.denoise\"\n \n-int DenoiseConfig::read(const libcamera::YamlObject ¶ms)\n+int DenoiseConfig::read(const libcamera::ValueNode ¶ms)\n {\n \tsdnEnable = params.contains(\"sdn\");\n \tif (sdnEnable) {\n@@ -82,7 +82,7 @@ char const *Denoise::name() const\n \treturn NAME;\n }\n \n-int Denoise::read(const libcamera::YamlObject ¶ms)\n+int Denoise::read(const libcamera::ValueNode ¶ms)\n {\n \tif (!params.contains(\"normal\")) {\n \t\tconfigs_[\"normal\"].read(params);\ndiff --git a/src/ipa/rpi/controller/rpi/denoise.h b/src/ipa/rpi/controller/rpi/denoise.h\nindex e23a2e8ff525..499b2ab74749 100644\n--- a/src/ipa/rpi/controller/rpi/denoise.h\n+++ b/src/ipa/rpi/controller/rpi/denoise.h\n@@ -31,7 +31,7 @@ struct DenoiseConfig {\n \tbool tdnEnable;\n \tbool sdnEnable;\n \tbool cdnEnable;\n-\tint read(const libcamera::YamlObject ¶ms);\n+\tint read(const libcamera::ValueNode ¶ms);\n };\n \n class Denoise : public DenoiseAlgorithm\n@@ -39,7 +39,7 @@ class Denoise : public DenoiseAlgorithm\n public:\n \tDenoise(Controller *controller);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid initialise() override;\n \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n \tvoid prepare(Metadata *imageMetadata) override;\ndiff --git a/src/ipa/rpi/controller/rpi/dpc.cpp b/src/ipa/rpi/controller/rpi/dpc.cpp\nindex 8aac03f794fc..a92207999fab 100644\n--- a/src/ipa/rpi/controller/rpi/dpc.cpp\n+++ b/src/ipa/rpi/controller/rpi/dpc.cpp\n@@ -31,7 +31,7 @@ char const *Dpc::name() const\n \treturn NAME;\n }\n \n-int Dpc::read(const libcamera::YamlObject ¶ms)\n+int Dpc::read(const libcamera::ValueNode ¶ms)\n {\n \tconfig_.strength = params[\"strength\"].get<int>(1);\n \tif (config_.strength < 0 || config_.strength > 2) {\ndiff --git a/src/ipa/rpi/controller/rpi/dpc.h b/src/ipa/rpi/controller/rpi/dpc.h\nindex 9cefb06d4a7c..a1a02af59cbc 100644\n--- a/src/ipa/rpi/controller/rpi/dpc.h\n+++ b/src/ipa/rpi/controller/rpi/dpc.h\n@@ -22,7 +22,7 @@ class Dpc : public Algorithm\n public:\n \tDpc(Controller *controller);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \n private:\ndiff --git a/src/ipa/rpi/controller/rpi/geq.cpp b/src/ipa/rpi/controller/rpi/geq.cpp\nindex 40e7191ba16a..9382a033f055 100644\n--- a/src/ipa/rpi/controller/rpi/geq.cpp\n+++ b/src/ipa/rpi/controller/rpi/geq.cpp\n@@ -34,7 +34,7 @@ char const *Geq::name() const\n \treturn NAME;\n }\n \n-int Geq::read(const libcamera::YamlObject ¶ms)\n+int Geq::read(const libcamera::ValueNode ¶ms)\n {\n \tconfig_.offset = params[\"offset\"].get<uint16_t>(0);\n \tconfig_.slope = params[\"slope\"].get<double>(0.0);\ndiff --git a/src/ipa/rpi/controller/rpi/geq.h b/src/ipa/rpi/controller/rpi/geq.h\nindex e8b9f42708c0..4827051b4f46 100644\n--- a/src/ipa/rpi/controller/rpi/geq.h\n+++ b/src/ipa/rpi/controller/rpi/geq.h\n@@ -26,7 +26,7 @@ class Geq : public Algorithm\n public:\n \tGeq(Controller *controller);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \n private:\ndiff --git a/src/ipa/rpi/controller/rpi/hdr.cpp b/src/ipa/rpi/controller/rpi/hdr.cpp\nindex 06400ea79a95..c256f7485f77 100644\n--- a/src/ipa/rpi/controller/rpi/hdr.cpp\n+++ b/src/ipa/rpi/controller/rpi/hdr.cpp\n@@ -23,7 +23,7 @@ LOG_DEFINE_CATEGORY(RPiHdr)\n \n #define NAME \"rpi.hdr\"\n \n-void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &modeName)\n+void HdrConfig::read(const libcamera::ValueNode ¶ms, const std::string &modeName)\n {\n \tname = modeName;\n \n@@ -111,7 +111,7 @@ char const *Hdr::name() const\n \treturn NAME;\n }\n \n-int Hdr::read(const libcamera::YamlObject ¶ms)\n+int Hdr::read(const libcamera::ValueNode ¶ms)\n {\n \t/* Make an \"HDR off\" mode by default so that tuning files don't have to. */\n \tHdrConfig &offMode = config_[\"Off\"];\ndiff --git a/src/ipa/rpi/controller/rpi/hdr.h b/src/ipa/rpi/controller/rpi/hdr.h\nindex 5c2f3988d789..58ff5ba83d2e 100644\n--- a/src/ipa/rpi/controller/rpi/hdr.h\n+++ b/src/ipa/rpi/controller/rpi/hdr.h\n@@ -52,7 +52,7 @@ struct HdrConfig {\n \tuint8_t diffPower;\n \tdouble motionThreshold;\n \n-\tvoid read(const libcamera::YamlObject ¶ms, const std::string &name);\n+\tvoid read(const libcamera::ValueNode ¶ms, const std::string &name);\n };\n \n class Hdr : public HdrAlgorithm\n@@ -61,7 +61,7 @@ public:\n \tHdr(Controller *controller);\n \tchar const *name() const override;\n \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \tvoid process(StatisticsPtr &stats, Metadata *imageMetadata) override;\n \tint setMode(std::string const &mode) override;\ndiff --git a/src/ipa/rpi/controller/rpi/lux.cpp b/src/ipa/rpi/controller/rpi/lux.cpp\nindex 7dab27cc0a90..2047a240bad5 100644\n--- a/src/ipa/rpi/controller/rpi/lux.cpp\n+++ b/src/ipa/rpi/controller/rpi/lux.cpp\n@@ -35,7 +35,7 @@ char const *Lux::name() const\n \treturn NAME;\n }\n \n-int Lux::read(const libcamera::YamlObject ¶ms)\n+int Lux::read(const libcamera::ValueNode ¶ms)\n {\n \tauto value = params[\"reference_shutter_speed\"].get<double>();\n \tif (!value)\ndiff --git a/src/ipa/rpi/controller/rpi/lux.h b/src/ipa/rpi/controller/rpi/lux.h\nindex db2227e41455..c9ffe38b69db 100644\n--- a/src/ipa/rpi/controller/rpi/lux.h\n+++ b/src/ipa/rpi/controller/rpi/lux.h\n@@ -23,7 +23,7 @@ class Lux : public Algorithm\n public:\n \tLux(Controller *controller);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \tvoid process(StatisticsPtr &stats, Metadata *imageMetadata) override;\ndiff --git a/src/ipa/rpi/controller/rpi/noise.cpp b/src/ipa/rpi/controller/rpi/noise.cpp\nindex 145175fb4940..d6e01c2cfe4e 100644\n--- a/src/ipa/rpi/controller/rpi/noise.cpp\n+++ b/src/ipa/rpi/controller/rpi/noise.cpp\n@@ -41,7 +41,7 @@ void Noise::switchMode(CameraMode const &cameraMode,\n \tmodeFactor_ = std::max(1.0, cameraMode.noiseFactor);\n }\n \n-int Noise::read(const libcamera::YamlObject ¶ms)\n+int Noise::read(const libcamera::ValueNode ¶ms)\n {\n \tauto value = params[\"reference_constant\"].get<double>();\n \tif (!value)\ndiff --git a/src/ipa/rpi/controller/rpi/noise.h b/src/ipa/rpi/controller/rpi/noise.h\nindex 6deae1f0282e..c449fa52ffd2 100644\n--- a/src/ipa/rpi/controller/rpi/noise.h\n+++ b/src/ipa/rpi/controller/rpi/noise.h\n@@ -19,7 +19,7 @@ public:\n \tNoise(Controller *controller);\n \tchar const *name() const override;\n \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \n private:\ndiff --git a/src/ipa/rpi/controller/rpi/saturation.cpp b/src/ipa/rpi/controller/rpi/saturation.cpp\nindex b83c5887c02e..5001f930a1ec 100644\n--- a/src/ipa/rpi/controller/rpi/saturation.cpp\n+++ b/src/ipa/rpi/controller/rpi/saturation.cpp\n@@ -27,7 +27,7 @@ char const *Saturation::name() const\n \treturn NAME;\n }\n \n-int Saturation::read(const libcamera::YamlObject ¶ms)\n+int Saturation::read(const libcamera::ValueNode ¶ms)\n {\n \tconfig_.shiftR = params[\"shift_r\"].get<uint8_t>(0);\n \tconfig_.shiftG = params[\"shift_g\"].get<uint8_t>(0);\ndiff --git a/src/ipa/rpi/controller/rpi/saturation.h b/src/ipa/rpi/controller/rpi/saturation.h\nindex c67d496ef065..e6a22c8bb94d 100644\n--- a/src/ipa/rpi/controller/rpi/saturation.h\n+++ b/src/ipa/rpi/controller/rpi/saturation.h\n@@ -21,7 +21,7 @@ class Saturation : public Algorithm\n public:\n \tSaturation(Controller *controller = NULL);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid initialise() override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \ndiff --git a/src/ipa/rpi/controller/rpi/sdn.cpp b/src/ipa/rpi/controller/rpi/sdn.cpp\nindex 594ea70133ac..13dfad02068c 100644\n--- a/src/ipa/rpi/controller/rpi/sdn.cpp\n+++ b/src/ipa/rpi/controller/rpi/sdn.cpp\n@@ -35,7 +35,7 @@ char const *Sdn::name() const\n \treturn NAME;\n }\n \n-int Sdn::read(const libcamera::YamlObject ¶ms)\n+int Sdn::read(const libcamera::ValueNode ¶ms)\n {\n \tdeviation_ = params[\"deviation\"].get<double>(3.2);\n \tstrength_ = params[\"strength\"].get<double>(0.75);\ndiff --git a/src/ipa/rpi/controller/rpi/sdn.h b/src/ipa/rpi/controller/rpi/sdn.h\nindex cb226de88c3c..20d847f0cefa 100644\n--- a/src/ipa/rpi/controller/rpi/sdn.h\n+++ b/src/ipa/rpi/controller/rpi/sdn.h\n@@ -18,7 +18,7 @@ class Sdn : public DenoiseAlgorithm\n public:\n \tSdn(Controller *controller = NULL);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid initialise() override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \tvoid setMode(DenoiseMode mode) override;\ndiff --git a/src/ipa/rpi/controller/rpi/sharpen.cpp b/src/ipa/rpi/controller/rpi/sharpen.cpp\nindex 1d143ff53287..e8723916c965 100644\n--- a/src/ipa/rpi/controller/rpi/sharpen.cpp\n+++ b/src/ipa/rpi/controller/rpi/sharpen.cpp\n@@ -37,7 +37,7 @@ void Sharpen::switchMode(CameraMode const &cameraMode,\n \tmodeFactor_ = std::max(1.0, cameraMode.noiseFactor);\n }\n \n-int Sharpen::read(const libcamera::YamlObject ¶ms)\n+int Sharpen::read(const libcamera::ValueNode ¶ms)\n {\n \tthreshold_ = params[\"threshold\"].get<double>(1.0);\n \tstrength_ = params[\"strength\"].get<double>(1.0);\ndiff --git a/src/ipa/rpi/controller/rpi/sharpen.h b/src/ipa/rpi/controller/rpi/sharpen.h\nindex 96ccd60934f8..2814ec85fef1 100644\n--- a/src/ipa/rpi/controller/rpi/sharpen.h\n+++ b/src/ipa/rpi/controller/rpi/sharpen.h\n@@ -19,7 +19,7 @@ public:\n \tSharpen(Controller *controller);\n \tchar const *name() const override;\n \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid setStrength(double strength) override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \ndiff --git a/src/ipa/rpi/controller/rpi/tonemap.cpp b/src/ipa/rpi/controller/rpi/tonemap.cpp\nindex 3422adfe7dee..3cbecf5379ac 100644\n--- a/src/ipa/rpi/controller/rpi/tonemap.cpp\n+++ b/src/ipa/rpi/controller/rpi/tonemap.cpp\n@@ -27,7 +27,7 @@ char const *Tonemap::name() const\n \treturn NAME;\n }\n \n-int Tonemap::read(const libcamera::YamlObject ¶ms)\n+int Tonemap::read(const libcamera::ValueNode ¶ms)\n {\n \tconfig_.detailConstant = params[\"detail_constant\"].get<uint16_t>(0);\n \tconfig_.detailSlope = params[\"detail_slope\"].get<double>(0.1);\ndiff --git a/src/ipa/rpi/controller/rpi/tonemap.h b/src/ipa/rpi/controller/rpi/tonemap.h\nindex 4e513b1d00da..4d486d136499 100644\n--- a/src/ipa/rpi/controller/rpi/tonemap.h\n+++ b/src/ipa/rpi/controller/rpi/tonemap.h\n@@ -25,7 +25,7 @@ class Tonemap : public Algorithm\n public:\n \tTonemap(Controller *controller = NULL);\n \tchar const *name() const override;\n-\tint read(const libcamera::YamlObject ¶ms) override;\n+\tint read(const libcamera::ValueNode ¶ms) override;\n \tvoid initialise() override;\n \tvoid prepare(Metadata *imageMetadata) override;\n \ndiff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp\nindex 464e43c278f3..677be56ed669 100644\n--- a/src/ipa/simple/algorithms/blc.cpp\n+++ b/src/ipa/simple/algorithms/blc.cpp\n@@ -24,7 +24,7 @@ BlackLevel::BlackLevel()\n }\n \n int BlackLevel::init([[maybe_unused]] IPAContext &context,\n-\t\t const YamlObject &tuningData)\n+\t\t const ValueNode &tuningData)\n {\n \tauto blackLevel = tuningData[\"blackLevel\"].get<int16_t>();\n \tif (blackLevel.has_value()) {\ndiff --git a/src/ipa/simple/algorithms/blc.h b/src/ipa/simple/algorithms/blc.h\nindex a5592d08740f..2933ff1fffe7 100644\n--- a/src/ipa/simple/algorithms/blc.h\n+++ b/src/ipa/simple/algorithms/blc.h\n@@ -22,7 +22,7 @@ public:\n \tBlackLevel();\n \t~BlackLevel() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n \tvoid prepare(IPAContext &context,\n \t\t const uint32_t frame,\ndiff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp\nindex 0a98406c1a3a..ec66f0193478 100644\n--- a/src/ipa/simple/algorithms/ccm.cpp\n+++ b/src/ipa/simple/algorithms/ccm.cpp\n@@ -27,7 +27,7 @@ namespace ipa::soft::algorithms {\n \n LOG_DEFINE_CATEGORY(IPASoftCcm)\n \n-int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData)\n+int Ccm::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData)\n {\n \tint ret = ccm_.readYaml(tuningData[\"ccms\"], \"ct\", \"ccm\");\n \tif (ret < 0) {\ndiff --git a/src/ipa/simple/algorithms/ccm.h b/src/ipa/simple/algorithms/ccm.h\nindex 8279a3d5967e..3e3755165c03 100644\n--- a/src/ipa/simple/algorithms/ccm.h\n+++ b/src/ipa/simple/algorithms/ccm.h\n@@ -25,7 +25,7 @@ public:\n \tCcm() = default;\n \t~Ccm() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context,\n \t\t const IPAConfigInfo &configInfo) override;\n \tvoid queueRequest(typename Module::Context &context,\ndiff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\nindex 54cb804e7822..5e09bce79ee1 100644\n--- a/src/ipa/simple/algorithms/lut.cpp\n+++ b/src/ipa/simple/algorithms/lut.cpp\n@@ -25,7 +25,7 @@ LOG_DEFINE_CATEGORY(IPASoftLut)\n namespace ipa::soft::algorithms {\n \n int Lut::init(IPAContext &context,\n-\t [[maybe_unused]] const YamlObject &tuningData)\n+\t [[maybe_unused]] const ValueNode &tuningData)\n {\n \tcontext.ctrlMap[&controls::Contrast] = ControlInfo(0.0f, 2.0f, 1.0f);\n \treturn 0;\ndiff --git a/src/ipa/simple/algorithms/lut.h b/src/ipa/simple/algorithms/lut.h\nindex ba8b9021b37e..a3f8fac23b19 100644\n--- a/src/ipa/simple/algorithms/lut.h\n+++ b/src/ipa/simple/algorithms/lut.h\n@@ -19,7 +19,7 @@ public:\n \tLut() = default;\n \t~Lut() = default;\n \n-\tint init(IPAContext &context, const YamlObject &tuningData) override;\n+\tint init(IPAContext &context, const ValueNode &tuningData) override;\n \tint configure(IPAContext &context, const IPAConfigInfo &configInfo) override;\n \tvoid queueRequest(typename Module::Context &context,\n \t\t\t const uint32_t frame,\ndiff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\nindex 57836c73ccfa..6200072b9268 100644\n--- a/src/ipa/simple/soft_simple.cpp\n+++ b/src/ipa/simple/soft_simple.cpp\n@@ -120,7 +120,7 @@ int IPASoftSimple::init(const IPASettings &settings,\n \t\treturn ret;\n \t}\n \n-\tstd::unique_ptr<libcamera::YamlObject> data = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> data = YamlParser::parse(file);\n \tif (!data)\n \t\treturn -EINVAL;\n \ndiff --git a/src/libcamera/converter/converter_dw100.cpp b/src/libcamera/converter/converter_dw100.cpp\nindex 5782cd0b21b7..86b530c13f96 100644\n--- a/src/libcamera/converter/converter_dw100.cpp\n+++ b/src/libcamera/converter/converter_dw100.cpp\n@@ -97,7 +97,7 @@ ConverterDW100Module::createModule(DeviceEnumerator *enumerator)\n * \\sa Dw100VertexMap::setDewarpParams()\n * \\return 0 if successful, an error code otherwise\n */\n-int ConverterDW100Module::init(const YamlObject ¶ms)\n+int ConverterDW100Module::init(const ValueNode ¶ms)\n {\n \tDewarpParms dp;\n \ndiff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp\nindex 621008844c74..010c1d8c35d9 100644\n--- a/src/libcamera/geometry.cpp\n+++ b/src/libcamera/geometry.cpp\n@@ -12,7 +12,7 @@\n \n #include <libcamera/base/log.h>\n \n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n /**\n * \\file geometry.h\n@@ -933,7 +933,7 @@ std::ostream &operator<<(std::ostream &out, const Rectangle &r)\n */\n template<>\n std::optional<Size>\n-YamlObject::Accessor<Size>::get(const YamlObject &obj) const\n+ValueNode::Accessor<Size>::get(const ValueNode &obj) const\n {\n \tif (obj.type_ != Type::List)\n \t\treturn std::nullopt;\ndiff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp\nindex 99d16e7c38c6..c4999d32d7c7 100644\n--- a/src/libcamera/global_configuration.cpp\n+++ b/src/libcamera/global_configuration.cpp\n@@ -65,7 +65,7 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName)\n \t\treturn true;\n \t}\n \n-\tstd::unique_ptr<YamlObject> configuration = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> configuration = YamlParser::parse(file);\n \tif (!configuration) {\n \t\tLOG(Configuration, Error)\n \t\t\t<< \"Failed to parse configuration file \" << fileName;\n@@ -146,7 +146,7 @@ GlobalConfiguration::GlobalConfiguration()\n std::optional<std::vector<std::string>> GlobalConfiguration::listOption(\n \tconst std::initializer_list<std::string_view> confPath) const\n {\n-\tconst YamlObject *c = &configuration();\n+\tconst ValueNode *c = &configuration();\n \tfor (auto part : confPath) {\n \t\tc = &(*c)[part];\n \t\tif (!*c)\n@@ -237,10 +237,10 @@ unsigned int GlobalConfiguration::version() const\n * This returns the whole configuration stored in the top-level section\n * `%configuration` of the YAML configuration file.\n *\n- * The requested part of the configuration can be accessed using \\a YamlObject\n+ * The requested part of the configuration can be accessed using \\a ValueNode\n * methods.\n *\n- * \\note \\a YamlObject type itself shouldn't be used in type declarations to\n+ * \\note \\a ValueNode type itself shouldn't be used in type declarations to\n * avoid trouble if we decide to change the underlying data objects in future.\n *\n * \\return The whole configuration section\ndiff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp\nindex b7c07e896538..4fe210830421 100644\n--- a/src/libcamera/matrix.cpp\n+++ b/src/libcamera/matrix.cpp\n@@ -314,7 +314,7 @@ template bool matrixInvert<double>(Span<const double> data, Span<double> dataOut\n * to the product of the number of rows and columns of the matrix (Rows x\n * Cols). The values shall be stored in row-major order.\n */\n-bool matrixValidateYaml(const YamlObject &obj, unsigned int size)\n+bool matrixValidateYaml(const ValueNode &obj, unsigned int size)\n {\n \tif (!obj.isList())\n \t\treturn false;\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex da89aa3714c3..a24c1ec63c96 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -57,8 +57,8 @@ libcamera_internal_sources = files([\n 'v4l2_request.cpp',\n 'v4l2_subdevice.cpp',\n 'v4l2_videodevice.cpp',\n+ 'value_node.cpp',\n 'vector.cpp',\n- 'yaml_object.cpp',\n 'yaml_parser.cpp',\n ])\n \ndiff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\nindex c7e3b185f89b..b2cfcf7395ca 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n@@ -443,7 +443,7 @@ int RkISP1CameraData::loadTuningFile(const std::string &path)\n \t\treturn ret;\n \t}\n \n-\tstd::unique_ptr<libcamera::YamlObject> data = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> data = YamlParser::parse(file);\n \tif (!data)\n \t\treturn -EINVAL;\n \ndiff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\nindex 684438bd5fb7..a2929bca2a03 100644\n--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n@@ -1116,7 +1116,7 @@ int CameraData::loadPipelineConfiguration()\n \n \tLOG(RPI, Info) << \"Using configuration file '\" << filename << \"'\";\n \n-\tstd::unique_ptr<YamlObject> root = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> root = YamlParser::parse(file);\n \tif (!root) {\n \t\tLOG(RPI, Warning) << \"Failed to parse configuration file, using defaults\";\n \t\treturn 0;\n@@ -1129,7 +1129,7 @@ int CameraData::loadPipelineConfiguration()\n \t\treturn 0;\n \t}\n \n-\tconst YamlObject &phConfig = (*root)[\"pipeline_handler\"];\n+\tconst ValueNode &phConfig = (*root)[\"pipeline_handler\"];\n \n \tif (phConfig.contains(\"disable_startup_frame_drops\"))\n \t\tLOG(RPI, Warning)\ndiff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\nindex c69a690f580c..d959f27705ef 100644\n--- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n@@ -26,7 +26,7 @@\n #include \"libcamera/internal/pipeline_handler.h\"\n #include \"libcamera/internal/request.h\"\n #include \"libcamera/internal/v4l2_videodevice.h\"\n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include <libcamera/ipa/raspberrypi_ipa_interface.h>\n #include <libcamera/ipa/raspberrypi_ipa_proxy.h>\n@@ -96,7 +96,7 @@ public:\n \tvirtual V4L2VideoDevice::Formats rawFormats() const = 0;\n \tvirtual V4L2VideoDevice *frontendDevice() = 0;\n \n-\tvirtual int platformPipelineConfigure(const std::unique_ptr<YamlObject> &root) = 0;\n+\tvirtual int platformPipelineConfigure(const std::unique_ptr<ValueNode> &root) = 0;\n \n \tstd::unique_ptr<ipa::RPi::IPAProxyRPi> ipa_;\n \ndiff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\nindex 7bcba32b9b58..f4133de47f23 100644\n--- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n+++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n@@ -743,7 +743,7 @@ public:\n \tCameraConfiguration::Status\n \tplatformValidate(RPi::RPiCameraConfiguration *rpiConfig) const override;\n \n-\tint platformPipelineConfigure(const std::unique_ptr<YamlObject> &root) override;\n+\tint platformPipelineConfigure(const std::unique_ptr<ValueNode> &root) override;\n \n \tvoid platformStart() override;\n \tvoid platformStop() override;\n@@ -1333,7 +1333,7 @@ PiSPCameraData::platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const\n \treturn status;\n }\n \n-int PiSPCameraData::platformPipelineConfigure(const std::unique_ptr<YamlObject> &root)\n+int PiSPCameraData::platformPipelineConfigure(const std::unique_ptr<ValueNode> &root)\n {\n \tconfig_ = {\n \t\t.numCfeConfigStatsBuffers = 12,\n@@ -1358,7 +1358,7 @@ int PiSPCameraData::platformPipelineConfigure(const std::unique_ptr<YamlObject>\n \t\treturn -EINVAL;\n \t}\n \n-\tconst YamlObject &phConfig = (*root)[\"pipeline_handler\"];\n+\tconst ValueNode &phConfig = (*root)[\"pipeline_handler\"];\n \tconfig_.numCfeConfigStatsBuffers =\n \t\tphConfig[\"num_cfe_config_stats_buffers\"].get<unsigned int>(config_.numCfeConfigStatsBuffers);\n \tconfig_.numCfeConfigQueue =\ndiff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\nindex 8a80439e9082..b5d4a2f670a9 100644\n--- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n@@ -69,7 +69,7 @@ public:\n \n \tCameraConfiguration::Status platformValidate(RPi::RPiCameraConfiguration *rpiConfig) const override;\n \n-\tint platformPipelineConfigure(const std::unique_ptr<YamlObject> &root) override;\n+\tint platformPipelineConfigure(const std::unique_ptr<ValueNode> &root) override;\n \n \tvoid platformStart() override;\n \tvoid platformStop() override;\n@@ -498,7 +498,7 @@ CameraConfiguration::Status Vc4CameraData::platformValidate(RPi::RPiCameraConfig\n \treturn status;\n }\n \n-int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr<YamlObject> &root)\n+int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr<ValueNode> &root)\n {\n \tconfig_ = {\n \t\t.minUnicamBuffers = 2,\n@@ -521,7 +521,7 @@ int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr<YamlObject> &\n \t\treturn -EINVAL;\n \t}\n \n-\tconst YamlObject &phConfig = (*root)[\"pipeline_handler\"];\n+\tconst ValueNode &phConfig = (*root)[\"pipeline_handler\"];\n \tconfig_.minUnicamBuffers =\n \t\tphConfig[\"min_unicam_buffers\"].get<unsigned int>(config_.minUnicamBuffers);\n \tconfig_.minTotalUnicamBuffers =\ndiff --git a/src/libcamera/pipeline/virtual/README.md b/src/libcamera/pipeline/virtual/README.md\nindex a9f39c15172b..0a02a9ea44b3 100644\n--- a/src/libcamera/pipeline/virtual/README.md\n+++ b/src/libcamera/pipeline/virtual/README.md\n@@ -48,7 +48,7 @@ in Virtual Pipeline Handler. `parseConfigFile()` is exposed to use in\n Virtual Pipeline Handler.\n \n This is the procedure of the Parser class:\n-1. `parseConfigFile()` parses the config file to `YamlObject` using `YamlParser::parse()`.\n+1. `parseConfigFile()` parses the config file to `ValueNode` using `YamlParser::parse()`.\n - Parse the top level of config file which are the camera ids and look into\n each camera properties.\n 2. For each camera, `parseCameraConfigData()` returns a camera with the configuration.\ndiff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp\nindex fdc729509371..5169fd39bc38 100644\n--- a/src/libcamera/pipeline/virtual/config_parser.cpp\n+++ b/src/libcamera/pipeline/virtual/config_parser.cpp\n@@ -29,7 +29,7 @@ ConfigParser::parseConfigFile(File &file, PipelineHandler *pipe)\n {\n \tstd::vector<std::unique_ptr<VirtualCameraData>> configurations;\n \n-\tstd::unique_ptr<YamlObject> cameras = YamlParser::parse(file);\n+\tstd::unique_ptr<ValueNode> cameras = YamlParser::parse(file);\n \tif (!cameras) {\n \t\tLOG(Virtual, Error) << \"Failed to parse config file.\";\n \t\treturn configurations;\n@@ -72,7 +72,7 @@ ConfigParser::parseConfigFile(File &file, PipelineHandler *pipe)\n }\n \n std::unique_ptr<VirtualCameraData>\n-ConfigParser::parseCameraConfigData(const YamlObject &cameraConfigData,\n+ConfigParser::parseCameraConfigData(const ValueNode &cameraConfigData,\n \t\t\t\t PipelineHandler *pipe)\n {\n \tstd::vector<VirtualCameraData::Resolution> resolutions;\n@@ -94,13 +94,13 @@ ConfigParser::parseCameraConfigData(const YamlObject &cameraConfigData,\n \treturn data;\n }\n \n-int ConfigParser::parseSupportedFormats(const YamlObject &cameraConfigData,\n+int ConfigParser::parseSupportedFormats(const ValueNode &cameraConfigData,\n \t\t\t\t\tstd::vector<VirtualCameraData::Resolution> *resolutions)\n {\n \tif (cameraConfigData.contains(\"supported_formats\")) {\n-\t\tconst YamlObject &supportedResolutions = cameraConfigData[\"supported_formats\"];\n+\t\tconst ValueNode &supportedResolutions = cameraConfigData[\"supported_formats\"];\n \n-\t\tfor (const YamlObject &supportedResolution : supportedResolutions.asList()) {\n+\t\tfor (const ValueNode &supportedResolution : supportedResolutions.asList()) {\n \t\t\tunsigned int width = supportedResolution[\"width\"].get<unsigned int>(1920);\n \t\t\tunsigned int height = supportedResolution[\"height\"].get<unsigned int>(1080);\n \t\t\tif (width == 0 || height == 0) {\n@@ -152,7 +152,7 @@ int ConfigParser::parseSupportedFormats(const YamlObject &cameraConfigData,\n \treturn 0;\n }\n \n-int ConfigParser::parseFrameGenerator(const YamlObject &cameraConfigData, VirtualCameraData *data)\n+int ConfigParser::parseFrameGenerator(const ValueNode &cameraConfigData, VirtualCameraData *data)\n {\n \tconst std::string testPatternKey = \"test_pattern\";\n \tconst std::string framesKey = \"frames\";\n@@ -178,7 +178,7 @@ int ConfigParser::parseFrameGenerator(const YamlObject &cameraConfigData, Virtua\n \t\treturn 0;\n \t}\n \n-\tconst YamlObject &frames = cameraConfigData[framesKey];\n+\tconst ValueNode &frames = cameraConfigData[framesKey];\n \n \t/* When there is no frames provided in the config file, use color bar test pattern */\n \tif (!frames) {\n@@ -231,7 +231,7 @@ int ConfigParser::parseFrameGenerator(const YamlObject &cameraConfigData, Virtua\n \treturn 0;\n }\n \n-int ConfigParser::parseLocation(const YamlObject &cameraConfigData, VirtualCameraData *data)\n+int ConfigParser::parseLocation(const ValueNode &cameraConfigData, VirtualCameraData *data)\n {\n \t/* Default value is properties::CameraLocationFront */\n \tint32_t location = properties::CameraLocationFront;\n@@ -252,7 +252,7 @@ int ConfigParser::parseLocation(const YamlObject &cameraConfigData, VirtualCamer\n \treturn 0;\n }\n \n-int ConfigParser::parseModel(const YamlObject &cameraConfigData, VirtualCameraData *data)\n+int ConfigParser::parseModel(const ValueNode &cameraConfigData, VirtualCameraData *data)\n {\n \tstd::string model = cameraConfigData[\"model\"].get<std::string>(\"Unknown\");\n \ndiff --git a/src/libcamera/pipeline/virtual/config_parser.h b/src/libcamera/pipeline/virtual/config_parser.h\nindex f696d8862897..97d6dffa31ec 100644\n--- a/src/libcamera/pipeline/virtual/config_parser.h\n+++ b/src/libcamera/pipeline/virtual/config_parser.h\n@@ -13,7 +13,7 @@\n #include <libcamera/base/file.h>\n \n #include \"libcamera/internal/pipeline_handler.h\"\n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"virtual.h\"\n \n@@ -27,13 +27,13 @@ public:\n \n private:\n \tstd::unique_ptr<VirtualCameraData>\n-\tparseCameraConfigData(const YamlObject &cameraConfigData, PipelineHandler *pipe);\n+\tparseCameraConfigData(const ValueNode &cameraConfigData, PipelineHandler *pipe);\n \n-\tint parseSupportedFormats(const YamlObject &cameraConfigData,\n+\tint parseSupportedFormats(const ValueNode &cameraConfigData,\n \t\t\t\t std::vector<VirtualCameraData::Resolution> *resolutions);\n-\tint parseFrameGenerator(const YamlObject &cameraConfigData, VirtualCameraData *data);\n-\tint parseLocation(const YamlObject &cameraConfigData, VirtualCameraData *data);\n-\tint parseModel(const YamlObject &cameraConfigData, VirtualCameraData *data);\n+\tint parseFrameGenerator(const ValueNode &cameraConfigData, VirtualCameraData *data);\n+\tint parseLocation(const ValueNode &cameraConfigData, VirtualCameraData *data);\n+\tint parseModel(const ValueNode &cameraConfigData, VirtualCameraData *data);\n };\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\nindex b032db54ded4..90f2110ade8c 100644\n--- a/src/libcamera/pipeline/virtual/virtual.cpp\n+++ b/src/libcamera/pipeline/virtual/virtual.cpp\n@@ -36,7 +36,7 @@\n #include \"libcamera/internal/framebuffer.h\"\n #include \"libcamera/internal/pipeline_handler.h\"\n #include \"libcamera/internal/request.h\"\n-#include \"libcamera/internal/yaml_object.h\"\n+#include \"libcamera/internal/value_node.h\"\n \n #include \"pipeline/virtual/config_parser.h\"\n \ndiff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp\nnew file mode 100644\nindex 000000000000..7374e7bdde8c\n--- /dev/null\n+++ b/src/libcamera/value_node.cpp\n@@ -0,0 +1,484 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2022, Google Inc.\n+ * Copyright (C) 2025, Ideas on Board.\n+ *\n+ * Data structure to manage tree of values\n+ */\n+\n+#include \"libcamera/internal/value_node.h\"\n+\n+#include <charconv>\n+#include <errno.h>\n+#include <string>\n+#include <vector>\n+\n+#include <libcamera/base/utils.h>\n+\n+/**\n+ * \\file value_node.h\n+ * \\brief Data structure to manage tree of values\n+ */\n+\n+namespace libcamera {\n+\n+namespace {\n+\n+/* Empty static ValueNode as a safe result for invalid operations */\n+static const ValueNode empty;\n+\n+} /* namespace */\n+\n+/**\n+ * \\class ValueNode\n+ * \\brief A class representing a tree structure of values\n+ *\n+ * The ValueNode class is designed to model a tree of values. Each node in the\n+ * tree is represented by a ValueNode instance. Intermediate nodes store\n+ * children either as an ordered list (sequence) or a string-indexed dictionary\n+ * (mapping). Leaf nodes can be empty or store a string value.\n+ */\n+\n+ValueNode::ValueNode()\n+\t: type_(Type::Empty)\n+{\n+}\n+\n+ValueNode::~ValueNode() = default;\n+\n+/**\n+ * \\fn ValueNode::isValue()\n+ * \\brief Return whether the ValueNode is a value\n+ *\n+ * \\return True if the ValueNode is a value, false otherwise\n+ */\n+\n+/**\n+ * \\fn ValueNode::isList()\n+ * \\brief Return whether the ValueNode is a list\n+ *\n+ * \\return True if the ValueNode is a list, false otherwise\n+ */\n+\n+/**\n+ * \\fn ValueNode::isDictionary()\n+ * \\brief Return whether the ValueNode is a dictionary\n+ *\n+ * \\return True if the ValueNode is a dictionary, false otherwise\n+ */\n+\n+/**\n+ * \\fn ValueNode::isEmpty()\n+ * \\brief Return whether the ValueNode is an empty\n+ *\n+ * \\return True if the ValueNode is empty, false otherwise\n+ */\n+\n+/**\n+ * \\fn ValueNode::operator bool()\n+ * \\brief Return whether the ValueNode is a non-empty\n+ *\n+ * \\return False if the ValueNode is empty, true otherwise\n+ */\n+\n+/**\n+ * \\fn ValueNode::size()\n+ * \\brief Retrieve the number of elements in a dictionary or list ValueNode\n+ *\n+ * This function retrieves the size of the ValueNode, defined as the number of\n+ * child elements it contains. Only ValueNode instances of Dictionary or List\n+ * types have a size, calling this function on other types of instances is\n+ * invalid and results in undefined behaviour.\n+ *\n+ * \\return The size of the ValueNode\n+ */\n+std::size_t ValueNode::size() const\n+{\n+\tswitch (type_) {\n+\tcase Type::Dictionary:\n+\tcase Type::List:\n+\t\treturn list_.size();\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n+/**\n+ * \\fn template<typename T> ValueNode::get<T>() const\n+ * \\brief Parse the ValueNode as a \\a T value\n+ * \\tparam T Type of the value\n+ *\n+ * This function parses the value of the ValueNode as a \\a T object, and\n+ * returns the value. If parsing fails (usually because the ValueNode doesn't\n+ * store a \\a T value), std::nullopt is returned.\n+ *\n+ * If the type \\a T is an std::vector, the ValueNode will be parsed as a list\n+ * of values.\n+ *\n+ * \\return The ValueNode value, or std::nullopt if parsing failed\n+ */\n+\n+/**\n+ * \\fn template<typename T, typename U> ValueNode::get<T>(U &&defaultValue) const\n+ * \\brief Parse the ValueNode as a \\a T value\n+ * \\tparam T Type of the value\n+ * \\tparam U Type of the default value\n+ * \\param[in] defaultValue The default value when failing to parse\n+ *\n+ * This function parses the value of the ValueNode as a \\a T object, and\n+ * returns the value. If parsing fails (usually because the ValueNode doesn't\n+ * store a \\a T value), the \\a defaultValue is returned. Type \\a U must be\n+ * convertible to type \\a T.\n+ *\n+ * Unlike the get() function, this overload does not support std::vector for the\n+ * type \\a T.\n+ *\n+ * \\return The ValueNode value, or \\a defaultValue if parsing failed\n+ */\n+\n+/**\n+ * \\fn template<typename T> ValueNode::set<T>(T &&value)\n+ * \\brief Set the value of a ValueNode\n+ * \\tparam T Type of the value\n+ * \\param[in] value The value\n+ *\n+ * This function sets the value stored in a ValueNode to \\a value. The value is\n+ * converted to a string in an implementation-specific way that guarantees that\n+ * subsequent calls to get<T>() will return the same value.\n+ *\n+ * Values can only be set on ValueNode of Type::Value type or empty ValueNode.\n+ * Attempting to set a value on a node of type Type::Dict or Type::List does not\n+ * modify the ValueNode.\n+ */\n+\n+#ifndef __DOXYGEN__\n+\n+template<>\n+std::optional<bool>\n+ValueNode::Accessor<bool>::get(const ValueNode &obj) const\n+{\n+\tif (obj.type_ != Type::Value)\n+\t\treturn std::nullopt;\n+\n+\tif (obj.value_ == \"true\")\n+\t\treturn true;\n+\telse if (obj.value_ == \"false\")\n+\t\treturn false;\n+\n+\treturn std::nullopt;\n+}\n+\n+template<>\n+void ValueNode::Accessor<bool>::set(ValueNode &obj, bool value)\n+{\n+\tif (obj.type_ != Type::Empty && obj.type_ != Type::Value)\n+\t\treturn;\n+\n+\tobj.type_ = Type::Value;\n+\tobj.value_ = value ? \"true\" : \"false\";\n+}\n+\n+template<typename T>\n+struct ValueNode::Accessor<T, std::enable_if_t<\n+\tstd::is_same_v<int8_t, T> ||\n+\tstd::is_same_v<uint8_t, T> ||\n+\tstd::is_same_v<int16_t, T> ||\n+\tstd::is_same_v<uint16_t, T> ||\n+\tstd::is_same_v<int32_t, T> ||\n+\tstd::is_same_v<uint32_t, T>>>\n+{\n+\tstd::optional<T> get(const ValueNode &obj) const\n+\t{\n+\t\tif (obj.type_ != Type::Value)\n+\t\t\treturn std::nullopt;\n+\n+\t\tconst std::string &str = obj.value_;\n+\t\tT value;\n+\n+\t\tauto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(),\n+\t\t\t\t\t\t value);\n+\t\tif (ptr != str.data() + str.size() || ec != std::errc())\n+\t\t\treturn std::nullopt;\n+\n+\t\treturn value;\n+\t}\n+\n+\tvoid set(ValueNode &obj, T value)\n+\t{\n+\t\tif (obj.type_ != Type::Empty && obj.type_ != Type::Value)\n+\t\t\treturn;\n+\n+\t\tobj.type_ = Type::Value;\n+\t\tobj.value_ = std::to_string(value);\n+\t}\n+};\n+\n+template struct ValueNode::Accessor<int8_t>;\n+template struct ValueNode::Accessor<uint8_t>;\n+template struct ValueNode::Accessor<int16_t>;\n+template struct ValueNode::Accessor<uint16_t>;\n+template struct ValueNode::Accessor<int32_t>;\n+template struct ValueNode::Accessor<uint32_t>;\n+\n+template<>\n+std::optional<float>\n+ValueNode::Accessor<float>::get(const ValueNode &obj) const\n+{\n+\treturn obj.get<double>();\n+}\n+\n+template<>\n+void ValueNode::Accessor<float>::set(ValueNode &obj, float value)\n+{\n+\tobj.set<double>(std::forward<float>(value));\n+}\n+\n+template<>\n+std::optional<double>\n+ValueNode::Accessor<double>::get(const ValueNode &obj) const\n+{\n+\tif (obj.type_ != Type::Value)\n+\t\treturn std::nullopt;\n+\n+\tif (obj.value_.empty())\n+\t\treturn std::nullopt;\n+\n+\tchar *end;\n+\n+\terrno = 0;\n+\tdouble value = utils::strtod(obj.value_.c_str(), &end);\n+\n+\tif ('\\0' != *end || errno == ERANGE)\n+\t\treturn std::nullopt;\n+\n+\treturn value;\n+}\n+\n+template<>\n+void ValueNode::Accessor<double>::set(ValueNode &obj, double value)\n+{\n+\tif (obj.type_ != Type::Empty && obj.type_ != Type::Value)\n+\t\treturn;\n+\n+\tobj.type_ = Type::Value;\n+\tobj.value_ = std::to_string(value);\n+}\n+\n+template<>\n+std::optional<std::string>\n+ValueNode::Accessor<std::string>::get(const ValueNode &obj) const\n+{\n+\tif (obj.type_ != Type::Value)\n+\t\treturn std::nullopt;\n+\n+\treturn obj.value_;\n+}\n+\n+template<>\n+void ValueNode::Accessor<std::string>::set(ValueNode &obj, std::string value)\n+{\n+\tif (obj.type_ != Type::Empty && obj.type_ != Type::Value)\n+\t\treturn;\n+\n+\tobj.type_ = Type::Value;\n+\tobj.value_ = std::move(value);\n+}\n+\n+template<typename T>\n+struct ValueNode::Accessor<std::vector<T>, std::enable_if_t<\n+\tstd::is_same_v<bool, T> ||\n+\tstd::is_same_v<float, T> ||\n+\tstd::is_same_v<double, T> ||\n+\tstd::is_same_v<int8_t, T> ||\n+\tstd::is_same_v<uint8_t, T> ||\n+\tstd::is_same_v<int16_t, T> ||\n+\tstd::is_same_v<uint16_t, T> ||\n+\tstd::is_same_v<int32_t, T> ||\n+\tstd::is_same_v<uint32_t, T> ||\n+\tstd::is_same_v<std::string, T>>>\n+{\n+\tstd::optional<std::vector<T>> get(const ValueNode &obj) const\n+\t{\n+\t\tif (obj.type_ != Type::List)\n+\t\t\treturn std::nullopt;\n+\n+\t\tstd::vector<T> values;\n+\t\tvalues.reserve(obj.list_.size());\n+\n+\t\tfor (const ValueNode &entry : obj.asList()) {\n+\t\t\tconst auto value = entry.get<T>();\n+\t\t\tif (!value)\n+\t\t\t\treturn std::nullopt;\n+\t\t\tvalues.emplace_back(*value);\n+\t\t}\n+\n+\t\treturn values;\n+\t}\n+};\n+\n+template struct ValueNode::Accessor<std::vector<bool>>;\n+template struct ValueNode::Accessor<std::vector<float>>;\n+template struct ValueNode::Accessor<std::vector<double>>;\n+template struct ValueNode::Accessor<std::vector<int8_t>>;\n+template struct ValueNode::Accessor<std::vector<uint8_t>>;\n+template struct ValueNode::Accessor<std::vector<int16_t>>;\n+template struct ValueNode::Accessor<std::vector<uint16_t>>;\n+template struct ValueNode::Accessor<std::vector<int32_t>>;\n+template struct ValueNode::Accessor<std::vector<uint32_t>>;\n+template struct ValueNode::Accessor<std::vector<std::string>>;\n+#endif /* __DOXYGEN__ */\n+\n+/**\n+ * \\fn ValueNode::asDict() const\n+ * \\brief Wrap a dictionary ValueNode in an adapter that exposes iterators\n+ *\n+ * The ValueNode class doesn't directly implement iterators, as the iterator\n+ * type depends on whether the node is a Dictionary or List. This function wraps\n+ * a ValueNode of Dictionary type into an adapter that exposes iterators, as\n+ * well as begin() and end() functions, allowing usage of range-based for loops\n+ * with ValueNode. As mappings are not ordered, the iteration order is not\n+ * specified.\n+ *\n+ * The iterator's value_type is a\n+ * <em>std::pair<const std::string &, const \\ref ValueNode &></em>.\n+ *\n+ * If the ValueNode is not of Dictionary type, the returned adapter operates\n+ * as an empty container.\n+ *\n+ * \\return An adapter of unspecified type compatible with range-based for loops\n+ */\n+\n+/**\n+ * \\fn ValueNode::asList() const\n+ * \\brief Wrap a list ValueNode in an adapter that exposes iterators\n+ *\n+ * The ValueNode class doesn't directly implement iterators, as the iterator\n+ * type depends on whether the node is a Dictionary or List. This function wraps\n+ * a ValueNode of List type into an adapter that exposes iterators, as well as\n+ * begin() and end() functions, allowing usage of range-based for loops with\n+ * ValueNode. As lists are ordered, the iteration order is matches the order in\n+ * which child nodes have been added.\n+ *\n+ * The iterator's value_type is a <em>const ValueNode &</em>.\n+ *\n+ * If the ValueNode is not of List type, the returned adapter operates as an\n+ * empty container.\n+ *\n+ * \\return An adapter of unspecified type compatible with range-based for loops\n+ */\n+\n+/**\n+ * \\brief Retrieve the element from list ValueNode by index\n+ * \\param[in] index The element index\n+ *\n+ * This function retrieves an element of the ValueNode. Only ValueNode\n+ * instances of List type associate elements with index, calling this function\n+ * on other types of instances or with an invalid index results in an empty\n+ * node.\n+ *\n+ * \\return The ValueNode as an element of the list\n+ */\n+const ValueNode &ValueNode::operator[](std::size_t index) const\n+{\n+\tif (type_ != Type::List || index >= size())\n+\t\treturn empty;\n+\n+\treturn *list_[index].value;\n+}\n+\n+/**\n+ * \\brief Check if an element of a dictionary exists\n+ * \\param[in] key The element key\n+ *\n+ * This function check if the ValueNode contains an element for the given \\a\n+ * key. Only ValueNode instances of Dictionary type associate elements with\n+ * keys, calling this function on other types of instances is invalid and\n+ * results in undefined behaviour.\n+ *\n+ * \\return True if an element exists, false otherwise\n+ */\n+bool ValueNode::contains(std::string_view key) const\n+{\n+\treturn dictionary_.find(key) != dictionary_.end();\n+}\n+\n+/**\n+ * \\brief Retrieve a member by key from the dictionary\n+ * \\param[in] key The element key\n+ *\n+ * This function retrieves a member of a ValueNode by \\a key. Only ValueNode\n+ * instances of Dictionary type associate elements with keys, calling this\n+ * function on other types of instances or with a nonexistent key results in an\n+ * empty node.\n+ *\n+ * \\return The ValueNode corresponding to the \\a key member\n+ */\n+const ValueNode &ValueNode::operator[](std::string_view key) const\n+{\n+\tif (type_ != Type::Dictionary)\n+\t\treturn empty;\n+\n+\tauto iter = dictionary_.find(key);\n+\tif (iter == dictionary_.end())\n+\t\treturn empty;\n+\n+\treturn *iter->second;\n+}\n+\n+/**\n+ * \\brief Add a child node to a list\n+ * \\param[in] child The child node\n+ *\n+ * Append the \\a child node as the last element of this node's children list.\n+ * This node must be empty, in which case it is converted to the Type::List\n+ * type, or be a list. Otherwise, the \\a child is discarded and the function\n+ * returns a nullptr.\n+ *\n+ * \\return A pointer to the \\a child node if successfully added, nullptr\n+ * otherwise\n+ */\n+ValueNode *ValueNode::add(std::unique_ptr<ValueNode> child)\n+{\n+\tif (type_ == Type::Empty)\n+\t\ttype_ = Type::List;\n+\n+\tif (type_ != Type::List)\n+\t\treturn nullptr;\n+\n+\tValue &elem = list_.emplace_back(std::string{}, std::move(child));\n+\treturn elem.value.get();\n+}\n+\n+/**\n+ * \\brief Add a child node to a dictionary\n+ * \\param[in] key The dictionary key\n+ * \\param[in] child The child node\n+ *\n+ * Add the \\a child node with the given \\a key to this node's children. This\n+ * node must be empty, in which case it is converted to the Type::Dictionary\n+ * type, or be a dictionary. Otherwise, the \\a child is discarded and the\n+ * function returns a nullptr.\n+ *\n+ * Keys are unique. If a child with the same \\a key already exist, the \\a child\n+ * is discarded and the function returns a nullptr.\n+ *\n+ * \\return A pointer to the \\a child node if successfully added, nullptr\n+ * otherwise\n+ */\n+ValueNode *ValueNode::add(std::string key, std::unique_ptr<ValueNode> child)\n+{\n+\tif (type_ == Type::Empty)\n+\t\ttype_ = Type::Dictionary;\n+\n+\tif (type_ != Type::Dictionary)\n+\t\treturn nullptr;\n+\n+\tif (dictionary_.find(key) != dictionary_.end())\n+\t\treturn nullptr;\n+\n+\tValue &elem = list_.emplace_back(std::move(key), std::move(child));\n+\tdictionary_.emplace(elem.key, elem.value.get());\n+\treturn elem.value.get();\n+}\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/vector.cpp b/src/libcamera/vector.cpp\nindex 4dad1b9001c5..86b9f9bb6d5e 100644\n--- a/src/libcamera/vector.cpp\n+++ b/src/libcamera/vector.cpp\n@@ -337,7 +337,7 @@ LOG_DEFINE_CATEGORY(Vector)\n */\n \n #ifndef __DOXYGEN__\n-bool vectorValidateYaml(const YamlObject &obj, unsigned int size)\n+bool vectorValidateYaml(const ValueNode &obj, unsigned int size)\n {\n \tif (!obj.isList())\n \t\treturn false;\ndiff --git a/src/libcamera/yaml_object.cpp b/src/libcamera/yaml_object.cpp\ndeleted file mode 100644\nindex 4328ccbff8f1..000000000000\n--- a/src/libcamera/yaml_object.cpp\n+++ /dev/null\n@@ -1,480 +0,0 @@\n-/* SPDX-License-Identifier: LGPL-2.1-or-later */\n-/*\n- * Copyright (C) 2022, Google Inc.\n- * Copyright (C) 2025, Ideas on Board.\n- *\n- * libcamera YAML object\n- */\n-\n-#include \"libcamera/internal/yaml_object.h\"\n-\n-#include <charconv>\n-#include <errno.h>\n-#include <string>\n-#include <vector>\n-\n-#include <libcamera/base/utils.h>\n-\n-/**\n- * \\file yaml_object.h\n- * \\brief YAML objects\n- */\n-\n-namespace libcamera {\n-\n-namespace {\n-\n-/* Empty static YamlObject as a safe result for invalid operations */\n-static const YamlObject empty;\n-\n-} /* namespace */\n-\n-/**\n- * \\class YamlObject\n- * \\brief A class representing the tree structure of the YAML content\n- *\n- * The YamlObject class represents the tree structure of YAML content. A\n- * YamlObject can be empty, a dictionary or list of YamlObjects, or a value if a\n- * tree leaf.\n- */\n-\n-YamlObject::YamlObject()\n-\t: type_(Type::Empty)\n-{\n-}\n-\n-YamlObject::~YamlObject() = default;\n-\n-/**\n- * \\fn YamlObject::isValue()\n- * \\brief Return whether the YamlObject is a value\n- *\n- * \\return True if the YamlObject is a value, false otherwise\n- */\n-\n-/**\n- * \\fn YamlObject::isList()\n- * \\brief Return whether the YamlObject is a list\n- *\n- * \\return True if the YamlObject is a list, false otherwise\n- */\n-\n-/**\n- * \\fn YamlObject::isDictionary()\n- * \\brief Return whether the YamlObject is a dictionary\n- *\n- * \\return True if the YamlObject is a dictionary, false otherwise\n- */\n-\n-/**\n- * \\fn YamlObject::isEmpty()\n- * \\brief Return whether the YamlObject is an empty\n- *\n- * \\return True if the YamlObject is empty, false otherwise\n- */\n-\n-/**\n- * \\fn YamlObject::operator bool()\n- * \\brief Return whether the YamlObject is a non-empty\n- *\n- * \\return False if the YamlObject is empty, true otherwise\n- */\n-\n-/**\n- * \\brief Retrieve the number of elements in a dictionary or list YamlObject\n- *\n- * This function retrieves the size of the YamlObject, defined as the number of\n- * child elements it contains. Only YamlObject instances of Dictionary or List\n- * types have a size, calling this function on other types of instances is\n- * invalid and results in undefined behaviour.\n- *\n- * \\return The size of the YamlObject\n- */\n-std::size_t YamlObject::size() const\n-{\n-\tswitch (type_) {\n-\tcase Type::Dictionary:\n-\tcase Type::List:\n-\t\treturn list_.size();\n-\tdefault:\n-\t\treturn 0;\n-\t}\n-}\n-\n-/**\n- * \\fn template<typename T> YamlObject::get<T>() const\n- * \\brief Parse the YamlObject as a \\a T value\n- * \\tparam T Type of the value\n- *\n- * This function parses the value of the YamlObject as a \\a T object, and\n- * returns the value. If parsing fails (usually because the YamlObject doesn't\n- * store a \\a T value), std::nullopt is returned.\n- *\n- * If the type \\a T is an std::vector, the YamlObject will be parsed as a list\n- * of values.\n- *\n- * \\return The YamlObject value, or std::nullopt if parsing failed\n- */\n-\n-/**\n- * \\fn template<typename T, typename U> YamlObject::get<T>(U &&defaultValue) const\n- * \\brief Parse the YamlObject as a \\a T value\n- * \\tparam T Type of the value\n- * \\tparam U Type of the default value\n- * \\param[in] defaultValue The default value when failing to parse\n- *\n- * This function parses the value of the YamlObject as a \\a T object, and\n- * returns the value. If parsing fails (usually because the YamlObject doesn't\n- * store a \\a T value), the \\a defaultValue is returned. Type \\a U must be\n- * convertible to type \\a T.\n- *\n- * Unlike the get() function, this overload does not support std::vector for the\n- * type \\a T.\n- *\n- * \\return The YamlObject value, or \\a defaultValue if parsing failed\n- */\n-\n-/**\n- * \\fn template<typename T> YamlObject::set<T>(T &&value)\n- * \\brief Set the value of a YamlObject\n- * \\tparam T Type of the value\n- * \\param[in] value The value\n- *\n- * This function sets the value stored in a YamlObject to \\a value. The value is\n- * converted to a string in an implementation-specific way that guarantees that\n- * subsequent calls to get<T>() will return the same value.\n- *\n- * Values can only be set on YamlObject of Type::Value type or empty YamlObject.\n- * Attempting to set a value on an object of type Type::Dict or Type::List does\n- * not modify the YamlObject.\n- */\n-\n-#ifndef __DOXYGEN__\n-\n-template<>\n-std::optional<bool>\n-YamlObject::Accessor<bool>::get(const YamlObject &obj) const\n-{\n-\tif (obj.type_ != Type::Value)\n-\t\treturn std::nullopt;\n-\n-\tif (obj.value_ == \"true\")\n-\t\treturn true;\n-\telse if (obj.value_ == \"false\")\n-\t\treturn false;\n-\n-\treturn std::nullopt;\n-}\n-\n-template<>\n-void YamlObject::Accessor<bool>::set(YamlObject &obj, bool value)\n-{\n-\tif (obj.type_ != Type::Empty && obj.type_ != Type::Value)\n-\t\treturn;\n-\n-\tobj.type_ = Type::Value;\n-\tobj.value_ = value ? \"true\" : \"false\";\n-}\n-\n-template<typename T>\n-struct YamlObject::Accessor<T, std::enable_if_t<\n-\tstd::is_same_v<int8_t, T> ||\n-\tstd::is_same_v<uint8_t, T> ||\n-\tstd::is_same_v<int16_t, T> ||\n-\tstd::is_same_v<uint16_t, T> ||\n-\tstd::is_same_v<int32_t, T> ||\n-\tstd::is_same_v<uint32_t, T>>>\n-{\n-\tstd::optional<T> get(const YamlObject &obj) const\n-\t{\n-\t\tif (obj.type_ != Type::Value)\n-\t\t\treturn std::nullopt;\n-\n-\t\tconst std::string &str = obj.value_;\n-\t\tT value;\n-\n-\t\tauto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(),\n-\t\t\t\t\t\t value);\n-\t\tif (ptr != str.data() + str.size() || ec != std::errc())\n-\t\t\treturn std::nullopt;\n-\n-\t\treturn value;\n-\t}\n-\n-\tvoid set(YamlObject &obj, T value)\n-\t{\n-\t\tif (obj.type_ != Type::Empty && obj.type_ != Type::Value)\n-\t\t\treturn;\n-\n-\t\tobj.type_ = Type::Value;\n-\t\tobj.value_ = std::to_string(value);\n-\t}\n-};\n-\n-template struct YamlObject::Accessor<int8_t>;\n-template struct YamlObject::Accessor<uint8_t>;\n-template struct YamlObject::Accessor<int16_t>;\n-template struct YamlObject::Accessor<uint16_t>;\n-template struct YamlObject::Accessor<int32_t>;\n-template struct YamlObject::Accessor<uint32_t>;\n-\n-template<>\n-std::optional<float>\n-YamlObject::Accessor<float>::get(const YamlObject &obj) const\n-{\n-\treturn obj.get<double>();\n-}\n-\n-template<>\n-void YamlObject::Accessor<float>::set(YamlObject &obj, float value)\n-{\n-\tobj.set<double>(std::forward<float>(value));\n-}\n-\n-template<>\n-std::optional<double>\n-YamlObject::Accessor<double>::get(const YamlObject &obj) const\n-{\n-\tif (obj.type_ != Type::Value)\n-\t\treturn std::nullopt;\n-\n-\tif (obj.value_.empty())\n-\t\treturn std::nullopt;\n-\n-\tchar *end;\n-\n-\terrno = 0;\n-\tdouble value = utils::strtod(obj.value_.c_str(), &end);\n-\n-\tif ('\\0' != *end || errno == ERANGE)\n-\t\treturn std::nullopt;\n-\n-\treturn value;\n-}\n-\n-template<>\n-void YamlObject::Accessor<double>::set(YamlObject &obj, double value)\n-{\n-\tif (obj.type_ != Type::Empty && obj.type_ != Type::Value)\n-\t\treturn;\n-\n-\tobj.type_ = Type::Value;\n-\tobj.value_ = std::to_string(value);\n-}\n-\n-template<>\n-std::optional<std::string>\n-YamlObject::Accessor<std::string>::get(const YamlObject &obj) const\n-{\n-\tif (obj.type_ != Type::Value)\n-\t\treturn std::nullopt;\n-\n-\treturn obj.value_;\n-}\n-\n-template<>\n-void YamlObject::Accessor<std::string>::set(YamlObject &obj, std::string value)\n-{\n-\tif (obj.type_ != Type::Empty && obj.type_ != Type::Value)\n-\t\treturn;\n-\n-\tobj.type_ = Type::Value;\n-\tobj.value_ = std::move(value);\n-}\n-\n-template<typename T>\n-struct YamlObject::Accessor<std::vector<T>, std::enable_if_t<\n-\tstd::is_same_v<bool, T> ||\n-\tstd::is_same_v<float, T> ||\n-\tstd::is_same_v<double, T> ||\n-\tstd::is_same_v<int8_t, T> ||\n-\tstd::is_same_v<uint8_t, T> ||\n-\tstd::is_same_v<int16_t, T> ||\n-\tstd::is_same_v<uint16_t, T> ||\n-\tstd::is_same_v<int32_t, T> ||\n-\tstd::is_same_v<uint32_t, T> ||\n-\tstd::is_same_v<std::string, T>>>\n-{\n-\tstd::optional<std::vector<T>> get(const YamlObject &obj) const\n-\t{\n-\t\tif (obj.type_ != Type::List)\n-\t\t\treturn std::nullopt;\n-\n-\t\tstd::vector<T> values;\n-\t\tvalues.reserve(obj.list_.size());\n-\n-\t\tfor (const YamlObject &entry : obj.asList()) {\n-\t\t\tconst auto value = entry.get<T>();\n-\t\t\tif (!value)\n-\t\t\t\treturn std::nullopt;\n-\t\t\tvalues.emplace_back(*value);\n-\t\t}\n-\n-\t\treturn values;\n-\t}\n-};\n-\n-template struct YamlObject::Accessor<std::vector<bool>>;\n-template struct YamlObject::Accessor<std::vector<float>>;\n-template struct YamlObject::Accessor<std::vector<double>>;\n-template struct YamlObject::Accessor<std::vector<int8_t>>;\n-template struct YamlObject::Accessor<std::vector<uint8_t>>;\n-template struct YamlObject::Accessor<std::vector<int16_t>>;\n-template struct YamlObject::Accessor<std::vector<uint16_t>>;\n-template struct YamlObject::Accessor<std::vector<int32_t>>;\n-template struct YamlObject::Accessor<std::vector<uint32_t>>;\n-template struct YamlObject::Accessor<std::vector<std::string>>;\n-#endif /* __DOXYGEN__ */\n-\n-/**\n- * \\fn YamlObject::asDict() const\n- * \\brief Wrap a dictionary YamlObject in an adapter that exposes iterators\n- *\n- * The YamlObject class doesn't directly implement iterators, as the iterator\n- * type depends on whether the object is a Dictionary or List. This function\n- * wraps a YamlObject of Dictionary type into an adapter that exposes\n- * iterators, as well as begin() and end() functions, allowing usage of\n- * range-based for loops with YamlObject. As YAML mappings are not ordered, the\n- * iteration order is not specified.\n- *\n- * The iterator's value_type is a\n- * <em>std::pair<const std::string &, const \\ref YamlObject &></em>.\n- *\n- * If the YamlObject is not of Dictionary type, the returned adapter operates\n- * as an empty container.\n- *\n- * \\return An adapter of unspecified type compatible with range-based for loops\n- */\n-\n-/**\n- * \\fn YamlObject::asList() const\n- * \\brief Wrap a list YamlObject in an adapter that exposes iterators\n- *\n- * The YamlObject class doesn't directly implement iterators, as the iterator\n- * type depends on whether the object is a Dictionary or List. This function\n- * wraps a YamlObject of List type into an adapter that exposes iterators, as\n- * well as begin() and end() functions, allowing usage of range-based for loops\n- * with YamlObject. As YAML lists are ordered, the iteration order is identical\n- * to the list order in the YAML data.\n- *\n- * The iterator's value_type is a <em>const YamlObject &</em>.\n- *\n- * If the YamlObject is not of List type, the returned adapter operates as an\n- * empty container.\n- *\n- * \\return An adapter of unspecified type compatible with range-based for loops\n- */\n-\n-/**\n- * \\brief Retrieve the element from list YamlObject by index\n- * \\param[in] index The element index\n- *\n- * This function retrieves an element of the YamlObject. Only YamlObject\n- * instances of List type associate elements with index, calling this function\n- * on other types of instances or with an invalid index results in an empty\n- * object.\n- *\n- * \\return The YamlObject as an element of the list\n- */\n-const YamlObject &YamlObject::operator[](std::size_t index) const\n-{\n-\tif (type_ != Type::List || index >= size())\n-\t\treturn empty;\n-\n-\treturn *list_[index].value;\n-}\n-\n-/**\n- * \\brief Check if an element of a dictionary exists\n- * \\param[in] key The element key\n- *\n- * This function check if the YamlObject contains an element for the given \\a\n- * key. Only YamlObject instances of Dictionary type associate elements with\n- * keys, calling this function on other types of instances is invalid and\n- * results in undefined behaviour.\n- *\n- * \\return True if an element exists, false otherwise\n- */\n-bool YamlObject::contains(std::string_view key) const\n-{\n-\treturn dictionary_.find(key) != dictionary_.end();\n-}\n-\n-/**\n- * \\brief Retrieve a member by key from the dictionary\n- * \\param[in] key The element key\n- *\n- * This function retrieves a member of a YamlObject by \\a key. Only YamlObject\n- * instances of Dictionary type associate elements with keys, calling this\n- * function on other types of instances or with a nonexistent key results in an\n- * empty object.\n- *\n- * \\return The YamlObject corresponding to the \\a key member\n- */\n-const YamlObject &YamlObject::operator[](std::string_view key) const\n-{\n-\tif (type_ != Type::Dictionary)\n-\t\treturn empty;\n-\n-\tauto iter = dictionary_.find(key);\n-\tif (iter == dictionary_.end())\n-\t\treturn empty;\n-\n-\treturn *iter->second;\n-}\n-\n-/**\n- * \\brief Add a child object to a list\n- * \\param[in] child The child object\n- *\n- * Append the \\a child node as the last element of this node's children list.\n- * This node must be empty, in which case it is converted to the Type::List\n- * type, or be a list. Otherwise, the \\a child is discarded and the function\n- * returns a nullptr.\n- *\n- * \\return The child object if successfully added, nullptr otherwise\n- */\n-YamlObject *YamlObject::add(std::unique_ptr<YamlObject> child)\n-{\n-\tif (type_ == Type::Empty)\n-\t\ttype_ = Type::List;\n-\n-\tif (type_ != Type::List)\n-\t\treturn nullptr;\n-\n-\tValue &elem = list_.emplace_back(std::string{}, std::move(child));\n-\treturn elem.value.get();\n-}\n-\n-/**\n- * \\brief Add a child object to a dictionary\n- * \\param[in] key The dictionary key\n- * \\param[in] child The child object\n- *\n- * Add the \\a child node with the given \\a key to this node's children. This\n- * node must be empty, in which case it is converted to the Type::Dictionary\n- * type, or be a dictionary. Otherwise, the \\a child is discarded and the\n- * function returns a nullptr.\n- *\n- * Keys are unique. If a child with the same \\a key already exist, the \\a child\n- * is discarded and the function returns a nullptr.\n- *\n- * \\return The child object if successfully added, nullptr otherwise\n- */\n-YamlObject *YamlObject::add(std::string key, std::unique_ptr<YamlObject> child)\n-{\n-\tif (type_ == Type::Empty)\n-\t\ttype_ = Type::Dictionary;\n-\n-\tif (type_ != Type::Dictionary)\n-\t\treturn nullptr;\n-\n-\tif (dictionary_.find(key) != dictionary_.end())\n-\t\treturn nullptr;\n-\n-\tValue &elem = list_.emplace_back(std::move(key), std::move(child));\n-\tdictionary_.emplace(elem.key, elem.value.get());\n-\treturn elem.value.get();\n-}\n-\n-} /* namespace libcamera */\ndiff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\nindex d83df0fb9597..b44818319845 100644\n--- a/src/libcamera/yaml_parser.cpp\n+++ b/src/libcamera/yaml_parser.cpp\n@@ -35,7 +35,7 @@ public:\n \t~YamlParserContext();\n \n \tint init(File &file);\n-\tint parseContent(YamlObject &yamlObject);\n+\tint parseContent(ValueNode &valueNode);\n \n private:\n \tstruct EventDeleter {\n@@ -55,7 +55,7 @@ private:\n \tstd::string readValue(EventPtr event);\n \tint parseDictionaryOrList(yaml_event_type_t endEventType,\n \t\t\t\t const std::function<int(EventPtr event)> &parseItem);\n-\tint parseNextYamlObject(YamlObject &yamlObject, EventPtr event);\n+\tint parseNextNode(ValueNode &valueNode, EventPtr event);\n \n \tbool parserValid_;\n \tyaml_parser_t parser_;\n@@ -153,15 +153,15 @@ YamlParserContext::EventPtr YamlParserContext::nextEvent()\n \n /**\n * \\brief Parse the content of a YAML document\n- * \\param[in] yamlObject The result of YamlObject\n+ * \\param[in] valueNode The result of ValueNode\n *\n * Check YAML start and end events of a YAML document, and parse the root object\n- * of the YAML document into a YamlObject.\n+ * of the YAML document into a ValueNode.\n *\n * \\return 0 on success or a negative error code otherwise\n * \\retval -EINVAL The parser has failed to validate end of a YAML file\n */\n-int YamlParserContext::parseContent(YamlObject &yamlObject)\n+int YamlParserContext::parseContent(ValueNode &valueNode)\n {\n \t/* Check start of the YAML file. */\n \tEventPtr event = nextEvent();\n@@ -174,7 +174,7 @@ int YamlParserContext::parseContent(YamlObject &yamlObject)\n \n \t/* Parse the root object. */\n \tevent = nextEvent();\n-\tif (parseNextYamlObject(yamlObject, std::move(event)))\n+\tif (parseNextNode(valueNode, std::move(event)))\n \t\treturn -EINVAL;\n \n \t/* Check end of the YAML file. */\n@@ -247,8 +247,8 @@ int YamlParserContext::parseDictionaryOrList(yaml_event_type_t endEventType,\n }\n \n /**\n- * \\brief Parse next YAML event and read it as a YamlObject\n- * \\param[in] yamlObject The result of YamlObject\n+ * \\brief Parse next YAML event and read it as a ValueNode\n+ * \\param[in] valueNode The result of ValueNode\n * \\param[in] event The leading event of the object\n *\n * Parse next YAML object separately as a value, list or dictionary.\n@@ -256,26 +256,26 @@ int YamlParserContext::parseDictionaryOrList(yaml_event_type_t endEventType,\n * \\return 0 on success or a negative error code otherwise\n * \\retval -EINVAL Fail to parse the YAML file.\n */\n-int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr event)\n+int YamlParserContext::parseNextNode(ValueNode &valueNode, EventPtr event)\n {\n \tif (!event)\n \t\treturn -EINVAL;\n \n \tswitch (event->type) {\n \tcase YAML_SCALAR_EVENT:\n-\t\tyamlObject.set(readValue(std::move(event)));\n+\t\tvalueNode.set(readValue(std::move(event)));\n \t\treturn 0;\n \n \tcase YAML_SEQUENCE_START_EVENT: {\n-\t\tauto handler = [this, &yamlObject](EventPtr evt) {\n-\t\t\tYamlObject *child = yamlObject.add(std::make_unique<YamlObject>());\n-\t\t\treturn parseNextYamlObject(*child, std::move(evt));\n+\t\tauto handler = [this, &valueNode](EventPtr evt) {\n+\t\t\tValueNode *child = valueNode.add(std::make_unique<ValueNode>());\n+\t\t\treturn parseNextNode(*child, std::move(evt));\n \t\t};\n \t\treturn parseDictionaryOrList(YAML_SEQUENCE_END_EVENT, handler);\n \t}\n \n \tcase YAML_MAPPING_START_EVENT: {\n-\t\tauto handler = [this, &yamlObject](EventPtr evtKey) {\n+\t\tauto handler = [this, &valueNode](EventPtr evtKey) {\n \t\t\t/* Parse key */\n \t\t\tif (evtKey->type != YAML_SCALAR_EVENT) {\n \t\t\t\tLOG(YamlParser, Error) << \"Expect key at line: \"\n@@ -292,9 +292,9 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even\n \t\t\tif (!evtValue)\n \t\t\t\treturn -EINVAL;\n \n-\t\t\tYamlObject *child = yamlObject.add(std::move(key),\n-\t\t\t\t\t\t\t std::make_unique<YamlObject>());\n-\t\t\treturn parseNextYamlObject(*child, std::move(evtValue));\n+\t\t\tValueNode *child = valueNode.add(std::move(key),\n+\t\t\t\t\t\t\t std::make_unique<ValueNode>());\n+\t\t\treturn parseNextNode(*child, std::move(evtValue));\n \t\t};\n \t\tint ret = parseDictionaryOrList(YAML_MAPPING_END_EVENT, handler);\n \t\tif (ret)\n@@ -316,7 +316,7 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even\n * \\brief A helper class for parsing a YAML file\n *\n * The YamlParser class provides an easy interface to parse the contents of a\n- * YAML file into a tree of YamlObject instances.\n+ * YAML file into a tree of ValueNode instances.\n *\n * Example usage:\n *\n@@ -334,17 +334,17 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even\n *\n * \\code{.cpp}\n *\n- * std::unique_ptr<YamlObject> root = YamlParser::parse(fh);\n+ * std::unique_ptr<ValueNode> root = YamlParser::parse(fh);\n * if (!root)\n * return;\n *\n * if (!root->isDictionary())\n * return;\n *\n- * const YamlObject &name = (*root)[\"name\"];\n+ * const ValueNode &name = (*root)[\"name\"];\n * std::cout << name.get<std::string>(\"\") << std::endl;\n *\n- * const YamlObject &numbers = (*root)[\"numbers\"];\n+ * const ValueNode &numbers = (*root)[\"numbers\"];\n * if (!numbers.isList())\n * return;\n *\n@@ -354,7 +354,7 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even\n * \\endcode\n *\n * The YamlParser::parse() function takes an open FILE, parses its contents, and\n- * returns a pointer to a YamlObject corresponding to the root node of the YAML\n+ * returns a pointer to a ValueNode corresponding to the root node of the YAML\n * document.\n *\n * The parser preserves the order of items in the YAML file, for both lists and\n@@ -362,23 +362,23 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even\n */\n \n /**\n- * \\brief Parse a YAML file as a YamlObject\n+ * \\brief Parse a YAML file as a ValueNode\n * \\param[in] file The YAML file to parse\n *\n * The YamlParser::parse() function takes a file, parses its contents, and\n- * returns a pointer to a YamlObject corresponding to the root node of the YAML\n+ * returns a pointer to a ValueNode corresponding to the root node of the YAML\n * document.\n *\n- * \\return Pointer to result YamlObject on success or nullptr otherwise\n+ * \\return Pointer to result ValueNode on success or nullptr otherwise\n */\n-std::unique_ptr<YamlObject> YamlParser::parse(File &file)\n+std::unique_ptr<ValueNode> YamlParser::parse(File &file)\n {\n \tYamlParserContext context;\n \n \tif (context.init(file))\n \t\treturn nullptr;\n \n-\tstd::unique_ptr<YamlObject> root = std::make_unique<YamlObject>();\n+\tstd::unique_ptr<ValueNode> root = std::make_unique<ValueNode>();\n \n \tif (context.parseContent(*root)) {\n \t\tLOG(YamlParser, Error)\ndiff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\nindex 01e734d23059..8c5826f4885b 100644\n--- a/test/yaml-parser.cpp\n+++ b/test/yaml-parser.cpp\n@@ -94,7 +94,7 @@ protected:\n \t\tDictionary,\n \t};\n \n-\tint testObjectType(const YamlObject &obj, const char *name, Type type)\n+\tint testObjectType(const ValueNode &obj, const char *name, Type type)\n \t{\n \t\tbool isList = type == Type::List || type == Type::Size;\n \t\tbool isScalar = !isList && type != Type::Dictionary;\n@@ -194,7 +194,7 @@ protected:\n \t\treturn TestPass;\n \t}\n \n-\tint testIntegerObject(const YamlObject &obj, const char *name, Type type,\n+\tint testIntegerObject(const ValueNode &obj, const char *name, Type type,\n \t\t\t int64_t value)\n \t{\n \t\tuint64_t unsignedValue = static_cast<uint64_t>(value);\n@@ -292,7 +292,7 @@ protected:\n \t\t\treturn TestFail;\n \t\t}\n \n-\t\tstd::unique_ptr<YamlObject> root = YamlParser::parse(file);\n+\t\tstd::unique_ptr<ValueNode> root = YamlParser::parse(file);\n \t\tif (root) {\n \t\t\tcerr << \"Invalid YAML file parse successfully\" << std::endl;\n \t\t\treturn TestFail;\n", "prefixes": [ "19/36" ] }