From patchwork Thu Jun 26 09:59:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 23659 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 409F3BDCBF for ; Thu, 26 Jun 2025 10:00:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B5E1A68DFC; Thu, 26 Jun 2025 12:00:19 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="SexQ9c3c"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 83D2168DFA for ; Thu, 26 Jun 2025 12:00:16 +0200 (CEST) Received: from neptunite.hamster-moth.ts.net (unknown [IPv6:2404:7a81:160:2100:258b:9e43:6dff:c39d]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1C868743; Thu, 26 Jun 2025 11:59:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1750931997; bh=wdTd5agQtsooTqocV7IfsdTtA7ZRA3j7uAHsNRLtngs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SexQ9c3cZ32d14VjcBVyPKv8yubeyLEjRv9e+01taaiwyXITcyfZeZbtThP19z3Bf rwnfW+/ChuGbJIB5lXmkDs93ApXLq00jyDGhnFnFbBu4x6quD0nK+4FJLpNHmiSwQo dEe8Exjx0V5sizvdteEg6WC67RuiUD2vAHe1n+Vs= From: Paul Elder To: libcamera-devel@lists.libcamera.org Cc: Paul Elder , kieran.bingham@ideasonboard.com Subject: [RFC PATCH 1/7] libcamera: ipa_manager: Factor out .so file searching Date: Thu, 26 Jun 2025 18:59:36 +0900 Message-ID: <20250626095944.1746345-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250626095944.1746345-1-paul.elder@ideasonboard.com> References: <20250626095944.1746345-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In the near future we will add support for layers/shoes on top of libcamera, which will need to search for shared object files similar to how IPAManager does. To avoid code duplication, move this code out of IPAManager into internal utils. Signed-off-by: Paul Elder --- include/libcamera/internal/ipa_manager.h | 4 - include/libcamera/internal/meson.build | 1 + include/libcamera/internal/utils.h | 26 ++++++ src/libcamera/ipa_manager.cpp | 108 ++++------------------- src/libcamera/meson.build | 1 + src/libcamera/utils.cpp | 107 ++++++++++++++++++++++ 6 files changed, 154 insertions(+), 93 deletions(-) create mode 100644 include/libcamera/internal/utils.h create mode 100644 src/libcamera/utils.cpp diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h index a0d448cf9862..6b0ba4b5477f 100644 --- a/include/libcamera/internal/ipa_manager.h +++ b/include/libcamera/internal/ipa_manager.h @@ -59,10 +59,6 @@ public: #endif private: - void parseDir(const char *libDir, unsigned int maxDepth, - std::vector &files); - unsigned int addDir(const char *libDir, unsigned int maxDepth = 0); - IPAModule *module(PipelineHandler *pipe, uint32_t minVersion, uint32_t maxVersion); diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 5c80a28c4cbe..690f5c5ec9f6 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -41,6 +41,7 @@ libcamera_internal_headers = files([ 'shared_mem_object.h', 'source_paths.h', 'sysfs.h', + 'utils.h', 'v4l2_device.h', 'v4l2_pixelformat.h', 'v4l2_subdevice.h', diff --git a/include/libcamera/internal/utils.h b/include/libcamera/internal/utils.h new file mode 100644 index 000000000000..742657bebb28 --- /dev/null +++ b/include/libcamera/internal/utils.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * Miscellaneous utility functions + */ + +#pragma once + +#include +#include +#include + +namespace libcamera { + +namespace utils { + +void parseDir(const char *libDir, unsigned int maxDepth, + std::vector &files); + +unsigned int addDir(const char *libDir, unsigned int maxDepth, + std::function func); + +} /* namespace utils */ + +} /* namespace libcamera */ diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 830750dcc0fb..ecad4845a077 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -8,9 +8,8 @@ #include "libcamera/internal/ipa_manager.h" #include -#include +#include #include -#include #include #include @@ -19,6 +18,7 @@ #include "libcamera/internal/ipa_module.h" #include "libcamera/internal/ipa_proxy.h" #include "libcamera/internal/pipeline_handler.h" +#include "libcamera/internal/utils.h" /** * \file ipa_manager.h @@ -110,6 +110,20 @@ IPAManager::IPAManager() unsigned int ipaCount = 0; + auto &modules = modules_; + std::function addDirHandler = + [&modules](const std::string &file) { + auto ipaModule = std::make_unique(file); + if (!ipaModule->isValid()) + return 0; + + LOG(IPAManager, Debug) << "Loaded IPA module '" << file << "'"; + + modules.push_back(std::move(ipaModule)); + + return 1; + }; + /* User-specified paths take precedence. */ const char *modulePaths = utils::secure_getenv("LIBCAMERA_IPA_MODULE_PATH"); if (modulePaths) { @@ -117,7 +131,7 @@ IPAManager::IPAManager() if (dir.empty()) continue; - ipaCount += addDir(dir.c_str()); + ipaCount += utils::addDir(dir.c_str(), 0, addDirHandler); } if (!ipaCount) @@ -138,11 +152,11 @@ IPAManager::IPAManager() << "libcamera is not installed. Adding '" << ipaBuildPath << "' to the IPA search path"; - ipaCount += addDir(ipaBuildPath.c_str(), maxDepth); + ipaCount += utils::addDir(ipaBuildPath.c_str(), maxDepth, addDirHandler); } /* Finally try to load IPAs from the installed system path. */ - ipaCount += addDir(IPA_MODULE_DIR); + ipaCount += utils::addDir(IPA_MODULE_DIR, 0, addDirHandler); if (!ipaCount) LOG(IPAManager, Warning) @@ -151,90 +165,6 @@ IPAManager::IPAManager() IPAManager::~IPAManager() = default; -/** - * \brief Identify shared library objects within a directory - * \param[in] libDir The directory to search for shared objects - * \param[in] maxDepth The maximum depth of sub-directories to parse - * \param[out] files A vector of paths to shared object library files - * - * Search a directory for .so files, allowing recursion down to sub-directories - * no further than the depth specified by \a maxDepth. - * - * Discovered shared objects are added to the \a files vector. - */ -void IPAManager::parseDir(const char *libDir, unsigned int maxDepth, - std::vector &files) -{ - struct dirent *ent; - DIR *dir; - - dir = opendir(libDir); - if (!dir) - return; - - while ((ent = readdir(dir)) != nullptr) { - if (ent->d_type == DT_DIR && maxDepth) { - if (strcmp(ent->d_name, ".") == 0 || - strcmp(ent->d_name, "..") == 0) - continue; - - std::string subdir = std::string(libDir) + "/" + ent->d_name; - - /* Recursion is limited to maxDepth. */ - parseDir(subdir.c_str(), maxDepth - 1, files); - - continue; - } - - int offset = strlen(ent->d_name) - 3; - if (offset < 0) - continue; - if (strcmp(&ent->d_name[offset], ".so")) - continue; - - files.push_back(std::string(libDir) + "/" + ent->d_name); - } - - closedir(dir); -} - -/** - * \brief Load IPA modules from a directory - * \param[in] libDir The directory to search for IPA modules - * \param[in] maxDepth The maximum depth of sub-directories to search - * - * This function tries to create an IPAModule instance for every shared object - * found in \a libDir, and skips invalid IPA modules. - * - * Sub-directories are searched up to a depth of \a maxDepth. A \a maxDepth - * value of 0 only searches the directory specified in \a libDir. - * - * \return Number of modules loaded by this call - */ -unsigned int IPAManager::addDir(const char *libDir, unsigned int maxDepth) -{ - std::vector files; - - parseDir(libDir, maxDepth, files); - - /* Ensure a stable ordering of modules. */ - std::sort(files.begin(), files.end()); - - unsigned int count = 0; - for (const std::string &file : files) { - auto ipaModule = std::make_unique(file); - if (!ipaModule->isValid()) - continue; - - LOG(IPAManager, Debug) << "Loaded IPA module '" << file << "'"; - - modules_.push_back(std::move(ipaModule)); - count++; - } - - return count; -} - /** * \brief Retrieve an IPA module that matches a given pipeline handler * \param[in] pipe The pipeline handler diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 28a3b0f36d53..8e2aa921a620 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -51,6 +51,7 @@ libcamera_internal_sources = files([ 'shared_mem_object.cpp', 'source_paths.cpp', 'sysfs.cpp', + 'utils.cpp', 'v4l2_device.cpp', 'v4l2_pixelformat.cpp', 'v4l2_subdevice.cpp', diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp new file mode 100644 index 000000000000..ef046ac3134e --- /dev/null +++ b/src/libcamera/utils.cpp @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * Miscellaneous utility functions (internal) + */ + +#include "libcamera/internal/utils.h" + +#include +#include +#include +#include +#include +#include +#include + +/** + * \file internal/utils.h + * \brief Miscellaneous utility functions (internal) + */ + +namespace libcamera { + +namespace utils { + +/** + * \brief Identify shared library objects within a directory + * \param[in] libDir The directory to search for shared objects + * \param[in] maxDepth The maximum depth of sub-directories to parse + * \param[out] files A vector of paths to shared object library files + * + * Search a directory for .so files, allowing recursion down to sub-directories + * no further than the depth specified by \a maxDepth. + * + * Discovered shared objects are added to the \a files vector. + */ +void parseDir(const char *libDir, unsigned int maxDepth, + std::vector &files) +{ + struct dirent *ent; + DIR *dir; + + dir = opendir(libDir); + if (!dir) + return; + + while ((ent = readdir(dir)) != nullptr) { + if (ent->d_type == DT_DIR && maxDepth) { + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) + continue; + + std::string subdir = std::string(libDir) + "/" + ent->d_name; + + /* Recursion is limited to maxDepth. */ + parseDir(subdir.c_str(), maxDepth - 1, files); + + continue; + } + + int offset = strlen(ent->d_name) - 3; + if (offset < 0) + continue; + if (strcmp(&ent->d_name[offset], ".so")) + continue; + + files.push_back(std::string(libDir) + "/" + ent->d_name); + } + + closedir(dir); +} + +/** + * \brief Execute some function on shared object files from a directory + * \param[in] libDir The directory to search for shared objects + * \param[in] maxDepth The maximum depth of sub-directories to search + * \param[in] func The function to execute on every shared object + * + * This function tries to execute the given function \a func for every shared + * object found in \a libDir. + * + * Sub-directories are searched up to a depth of \a maxDepth. A \a maxDepth + * value of 0 only searches the directory specified in \a libDir. + * + * \return Number of shared objects loaded by this call + */ +unsigned int addDir(const char *libDir, unsigned int maxDepth, + std::function func) +{ + std::vector files; + + parseDir(libDir, maxDepth, files); + + /* Ensure a stable ordering of modules. */ + std::sort(files.begin(), files.end()); + + unsigned int count = 0; + for (const std::string &file : files) + count += func(file); + + return count; +} + +} /* namespace utils */ + +} /* namespace libcamera */