@@ -12,6 +12,8 @@
#include <string>
#include <string_view>
+#include <libcamera/base/utils.h>
+
#include "libcamera/internal/yaml_parser.h"
namespace libcamera {
@@ -25,11 +27,28 @@ public:
unsigned int version() const;
Configuration configuration() const;
- std::optional<std::string> option(
+
+ template<typename T>
+ std::optional<T> option(
+ const std::initializer_list<std::string_view> confPath) const
+ {
+ const YamlObject *c = &configuration();
+ for (auto part : confPath) {
+ c = &(*c)[part];
+ if (!*c)
+ return {};
+ }
+ return c->get<T>();
+ }
+
+ std::optional<std::vector<std::string>> listOption(
const std::initializer_list<std::string_view> confPath) const;
std::optional<std::string> envOption(
const char *const envVariable,
const std::initializer_list<std::string_view> confPath) const;
+ std::optional<std::vector<std::string>> envListOption(
+ const char *const envVariable,
+ const std::initializer_list<std::string_view> confPath) const;
private:
bool loadFile(const std::filesystem::path &fileName);
@@ -17,6 +17,7 @@
#include <libcamera/ipa/ipa_module_info.h>
#include "libcamera/internal/camera_manager.h"
+#include "libcamera/internal/global_configuration.h"
#include "libcamera/internal/ipa_module.h"
#include "libcamera/internal/pipeline_handler.h"
#include "libcamera/internal/pub_key.h"
@@ -28,7 +29,7 @@ LOG_DECLARE_CATEGORY(IPAManager)
class IPAManager
{
public:
- IPAManager();
+ IPAManager(const GlobalConfiguration &configuration);
~IPAManager();
template<typename T>
@@ -42,7 +43,8 @@ public:
if (!m)
return nullptr;
- std::unique_ptr<T> proxy = std::make_unique<T>(m, !self->isSignatureValid(m));
+ const GlobalConfiguration &configuration = cm->_d()->configuration();
+ std::unique_ptr<T> proxy = std::make_unique<T>(m, !self->isSignatureValid(m), configuration);
if (!proxy->isValid()) {
LOG(IPAManager, Error) << "Failed to load proxy";
return nullptr;
@@ -73,6 +75,7 @@ private:
#if HAVE_IPA_PUBKEY
static const uint8_t publicKeyData_[];
static const PubKey pubKey_;
+ bool forceIsolation_;
#endif
};
@@ -7,10 +7,14 @@
#pragma once
+#include <optional>
#include <string>
+#include <vector>
#include <libcamera/ipa/ipa_interface.h>
+#include "libcamera/internal/global_configuration.h"
+
namespace libcamera {
class IPAModule;
@@ -24,7 +28,7 @@ public:
ProxyRunning,
};
- IPAProxy(IPAModule *ipam);
+ IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration);
~IPAProxy();
bool isValid() const { return valid_; }
@@ -40,6 +44,8 @@ protected:
private:
IPAModule *ipam_;
+ std::optional<std::vector<std::string>> configPaths_;
+ std::optional<std::vector<std::string>> execPaths_;
};
} /* namespace libcamera */
@@ -41,7 +41,7 @@ LOG_DEFINE_CATEGORY(Camera)
CameraManager::Private::Private()
: initialized_(false)
{
- ipaManager_ = std::make_unique<IPAManager>();
+ ipaManager_ = std::make_unique<IPAManager>(this->configuration());
}
int CameraManager::Private::start()
@@ -9,9 +9,11 @@
#include <filesystem>
#include <memory>
+#include <optional>
#include <string>
#include <string_view>
#include <sys/types.h>
+#include <vector>
#include <libcamera/base/file.h>
#include <libcamera/base/log.h>
@@ -116,13 +118,22 @@ GlobalConfiguration::GlobalConfiguration()
*/
/**
+ * \fn std::optional<T> GlobalConfiguration::option(const std::initializer_list<std::string_view> &confPath) const
* \brief Return value of the configuration option identified by \a confPath
* \param[in] confPath Sequence of the YAML section names (excluding
* `configuration') leading to the requested option
* \return A value if an item corresponding to \a confPath exists in the
* configuration file, no value otherwise
*/
-std::optional<std::string> GlobalConfiguration::option(
+
+/**
+ * \brief Return values of the configuration option identified by \a confPath
+ * \tparam T The type of the retrieved configuration value
+ * \param[in] confPath Sequence of the YAML section names (excluding
+ * `configuration') leading to the requested list option, separated by dots
+ * \return A vector of strings or no value if not found
+ */
+std::optional<std::vector<std::string>> GlobalConfiguration::listOption(
const std::initializer_list<std::string_view> confPath) const
{
const YamlObject *c = &configuration();
@@ -131,7 +142,7 @@ std::optional<std::string> GlobalConfiguration::option(
if (!*c)
return {};
}
- return c->get<std::string>();
+ return c->getList<std::string>();
}
/**
@@ -158,7 +169,37 @@ std::optional<std::string> GlobalConfiguration::envOption(
const char *envValue = utils::secure_getenv(envVariable);
if (envValue)
return std::optional{ std::string{ envValue } };
- return option(confPath);
+ return option<std::string>(confPath);
+}
+
+/**
+ * \brief Return values of the configuration option from a file or environment
+ * \param[in] envVariable Environment variable to get the value from
+ * \param[in] confPath The same as in GlobalConfiguration::option
+ *
+ * This helper looks first at the given environment variable and if it is
+ * defined (even if it is empty) then it splits its value by semicolons and
+ * returns the resulting list of strings. Otherwise it looks for \a confPath the
+ * same way as in GlobalConfiguration::option, value of which must be a list of
+ * strings.
+ *
+ * \note Support for using environment variables to configure libcamera behavior
+ * is provided here mostly for backward compatibility reasons. Introducing new
+ * configuration environment variables is discouraged.
+ *
+ * \return A vector of strings retrieved from the given environment option or
+ * configuration file or no value if not found; the vector may be empty
+ */
+std::optional<std::vector<std::string>> GlobalConfiguration::envListOption(
+ const char *const envVariable,
+ const std::initializer_list<std::string_view> confPath) const
+{
+ const char *envValue = utils::secure_getenv(envVariable);
+ if (envValue) {
+ auto items = utils::split(envValue, ":");
+ return std::vector<std::string>(items.begin(), items.end());
+ }
+ return listOption(confPath);
}
/**
@@ -9,13 +9,17 @@
#include <algorithm>
#include <dirent.h>
+#include <numeric>
#include <string.h>
+#include <string>
#include <sys/types.h>
+#include <vector>
#include <libcamera/base/file.h>
#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>
+#include "libcamera/internal/global_configuration.h"
#include "libcamera/internal/ipa_module.h"
#include "libcamera/internal/ipa_proxy.h"
#include "libcamera/internal/pipeline_handler.h"
@@ -101,30 +105,36 @@ LOG_DEFINE_CATEGORY(IPAManager)
* The IPAManager class is meant to only be instantiated once, by the
* CameraManager.
*/
-IPAManager::IPAManager()
+IPAManager::IPAManager(const GlobalConfiguration &configuration)
{
#if HAVE_IPA_PUBKEY
if (!pubKey_.isValid())
LOG(IPAManager, Warning) << "Public key not valid";
+
+ char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION");
+ forceIsolation_ = (force && force[0] != '\0') ||
+ (!force && configuration.option<bool>({ "ipa", "force_isolation" })
+ .value_or(false));
#endif
unsigned int ipaCount = 0;
/* User-specified paths take precedence. */
- const char *modulePaths = utils::secure_getenv("LIBCAMERA_IPA_MODULE_PATH");
- if (modulePaths) {
- for (const auto &dir : utils::split(modulePaths, ":")) {
- if (dir.empty())
- continue;
-
- ipaCount += addDir(dir.c_str());
- }
+ const auto modulePaths =
+ configuration.envListOption(
+ "LIBCAMERA_IPA_MODULE_PATH", { "ipa", "module_paths" });
+ for (const auto &dir : modulePaths.value_or(std::vector<std::string>())) {
+ if (dir.empty())
+ continue;
- if (!ipaCount)
- LOG(IPAManager, Warning)
- << "No IPA found in '" << modulePaths << "'";
+ ipaCount += addDir(dir.c_str());
}
+ if (!ipaCount)
+ LOG(IPAManager, Warning) << "No IPA found in '"
+ << utils::join(modulePaths.value_or(std::vector<std::string>()), ":")
+ << "'";
+
/*
* When libcamera is used before it is installed, load IPAs from the
* same build directory as the libcamera library itself.
@@ -279,11 +289,10 @@ IPAModule *IPAManager::module(PipelineHandler *pipe, uint32_t minVersion,
bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa) const
{
#if HAVE_IPA_PUBKEY
- char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION");
- if (force && force[0] != '\0') {
+ if (forceIsolation_) {
LOG(IPAManager, Debug)
<< "Isolation of IPA module " << ipa->path()
- << " forced through environment variable";
+ << " forced through configuration";
return false;
}
@@ -7,13 +7,16 @@
#include "libcamera/internal/ipa_proxy.h"
+#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include <vector>
#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>
+#include "libcamera/internal/global_configuration.h"
#include "libcamera/internal/ipa_module.h"
/**
@@ -48,10 +51,15 @@ LOG_DEFINE_CATEGORY(IPAProxy)
/**
* \brief Construct an IPAProxy instance
* \param[in] ipam The IPA module
+ * \param[in] configuration The global configuration
*/
-IPAProxy::IPAProxy(IPAModule *ipam)
+IPAProxy::IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration)
: valid_(false), state_(ProxyStopped), ipam_(ipam)
{
+ configPaths_ = configuration.envListOption("LIBCAMERA_IPA_CONFIG_PATH",
+ { "ipa", "config_paths" });
+ execPaths_ = configuration.envListOption(
+ "LIBCAMERA_IPA_PROXY_PATH", { "ipa", "proxy_paths" });
}
IPAProxy::~IPAProxy()
@@ -122,20 +130,15 @@ std::string IPAProxy::configurationFile(const std::string &name,
int ret;
/*
- * Check the directory pointed to by the IPA config path environment
- * variable next.
+ * Check the directory pointed to by the IPA config path next.
*/
- const char *confPaths = utils::secure_getenv("LIBCAMERA_IPA_CONFIG_PATH");
- if (confPaths) {
- for (const auto &dir : utils::split(confPaths, ":")) {
- if (dir.empty())
- continue;
-
- std::string confPath = dir + "/" + ipaName + "/" + name;
- ret = stat(confPath.c_str(), &statbuf);
- if (ret == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG)
- return confPath;
- }
+ for (const auto &dir : configPaths_.value_or(std::vector<std::string>())) {
+ if (dir.empty())
+ continue;
+ std::string confPath = dir + "/" + ipaName + "/" + name;
+ ret = stat(confPath.c_str(), &statbuf);
+ if (ret == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG)
+ return confPath;
}
std::string root = utils::libcameraSourcePath();
@@ -199,18 +202,14 @@ std::string IPAProxy::resolvePath(const std::string &file) const
{
std::string proxyFile = "/" + file;
- /* Check env variable first. */
- const char *execPaths = utils::secure_getenv("LIBCAMERA_IPA_PROXY_PATH");
- if (execPaths) {
- for (const auto &dir : utils::split(execPaths, ":")) {
- if (dir.empty())
- continue;
-
- std::string proxyPath = dir;
- proxyPath += proxyFile;
- if (!access(proxyPath.c_str(), X_OK))
- return proxyPath;
- }
+ /* Check the configuration first. */
+ for (const auto &dir : execPaths_.value_or(std::vector<std::string>())) {
+ if (dir.empty())
+ continue;
+
+ std::string proxyPath = dir + proxyFile;
+ if (!access(proxyPath.c_str(), X_OK))
+ return proxyPath;
}
/*
@@ -45,8 +45,8 @@ namespace {{ns}} {
{% endfor %}
{%- endif %}
-{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate)
- : IPAProxy(ipam), isolate_(isolate),
+{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration)
+ : IPAProxy(ipam, configuration), isolate_(isolate),
controlSerializer_(ControlSerializer::Role::Proxy), seq_(0)
{
LOG(IPAProxy, Debug)
@@ -37,7 +37,7 @@ namespace {{ns}} {
class {{proxy_name}} : public IPAProxy, public {{interface_name}}, public Object
{
public:
- {{proxy_name}}(IPAModule *ipam, bool isolate);
+ {{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration);
~{{proxy_name}}();
{% for method in interface_main.methods %}
This patch adds configuration options for environment variables used in the IPA proxy. Two utility functions configuration retrieval functions are added, to retrieve lists of values. The configuration snippet: configuration: ipa: config_paths: - config path 1 - config path 2 - ... module_paths: - module path 1 - module path 2 - ... proxy_paths: - proxy path 1 - proxy path 2 - ... force_isolation: BOOL LIBCAMERA_<IPA_NAME>_TUNING_FILE remains configurable only via the environment variable; this is supposed to be used only for testing and debugging and it's not clear what to do about IPA names like "rpi/vc4" and "rpi/pisp" exactly. There are two ways to pass the configuration to the places where it is needed: Either to pass it as an argument to the method calls that need it, or to pass it to the class constructors and extract the needed configuration from there. This patch uses the second method as it is less polluting the code. Signed-off-by: Milan Zamazal <mzamazal@redhat.com> --- .../libcamera/internal/global_configuration.h | 21 +++++++- include/libcamera/internal/ipa_manager.h | 7 ++- include/libcamera/internal/ipa_proxy.h | 8 ++- src/libcamera/camera_manager.cpp | 2 +- src/libcamera/global_configuration.cpp | 47 +++++++++++++++-- src/libcamera/ipa_manager.cpp | 39 ++++++++------ src/libcamera/ipa_proxy.cpp | 51 +++++++++---------- .../module_ipa_proxy.cpp.tmpl | 4 +- .../module_ipa_proxy.h.tmpl | 2 +- 9 files changed, 129 insertions(+), 52 deletions(-)