Message ID | 20250912142915.53949-2-mzamazal@redhat.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
(CC'ing Nicholas Roth) On Fri, Sep 12, 2025 at 04:29:02PM +0200, Milan Zamazal wrote: > Currently, libcamera can be configured in runtime using several > environment variables. With introducing more and more variables, this > mechanism reaches its limits. It would be simpler and more flexible if > it was possible to configure libcamera in a single file. > > For example, there was a request to define pipeline precedence in > runtime. We want to compile in multiple pipelines, in order to have > them accessible within single packages in distributions. And then being > able to select among the pipelines manually as needed based on the > particular hardware or operating system environment. Having the > configuration file then allows easy switching between hardware, GPU or > CPU IPAs. The configuration file can also be used to enable or disable > experimental features and avoid the need to track local patches changing > configuration options hard-wired in the code when working on new > features. > > This patch introduces basic support for configuration files. > GlobalConfiguration class reads and stores the configuration. Its > instance can be used by other libcamera objects to access the > configuration. A GlobalConfiguration instance is supposed to be stored > in a well-defined place, e.g. a CameraManager instance. It is possible > to have multiple GlobalConfiguration instances, which may or may not > make sense. > > libcamera configuration can be specified using a system-wide > configuration file or a user configuration file. The user configuration > file takes precedence if present. There is currently no way to merge > multiple configuration files, the one found is used as the only > configuration file. If no configuration file is present, nothing > changes to the current libcamera behavior (except for some log > messages related to configuration file lookup). > > The configuration file is a YAML file. We already have a mechanism for > handling YAML configuration files in libcamera and the given > infrastructure can be reused for the purpose. However, the > configuration type is abstracted to make contingent future change of the > underlying class easier while retaining (most of) the original API. > > The configuration is versioned. This has currently no particular > meaning but is likely to have its purpose in future, especially once > configuration validation is introduced. > > The configuration YAML file looks as follows: > > --- > version: 1 > configuration: > WHATEVER CONFIGURATION NEEDED > > This patch introduces just the basic idea. Actually using the > configuration in the corresponding places (everything what is currently > configurable via environment variables should be configurable in the > file configuration) and other enhancements are implemented in the > followup patches. > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> > Signed-off-by: Milan Zamazal <mzamazal@redhat.com> > --- > .../libcamera/internal/global_configuration.h | 34 ++++ > include/libcamera/internal/meson.build | 1 + > src/libcamera/global_configuration.cpp | 148 ++++++++++++++++++ > src/libcamera/meson.build | 1 + > 4 files changed, 184 insertions(+) > create mode 100644 include/libcamera/internal/global_configuration.h > create mode 100644 src/libcamera/global_configuration.cpp > > diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h > new file mode 100644 > index 000000000..f695498c4 > --- /dev/null > +++ b/include/libcamera/internal/global_configuration.h > @@ -0,0 +1,34 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2024-2025 Red Hat, inc. > + * > + * Global configuration handling > + */ > + > +#pragma once > + > +#include <filesystem> We removed all usage of std::filesystem in commit 6a2f971035c2df711b10200f9c8c011d9a420e58 Author: Nicholas Roth <nicholas@rothemail.net> Date: Thu Oct 27 22:17:21 2022 -0500 android: remove references to std::filesystem because the Android 11 (and older) toolchain didn't support it. Android 12 has been released 4 years ago, in October 2021. The virtual pipeline handler has reintroduced usage of std::filesystem in November 2024 and nobody has screamed. I supposed it's fine. If someone complains, we can address the issue on top. > + > +#include "libcamera/internal/yaml_parser.h" > + > +namespace libcamera { > + > +class GlobalConfiguration > +{ > +public: > + using Configuration = const YamlObject &; > + > + GlobalConfiguration(); > + > + unsigned int version() const; > + Configuration configuration() const; > + > +private: > + bool loadFile(const std::filesystem::path &fileName); > + void load(); > + > + std::unique_ptr<YamlObject> yamlConfiguration_ = > + std::make_unique<YamlObject>(); > +}; > + > +} /* namespace libcamera */ > diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build > index 5c80a28c4..45c299f6a 100644 > --- a/include/libcamera/internal/meson.build > +++ b/include/libcamera/internal/meson.build > @@ -23,6 +23,7 @@ libcamera_internal_headers = files([ > 'dma_buf_allocator.h', > 'formats.h', > 'framebuffer.h', > + 'global_configuration.h', > 'ipa_data_serializer.h', > 'ipa_manager.h', > 'ipa_module.h', > diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp > new file mode 100644 > index 000000000..d02668111 > --- /dev/null > +++ b/src/libcamera/global_configuration.cpp > @@ -0,0 +1,148 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2024-2025 Red Hat, inc. > + * > + * Global configuration handling > + */ > + > +#include "libcamera/internal/global_configuration.h" > + > +#include <filesystem> > +#include <string_view> > +#include <sys/types.h> > + > +#include <libcamera/base/file.h> > +#include <libcamera/base/log.h> > +#include <libcamera/base/utils.h> > + > +#include "libcamera/internal/yaml_parser.h" > + > +namespace libcamera { > + > +namespace { > +const std::vector<std::filesystem::path> globalConfigurationFiles = { > + std::filesystem::path(LIBCAMERA_SYSCONF_DIR) / "configuration.yaml", > + std::filesystem::path(LIBCAMERA_DATA_DIR) / "configuration.yaml", > +}; > +} > + > +LOG_DEFINE_CATEGORY(Configuration) > + > +/** > + * \class GlobalConfiguration > + * \brief Support for global libcamera configuration > + * > + * The configuration file is a YAML file and the configuration itself is stored > + * under `configuration' top-level item. > + * > + * The configuration file is looked up in user's home directory first and if it > + * is not found then in system-wide configuration directories. If multiple > + * configuration files exist then only the first one found is used and no > + * configuration merging is performed. > + * > + * If the first found configuration file cannot be opened or parsed, an error is > + * reported and no configuration file is used. This is to prevent libcamera from > + * using an unintended configuration file. > + */ > + > +bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) > +{ > + File file(fileName); > + if (!file.open(File::OpenModeFlag::ReadOnly)) { > + if (file.error() == -ENOENT) > + return false; > + > + LOG(Configuration, Error) > + << "Failed to open configuration file " << fileName; > + return true; > + } > + > + std::unique_ptr<YamlObject> configuration = YamlParser::parse(file); > + if (!configuration) { > + LOG(Configuration, Error) > + << "Failed to parse configuration file " << fileName; > + return true; > + } > + > + yamlConfiguration_ = std::move(configuration); > + return true; > +} > + > +void GlobalConfiguration::load() > +{ > + std::filesystem::path userConfigurationDirectory; > + const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); > + if (xdgConfigHome) { > + userConfigurationDirectory = xdgConfigHome; > + } else { > + const char *home = utils::secure_getenv("HOME"); > + if (home) > + userConfigurationDirectory = > + std::filesystem::path(home) / ".config"; > + } > + > + if (!userConfigurationDirectory.empty()) { > + std::filesystem::path user_configuration_file = > + userConfigurationDirectory / "libcamera" / "configuration.yaml"; > + if (loadFile(user_configuration_file)) > + return; > + } > + > + for (const auto &path : globalConfigurationFiles) { > + if (loadFile(path)) > + return; > + } > +} > + > +/** > + * \brief Initialize the global configuration > + */ > +GlobalConfiguration::GlobalConfiguration() > +{ > + load(); > +} > + > +/** > + * \typedef GlobalConfiguration::Configuration > + * \brief Type representing global libcamera configuration > + * > + * All code outside GlobalConfiguration must use this type declaration and not > + * the underlying type. > + */ > + > +/** > + * \brief Return configuration version > + * > + * The version is (optionally) declared in the configuration file in the The version is not optional, parsing returns an error if it's not present. I'll drop "(optionally)". > + * top-level section `version', alongside `configuration'. This has currently no > + * real use but may be needed in future if configuration incompatibilities > + * occur. > + * > + * \return Configuration version as declared in the configuration file or 0 if > + * no version is declared there And here I'll use * \return Configuration version as declared in the configuration file or 0 if * no global configuration is available Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > + */ > +unsigned int GlobalConfiguration::version() const > +{ > + return (*yamlConfiguration_)["version"].get<unsigned int>().value_or(0); > +} > + > +/** > + * \brief Return libcamera global configuration > + * > + * This returns the whole configuration stored in the top-level section > + * `configuration' of the YAML configuration file. > + * > + * The requested part of the configuration can be accessed using \a YamlObject > + * methods. > + * > + * \note \a YamlObject type itself shouldn't be used in type declarations to > + * avoid trouble if we decide to change the underlying data objects in future. > + * > + * \return The whole configuration section > + */ > +GlobalConfiguration::Configuration GlobalConfiguration::configuration() const > +{ > + return (*yamlConfiguration_)["configuration"]; > +} > + > +} /* namespace libcamera */ > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build > index b3ca27f21..5b9b86f21 100644 > --- a/src/libcamera/meson.build > +++ b/src/libcamera/meson.build > @@ -31,6 +31,7 @@ libcamera_internal_sources = files([ > 'device_enumerator_sysfs.cpp', > 'dma_buf_allocator.cpp', > 'formats.cpp', > + 'global_configuration.cpp', > 'ipa_controls.cpp', > 'ipa_data_serializer.cpp', > 'ipa_interface.cpp',
On Fri, Sep 19, 2025 at 07:43:48PM +0300, Laurent Pinchart wrote: > (CC'ing Nicholas Roth) > > On Fri, Sep 12, 2025 at 04:29:02PM +0200, Milan Zamazal wrote: > > Currently, libcamera can be configured in runtime using several > > environment variables. With introducing more and more variables, this > > mechanism reaches its limits. It would be simpler and more flexible if > > it was possible to configure libcamera in a single file. > > > > For example, there was a request to define pipeline precedence in > > runtime. We want to compile in multiple pipelines, in order to have > > them accessible within single packages in distributions. And then being > > able to select among the pipelines manually as needed based on the > > particular hardware or operating system environment. Having the > > configuration file then allows easy switching between hardware, GPU or > > CPU IPAs. The configuration file can also be used to enable or disable > > experimental features and avoid the need to track local patches changing > > configuration options hard-wired in the code when working on new > > features. > > > > This patch introduces basic support for configuration files. > > GlobalConfiguration class reads and stores the configuration. Its > > instance can be used by other libcamera objects to access the > > configuration. A GlobalConfiguration instance is supposed to be stored > > in a well-defined place, e.g. a CameraManager instance. It is possible > > to have multiple GlobalConfiguration instances, which may or may not > > make sense. > > > > libcamera configuration can be specified using a system-wide > > configuration file or a user configuration file. The user configuration > > file takes precedence if present. There is currently no way to merge > > multiple configuration files, the one found is used as the only > > configuration file. If no configuration file is present, nothing > > changes to the current libcamera behavior (except for some log > > messages related to configuration file lookup). > > > > The configuration file is a YAML file. We already have a mechanism for > > handling YAML configuration files in libcamera and the given > > infrastructure can be reused for the purpose. However, the > > configuration type is abstracted to make contingent future change of the > > underlying class easier while retaining (most of) the original API. > > > > The configuration is versioned. This has currently no particular > > meaning but is likely to have its purpose in future, especially once > > configuration validation is introduced. > > > > The configuration YAML file looks as follows: > > > > --- > > version: 1 > > configuration: > > WHATEVER CONFIGURATION NEEDED > > > > This patch introduces just the basic idea. Actually using the > > configuration in the corresponding places (everything what is currently > > configurable via environment variables should be configurable in the > > file configuration) and other enhancements are implemented in the > > followup patches. > > > > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> > > Signed-off-by: Milan Zamazal <mzamazal@redhat.com> > > --- > > .../libcamera/internal/global_configuration.h | 34 ++++ > > include/libcamera/internal/meson.build | 1 + > > src/libcamera/global_configuration.cpp | 148 ++++++++++++++++++ > > src/libcamera/meson.build | 1 + > > 4 files changed, 184 insertions(+) > > create mode 100644 include/libcamera/internal/global_configuration.h > > create mode 100644 src/libcamera/global_configuration.cpp > > > > diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h > > new file mode 100644 > > index 000000000..f695498c4 > > --- /dev/null > > +++ b/include/libcamera/internal/global_configuration.h > > @@ -0,0 +1,34 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2024-2025 Red Hat, inc. > > + * > > + * Global configuration handling > > + */ > > + > > +#pragma once > > + > > +#include <filesystem> > > We removed all usage of std::filesystem in > > commit 6a2f971035c2df711b10200f9c8c011d9a420e58 > Author: Nicholas Roth <nicholas@rothemail.net> > Date: Thu Oct 27 22:17:21 2022 -0500 > > android: remove references to std::filesystem > > because the Android 11 (and older) toolchain didn't support it. Android > 12 has been released 4 years ago, in October 2021. The virtual pipeline > handler has reintroduced usage of std::filesystem in November 2024 and > nobody has screamed. I supposed it's fine. If someone complains, we can > address the issue on top. > > > + > > +#include "libcamera/internal/yaml_parser.h" > > + > > +namespace libcamera { > > + > > +class GlobalConfiguration > > +{ > > +public: > > + using Configuration = const YamlObject &; > > + > > + GlobalConfiguration(); > > + > > + unsigned int version() const; > > + Configuration configuration() const; > > + > > +private: > > + bool loadFile(const std::filesystem::path &fileName); > > + void load(); > > + > > + std::unique_ptr<YamlObject> yamlConfiguration_ = > > + std::make_unique<YamlObject>(); > > +}; > > + > > +} /* namespace libcamera */ > > diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build > > index 5c80a28c4..45c299f6a 100644 > > --- a/include/libcamera/internal/meson.build > > +++ b/include/libcamera/internal/meson.build > > @@ -23,6 +23,7 @@ libcamera_internal_headers = files([ > > 'dma_buf_allocator.h', > > 'formats.h', > > 'framebuffer.h', > > + 'global_configuration.h', > > 'ipa_data_serializer.h', > > 'ipa_manager.h', > > 'ipa_module.h', > > diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp > > new file mode 100644 > > index 000000000..d02668111 > > --- /dev/null > > +++ b/src/libcamera/global_configuration.cpp > > @@ -0,0 +1,148 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2024-2025 Red Hat, inc. > > + * > > + * Global configuration handling > > + */ > > + > > +#include "libcamera/internal/global_configuration.h" > > + > > +#include <filesystem> > > +#include <string_view> > > +#include <sys/types.h> > > + > > +#include <libcamera/base/file.h> > > +#include <libcamera/base/log.h> > > +#include <libcamera/base/utils.h> > > + > > +#include "libcamera/internal/yaml_parser.h" > > + > > +namespace libcamera { > > + > > +namespace { > > +const std::vector<std::filesystem::path> globalConfigurationFiles = { > > + std::filesystem::path(LIBCAMERA_SYSCONF_DIR) / "configuration.yaml", > > + std::filesystem::path(LIBCAMERA_DATA_DIR) / "configuration.yaml", > > +}; > > +} > > + > > +LOG_DEFINE_CATEGORY(Configuration) > > + > > +/** > > + * \class GlobalConfiguration > > + * \brief Support for global libcamera configuration > > + * > > + * The configuration file is a YAML file and the configuration itself is stored > > + * under `configuration' top-level item. > > + * > > + * The configuration file is looked up in user's home directory first and if it s/user/the user/ > > + * is not found then in system-wide configuration directories. If multiple > > + * configuration files exist then only the first one found is used and no > > + * configuration merging is performed. > > + * > > + * If the first found configuration file cannot be opened or parsed, an error is > > + * reported and no configuration file is used. This is to prevent libcamera from > > + * using an unintended configuration file. > > + */ > > + > > +bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) > > +{ > > + File file(fileName); > > + if (!file.open(File::OpenModeFlag::ReadOnly)) { > > + if (file.error() == -ENOENT) > > + return false; > > + > > + LOG(Configuration, Error) > > + << "Failed to open configuration file " << fileName; > > + return true; > > + } > > + > > + std::unique_ptr<YamlObject> configuration = YamlParser::parse(file); > > + if (!configuration) { > > + LOG(Configuration, Error) > > + << "Failed to parse configuration file " << fileName; > > + return true; > > + } > > + > > + yamlConfiguration_ = std::move(configuration); > > + return true; > > +} > > + > > +void GlobalConfiguration::load() > > +{ > > + std::filesystem::path userConfigurationDirectory; > > + const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); > > + if (xdgConfigHome) { > > + userConfigurationDirectory = xdgConfigHome; > > + } else { > > + const char *home = utils::secure_getenv("HOME"); > > + if (home) > > + userConfigurationDirectory = > > + std::filesystem::path(home) / ".config"; > > + } > > + > > + if (!userConfigurationDirectory.empty()) { > > + std::filesystem::path user_configuration_file = > > + userConfigurationDirectory / "libcamera" / "configuration.yaml"; > > + if (loadFile(user_configuration_file)) > > + return; > > + } > > + > > + for (const auto &path : globalConfigurationFiles) { > > + if (loadFile(path)) > > + return; > > + } > > +} > > + > > +/** > > + * \brief Initialize the global configuration > > + */ > > +GlobalConfiguration::GlobalConfiguration() > > +{ > > + load(); > > +} > > + > > +/** > > + * \typedef GlobalConfiguration::Configuration > > + * \brief Type representing global libcamera configuration > > + * > > + * All code outside GlobalConfiguration must use this type declaration and not > > + * the underlying type. > > + */ > > + > > +/** > > + * \brief Return configuration version > > + * > > + * The version is (optionally) declared in the configuration file in the > > The version is not optional, parsing returns an error if it's not > present. I'll drop "(optionally)". > > > + * top-level section `version', alongside `configuration'. This has currently no > > + * real use but may be needed in future if configuration incompatibilities > > + * occur. > > + * > > + * \return Configuration version as declared in the configuration file or 0 if > > + * no version is declared there > > And here I'll use > > * \return Configuration version as declared in the configuration file or 0 if > * no global configuration is available > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > > > + */ > > +unsigned int GlobalConfiguration::version() const > > +{ > > + return (*yamlConfiguration_)["version"].get<unsigned int>().value_or(0); > > +} > > + > > +/** > > + * \brief Return libcamera global configuration > > + * > > + * This returns the whole configuration stored in the top-level section > > + * `configuration' of the YAML configuration file. > > + * > > + * The requested part of the configuration can be accessed using \a YamlObject > > + * methods. > > + * > > + * \note \a YamlObject type itself shouldn't be used in type declarations to > > + * avoid trouble if we decide to change the underlying data objects in future. > > + * > > + * \return The whole configuration section > > + */ > > +GlobalConfiguration::Configuration GlobalConfiguration::configuration() const > > +{ > > + return (*yamlConfiguration_)["configuration"]; > > +} > > + > > +} /* namespace libcamera */ > > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build > > index b3ca27f21..5b9b86f21 100644 > > --- a/src/libcamera/meson.build > > +++ b/src/libcamera/meson.build > > @@ -31,6 +31,7 @@ libcamera_internal_sources = files([ > > 'device_enumerator_sysfs.cpp', > > 'dma_buf_allocator.cpp', > > 'formats.cpp', > > + 'global_configuration.cpp', > > 'ipa_controls.cpp', > > 'ipa_data_serializer.cpp', > > 'ipa_interface.cpp',
diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h new file mode 100644 index 000000000..f695498c4 --- /dev/null +++ b/include/libcamera/internal/global_configuration.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024-2025 Red Hat, inc. + * + * Global configuration handling + */ + +#pragma once + +#include <filesystem> + +#include "libcamera/internal/yaml_parser.h" + +namespace libcamera { + +class GlobalConfiguration +{ +public: + using Configuration = const YamlObject &; + + GlobalConfiguration(); + + unsigned int version() const; + Configuration configuration() const; + +private: + bool loadFile(const std::filesystem::path &fileName); + void load(); + + std::unique_ptr<YamlObject> yamlConfiguration_ = + std::make_unique<YamlObject>(); +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 5c80a28c4..45c299f6a 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -23,6 +23,7 @@ libcamera_internal_headers = files([ 'dma_buf_allocator.h', 'formats.h', 'framebuffer.h', + 'global_configuration.h', 'ipa_data_serializer.h', 'ipa_manager.h', 'ipa_module.h', diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp new file mode 100644 index 000000000..d02668111 --- /dev/null +++ b/src/libcamera/global_configuration.cpp @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024-2025 Red Hat, inc. + * + * Global configuration handling + */ + +#include "libcamera/internal/global_configuration.h" + +#include <filesystem> +#include <string_view> +#include <sys/types.h> + +#include <libcamera/base/file.h> +#include <libcamera/base/log.h> +#include <libcamera/base/utils.h> + +#include "libcamera/internal/yaml_parser.h" + +namespace libcamera { + +namespace { +const std::vector<std::filesystem::path> globalConfigurationFiles = { + std::filesystem::path(LIBCAMERA_SYSCONF_DIR) / "configuration.yaml", + std::filesystem::path(LIBCAMERA_DATA_DIR) / "configuration.yaml", +}; +} + +LOG_DEFINE_CATEGORY(Configuration) + +/** + * \class GlobalConfiguration + * \brief Support for global libcamera configuration + * + * The configuration file is a YAML file and the configuration itself is stored + * under `configuration' top-level item. + * + * The configuration file is looked up in user's home directory first and if it + * is not found then in system-wide configuration directories. If multiple + * configuration files exist then only the first one found is used and no + * configuration merging is performed. + * + * If the first found configuration file cannot be opened or parsed, an error is + * reported and no configuration file is used. This is to prevent libcamera from + * using an unintended configuration file. + */ + +bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName) +{ + File file(fileName); + if (!file.open(File::OpenModeFlag::ReadOnly)) { + if (file.error() == -ENOENT) + return false; + + LOG(Configuration, Error) + << "Failed to open configuration file " << fileName; + return true; + } + + std::unique_ptr<YamlObject> configuration = YamlParser::parse(file); + if (!configuration) { + LOG(Configuration, Error) + << "Failed to parse configuration file " << fileName; + return true; + } + + yamlConfiguration_ = std::move(configuration); + return true; +} + +void GlobalConfiguration::load() +{ + std::filesystem::path userConfigurationDirectory; + const char *xdgConfigHome = utils::secure_getenv("XDG_CONFIG_HOME"); + if (xdgConfigHome) { + userConfigurationDirectory = xdgConfigHome; + } else { + const char *home = utils::secure_getenv("HOME"); + if (home) + userConfigurationDirectory = + std::filesystem::path(home) / ".config"; + } + + if (!userConfigurationDirectory.empty()) { + std::filesystem::path user_configuration_file = + userConfigurationDirectory / "libcamera" / "configuration.yaml"; + if (loadFile(user_configuration_file)) + return; + } + + for (const auto &path : globalConfigurationFiles) { + if (loadFile(path)) + return; + } +} + +/** + * \brief Initialize the global configuration + */ +GlobalConfiguration::GlobalConfiguration() +{ + load(); +} + +/** + * \typedef GlobalConfiguration::Configuration + * \brief Type representing global libcamera configuration + * + * All code outside GlobalConfiguration must use this type declaration and not + * the underlying type. + */ + +/** + * \brief Return configuration version + * + * The version is (optionally) declared in the configuration file in the + * top-level section `version', alongside `configuration'. This has currently no + * real use but may be needed in future if configuration incompatibilities + * occur. + * + * \return Configuration version as declared in the configuration file or 0 if + * no version is declared there + */ +unsigned int GlobalConfiguration::version() const +{ + return (*yamlConfiguration_)["version"].get<unsigned int>().value_or(0); +} + +/** + * \brief Return libcamera global configuration + * + * This returns the whole configuration stored in the top-level section + * `configuration' of the YAML configuration file. + * + * The requested part of the configuration can be accessed using \a YamlObject + * methods. + * + * \note \a YamlObject type itself shouldn't be used in type declarations to + * avoid trouble if we decide to change the underlying data objects in future. + * + * \return The whole configuration section + */ +GlobalConfiguration::Configuration GlobalConfiguration::configuration() const +{ + return (*yamlConfiguration_)["configuration"]; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index b3ca27f21..5b9b86f21 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -31,6 +31,7 @@ libcamera_internal_sources = files([ 'device_enumerator_sysfs.cpp', 'dma_buf_allocator.cpp', 'formats.cpp', + 'global_configuration.cpp', 'ipa_controls.cpp', 'ipa_data_serializer.cpp', 'ipa_interface.cpp',