From dbc97942f407f8b1927e7b6d9d8cca7e2afc544d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Wed, 14 Jan 2026 19:46:59 +0100 Subject: [PATCH 1/6] spa: libcamera: manager: simplify property emission There are no conditional properties, so everything can be in the array initializer, which always deduces the size correctly, so do that. --- spa/plugins/libcamera/libcamera-manager.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/spa/plugins/libcamera/libcamera-manager.cpp b/spa/plugins/libcamera/libcamera-manager.cpp index 5c1620571..de59f6fbc 100644 --- a/spa/plugins/libcamera/libcamera-manager.cpp +++ b/spa/plugins/libcamera/libcamera-manager.cpp @@ -118,9 +118,7 @@ void remove_device(struct impl *impl, struct device *device) int emit_object_info(struct impl *impl, const struct device *device) { struct spa_device_object_info info; - struct spa_dict_item items[20]; struct spa_dict dict; - uint32_t n_items = 0; info = SPA_DEVICE_OBJECT_INFO_INIT(); @@ -130,14 +128,14 @@ int emit_object_info(struct impl *impl, const struct device *device) SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; info.flags = 0; -#define ADD_ITEM(key, value) items[n_items++] = SPA_DICT_ITEM_INIT(key, value) - ADD_ITEM(SPA_KEY_DEVICE_ENUM_API,"libcamera.manager"); - ADD_ITEM(SPA_KEY_DEVICE_API, "libcamera"); - ADD_ITEM(SPA_KEY_MEDIA_CLASS, "Video/Device"); - ADD_ITEM(SPA_KEY_API_LIBCAMERA_PATH, device->camera->id().c_str()); -#undef ADD_ITEM + const spa_dict_item items[] = { + { SPA_KEY_DEVICE_ENUM_API, "libcamera.manager" }, + { SPA_KEY_DEVICE_API, "libcamera" }, + { SPA_KEY_MEDIA_CLASS, "Video/Device" }, + { SPA_KEY_API_LIBCAMERA_PATH, device->camera->id().c_str() }, + }; - dict = SPA_DICT_INIT(items, n_items); + dict = SPA_DICT_INIT_ARRAY(items); info.props = &dict; spa_device_emit_object_info(&impl->hooks, impl->id_of(*device), &info); From d46361a1b94103dc3ebdf206c734a437b848e6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Fri, 19 Jun 2026 10:50:32 +0200 Subject: [PATCH 2/6] spa: libcamera: remove some unnecessary includes Also add the missing include guard. --- spa/plugins/libcamera/libcamera.c | 2 -- spa/plugins/libcamera/libcamera.h | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/spa/plugins/libcamera/libcamera.c b/spa/plugins/libcamera/libcamera.c index 207b85735..2fea4ab66 100644 --- a/spa/plugins/libcamera/libcamera.c +++ b/spa/plugins/libcamera/libcamera.c @@ -2,8 +2,6 @@ /* SPDX-FileCopyrightText: Copyright © 2020 collabora */ /* SPDX-License-Identifier: MIT */ -#include - #include #include diff --git a/spa/plugins/libcamera/libcamera.h b/spa/plugins/libcamera/libcamera.h index 7d279819a..29e58a868 100644 --- a/spa/plugins/libcamera/libcamera.h +++ b/spa/plugins/libcamera/libcamera.h @@ -2,12 +2,9 @@ /* SPDX-FileCopyrightText: Copyright © 2020 collabora */ /* SPDX-License-Identifier: MIT */ -#include - -#include +#pragma once #include -#include #ifdef __cplusplus extern "C" { From 390a4ce4325afff1344d102bd7967f1338704284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Fri, 19 Jun 2026 11:00:26 +0200 Subject: [PATCH 3/6] spa: libcamera: compile fully as C++ There was one file "libcamera.c" that was a C source file, which prevents the addition of C++ functions, includes, etc. to "libcamera.h". So compile that file as C++ as well. --- spa/plugins/libcamera/libcamera-device.cpp | 2 +- spa/plugins/libcamera/libcamera-manager.cpp | 2 +- spa/plugins/libcamera/libcamera-source.cpp | 2 +- spa/plugins/libcamera/{libcamera.c => libcamera.cpp} | 6 +++++- spa/plugins/libcamera/{libcamera.h => libcamera.hpp} | 8 ++------ spa/plugins/libcamera/meson.build | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) rename spa/plugins/libcamera/{libcamera.c => libcamera.cpp} (94%) rename spa/plugins/libcamera/{libcamera.h => libcamera.hpp} (87%) diff --git a/spa/plugins/libcamera/libcamera-device.cpp b/spa/plugins/libcamera/libcamera-device.cpp index 6517860fc..f3fc0b4e9 100644 --- a/spa/plugins/libcamera/libcamera-device.cpp +++ b/spa/plugins/libcamera/libcamera-device.cpp @@ -21,7 +21,7 @@ #include #include -#include "libcamera.h" +#include "libcamera.hpp" #include "libcamera-manager.hpp" #include diff --git a/spa/plugins/libcamera/libcamera-manager.cpp b/spa/plugins/libcamera/libcamera-manager.cpp index de59f6fbc..277a680b3 100644 --- a/spa/plugins/libcamera/libcamera-manager.cpp +++ b/spa/plugins/libcamera/libcamera-manager.cpp @@ -25,7 +25,7 @@ using namespace libcamera; #include #include -#include "libcamera.h" +#include "libcamera.hpp" #include "libcamera-manager.hpp" namespace { diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index fba3d8b0b..e4ed7f2ec 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -42,7 +42,7 @@ #include #include -#include "libcamera.h" +#include "libcamera.hpp" #include "libcamera-manager.hpp" using namespace libcamera; diff --git a/spa/plugins/libcamera/libcamera.c b/spa/plugins/libcamera/libcamera.cpp similarity index 94% rename from spa/plugins/libcamera/libcamera.c rename to spa/plugins/libcamera/libcamera.cpp index 2fea4ab66..3ea094e90 100644 --- a/spa/plugins/libcamera/libcamera.c +++ b/spa/plugins/libcamera/libcamera.cpp @@ -5,7 +5,9 @@ #include #include -#include "libcamera.h" +#include "libcamera.hpp" + +extern "C" { SPA_LOG_TOPIC_DEFINE(libcamera_log_topic, "spa.libcamera"); @@ -34,3 +36,5 @@ int spa_handle_factory_enum(const struct spa_handle_factory **factory, (*index)++; return 1; } + +} diff --git a/spa/plugins/libcamera/libcamera.h b/spa/plugins/libcamera/libcamera.hpp similarity index 87% rename from spa/plugins/libcamera/libcamera.h rename to spa/plugins/libcamera/libcamera.hpp index 29e58a868..0d74df21e 100644 --- a/spa/plugins/libcamera/libcamera.h +++ b/spa/plugins/libcamera/libcamera.hpp @@ -6,9 +6,7 @@ #include -#ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ extern const struct spa_handle_factory spa_libcamera_source_factory; extern const struct spa_handle_factory spa_libcamera_manager_factory; @@ -18,11 +16,9 @@ extern const struct spa_handle_factory spa_libcamera_device_factory; #define SPA_LOG_TOPIC_DEFAULT &libcamera_log_topic extern struct spa_log_topic libcamera_log_topic; +} + static inline void libcamera_log_topic_init(struct spa_log *log) { spa_log_topic_init(log, &libcamera_log_topic); } - -#ifdef __cplusplus -} -#endif /* __cplusplus */ diff --git a/spa/plugins/libcamera/meson.build b/spa/plugins/libcamera/meson.build index 9f396aba2..00df52cbb 100644 --- a/spa/plugins/libcamera/meson.build +++ b/spa/plugins/libcamera/meson.build @@ -1,5 +1,5 @@ libcamera_sources = [ - 'libcamera.c', + 'libcamera.cpp', 'libcamera-manager.cpp', 'libcamera-device.cpp', 'libcamera-source.cpp' From 6dc55d2cb41bf4cce940f63541f429bed2408dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Fri, 19 Jun 2026 11:14:51 +0200 Subject: [PATCH 4/6] spa: libcamera: move CameraManager acquisition Now that there is a "libcamera.cpp", move `libcamera_manager_acquire()` into that file since it is a common function used by all three factories. --- spa/plugins/libcamera/libcamera-device.cpp | 1 - spa/plugins/libcamera/libcamera-manager.cpp | 20 ----------------- spa/plugins/libcamera/libcamera-manager.hpp | 9 -------- spa/plugins/libcamera/libcamera-source.cpp | 1 - spa/plugins/libcamera/libcamera.cpp | 24 +++++++++++++++++++++ spa/plugins/libcamera/libcamera.hpp | 6 ++++++ 6 files changed, 30 insertions(+), 31 deletions(-) delete mode 100644 spa/plugins/libcamera/libcamera-manager.hpp diff --git a/spa/plugins/libcamera/libcamera-device.cpp b/spa/plugins/libcamera/libcamera-device.cpp index f3fc0b4e9..ce29671bd 100644 --- a/spa/plugins/libcamera/libcamera-device.cpp +++ b/spa/plugins/libcamera/libcamera-device.cpp @@ -22,7 +22,6 @@ #include #include "libcamera.hpp" -#include "libcamera-manager.hpp" #include #include diff --git a/spa/plugins/libcamera/libcamera-manager.cpp b/spa/plugins/libcamera/libcamera-manager.cpp index 277a680b3..9dc4ce49f 100644 --- a/spa/plugins/libcamera/libcamera-manager.cpp +++ b/spa/plugins/libcamera/libcamera-manager.cpp @@ -26,7 +26,6 @@ using namespace libcamera; #include #include "libcamera.hpp" -#include "libcamera-manager.hpp" namespace { @@ -388,22 +387,3 @@ const struct spa_handle_factory spa_libcamera_manager_factory = { impl_enum_interface_info, }; } - -std::shared_ptr libcamera_manager_acquire(int& res) -{ - static std::weak_ptr global_manager; - static std::mutex lock; - - std::lock_guard guard(lock); - - if (auto manager = global_manager.lock()) - return manager; - - auto manager = std::make_shared(); - if ((res = manager->start()) < 0) - return {}; - - global_manager = manager; - - return manager; -} diff --git a/spa/plugins/libcamera/libcamera-manager.hpp b/spa/plugins/libcamera/libcamera-manager.hpp deleted file mode 100644 index 71ebd6f8d..000000000 --- a/spa/plugins/libcamera/libcamera-manager.hpp +++ /dev/null @@ -1,9 +0,0 @@ -/* Spa libcamera support */ -/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */ -/* SPDX-License-Identifier: MIT */ - -#include - -#include - -std::shared_ptr libcamera_manager_acquire(int& res); diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index e4ed7f2ec..f027f661e 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -43,7 +43,6 @@ #include #include "libcamera.hpp" -#include "libcamera-manager.hpp" using namespace libcamera; diff --git a/spa/plugins/libcamera/libcamera.cpp b/spa/plugins/libcamera/libcamera.cpp index 3ea094e90..93671159a 100644 --- a/spa/plugins/libcamera/libcamera.cpp +++ b/spa/plugins/libcamera/libcamera.cpp @@ -2,6 +2,11 @@ /* SPDX-FileCopyrightText: Copyright © 2020 collabora */ /* SPDX-License-Identifier: MIT */ +#include +#include + +#include + #include #include @@ -38,3 +43,22 @@ int spa_handle_factory_enum(const struct spa_handle_factory **factory, } } + +std::shared_ptr libcamera_manager_acquire(int& res) +{ + static std::weak_ptr global_manager; + static std::mutex lock; + + std::lock_guard guard(lock); + + if (auto manager = global_manager.lock()) + return manager; + + auto manager = std::make_shared(); + if ((res = manager->start()) < 0) + return {}; + + global_manager = manager; + + return manager; +} diff --git a/spa/plugins/libcamera/libcamera.hpp b/spa/plugins/libcamera/libcamera.hpp index 0d74df21e..9b1089182 100644 --- a/spa/plugins/libcamera/libcamera.hpp +++ b/spa/plugins/libcamera/libcamera.hpp @@ -4,6 +4,10 @@ #pragma once +#include + +#include + #include extern "C" { @@ -22,3 +26,5 @@ static inline void libcamera_log_topic_init(struct spa_log *log) { spa_log_topic_init(log, &libcamera_log_topic); } + +std::shared_ptr libcamera_manager_acquire(int& res); From 44176d4118ffd2d3c37fa10a3978492a82200afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sat, 3 Jan 2026 22:34:40 +0100 Subject: [PATCH 5/6] spa: libcamera: expose libcamera version Expose the libcamera header and library versions in the device properties similarly to `api.v4l2.cap.version` used by the v4l2 plugin. The keys are not yet promoted into the public `keys.h` header file. --- spa/plugins/libcamera/libcamera-device.cpp | 4 +++- spa/plugins/libcamera/libcamera-manager.cpp | 2 ++ spa/plugins/libcamera/libcamera-source.cpp | 2 ++ spa/plugins/libcamera/libcamera.hpp | 18 ++++++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/spa/plugins/libcamera/libcamera-device.cpp b/spa/plugins/libcamera/libcamera-device.cpp index ce29671bd..c135b78b1 100644 --- a/spa/plugins/libcamera/libcamera-device.cpp +++ b/spa/plugins/libcamera/libcamera-device.cpp @@ -98,7 +98,7 @@ const char *cameraRot(const Camera& camera) int emit_info(struct impl *impl, bool full) { - struct spa_dict_item items[10]; + struct spa_dict_item items[12]; struct spa_dict dict; uint32_t n_items = 0; struct spa_device_info info; @@ -117,6 +117,8 @@ int emit_info(struct impl *impl, bool full) ADD_ITEM(SPA_KEY_DEVICE_API, "libcamera"); ADD_ITEM(SPA_KEY_MEDIA_CLASS, "Video/Device"); ADD_ITEM(SPA_KEY_API_LIBCAMERA_PATH, impl->device_id.c_str()); + ADD_ITEM(KEY_VERSION_LIBRARY, libcamera_library_version()); + ADD_ITEM(KEY_VERSION_HEADER, libcamera_header_version()); if (auto location = cameraLoc(camera)) ADD_ITEM(SPA_KEY_API_LIBCAMERA_LOCATION, location); diff --git a/spa/plugins/libcamera/libcamera-manager.cpp b/spa/plugins/libcamera/libcamera-manager.cpp index 9dc4ce49f..a2749a3c8 100644 --- a/spa/plugins/libcamera/libcamera-manager.cpp +++ b/spa/plugins/libcamera/libcamera-manager.cpp @@ -132,6 +132,8 @@ int emit_object_info(struct impl *impl, const struct device *device) { SPA_KEY_DEVICE_API, "libcamera" }, { SPA_KEY_MEDIA_CLASS, "Video/Device" }, { SPA_KEY_API_LIBCAMERA_PATH, device->camera->id().c_str() }, + { KEY_VERSION_LIBRARY, libcamera_library_version() }, + { KEY_VERSION_HEADER, libcamera_header_version() }, }; dict = SPA_DICT_INIT_ARRAY(items); diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index f027f661e..ff3376e4f 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -1608,6 +1608,8 @@ void emit_node_info(struct impl *impl, bool full) { SPA_KEY_MEDIA_CLASS, "Video/Source" }, { SPA_KEY_MEDIA_ROLE, "Camera" }, { SPA_KEY_NODE_DRIVER, "true" }, + { KEY_VERSION_LIBRARY, libcamera_library_version() }, + { KEY_VERSION_HEADER, libcamera_header_version() }, }; uint64_t old = full ? impl->info.change_mask : 0; if (full) diff --git a/spa/plugins/libcamera/libcamera.hpp b/spa/plugins/libcamera/libcamera.hpp index 9b1089182..7f21863a7 100644 --- a/spa/plugins/libcamera/libcamera.hpp +++ b/spa/plugins/libcamera/libcamera.hpp @@ -7,8 +7,13 @@ #include #include +#include #include +#include + +#define KEY_VERSION_LIBRARY "api.libcamera.version.library" +#define KEY_VERSION_HEADER "api.libcamera.version.header" extern "C" { @@ -27,4 +32,17 @@ static inline void libcamera_log_topic_init(struct spa_log *log) spa_log_topic_init(log, &libcamera_log_topic); } +static inline const char *libcamera_library_version() +{ + return libcamera::CameraManager::version().c_str(); +} + +static inline const char *libcamera_header_version() +{ + return + SPA_STRINGIFY(LIBCAMERA_VERSION_MAJOR) "." + SPA_STRINGIFY(LIBCAMERA_VERSION_MINOR) "." + SPA_STRINGIFY(LIBCAMERA_VERSION_PATCH); +} + std::shared_ptr libcamera_manager_acquire(int& res); From 559a30b0b475de9fa7ba766ad80805d574e574a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Fri, 19 Jun 2026 11:34:09 +0200 Subject: [PATCH 6/6] spa: libcamera: source: reject buffers with incorrect number of planes `SPA_PARAM_BUFFERS_blocks` is a specific value, the plugin host should not use any other number of data planes, so reject other values. For example, the `buffers[i]->n_datas > planes.size()` situation was not handled correctly, and this removes the need for handling that. --- spa/plugins/libcamera/libcamera-source.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index ff3376e4f..c72860b35 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -1218,8 +1218,8 @@ spa_libcamera_alloc_buffers(struct impl *impl, struct port *port, for (uint32_t i = 0; i < n_buffers; i++) { struct buffer *b; - if (buffers[i]->n_datas < 1) { - spa_log_error(impl->log, "invalid buffer data"); + if (buffers[i]->n_datas != port->buffers_blocks) { + spa_log_error(impl->log, "invalid number of data planes"); return -EINVAL; } @@ -1242,6 +1242,8 @@ spa_libcamera_alloc_buffers(struct impl *impl, struct port *port, const auto& planes = bufs[i]->planes(); spa_data *d = buffers[i]->datas; + spa_assert(buffers[i]->n_datas <= planes.size()); + for(uint32_t j = 0; j < buffers[i]->n_datas; ++j) { const auto memtype = choose_memtype(d[j].type); if (memtype == SPA_DATA_Invalid) { @@ -1257,30 +1259,22 @@ spa_libcamera_alloc_buffers(struct impl *impl, struct port *port, d[j].chunk->stride = port->streamConfig.stride; d[j].chunk->flags = 0; /* Update parameters according to the plane information */ - unsigned int numPlanes = planes.size(); - if (buffers[i]->n_datas < numPlanes) { + if (buffers[i]->n_datas < planes.size()) { if (j < buffers[i]->n_datas - 1) { d[j].maxsize = planes[j].length; d[j].chunk->offset = planes[j].offset; d[j].chunk->size = planes[j].length; } else { d[j].chunk->offset = planes[j].offset; - for (uint8_t k = j; k < numPlanes; k++) { + for (uint8_t k = j; k < planes.size(); k++) { d[j].maxsize += planes[k].length; d[j].chunk->size += planes[k].length; } } - } else if (buffers[i]->n_datas == numPlanes) { + } else { d[j].maxsize = planes[j].length; d[j].chunk->offset = planes[j].offset; d[j].chunk->size = planes[j].length; - } else { - spa_log_warn(impl->log, "buffer index: i: %d, data member " - "numbers: %d is greater than plane number: %d", - i, buffers[i]->n_datas, numPlanes); - d[j].maxsize = port->streamConfig.frameSize; - d[j].chunk->offset = 0; - d[j].chunk->size = port->streamConfig.frameSize; } switch (memtype) {