From 1984298aba74b337774e543e55c94397a97b3a58 Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Fri, 10 May 2024 13:18:07 +0100 Subject: [PATCH 1/6] core: Allow dynamic loading of postprocessing stages Instead of having postprocessing stages built directly into rpicam_app.so, allow them to be loaded dynamically at runtime. These .so files will be installed to the //rpicam-apps-postproc/ directory. Signed-off-by: Naushir Patuck --- core/post_processor.cpp | 66 ++++++++++++++++++++++++++++++ core/post_processor.hpp | 19 +++++++++ meson.build | 3 +- post_processing_stages/meson.build | 6 +++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/core/post_processor.cpp b/core/post_processor.cpp index 9c1d36e0..b3cabfff 100644 --- a/core/post_processor.cpp +++ b/core/post_processor.cpp @@ -5,6 +5,8 @@ * post_processor.cpp - Post processor implementation. */ +#include +#include #include #include "core/rpicam_app.hpp" @@ -15,8 +17,72 @@ #include #include +#include "post_processing_stages/postproc_lib.h" + +namespace fs = std::filesystem; + +PostProcessingLib::PostProcessingLib(const std::string &lib) +{ + if (!lib.empty()) + { + lib_ = dlopen(lib.c_str(), RTLD_LAZY); + if (!lib_) + LOG_ERROR("Unable to open " << lib << " with error: " << dlerror()); + } +} + +PostProcessingLib::PostProcessingLib(PostProcessingLib &&other) +{ + lib_ = other.lib_; + symbol_map_ = std::move(other.symbol_map_); + other.lib_ = nullptr; +} + +PostProcessingLib::~PostProcessingLib() +{ + if (lib_) + dlclose(lib_); +} + +const void *PostProcessingLib::GetSymbol(const std::string &symbol) +{ + if (!lib_) + return nullptr; + + std::scoped_lock l(lock_); + + const auto it = symbol_map_.find(symbol); + if (it == symbol_map_.end()) + { + const void *fn = dlsym(lib_, symbol.c_str()); + + if (!fn) + { + LOG_ERROR("Unable to find postprocessing symbol " << symbol << " with error: " << dlerror()); + return nullptr; + } + + symbol_map_[symbol] = fn; + } + + return symbol_map_[symbol]; +} + PostProcessor::PostProcessor(RPiCamApp *app) : app_(app) { + const fs::path path(POSTPROC_LIB_DIR); + const std::string ext(".so"); + + if (!fs::exists(path)) + return; + + // Dynamically load all .so files from the system postprocessing lib path. + // This will automatically register the stages with the factory. + for (auto const &p : fs::recursive_directory_iterator(path)) + { + if (p.path().extension() == ext) + dynamic_stages_.emplace_back(p.path().string()); + } } PostProcessor::~PostProcessor() diff --git a/core/post_processor.hpp b/core/post_processor.hpp index 160b5c75..f7bc395f 100644 --- a/core/post_processor.hpp +++ b/core/post_processor.hpp @@ -29,6 +29,24 @@ using PostProcessorCallback = std::function; using StreamConfiguration = libcamera::StreamConfiguration; typedef std::unique_ptr StagePtr; +// Dynamic postprocessing library helper. +class PostProcessingLib +{ +public: + PostProcessingLib(const std::string &lib); + PostProcessingLib(PostProcessingLib &&other); + PostProcessingLib(const PostProcessingLib &other) = delete; + PostProcessingLib &operator=(const PostProcessingLib &other) = delete; + ~PostProcessingLib(); + + const void *GetSymbol(const std::string &symbol); + +private: + void *lib_ = nullptr; + std::map symbol_map_; + std::mutex lock_; +}; + class PostProcessor { public: @@ -57,6 +75,7 @@ class PostProcessor RPiCamApp *app_; std::vector stages_; + std::vector dynamic_stages_; void outputThread(); std::queue requests_; diff --git a/meson.build b/meson.build index 7140c423..7bc54a45 100644 --- a/meson.build +++ b/meson.build @@ -31,6 +31,7 @@ elif neon == 'armv8-neon' cpp_arguments += ['-mfpu=neon-fp-armv8', '-ftree-vectorize'] endif +dl_dep = dependency('dl', required : true) libcamera_dep = dependency('libcamera', required : true) summary({ @@ -40,7 +41,7 @@ summary({ section : 'libcamera') rpicam_app_src = [] -rpicam_app_dep = [libcamera_dep] +rpicam_app_dep = [libcamera_dep, dl_dep] subdir('core') subdir('encoder') diff --git a/post_processing_stages/meson.build b/post_processing_stages/meson.build index d0af4b35..30496537 100644 --- a/post_processing_stages/meson.build +++ b/post_processing_stages/meson.build @@ -1,3 +1,9 @@ +posproc_libdir = get_option('prefix') / get_option('libdir') / 'rpicam-apps-pp' + +conf_data = configuration_data() +conf_data.set('POSTPROC_LIB_DIR', '"' + posproc_libdir + '"') +configure_file(output : 'postproc_lib.h', configuration : conf_data) + rpicam_app_src += files([ 'hdr_stage.cpp', 'histogram.cpp', From cc1d2d69091ac30a58c77950f6c833f45eba9c7a Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Mon, 13 May 2024 08:49:21 +0100 Subject: [PATCH 2/6] postprocessing: Split existing postproc stages into loadable so files Split the existing postprocessing stages into 3 .so files: - Core stages - OpenCV stages - TFLite stages These are installed into the //rpicam-apps-postproc/ directory. Additionally, switch enable_tflite and enable_opencv meson option types to "feature". Signed-off-by: Naushir Patuck --- .github/workflows/rpicam-apps-test.yml | 2 +- meson.build | 4 +- meson_options.txt | 8 +-- post_processing_stages/meson.build | 80 ++++++++++++++++++-------- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/.github/workflows/rpicam-apps-test.yml b/.github/workflows/rpicam-apps-test.yml index 387ecf8a..79ea6a8a 100644 --- a/.github/workflows/rpicam-apps-test.yml +++ b/.github/workflows/rpicam-apps-test.yml @@ -56,7 +56,7 @@ jobs: clean: true - name: Configure meson - run: meson setup ${{github.workspace}}/build --pkg-config-path=${{env.LIBCAMERA_LKG_DIR}}/lib/aarch64-linux-gnu/pkgconfig/ -Dbuildtype=release -Denable_drm=false -Denable_egl=false -Denable_qt=false -Denable_opencv=false -Denable_tflite=false -Denable_libav=false + run: meson setup ${{github.workspace}}/build --pkg-config-path=${{env.LIBCAMERA_LKG_DIR}}/lib/aarch64-linux-gnu/pkgconfig/ -Dbuildtype=release -Denable_drm=false -Denable_egl=false -Denable_qt=false -Denable_opencv='disabled' -Denable_tflite='disabled' -Denable_libav=false timeout-minutes: 5 - name: Build diff --git a/meson.build b/meson.build index 7bc54a45..7e83f93f 100644 --- a/meson.build +++ b/meson.build @@ -48,11 +48,13 @@ subdir('encoder') subdir('image') subdir('output') subdir('preview') -subdir('post_processing_stages') subdir('utils') add_project_arguments(cpp_arguments, language : 'cpp') +# Must be put after add_project_arguments as it defines shared library targets. +subdir('post_processing_stages') + rpicam_app = library( 'rpicam_app', rpicam_app_src, diff --git a/meson_options.txt b/meson_options.txt index ad0c7aa0..fd60e9d0 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -19,13 +19,13 @@ option('enable_qt', description : 'Enable QT preview window support') option('enable_opencv', - type : 'boolean', - value : true, + type : 'feature', + value : 'disabled', description : 'Enable OpenCV postprocessing support') option('enable_tflite', - type : 'boolean', - value : false, + type : 'feature', + value : 'disabled', description : 'Enable Tensorflow Lite postprocessing support') option('neon_flags', diff --git a/post_processing_stages/meson.build b/post_processing_stages/meson.build index 30496537..df426e01 100644 --- a/post_processing_stages/meson.build +++ b/post_processing_stages/meson.build @@ -1,55 +1,85 @@ -posproc_libdir = get_option('prefix') / get_option('libdir') / 'rpicam-apps-pp' +posproc_libdir = get_option('prefix') / get_option('libdir') / 'rpicam-apps-postproc' conf_data = configuration_data() conf_data.set('POSTPROC_LIB_DIR', '"' + posproc_libdir + '"') configure_file(output : 'postproc_lib.h', configuration : conf_data) +# Core postprocessing framework files. rpicam_app_src += files([ - 'hdr_stage.cpp', 'histogram.cpp', - 'motion_detect_stage.cpp', - 'negate_stage.cpp', 'post_processing_stage.cpp', 'pwl.cpp', ]) -post_processing_headers = files([ - 'histogram.hpp', - 'object_detect.hpp', - 'post_processing_stage.hpp', - 'pwl.hpp', - 'segmentation.hpp', - 'tf_stage.hpp', +# Core postprocessing stages. +core_postproc_src = files([ + 'hdr_stage.cpp', + 'motion_detect_stage.cpp', + 'negate_stage.cpp', ]) -enable_opencv = get_option('enable_opencv') -opencv_dep = dependency('opencv4', required : false) -if enable_opencv and opencv_dep.found() - rpicam_app_src += files([ +core_postproc_lib = shared_module('core-postproc', core_postproc_src, + include_directories : '../..', + dependencies : libcamera_dep, + cpp_args : cpp_arguments, + install : true, + install_dir : posproc_libdir, + name_prefix : '', + ) + +# OpenCV based postprocessing stages. +enable_opencv = false +opencv_dep = dependency('opencv4', required : get_option('enable_opencv')) +if opencv_dep.found() + opencv_postproc_src = files([ 'sobel_cv_stage.cpp', 'face_detect_cv_stage.cpp', 'annotate_cv_stage.cpp', 'plot_pose_cv_stage.cpp', 'object_detect_draw_cv_stage.cpp', ]) - rpicam_app_dep += opencv_dep -else - enable_opencv = false + + opencv_postproc_lib = shared_module('opencv-postproc', opencv_postproc_src, + include_directories : '../..', + dependencies : [libcamera_dep, opencv_dep], + cpp_args : cpp_arguments, + install : true, + install_dir : posproc_libdir, + name_prefix : '', + ) + enable_opencv = true endif -enable_tflite = get_option('enable_tflite') -tflite_dep = dependency('tensorflow-lite', required : false) -if enable_tflite and tflite_dep.found() - rpicam_app_src += files([ +# TFlite based postprocessing stages. +enable_tflite = false +tflite_dep = dependency('tensorflow-lite', required : get_option('enable_tflite')) +if tflite_dep.found() + tflite_postproc_src = files([ 'tf_stage.cpp', 'object_classify_tf_stage.cpp', 'pose_estimation_tf_stage.cpp', 'object_detect_tf_stage.cpp', 'segmentation_tf_stage.cpp', ]) - rpicam_app_dep += tflite_dep -else - enable_tflite = false + + tflite_postproc_lib = shared_module('tflite-postproc', tflite_postproc_src, + include_directories : '../..', + dependencies : [libcamera_dep, tflite_dep], + cpp_args : cpp_arguments, + install : true, + install_dir : posproc_libdir, + name_prefix : '', + ) + enable_tflite = true endif +post_processing_headers = files([ + 'histogram.hpp', + 'object_detect.hpp', + 'post_processing_stage.hpp', + 'pwl.hpp', + 'segmentation.hpp', + 'tf_stage.hpp', +]) + install_headers(post_processing_headers, subdir: meson.project_name() / 'post_processing_stages') From 9158bb2834f936110d60541708833bcca4b33add Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Mon, 13 May 2024 13:36:44 +0100 Subject: [PATCH 3/6] postprocessing: More robust factory handling for postproc stages Ensure we alway have a valid factory map object, even if no stages have been registered. Signed-off-by: Naushir Patuck --- post_processing_stages/post_processing_stage.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/post_processing_stages/post_processing_stage.cpp b/post_processing_stages/post_processing_stage.cpp index 86773f33..3bab5ad8 100644 --- a/post_processing_stages/post_processing_stage.cpp +++ b/post_processing_stages/post_processing_stage.cpp @@ -244,15 +244,18 @@ std::vector PostProcessingStage::Yuv420ToRgb(const uint8_t *src, Stream return output; } -static std::map *stages_ptr; +static std::map &stages() +{ + static std::map stages; + return stages; +} + std::map const &GetPostProcessingStages() { - return *stages_ptr; + return stages(); } RegisterStage::RegisterStage(char const *name, StageCreateFunc create_func) { - static std::map stages; - stages_ptr = &stages; - stages[std::string(name)] = create_func; + stages()[std::string(name)] = create_func; } From 3b37b76541dcc8259432dc0a8159543acfb09fd3 Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Mon, 13 May 2024 14:44:56 +0100 Subject: [PATCH 4/6] options: Add custom postprocessing lib path option Allow the user to set a custom path for the postprocessing library location. This is useful for local builds. Update regression tests to use the build location of the postprocessing libs. Signed-off-by: Naushir Patuck --- .github/workflows/rpicam-apps-test.yml | 2 +- core/options.cpp | 3 +++ core/options.hpp | 1 + core/post_processor.cpp | 18 +++++++++++++----- core/post_processor.hpp | 2 ++ core/rpicam_app.cpp | 3 +++ utils/test.py | 20 ++++++++++++-------- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/.github/workflows/rpicam-apps-test.yml b/.github/workflows/rpicam-apps-test.yml index 79ea6a8a..40aaa0f2 100644 --- a/.github/workflows/rpicam-apps-test.yml +++ b/.github/workflows/rpicam-apps-test.yml @@ -107,7 +107,7 @@ jobs: run: ldd ${{github.workspace}}/build/apps/rpicam-hello | grep libcamera - name: Test - run: ${{github.workspace}}/utils/test.py --exe-dir ${{github.workspace}}/build/apps/ --output-dir ${{github.workspace}}/test_output --json-dir ${{github.workspace}}/assets + run: ${{github.workspace}}/utils/test.py --exe-dir ${{github.workspace}}/build/apps/ --output-dir ${{github.workspace}}/test_output --json-dir ${{github.workspace}}/assets --post-process-libs ${{github.workspace}}/build/post_processing_stages/ timeout-minutes: 8 - name: Upload test output diff --git a/core/options.cpp b/core/options.cpp index 41284b5f..a6ad3668 100644 --- a/core/options.cpp +++ b/core/options.cpp @@ -204,6 +204,8 @@ Options::Options() "Set the output file name") ("post-process-file", value(&post_process_file), "Set the file name for configuring the post-processing") + ("post-process-libs", value(&post_process_libs), + "Set a custom location for the post-processing library .so files") ("nopreview,n", value(&nopreview)->default_value(false)->implicit_value(true), "Do not show a preview window") ("preview,p", value(&preview)->default_value("0,0,0,0"), @@ -631,6 +633,7 @@ void Options::Print() const std::cerr << " height: " << height << std::endl; std::cerr << " output: " << output << std::endl; std::cerr << " post_process_file: " << post_process_file << std::endl; + std::cerr << " post_process_libs: " << post_process_libs << std::endl; if (nopreview) std::cerr << " preview: none" << std::endl; else if (fullscreen) diff --git a/core/options.hpp b/core/options.hpp index 11e09c64..d6b5cb16 100644 --- a/core/options.hpp +++ b/core/options.hpp @@ -114,6 +114,7 @@ struct Options std::string config_file; std::string output; std::string post_process_file; + std::string post_process_libs; unsigned int width; unsigned int height; bool nopreview; diff --git a/core/post_processor.cpp b/core/post_processor.cpp index b3cabfff..936f7cdd 100644 --- a/core/post_processor.cpp +++ b/core/post_processor.cpp @@ -9,6 +9,7 @@ #include #include +#include "core/options.hpp" #include "core/rpicam_app.hpp" #include "core/post_processor.hpp" @@ -70,7 +71,18 @@ const void *PostProcessingLib::GetSymbol(const std::string &symbol) PostProcessor::PostProcessor(RPiCamApp *app) : app_(app) { - const fs::path path(POSTPROC_LIB_DIR); +} + +PostProcessor::~PostProcessor() +{ + // Must clear stages_ before dynamic_stages_ as the latter will unload the necessary symbols. + stages_.clear(); + dynamic_stages_.clear(); +} + +void PostProcessor::LoadModules(const std::string &lib_dir) +{ + const fs::path path(!lib_dir.empty() ? lib_dir : POSTPROC_LIB_DIR); const std::string ext(".so"); if (!fs::exists(path)) @@ -85,10 +97,6 @@ PostProcessor::PostProcessor(RPiCamApp *app) : app_(app) } } -PostProcessor::~PostProcessor() -{ -} - void PostProcessor::Read(std::string const &filename) { boost::property_tree::ptree root; diff --git a/core/post_processor.hpp b/core/post_processor.hpp index f7bc395f..4eb733ca 100644 --- a/core/post_processor.hpp +++ b/core/post_processor.hpp @@ -54,6 +54,8 @@ class PostProcessor ~PostProcessor(); + void LoadModules(const std::string &lib_dir); + void Read(std::string const &filename); void SetCallback(PostProcessorCallback callback); diff --git a/core/rpicam_app.cpp b/core/rpicam_app.cpp index cc0cbb55..959ed465 100644 --- a/core/rpicam_app.cpp +++ b/core/rpicam_app.cpp @@ -158,7 +158,10 @@ void RPiCamApp::OpenCamera() LOG(2, "Acquired camera " << cam_id); if (!options_->post_process_file.empty()) + { + post_processor_.LoadModules(options_->post_process_libs); post_processor_.Read(options_->post_process_file); + } // The queue takes over ownership from the post-processor. post_processor_.SetCallback( [this](CompletedRequestPtr &r) { this->msg_queue_.Post(Msg(MsgType::RequestComplete, std::move(r))); }); diff --git a/utils/test.py b/utils/test.py index 3fc66f08..4706f85b 100755 --- a/utils/test.py +++ b/utils/test.py @@ -543,7 +543,7 @@ def test_raw(exe_dir, output_dir): print("rpicam-raw tests passed") -def test_post_processing(exe_dir, output_dir, json_dir): +def test_post_processing(exe_dir, output_dir, json_dir, postproc_dir): logfile = os.path.join(output_dir, 'log.txt') print("Testing post-processing") clean_dir(output_dir) @@ -554,9 +554,10 @@ def test_post_processing(exe_dir, output_dir, json_dir): check_exists(executable, 'post-processing') json_file = os.path.join(json_dir, 'negate.json') check_exists(json_file, 'post-processing') - retcode, time_taken = run_executable([executable, '-t', '2000', - '--post-process-file', json_file], - logfile) + args = [executable, '-t', '2000', '--post-process-file', json_file] + if postproc_dir: + args += ['--post-process-libs', postproc_dir] + retcode, time_taken = run_executable(args, logfile) check_retcode(retcode, "test_post_processing: negate test") check_time(time_taken, 2, 8, "test_post_processing: negate test") @@ -622,7 +623,7 @@ def test_post_processing(exe_dir, output_dir, json_dir): print("post-processing tests passed") -def test_all(apps, exe_dir, output_dir, json_dir): +def test_all(apps, exe_dir, output_dir, json_dir, postproc_dir): try: if 'hello' in apps: test_hello(exe_dir, output_dir) @@ -635,7 +636,7 @@ def test_all(apps, exe_dir, output_dir, json_dir): if 'raw' in apps: test_raw(exe_dir, output_dir) if 'post-processing' in apps: - test_post_processing(exe_dir, output_dir, json_dir) + test_post_processing(exe_dir, output_dir, json_dir, postproc_dir) print("All tests passed") clean_dir(output_dir) @@ -657,10 +658,13 @@ def test_all(apps, exe_dir, output_dir, json_dir): help='Directory name for output files') parser.add_argument('--json-dir', '-j', action='store', default='.', help='Directory name for JSON post-processing files') + parser.add_argument('--post-process-libs', '-p', action='store', default=None, + help='Directory name custom post-processing libraries') args = parser.parse_args() apps = args.apps.split(',') exe_dir = args.exe_dir.rstrip('/') output_dir = args.output_dir json_dir = args.json_dir - print("Exe_dir:", exe_dir, "Output_dir:", output_dir, "Json_dir:", json_dir) - test_all(apps, exe_dir, output_dir, json_dir) + postproc_dir = args.post_process_libs + print("Exe_dir:", exe_dir, "Output_dir:", output_dir, "Json_dir:", json_dir, "Postproc_dir:", postproc_dir) + test_all(apps, exe_dir, output_dir, json_dir, postproc_dir) From 5f9841611fd792d078ee6358e7ff150b15a81c01 Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Tue, 14 May 2024 09:55:43 +0100 Subject: [PATCH 5/6] postprocessor: Add Yuv420ToRgb override passing a destination pointer Allow the caller to allocate buffers use use for the conversion externally. Signed-off-by: Naushir Patuck --- post_processing_stages/post_processing_stage.cpp | 11 +++++++---- post_processing_stages/post_processing_stage.hpp | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/post_processing_stages/post_processing_stage.cpp b/post_processing_stages/post_processing_stage.cpp index 3bab5ad8..d0014bf4 100644 --- a/post_processing_stages/post_processing_stage.cpp +++ b/post_processing_stages/post_processing_stage.cpp @@ -44,7 +44,12 @@ void PostProcessingStage::Teardown() std::vector PostProcessingStage::Yuv420ToRgb(const uint8_t *src, StreamInfo &src_info, StreamInfo &dst_info) { std::vector output(dst_info.height * dst_info.stride); + Yuv420ToRgb(output.data(), src, src_info, dst_info); + return output; +} +void PostProcessingStage::Yuv420ToRgb(uint8_t *dst, const uint8_t *src, StreamInfo &src_info, StreamInfo &dst_info) +{ assert(src_info.width >= dst_info.width && src_info.height >= dst_info.height); int off_x = ((src_info.width - dst_info.width) / 2) & ~1, off_y = ((src_info.height - dst_info.height) / 2) & ~1; int src_Y_size = src_info.height * src_info.stride, src_U_size = (src_info.height / 2) * (src_info.stride / 2); @@ -59,7 +64,7 @@ std::vector PostProcessingStage::Yuv420ToRgb(const uint8_t *src, Stream const uint8_t *src_U = src + src_Y_size + ((y + off_y) / 2) * (src_info.stride / 2) + off_x / 2; const uint8_t *src_V = src_U + src_U_size; const uint8_t *src_Y1 = src_Y0 + src_info.stride; - uint8_t *dst0 = &output[y * dst_info.stride]; + uint8_t *dst0 = &dst[y * dst_info.stride]; uint8_t *dst1 = dst0 + dst_info.stride; unsigned int x = 0; @@ -213,7 +218,7 @@ std::vector PostProcessingStage::Yuv420ToRgb(const uint8_t *src, Stream const uint8_t *src_Y0 = src + (y + off_y) * src_info.stride + off_x; const uint8_t *src_U = src + src_Y_size + ((y + off_y) / 2) * (src_info.stride / 2) + off_x / 2; const uint8_t *src_V = src_U + src_U_size; - uint8_t *dst0 = &output[y * dst_info.stride]; + uint8_t *dst0 = &dst[y * dst_info.stride]; unsigned int x = 0; for (; x < dst_info.width; x++) @@ -240,8 +245,6 @@ std::vector PostProcessingStage::Yuv420ToRgb(const uint8_t *src, Stream *(dst0++) = B0; } } - - return output; } static std::map &stages() diff --git a/post_processing_stages/post_processing_stage.hpp b/post_processing_stages/post_processing_stage.hpp index 687afbec..e745a491 100644 --- a/post_processing_stages/post_processing_stage.hpp +++ b/post_processing_stages/post_processing_stage.hpp @@ -56,6 +56,7 @@ class PostProcessingStage // Convert YUV420 image to RGB. We crop from the centre of the image if the src // image is larger than the destination. static std::vector Yuv420ToRgb(const uint8_t *src, StreamInfo &src_info, StreamInfo &dst_info); + static void Yuv420ToRgb(uint8_t *dst, const uint8_t *src, StreamInfo &src_info, StreamInfo &dst_info); protected: // Helper to calculate the execution time of any callable object and return it in as a std::chrono::duration. From 0896d1f5a88f0c5778d1b82906929627a2bd7a1f Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Tue, 14 May 2024 13:15:19 +0100 Subject: [PATCH 6/6] build: Use 'feature' type for all meson options. For consistency, use 'feature' types for enable_libav, enable_drm, enable_egl and enable_qt meson options. Signed-off-by: Naushir Patuck --- .github/workflows/rpicam-apps-test.yml | 2 +- encoder/meson.build | 20 ++++++++--------- meson_options.txt | 16 +++++++------- preview/meson.build | 30 +++++++++++--------------- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/.github/workflows/rpicam-apps-test.yml b/.github/workflows/rpicam-apps-test.yml index 40aaa0f2..aff48c99 100644 --- a/.github/workflows/rpicam-apps-test.yml +++ b/.github/workflows/rpicam-apps-test.yml @@ -56,7 +56,7 @@ jobs: clean: true - name: Configure meson - run: meson setup ${{github.workspace}}/build --pkg-config-path=${{env.LIBCAMERA_LKG_DIR}}/lib/aarch64-linux-gnu/pkgconfig/ -Dbuildtype=release -Denable_drm=false -Denable_egl=false -Denable_qt=false -Denable_opencv='disabled' -Denable_tflite='disabled' -Denable_libav=false + run: meson setup ${{github.workspace}}/build --pkg-config-path=${{env.LIBCAMERA_LKG_DIR}}/lib/aarch64-linux-gnu/pkgconfig/ -Dbuildtype=release -Denable_drm='disabled' -Denable_egl='disabled' -Denable_qt='disabled' -Denable_opencv='disabled' -Denable_tflite='disabled' -Denable_libav='disabled' timeout-minutes: 5 - name: Build diff --git a/encoder/meson.build b/encoder/meson.build index b5cea34d..b3c5ce36 100644 --- a/encoder/meson.build +++ b/encoder/meson.build @@ -12,20 +12,18 @@ encoder_headers = files([ 'null_encoder.hpp', ]) -enable_libav = get_option('enable_libav') libav_dep_names = ['libavcodec', 'libavdevice', 'libavformat', 'libavutil', 'libswresample'] libav_deps = [] -if enable_libav - foreach name : libav_dep_names - dep = dependency(name, required : false) - if not dep.found() - enable_libav = false - break - endif - libav_deps += dep - endforeach -endif +enable_libav = true +foreach name : libav_dep_names + dep = dependency(name, required : get_option('enable_libav')) + if not dep.found() + enable_libav = false + break + endif + libav_deps += dep +endforeach if enable_libav rpicam_app_src += files('libav_encoder.cpp') diff --git a/meson_options.txt b/meson_options.txt index fd60e9d0..2a9dd0b7 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,21 +1,21 @@ option('enable_libav', - type : 'boolean', - value : true, + type : 'feature', + value : 'auto', description : 'Enable the libav encoder for video/audio capture') option('enable_drm', - type : 'boolean', - value : true, + type : 'feature', + value : 'auto', description : 'Enable DRM preview window support') option('enable_egl', - type : 'boolean', - value : true, + type : 'feature', + value : 'auto', description : 'Enable EGL preview window support') option('enable_qt', - type : 'boolean', - value : true, + type : 'feature', + value : 'auto', description : 'Enable QT preview window support') option('enable_opencv', diff --git a/preview/meson.build b/preview/meson.build index 420f737c..78f71a72 100644 --- a/preview/meson.build +++ b/preview/meson.build @@ -7,38 +7,34 @@ preview_headers = files([ 'preview.hpp', ]) -enable_drm = get_option('enable_drm') -drm_deps = dependency('libdrm', required : false) +enable_drm = false +drm_deps = dependency('libdrm', required : get_option('enable_drm')) -if enable_drm and drm_deps.found() +if drm_deps.found() rpicam_app_dep += drm_deps rpicam_app_src += files('drm_preview.cpp') cpp_arguments += '-DLIBDRM_PRESENT=1' -else - enable_drm = false + enable_drm = true endif -enable_egl = get_option('enable_egl') -x11_deps = dependency('x11', required : false) -epoxy_deps = dependency('epoxy', required : false) +enable_egl = false +x11_deps = dependency('x11', required : get_option('enable_egl')) +epoxy_deps = dependency('epoxy', required : get_option('enable_egl')) -if enable_egl and x11_deps.found() and epoxy_deps.found() +if x11_deps.found() and epoxy_deps.found() rpicam_app_dep += [x11_deps, epoxy_deps] rpicam_app_src += files('egl_preview.cpp') cpp_arguments += '-DLIBEGL_PRESENT=1' -else - enable_egl = false + enable_egl = true endif -enable_qt = get_option('enable_qt') -qt_dep = dependency('qt5', modules : ['Core', 'Widgets'], required : false) - -if enable_qt and qt_dep.found() +enable_qt = false +qt_dep = dependency('qt5', modules : ['Core', 'Widgets'], required : get_option('enable_qt')) +if qt_dep.found() rpicam_app_dep += qt_dep rpicam_app_src += files('qt_preview.cpp') cpp_arguments += '-DQT_PRESENT=1' -else - enable_qt = false + enable_qt = true endif install_headers(preview_headers, subdir: meson.project_name() / 'preview')