[{"id":37650,"web_url":"https://patchwork.libcamera.org/comment/37650/","msgid":"<256652aa-3e60-4e6c-b0b4-5e897abb632b@ideasonboard.com>","date":"2026-01-14T11:28:37","subject":"Re: [PATCH 19/36] libcamera: Rename YamlObject to ValueNode","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2026. 01. 13. 1:07 keltezéssel, Laurent Pinchart írta:\n> The YamlObject class is now a generic data container to model trees of\n> values. Rename it to ValueNode and expand the class documentation.\n> \n> While at it, drop the unneeded libcamera:: namespace prefix when using\n> the ValueNode class.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n\nSeems ok to me. There are no \"YamlObject\" left in the source, so it must be correct, right?\n\nReviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n\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\n> \n> diff --git a/include/libcamera/internal/converter/converter_dw100.h b/include/libcamera/internal/converter/converter_dw100.h\n> index 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 &params);\n> +\tint init(const ValueNode &params);\n>   \n>   \tint configure(const StreamConfiguration &inputCfg,\n>   \t\t      const std::vector<std::reference_wrapper<StreamConfiguration>>\n> diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h\n> index 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 */\n> diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h\n> index 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;\n> diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\n> index 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>   \n> diff --git a/include/libcamera/internal/yaml_object.h b/include/libcamera/internal/value_node.h\n> similarity index 81%\n> rename from include/libcamera/internal/yaml_object.h\n> rename to include/libcamera/internal/value_node.h\n> index 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 */\n> diff --git a/include/libcamera/internal/vector.h b/include/libcamera/internal/vector.h\n> index 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;\n> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> index 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 */\n> diff --git a/src/android/camera_hal_config.cpp b/src/android/camera_hal_config.cpp\n> index 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\"))\n> diff --git a/src/ipa/ipu3/algorithms/agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp\n> index 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>   \n> diff --git a/src/ipa/ipu3/algorithms/agc.h b/src/ipa/ipu3/algorithms/agc.h\n> index 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,\n> diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\n> index 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>   \n> diff --git a/src/ipa/libipa/agc_mean_luminance.cpp b/src/ipa/libipa/agc_mean_luminance.cpp\n> index 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>   \n> diff --git a/src/ipa/libipa/agc_mean_luminance.h b/src/ipa/libipa/agc_mean_luminance.h\n> index 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,\n> diff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp\n> index 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\n> diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h\n> index 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}\n> diff --git a/src/ipa/libipa/awb.cpp b/src/ipa/libipa/awb.cpp\n> index 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.\";\n> diff --git a/src/ipa/libipa/awb.h b/src/ipa/libipa/awb.h\n> index 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 {\n> diff --git a/src/ipa/libipa/awb_bayes.cpp b/src/ipa/libipa/awb_bayes.cpp\n> index 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;\n> diff --git a/src/ipa/libipa/awb_bayes.h b/src/ipa/libipa/awb_bayes.h\n> index 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;\n> diff --git a/src/ipa/libipa/awb_grey.cpp b/src/ipa/libipa/awb_grey.cpp\n> index 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\");\n> diff --git a/src/ipa/libipa/awb_grey.h b/src/ipa/libipa/awb_grey.h\n> index 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>   \n> diff --git a/src/ipa/libipa/interpolator.cpp b/src/ipa/libipa/interpolator.cpp\n> index 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\n> diff --git a/src/ipa/libipa/interpolator.h b/src/ipa/libipa/interpolator.h\n> index 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{\n> diff --git a/src/ipa/libipa/lsc_polynomial.h b/src/ipa/libipa/lsc_polynomial.h\n> index 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>();\n> diff --git a/src/ipa/libipa/lux.cpp b/src/ipa/libipa/lux.cpp\n> index 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) {\n> diff --git a/src/ipa/libipa/lux.h b/src/ipa/libipa/lux.h\n> index 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;\n> diff --git a/src/ipa/libipa/module.cpp b/src/ipa/libipa/module.cpp\n> index 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\n> diff --git a/src/ipa/libipa/module.h b/src/ipa/libipa/module.h\n> index 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>   \n> diff --git a/src/ipa/libipa/pwl.cpp b/src/ipa/libipa/pwl.cpp\n> index 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()) {\n> diff --git a/src/ipa/mali-c55/algorithms/agc.cpp b/src/ipa/mali-c55/algorithms/agc.cpp\n> index 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)\n> diff --git a/src/ipa/mali-c55/algorithms/agc.h b/src/ipa/mali-c55/algorithms/agc.h\n> index 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,\n> diff --git a/src/ipa/mali-c55/algorithms/blc.cpp b/src/ipa/mali-c55/algorithms/blc.cpp\n> index 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);\n> diff --git a/src/ipa/mali-c55/algorithms/blc.h b/src/ipa/mali-c55/algorithms/blc.h\n> index 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,\n> diff --git a/src/ipa/mali-c55/algorithms/lsc.cpp b/src/ipa/mali-c55/algorithms/lsc.cpp\n> index 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;\n> diff --git a/src/ipa/mali-c55/algorithms/lsc.h b/src/ipa/mali-c55/algorithms/lsc.h\n> index 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;\n> diff --git a/src/ipa/mali-c55/mali-c55.cpp b/src/ipa/mali-c55/mali-c55.cpp\n> index 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>   \n> diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\n> index 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;\n> diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h\n> index 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>   \n> diff --git a/src/ipa/rkisp1/algorithms/awb.cpp b/src/ipa/rkisp1/algorithms/awb.cpp\n> index 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,\n> diff --git a/src/ipa/rkisp1/algorithms/awb.h b/src/ipa/rkisp1/algorithms/awb.h\n> index 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,\n> diff --git a/src/ipa/rkisp1/algorithms/blc.cpp b/src/ipa/rkisp1/algorithms/blc.cpp\n> index 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>();\n> diff --git a/src/ipa/rkisp1/algorithms/blc.h b/src/ipa/rkisp1/algorithms/blc.h\n> index 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,\n> diff --git a/src/ipa/rkisp1/algorithms/ccm.cpp b/src/ipa/rkisp1/algorithms/ccm.cpp\n> index 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(\n> diff --git a/src/ipa/rkisp1/algorithms/ccm.h b/src/ipa/rkisp1/algorithms/ccm.h\n> index 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);\n> diff --git a/src/ipa/rkisp1/algorithms/cproc.cpp b/src/ipa/rkisp1/algorithms/cproc.cpp\n> index 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>   \n> diff --git a/src/ipa/rkisp1/algorithms/cproc.h b/src/ipa/rkisp1/algorithms/cproc.h\n> index 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,\n> diff --git a/src/ipa/rkisp1/algorithms/dpcc.cpp b/src/ipa/rkisp1/algorithms/dpcc.cpp\n> index 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\")) {\n> diff --git a/src/ipa/rkisp1/algorithms/dpcc.h b/src/ipa/rkisp1/algorithms/dpcc.h\n> index 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;\n> diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp\n> index 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);\n> diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h\n> index 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;\n> diff --git a/src/ipa/rkisp1/algorithms/filter.cpp b/src/ipa/rkisp1/algorithms/filter.cpp\n> index 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);\n> diff --git a/src/ipa/rkisp1/algorithms/filter.h b/src/ipa/rkisp1/algorithms/filter.h\n> index 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;\n> diff --git a/src/ipa/rkisp1/algorithms/goc.cpp b/src/ipa/rkisp1/algorithms/goc.cpp\n> index 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) {\n> diff --git a/src/ipa/rkisp1/algorithms/goc.h b/src/ipa/rkisp1/algorithms/goc.h\n> index 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,\n> diff --git a/src/ipa/rkisp1/algorithms/gsl.cpp b/src/ipa/rkisp1/algorithms/gsl.cpp\n> index 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: \"\n> diff --git a/src/ipa/rkisp1/algorithms/gsl.h b/src/ipa/rkisp1/algorithms/gsl.h\n> index 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;\n> diff --git a/src/ipa/rkisp1/algorithms/lsc.cpp b/src/ipa/rkisp1/algorithms/lsc.cpp\n> index 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\";\n> diff --git a/src/ipa/rkisp1/algorithms/lsc.h b/src/ipa/rkisp1/algorithms/lsc.h\n> index 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,\n> diff --git a/src/ipa/rkisp1/algorithms/lux.cpp b/src/ipa/rkisp1/algorithms/lux.cpp\n> index 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>   }\n> diff --git a/src/ipa/rkisp1/algorithms/lux.h b/src/ipa/rkisp1/algorithms/lux.h\n> index 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;\n> diff --git a/src/ipa/rkisp1/algorithms/wdr.cpp b/src/ipa/rkisp1/algorithms/wdr.cpp\n> index 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)\n> diff --git a/src/ipa/rkisp1/algorithms/wdr.h b/src/ipa/rkisp1/algorithms/wdr.h\n> index 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,\n> diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp\n> index 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>   \n> diff --git a/src/ipa/rpi/controller/algorithm.cpp b/src/ipa/rpi/controller/algorithm.cpp\n> index 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 &params)\n> +int Algorithm::read([[maybe_unused]] const libcamera::ValueNode &params)\n>   {\n>   \treturn 0;\n>   }\n> diff --git a/src/ipa/rpi/controller/algorithm.h b/src/ipa/rpi/controller/algorithm.h\n> index 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 &params);\n> +\tvirtual int read(const libcamera::ValueNode &params);\n>   \tvirtual void initialise();\n>   \tvirtual void switchMode(CameraMode const &cameraMode, Metadata *metadata);\n>   \tvirtual void prepare(Metadata *imageMetadata);\n> diff --git a/src/ipa/rpi/controller/controller.cpp b/src/ipa/rpi/controller/controller.cpp\n> index 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 &params)\n> +int Controller::createAlgorithm(const std::string &name, const ValueNode &params)\n>   {\n>   \tauto it = getAlgorithms().find(name);\n>   \tif (it == getAlgorithms().end()) {\n> diff --git a/src/ipa/rpi/controller/controller.h b/src/ipa/rpi/controller/controller.h\n> index 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 &params);\n> +\tint createAlgorithm(const std::string &name, const libcamera::ValueNode &params);\n>   \n>   \tMetadata globalMetadata_;\n>   \tstd::vector<AlgorithmPtr> algorithms_;\n> diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp\n> index 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 &params, char const *name)\n> +static void readNumber(T &dest, const libcamera::ValueNode &params, 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 &params, char const\n>   \t\tLOG(RPiAf, Warning) << \"Missing parameter \\\"\" << name << \"\\\"\";\n>   }\n>   \n> -void Af::RangeDependentParams::read(const libcamera::YamlObject &params)\n> +void Af::RangeDependentParams::read(const libcamera::ValueNode &params)\n>   {\n>   \n>   \treadNumber<double>(focusMin, params, \"min\");\n> @@ -85,7 +85,7 @@ void Af::RangeDependentParams::read(const libcamera::YamlObject &params)\n>   \treadNumber<double>(focusDefault, params, \"default\");\n>   }\n>   \n> -void Af::SpeedDependentParams::read(const libcamera::YamlObject &params)\n> +void Af::SpeedDependentParams::read(const libcamera::ValueNode &params)\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 &params)\n>   \treadNumber<uint32_t>(stepFrames, params, \"step_frames\");\n>   }\n>   \n> -int Af::CfgParams::read(const libcamera::YamlObject &params)\n> +int Af::CfgParams::read(const libcamera::ValueNode &params)\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 &params)\n> +int Af::read(const libcamera::ValueNode &params)\n>   {\n>   \treturn cfg_.read(params);\n>   }\n> diff --git a/src/ipa/rpi/controller/rpi/af.h b/src/ipa/rpi/controller/rpi/af.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) 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 &params);\n> +\t\tvoid read(const libcamera::ValueNode &params);\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 &params);\n> +\t\tvoid read(const libcamera::ValueNode &params);\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 &params);\n> +\t\tint read(const libcamera::ValueNode &params);\n>   \t\tvoid initialise();\n>   \t};\n>   \n> diff --git a/src/ipa/rpi/controller/rpi/agc.cpp b/src/ipa/rpi/controller/rpi/agc.cpp\n> index 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 &params)\n> +int Agc::read(const libcamera::ValueNode &params)\n>   {\n>   \t/*\n>   \t * When there is only a single channel we can read the old style syntax.\n> diff --git a/src/ipa/rpi/controller/rpi/agc.h b/src/ipa/rpi/controller/rpi/agc.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tunsigned int getConvergenceFrames() const override;\n>   \tstd::vector<double> const &getWeights() const override;\n>   \tvoid setEv(unsigned int channel, double ev) override;\n> diff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp\n> index 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 &params)\n> +int AgcMeteringMode::read(const libcamera::ValueNode &params)\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 &params)\n>   \n>   static std::tuple<int, std::string>\n>   readMeteringModes(std::map<std::string, AgcMeteringMode> &metering_modes,\n> -\t\t  const libcamera::YamlObject &params)\n> +\t\t  const libcamera::ValueNode &params)\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 &params)\n> +int AgcExposureMode::read(const libcamera::ValueNode &params)\n>   {\n>   \tauto value = params[\"shutter\"].get<std::vector<double>>();\n>   \tif (!value)\n> @@ -94,7 +94,7 @@ int AgcExposureMode::read(const libcamera::YamlObject &params)\n>   \n>   static std::tuple<int, std::string>\n>   readExposureModes(std::map<std::string, AgcExposureMode> &exposureModes,\n> -\t\t  const libcamera::YamlObject &params)\n> +\t\t  const libcamera::ValueNode &params)\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 &params)\n> +int AgcConstraint::read(const libcamera::ValueNode &params)\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 &params)\n>   }\n>   \n>   static std::tuple<int, AgcConstraintMode>\n> -readConstraintMode(const libcamera::YamlObject &params)\n> +readConstraintMode(const libcamera::ValueNode &params)\n>   {\n>   \tAgcConstraintMode mode;\n>   \tint ret;\n> @@ -158,7 +158,7 @@ readConstraintMode(const libcamera::YamlObject &params)\n>   \n>   static std::tuple<int, std::string>\n>   readConstraintModes(std::map<std::string, AgcConstraintMode> &constraintModes,\n> -\t\t    const libcamera::YamlObject &params)\n> +\t\t    const libcamera::ValueNode &params)\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 &params)\n> +int AgcChannelConstraint::read(const libcamera::ValueNode &params)\n>   {\n>   \tauto channelValue = params[\"channel\"].get<unsigned int>();\n>   \tif (!channelValue) {\n> @@ -204,7 +204,7 @@ int AgcChannelConstraint::read(const libcamera::YamlObject &params)\n>   }\n>   \n>   static int readChannelConstraints(std::vector<AgcChannelConstraint> &channelConstraints,\n> -\t\t\t\t  const libcamera::YamlObject &params)\n> +\t\t\t\t  const libcamera::ValueNode &params)\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 &params)\n> +int AgcConfig::read(const libcamera::ValueNode &params)\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 &params,\n> +int AgcChannel::read(const libcamera::ValueNode &params,\n>   \t\t     const Controller::HardwareConfig &hardwareConfig)\n>   {\n>   \tint ret = config_.read(params);\n> diff --git a/src/ipa/rpi/controller/rpi/agc_channel.h b/src/ipa/rpi/controller/rpi/agc_channel.h\n> index 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 &params);\n> +\tint read(const libcamera::ValueNode &params);\n>   };\n>   \n>   struct AgcExposureMode {\n>   \tstd::vector<libcamera::utils::Duration> exposureTime;\n>   \tstd::vector<double> gain;\n> -\tint read(const libcamera::YamlObject &params);\n> +\tint read(const libcamera::ValueNode &params);\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 &params);\n> +\tint read(const libcamera::ValueNode &params);\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 &params);\n> +\tint read(const libcamera::ValueNode &params);\n>   };\n>   \n>   struct AgcConfig {\n> -\tint read(const libcamera::YamlObject &params);\n> +\tint read(const libcamera::ValueNode &params);\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 &params,\n> +\tint read(const libcamera::ValueNode &params,\n>   \t\t const Controller::HardwareConfig &hardwareConfig);\n>   \tunsigned int getConvergenceFrames() const;\n>   \tstd::vector<double> const &getWeights() const;\n> diff --git a/src/ipa/rpi/controller/rpi/alsc.cpp b/src/ipa/rpi/controller/rpi/alsc.cpp\n> index 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 &params)\n> +static int generateLut(Array2D<double> &lut, const libcamera::ValueNode &params)\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 &params\n>   \treturn 0;\n>   }\n>   \n> -static int readLut(Array2D<double> &lut, const libcamera::YamlObject &params)\n> +static int readLut(Array2D<double> &lut, const libcamera::ValueNode &params)\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 &params)\n>   }\n>   \n>   static int readCalibrations(std::vector<AlscCalibration> &calibrations,\n> -\t\t\t    const libcamera::YamlObject &params,\n> +\t\t\t    const libcamera::ValueNode &params,\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 &params)\n> +int Alsc::read(const libcamera::ValueNode &params)\n>   {\n>   \tconfig_.tableSize = getHardwareConfig().awbRegions;\n>   \tconfig_.framePeriod = params[\"frame_period\"].get<uint16_t>(12);\n> diff --git a/src/ipa/rpi/controller/rpi/alsc.h b/src/ipa/rpi/controller/rpi/alsc.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \tvoid process(StatisticsPtr &stats, Metadata *imageMetadata) override;\n>   \n> diff --git a/src/ipa/rpi/controller/rpi/awb.cpp b/src/ipa/rpi/controller/rpi/awb.cpp\n> index 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 &params)\n> +int AwbMode::read(const libcamera::ValueNode &params)\n>   {\n>   \tauto value = params[\"lo\"].get<double>();\n>   \tif (!value)\n> @@ -45,7 +45,7 @@ int AwbMode::read(const libcamera::YamlObject &params)\n>   \treturn 0;\n>   }\n>   \n> -int AwbPrior::read(const libcamera::YamlObject &params)\n> +int AwbPrior::read(const libcamera::ValueNode &params)\n>   {\n>   \tauto value = params[\"lux\"].get<double>();\n>   \tif (!value)\n> @@ -56,7 +56,7 @@ int AwbPrior::read(const libcamera::YamlObject &params)\n>   \treturn prior.empty() ? -EINVAL : 0;\n>   }\n>   \n> -static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::YamlObject &params)\n> +static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::ValueNode &params)\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 &params)\n> +int AwbConfig::read(const libcamera::ValueNode &params)\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 &params)\n> +int Awb::read(const libcamera::ValueNode &params)\n>   {\n>   \treturn config_.read(params);\n>   }\n> diff --git a/src/ipa/rpi/controller/rpi/awb.h b/src/ipa/rpi/controller/rpi/awb.h\n> index 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 &params);\n> +\tint read(const libcamera::ValueNode &params);\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 &params);\n> +\tint read(const libcamera::ValueNode &params);\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 &params);\n> +\tint read(const libcamera::ValueNode &params);\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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tunsigned int getConvergenceFrames() const override;\n>   \tvoid initialValues(double &gainR, double &gainB) override;\n>   \tvoid setMode(std::string const &name) override;\n> diff --git a/src/ipa/rpi/controller/rpi/black_level.cpp b/src/ipa/rpi/controller/rpi/black_level.cpp\n> index 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 &params)\n> +int BlackLevel::read(const libcamera::ValueNode &params)\n>   {\n>   \t/* 64 in 10 bits scaled to 16 bits */\n>   \tuint16_t blackLevel = params[\"black_level\"].get<uint16_t>(4096);\n> diff --git a/src/ipa/rpi/controller/rpi/black_level.h b/src/ipa/rpi/controller/rpi/black_level.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid initialValues(uint16_t &blackLevelR, uint16_t &blackLevelG,\n>   \t\t\t   uint16_t &blackLevelB) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n> diff --git a/src/ipa/rpi/controller/rpi/cac.cpp b/src/ipa/rpi/controller/rpi/cac.cpp\n> index 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 &params, std::vector<double> &inputArray, const Size &size)\n> +static bool arrayToSet(const libcamera::ValueNode &params, 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 &params)\n> +int Cac::read(const libcamera::ValueNode &params)\n>   {\n>   \tconfig_.enabled = params.contains(\"lut_rx\") && params.contains(\"lut_ry\") &&\n>   \t\t\t  params.contains(\"lut_bx\") && params.contains(\"lut_by\");\n> diff --git a/src/ipa/rpi/controller/rpi/cac.h b/src/ipa/rpi/controller/rpi/cac.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \n>   private:\n> diff --git a/src/ipa/rpi/controller/rpi/ccm.cpp b/src/ipa/rpi/controller/rpi/ccm.cpp\n> index 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 &params)\n> +int Ccm::read(const libcamera::ValueNode &params)\n>   {\n>   \tif (params.contains(\"saturation\")) {\n>   \t\tconfig_.saturation = params[\"saturation\"].get<ipa::Pwl>(ipa::Pwl{});\n> diff --git a/src/ipa/rpi/controller/rpi/ccm.h b/src/ipa/rpi/controller/rpi/ccm.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid enableAuto() override;\n>   \tvoid setSaturation(double saturation) override;\n>   \tvoid setCcm(Matrix3x3 const &matrix) override;\n> diff --git a/src/ipa/rpi/controller/rpi/contrast.cpp b/src/ipa/rpi/controller/rpi/contrast.cpp\n> index 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 &params)\n> +int Contrast::read(const libcamera::ValueNode &params)\n>   {\n>   \t// enable adaptive enhancement by default\n>   \tconfig_.ceEnable = params[\"ce_enable\"].get<int>(1);\n> diff --git a/src/ipa/rpi/controller/rpi/contrast.h b/src/ipa/rpi/controller/rpi/contrast.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid setBrightness(double brightness) override;\n>   \tvoid setContrast(double contrast) override;\n>   \tvoid enableCe(bool enable) override;\n> diff --git a/src/ipa/rpi/controller/rpi/decompand.cpp b/src/ipa/rpi/controller/rpi/decompand.cpp\n> index 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 &params)\n> +int Decompand::read(const libcamera::ValueNode &params)\n>   {\n>   \tconfig_.bitdepth = params[\"bitdepth\"].get<uint32_t>(0);\n>   \tconfig_.decompandCurve = params[\"decompand_curve\"].get<ipa::Pwl>(ipa::Pwl{});\n> diff --git a/src/ipa/rpi/controller/rpi/decompand.h b/src/ipa/rpi/controller/rpi/decompand.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid initialise() override;\n>   \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n>   \tvoid initialValues(libcamera::ipa::Pwl &decompandCurve) override;\n> diff --git a/src/ipa/rpi/controller/rpi/denoise.cpp b/src/ipa/rpi/controller/rpi/denoise.cpp\n> index 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 &params)\n> +int DenoiseConfig::read(const libcamera::ValueNode &params)\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 &params)\n> +int Denoise::read(const libcamera::ValueNode &params)\n>   {\n>   \tif (!params.contains(\"normal\")) {\n>   \t\tconfigs_[\"normal\"].read(params);\n> diff --git a/src/ipa/rpi/controller/rpi/denoise.h b/src/ipa/rpi/controller/rpi/denoise.h\n> index 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 &params);\n> +\tint read(const libcamera::ValueNode &params);\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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid initialise() override;\n>   \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n> diff --git a/src/ipa/rpi/controller/rpi/dpc.cpp b/src/ipa/rpi/controller/rpi/dpc.cpp\n> index 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 &params)\n> +int Dpc::read(const libcamera::ValueNode &params)\n>   {\n>   \tconfig_.strength = params[\"strength\"].get<int>(1);\n>   \tif (config_.strength < 0 || config_.strength > 2) {\n> diff --git a/src/ipa/rpi/controller/rpi/dpc.h b/src/ipa/rpi/controller/rpi/dpc.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \n>   private:\n> diff --git a/src/ipa/rpi/controller/rpi/geq.cpp b/src/ipa/rpi/controller/rpi/geq.cpp\n> index 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 &params)\n> +int Geq::read(const libcamera::ValueNode &params)\n>   {\n>   \tconfig_.offset = params[\"offset\"].get<uint16_t>(0);\n>   \tconfig_.slope = params[\"slope\"].get<double>(0.0);\n> diff --git a/src/ipa/rpi/controller/rpi/geq.h b/src/ipa/rpi/controller/rpi/geq.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \n>   private:\n> diff --git a/src/ipa/rpi/controller/rpi/hdr.cpp b/src/ipa/rpi/controller/rpi/hdr.cpp\n> index 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 &params, const std::string &modeName)\n> +void HdrConfig::read(const libcamera::ValueNode &params, 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 &params)\n> +int Hdr::read(const libcamera::ValueNode &params)\n>   {\n>   \t/* Make an \"HDR off\" mode by default so that tuning files don't have to. */\n>   \tHdrConfig &offMode = config_[\"Off\"];\n> diff --git a/src/ipa/rpi/controller/rpi/hdr.h b/src/ipa/rpi/controller/rpi/hdr.h\n> index 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 &params, const std::string &name);\n> +\tvoid read(const libcamera::ValueNode &params, 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \tvoid process(StatisticsPtr &stats, Metadata *imageMetadata) override;\n>   \tint setMode(std::string const &mode) override;\n> diff --git a/src/ipa/rpi/controller/rpi/lux.cpp b/src/ipa/rpi/controller/rpi/lux.cpp\n> index 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 &params)\n> +int Lux::read(const libcamera::ValueNode &params)\n>   {\n>   \tauto value = params[\"reference_shutter_speed\"].get<double>();\n>   \tif (!value)\n> diff --git a/src/ipa/rpi/controller/rpi/lux.h b/src/ipa/rpi/controller/rpi/lux.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \tvoid process(StatisticsPtr &stats, Metadata *imageMetadata) override;\n> diff --git a/src/ipa/rpi/controller/rpi/noise.cpp b/src/ipa/rpi/controller/rpi/noise.cpp\n> index 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 &params)\n> +int Noise::read(const libcamera::ValueNode &params)\n>   {\n>   \tauto value = params[\"reference_constant\"].get<double>();\n>   \tif (!value)\n> diff --git a/src/ipa/rpi/controller/rpi/noise.h b/src/ipa/rpi/controller/rpi/noise.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \n>   private:\n> diff --git a/src/ipa/rpi/controller/rpi/saturation.cpp b/src/ipa/rpi/controller/rpi/saturation.cpp\n> index 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 &params)\n> +int Saturation::read(const libcamera::ValueNode &params)\n>   {\n>   \tconfig_.shiftR = params[\"shift_r\"].get<uint8_t>(0);\n>   \tconfig_.shiftG = params[\"shift_g\"].get<uint8_t>(0);\n> diff --git a/src/ipa/rpi/controller/rpi/saturation.h b/src/ipa/rpi/controller/rpi/saturation.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid initialise() override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \n> diff --git a/src/ipa/rpi/controller/rpi/sdn.cpp b/src/ipa/rpi/controller/rpi/sdn.cpp\n> index 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 &params)\n> +int Sdn::read(const libcamera::ValueNode &params)\n>   {\n>   \tdeviation_ = params[\"deviation\"].get<double>(3.2);\n>   \tstrength_ = params[\"strength\"].get<double>(0.75);\n> diff --git a/src/ipa/rpi/controller/rpi/sdn.h b/src/ipa/rpi/controller/rpi/sdn.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid initialise() override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \tvoid setMode(DenoiseMode mode) override;\n> diff --git a/src/ipa/rpi/controller/rpi/sharpen.cpp b/src/ipa/rpi/controller/rpi/sharpen.cpp\n> index 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 &params)\n> +int Sharpen::read(const libcamera::ValueNode &params)\n>   {\n>   \tthreshold_ = params[\"threshold\"].get<double>(1.0);\n>   \tstrength_ = params[\"strength\"].get<double>(1.0);\n> diff --git a/src/ipa/rpi/controller/rpi/sharpen.h b/src/ipa/rpi/controller/rpi/sharpen.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid setStrength(double strength) override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \n> diff --git a/src/ipa/rpi/controller/rpi/tonemap.cpp b/src/ipa/rpi/controller/rpi/tonemap.cpp\n> index 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 &params)\n> +int Tonemap::read(const libcamera::ValueNode &params)\n>   {\n>   \tconfig_.detailConstant = params[\"detail_constant\"].get<uint16_t>(0);\n>   \tconfig_.detailSlope = params[\"detail_slope\"].get<double>(0.1);\n> diff --git a/src/ipa/rpi/controller/rpi/tonemap.h b/src/ipa/rpi/controller/rpi/tonemap.h\n> index 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 &params) override;\n> +\tint read(const libcamera::ValueNode &params) override;\n>   \tvoid initialise() override;\n>   \tvoid prepare(Metadata *imageMetadata) override;\n>   \n> diff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp\n> index 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()) {\n> diff --git a/src/ipa/simple/algorithms/blc.h b/src/ipa/simple/algorithms/blc.h\n> index 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,\n> diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp\n> index 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) {\n> diff --git a/src/ipa/simple/algorithms/ccm.h b/src/ipa/simple/algorithms/ccm.h\n> index 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,\n> diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp\n> index 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;\n> diff --git a/src/ipa/simple/algorithms/lut.h b/src/ipa/simple/algorithms/lut.h\n> index 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,\n> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp\n> index 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>   \n> diff --git a/src/libcamera/converter/converter_dw100.cpp b/src/libcamera/converter/converter_dw100.cpp\n> index 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 &params)\n> +int ConverterDW100Module::init(const ValueNode &params)\n>   {\n>   \tDewarpParms dp;\n>   \n> diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp\n> index 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;\n> diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp\n> index 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\n> diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp\n> index 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;\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index 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>   \n> diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n> index 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>   \n> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n> index 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)\n> diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n> index 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>   \n> diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp\n> index 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 =\n> diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n> index 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 =\n> diff --git a/src/libcamera/pipeline/virtual/README.md b/src/libcamera/pipeline/virtual/README.md\n> index 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.\n> diff --git a/src/libcamera/pipeline/virtual/config_parser.cpp b/src/libcamera/pipeline/virtual/config_parser.cpp\n> index 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>   \n> diff --git a/src/libcamera/pipeline/virtual/config_parser.h b/src/libcamera/pipeline/virtual/config_parser.h\n> index 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 */\n> diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\n> index 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>   \n> diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp\n> new file mode 100644\n> index 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 */\n> diff --git a/src/libcamera/vector.cpp b/src/libcamera/vector.cpp\n> index 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;\n> diff --git a/src/libcamera/yaml_object.cpp b/src/libcamera/yaml_object.cpp\n> deleted file mode 100644\n> index 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 */\n> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> index 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)\n> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> index 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;","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 CF688C3226\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 14 Jan 2026 11:28:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0367461FBC;\n\tWed, 14 Jan 2026 12:28:43 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 80DEF61F9F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 14 Jan 2026 12:28:41 +0100 (CET)","from [192.168.33.18] (185.221.143.114.nat.pool.zt.hu\n\t[185.221.143.114])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 3481A24A;\n\tWed, 14 Jan 2026 12:28:14 +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=\"gb401lMR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1768390094;\n\tbh=msOA/7V5wNjHMDaOPJUr723gkak4mCFr7kPiN1+BC8E=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=gb401lMRcP5PnCcKv6H8P6Gzi/OnyQSJLHk/kbQy3DOLz4iydrCwQouhHaoddmzpO\n\timlmZE+q43hogpYeOSB7YNULnoA2ABLoYiR3c5Wsj5Y9iplILrrlhqvBdAQ9bSieqH\n\tTYqOucMIvCuRCkK9DaEh1sC/1pIqZjJ6KWwvuwfA=","Message-ID":"<256652aa-3e60-4e6c-b0b4-5e897abb632b@ideasonboard.com>","Date":"Wed, 14 Jan 2026 12:28:37 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH 19/36] libcamera: Rename YamlObject to ValueNode","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20260113000808.15395-1-laurent.pinchart@ideasonboard.com>\n\t<20260113000808.15395-20-laurent.pinchart@ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260113000808.15395-20-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","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>"}},{"id":37711,"web_url":"https://patchwork.libcamera.org/comment/37711/","msgid":"<20260118224859.GB7759@pendragon.ideasonboard.com>","date":"2026-01-18T22:48:59","subject":"Re: [PATCH 19/36] libcamera: Rename YamlObject to ValueNode","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Wed, Jan 14, 2026 at 12:28:37PM +0100, Barnabás Pőcze wrote:\n> 2026. 01. 13. 1:07 keltezéssel, Laurent Pinchart írta:\n> > The YamlObject class is now a generic data container to model trees of\n> > values. Rename it to ValueNode and expand the class documentation.\n> > \n> > While at it, drop the unneeded libcamera:: namespace prefix when using\n> > the ValueNode class.\n> > \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> \n> Seems ok to me. There are no \"YamlObject\" left in the source, so it\n> must be correct, right?\n\nThat's my understanding too :-)\n\n> Reviewed-by: Barnabás Pőcze <barnabas.pocze@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\n\n[snip]","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 462C5BDCBE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 18 Jan 2026 22:49:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0E72461FBC;\n\tSun, 18 Jan 2026 23:49:22 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BAC5661FB7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 18 Jan 2026 23:49:20 +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 B068F22A;\n\tSun, 18 Jan 2026 23:48:50 +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=\"e/JzgUqK\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1768776530;\n\tbh=2FIe+oo1RNqNKBRl9cb8ZWfzRBXhPK9lI1TZY0pIO3g=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=e/JzgUqKhmLvXUl1tBA+Pk5IS9BZa+/oXP441njp9o/fKix31Axlfxlby+oii7vT7\n\tSUtNwYGLE1HqqGk6x1bafmmWzZ34wq6hAbbxJeSVozn/ffQSsXXVgLZJvKLVcsq2yO\n\trvHzwhvWs4TRNUQTaUXs0T40/UN6ygYji1eOlePs=","Date":"Mon, 19 Jan 2026 00:48:59 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 19/36] libcamera: Rename YamlObject to ValueNode","Message-ID":"<20260118224859.GB7759@pendragon.ideasonboard.com>","References":"<20260113000808.15395-1-laurent.pinchart@ideasonboard.com>\n\t<20260113000808.15395-20-laurent.pinchart@ideasonboard.com>\n\t<256652aa-3e60-4e6c-b0b4-5e897abb632b@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<256652aa-3e60-4e6c-b0b4-5e897abb632b@ideasonboard.com>","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>"}}]