[19/36] libcamera: Rename YamlObject to ValueNode
diff mbox series

Message ID 20260113000808.15395-20-laurent.pinchart@ideasonboard.com
State New
Headers show
Series
  • libcamera: Global configuration file improvements
Related show

Commit Message

Laurent Pinchart Jan. 13, 2026, 12:07 a.m. UTC
The YamlObject class is now a generic data container to model trees of
values. Rename it to ValueNode and expand the class documentation.

While at it, drop the unneeded libcamera:: namespace prefix when using
the ValueNode class.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../internal/converter/converter_dw100.h      |   2 +-
 .../libcamera/internal/global_configuration.h |  10 +-
 include/libcamera/internal/matrix.h           |  10 +-
 include/libcamera/internal/meson.build        |   2 +-
 .../internal/{yaml_object.h => value_node.h}  |  34 +-
 include/libcamera/internal/vector.h           |  10 +-
 include/libcamera/internal/yaml_parser.h      |   4 +-
 src/android/camera_hal_config.cpp             |  16 +-
 src/ipa/ipu3/algorithms/agc.cpp               |   4 +-
 src/ipa/ipu3/algorithms/agc.h                 |   2 +-
 src/ipa/ipu3/ipu3.cpp                         |   2 +-
 src/ipa/libipa/agc_mean_luminance.cpp         |  16 +-
 src/ipa/libipa/agc_mean_luminance.h           |  12 +-
 src/ipa/libipa/algorithm.cpp                  |   2 +-
 src/ipa/libipa/algorithm.h                    |   4 +-
 src/ipa/libipa/awb.cpp                        |   6 +-
 src/ipa/libipa/awb.h                          |   6 +-
 src/ipa/libipa/awb_bayes.cpp                  |   4 +-
 src/ipa/libipa/awb_bayes.h                    |   6 +-
 src/ipa/libipa/awb_grey.cpp                   |   2 +-
 src/ipa/libipa/awb_grey.h                     |   2 +-
 src/ipa/libipa/interpolator.cpp               |   2 +-
 src/ipa/libipa/interpolator.h                 |   4 +-
 src/ipa/libipa/lsc_polynomial.h               |   6 +-
 src/ipa/libipa/lux.cpp                        |   6 +-
 src/ipa/libipa/lux.h                          |   4 +-
 src/ipa/libipa/module.cpp                     |   2 +-
 src/ipa/libipa/module.h                       |   6 +-
 src/ipa/libipa/pwl.cpp                        |   2 +-
 src/ipa/mali-c55/algorithms/agc.cpp           |   2 +-
 src/ipa/mali-c55/algorithms/agc.h             |   2 +-
 src/ipa/mali-c55/algorithms/blc.cpp           |   4 +-
 src/ipa/mali-c55/algorithms/blc.h             |   2 +-
 src/ipa/mali-c55/algorithms/lsc.cpp           |   6 +-
 src/ipa/mali-c55/algorithms/lsc.h             |   2 +-
 src/ipa/mali-c55/mali-c55.cpp                 |   2 +-
 src/ipa/rkisp1/algorithms/agc.cpp             |  10 +-
 src/ipa/rkisp1/algorithms/agc.h               |   4 +-
 src/ipa/rkisp1/algorithms/awb.cpp             |   2 +-
 src/ipa/rkisp1/algorithms/awb.h               |   2 +-
 src/ipa/rkisp1/algorithms/blc.cpp             |   4 +-
 src/ipa/rkisp1/algorithms/blc.h               |   2 +-
 src/ipa/rkisp1/algorithms/ccm.cpp             |   4 +-
 src/ipa/rkisp1/algorithms/ccm.h               |   4 +-
 src/ipa/rkisp1/algorithms/cproc.cpp           |   2 +-
 src/ipa/rkisp1/algorithms/cproc.h             |   2 +-
 src/ipa/rkisp1/algorithms/dpcc.cpp            |  22 +-
 src/ipa/rkisp1/algorithms/dpcc.h              |   2 +-
 src/ipa/rkisp1/algorithms/dpf.cpp             |   8 +-
 src/ipa/rkisp1/algorithms/dpf.h               |   2 +-
 src/ipa/rkisp1/algorithms/filter.cpp          |   2 +-
 src/ipa/rkisp1/algorithms/filter.h            |   2 +-
 src/ipa/rkisp1/algorithms/goc.cpp             |   4 +-
 src/ipa/rkisp1/algorithms/goc.h               |   2 +-
 src/ipa/rkisp1/algorithms/gsl.cpp             |   6 +-
 src/ipa/rkisp1/algorithms/gsl.h               |   2 +-
 src/ipa/rkisp1/algorithms/lsc.cpp             |  14 +-
 src/ipa/rkisp1/algorithms/lsc.h               |   2 +-
 src/ipa/rkisp1/algorithms/lux.cpp             |   2 +-
 src/ipa/rkisp1/algorithms/lux.h               |   2 +-
 src/ipa/rkisp1/algorithms/wdr.cpp             |   4 +-
 src/ipa/rkisp1/algorithms/wdr.h               |   2 +-
 src/ipa/rkisp1/rkisp1.cpp                     |   2 +-
 src/ipa/rpi/controller/algorithm.cpp          |   2 +-
 src/ipa/rpi/controller/algorithm.h            |   4 +-
 src/ipa/rpi/controller/controller.cpp         |   4 +-
 src/ipa/rpi/controller/controller.h           |   4 +-
 src/ipa/rpi/controller/rpi/af.cpp             |  10 +-
 src/ipa/rpi/controller/rpi/af.h               |   8 +-
 src/ipa/rpi/controller/rpi/agc.cpp            |   2 +-
 src/ipa/rpi/controller/rpi/agc.h              |   2 +-
 src/ipa/rpi/controller/rpi/agc_channel.cpp    |  24 +-
 src/ipa/rpi/controller/rpi/agc_channel.h      |  12 +-
 src/ipa/rpi/controller/rpi/alsc.cpp           |  10 +-
 src/ipa/rpi/controller/rpi/alsc.h             |   2 +-
 src/ipa/rpi/controller/rpi/awb.cpp            |  10 +-
 src/ipa/rpi/controller/rpi/awb.h              |   8 +-
 src/ipa/rpi/controller/rpi/black_level.cpp    |   2 +-
 src/ipa/rpi/controller/rpi/black_level.h      |   2 +-
 src/ipa/rpi/controller/rpi/cac.cpp            |   4 +-
 src/ipa/rpi/controller/rpi/cac.h              |   2 +-
 src/ipa/rpi/controller/rpi/ccm.cpp            |   2 +-
 src/ipa/rpi/controller/rpi/ccm.h              |   2 +-
 src/ipa/rpi/controller/rpi/contrast.cpp       |   2 +-
 src/ipa/rpi/controller/rpi/contrast.h         |   2 +-
 src/ipa/rpi/controller/rpi/decompand.cpp      |   2 +-
 src/ipa/rpi/controller/rpi/decompand.h        |   2 +-
 src/ipa/rpi/controller/rpi/denoise.cpp        |   4 +-
 src/ipa/rpi/controller/rpi/denoise.h          |   4 +-
 src/ipa/rpi/controller/rpi/dpc.cpp            |   2 +-
 src/ipa/rpi/controller/rpi/dpc.h              |   2 +-
 src/ipa/rpi/controller/rpi/geq.cpp            |   2 +-
 src/ipa/rpi/controller/rpi/geq.h              |   2 +-
 src/ipa/rpi/controller/rpi/hdr.cpp            |   4 +-
 src/ipa/rpi/controller/rpi/hdr.h              |   4 +-
 src/ipa/rpi/controller/rpi/lux.cpp            |   2 +-
 src/ipa/rpi/controller/rpi/lux.h              |   2 +-
 src/ipa/rpi/controller/rpi/noise.cpp          |   2 +-
 src/ipa/rpi/controller/rpi/noise.h            |   2 +-
 src/ipa/rpi/controller/rpi/saturation.cpp     |   2 +-
 src/ipa/rpi/controller/rpi/saturation.h       |   2 +-
 src/ipa/rpi/controller/rpi/sdn.cpp            |   2 +-
 src/ipa/rpi/controller/rpi/sdn.h              |   2 +-
 src/ipa/rpi/controller/rpi/sharpen.cpp        |   2 +-
 src/ipa/rpi/controller/rpi/sharpen.h          |   2 +-
 src/ipa/rpi/controller/rpi/tonemap.cpp        |   2 +-
 src/ipa/rpi/controller/rpi/tonemap.h          |   2 +-
 src/ipa/simple/algorithms/blc.cpp             |   2 +-
 src/ipa/simple/algorithms/blc.h               |   2 +-
 src/ipa/simple/algorithms/ccm.cpp             |   2 +-
 src/ipa/simple/algorithms/ccm.h               |   2 +-
 src/ipa/simple/algorithms/lut.cpp             |   2 +-
 src/ipa/simple/algorithms/lut.h               |   2 +-
 src/ipa/simple/soft_simple.cpp                |   2 +-
 src/libcamera/converter/converter_dw100.cpp   |   2 +-
 src/libcamera/geometry.cpp                    |   4 +-
 src/libcamera/global_configuration.cpp        |   8 +-
 src/libcamera/matrix.cpp                      |   2 +-
 src/libcamera/meson.build                     |   2 +-
 src/libcamera/pipeline/rkisp1/rkisp1.cpp      |   2 +-
 .../pipeline/rpi/common/pipeline_base.cpp     |   4 +-
 .../pipeline/rpi/common/pipeline_base.h       |   4 +-
 src/libcamera/pipeline/rpi/pisp/pisp.cpp      |   6 +-
 src/libcamera/pipeline/rpi/vc4/vc4.cpp        |   6 +-
 src/libcamera/pipeline/virtual/README.md      |   2 +-
 .../pipeline/virtual/config_parser.cpp        |  18 +-
 .../pipeline/virtual/config_parser.h          |  12 +-
 src/libcamera/pipeline/virtual/virtual.cpp    |   2 +-
 src/libcamera/value_node.cpp                  | 484 ++++++++++++++++++
 src/libcamera/vector.cpp                      |   2 +-
 src/libcamera/yaml_object.cpp                 | 480 -----------------
 src/libcamera/yaml_parser.cpp                 |  54 +-
 test/yaml-parser.cpp                          |   6 +-
 133 files changed, 807 insertions(+), 803 deletions(-)
 rename include/libcamera/internal/{yaml_object.h => value_node.h} (81%)
 create mode 100644 src/libcamera/value_node.cpp
 delete mode 100644 src/libcamera/yaml_object.cpp

Patch
diff mbox series

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