diff options
author | Jacopo Mondi <jacopo.mondi@ideasonboard.com> | 2025-02-17 17:31:14 +0100 |
---|---|---|
committer | Jacopo Mondi <jacopo.mondi@ideasonboard.com> | 2025-02-21 18:13:24 +0100 |
commit | c05950646ac5e4f9ec128b5535d8266451c69073 (patch) | |
tree | c48f4150b8e3435509fb8e7ee8b7d10116dea55e | |
parent | 9834402f81bb1fc597b0b9dcdf7cdceda09083b4 (diff) |
HACK: play with C ABI
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
-rw-r--r-- | include/libcamera/camera_manager.h | 2 | ||||
-rw-r--r-- | include/libcamera_c/camera_c.h | 61 | ||||
-rw-r--r-- | include/libcamera_c/camera_manager_c.h | 52 | ||||
-rw-r--r-- | include/libcamera_c/meson.build | 12 | ||||
-rw-r--r-- | include/libcamera_c/request_c.h | 25 | ||||
-rw-r--r-- | include/meson.build | 1 | ||||
-rw-r--r-- | src/apps/c_apps/c_main.c | 130 | ||||
-rw-r--r-- | src/apps/c_apps/meson.build | 8 | ||||
-rw-r--r-- | src/apps/meson.build | 2 | ||||
-rw-r--r-- | src/libcamera/camera_manager.cpp | 2 | ||||
-rw-r--r-- | src/libcamera_c/camera_c.cpp | 69 | ||||
-rw-r--r-- | src/libcamera_c/camera_manager_c.cpp | 114 | ||||
-rw-r--r-- | src/libcamera_c/meson.build | 30 | ||||
-rw-r--r-- | src/libcamera_c/request_c.cpp | 8 | ||||
-rw-r--r-- | src/meson.build | 1 |
15 files changed, 515 insertions, 2 deletions
diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h index b50df782..be05d692 100644 --- a/include/libcamera/camera_manager.h +++ b/include/libcamera/camera_manager.h @@ -30,7 +30,7 @@ public: int start(); void stop(); - std::vector<std::shared_ptr<Camera>> cameras() const; + const std::vector<std::shared_ptr<Camera>> &cameras() const; std::shared_ptr<Camera> get(const std::string &id); static const std::string &version() { return version_; } diff --git a/include/libcamera_c/camera_c.h b/include/libcamera_c/camera_c.h new file mode 100644 index 00000000..74c5fbea --- /dev/null +++ b/include/libcamera_c/camera_c.h @@ -0,0 +1,61 @@ +#pragma once + +#include "request_c.h" + +enum stream_roles { + RAW, + STILL_CAPTURE, + VIDEO_RECORDING, + VIEWFINDER, +}; + +#ifdef __cplusplus +#include <memory> + +#include <libcamera.h> + +typedef std::unique_ptr<libcamera::CameraConfiguration> camera_configuration_t; +typedef libcamera::Camera * camera_t; +typedef std::shared_ptr<libcamera::Camera> managed_camera_t; + +extern "C" { + +#else /* __cplusplus */ +#include <stddef.h> + +typedef struct camera_configuration { +#define LIBCAMERA_UNIQUE_PTR 8 + char padding[LIBCAMERA_UNIQUE_PTR]; +} camera_configuration_t; + +/* pointer to Camera */ +typedef void * camera_t; + +/* Camera wrapped in a shared_ptr*/ +struct managed_camera { +#define LIBCAMERA_SHARED_PTR 16 + char padding[LIBCAMERA_SHARED_PTR]; +}; +typedef struct managed_camera managed_camera_t; +#endif + +const char *camera_id(camera_t); +const char *shared_ptr_camera_id(const managed_camera_t *); + +void camera_put(managed_camera_t *); + +void camera_generate_configuration(managed_camera_t *, enum stream_roles *, + size_t, camera_configuration_t *); + +void camera_drop_configuration(camera_configuration_t *); + +void camera_acquire(managed_camera_t *); +void camera_release(managed_camera_t *); + +void camera_configure(managed_camera_t *, camera_configuration_t *); + +void camera_create_request(managed_camera_t *, request_t *); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */
\ No newline at end of file diff --git a/include/libcamera_c/camera_manager_c.h b/include/libcamera_c/camera_manager_c.h new file mode 100644 index 00000000..7c91f0dd --- /dev/null +++ b/include/libcamera_c/camera_manager_c.h @@ -0,0 +1,52 @@ +# pragma once + +#include "camera_c.h" + +typedef void (*camera_manager_list_camera_cbk)(camera_t camera); + +#ifdef __cplusplus + +#include <cstddef> + +typedef struct camera_manager camera_manager_t; + +extern "C" { +#else +struct camera_manager { + void *manager_; +}; +typedef struct camera_manager camera_manager_t; + +#endif /* __cplusplus */ + +/* CameraManager */ +camera_manager_t *camera_manager_create(); +void camera_manager_delete(camera_manager_t *); +int camera_manager_start(camera_manager_t *); +void camera_manager_stop(camera_manager_t *); + +/* CameraManager::cameras() */ +size_t camera_manager_num_cameras(camera_manager_t *); + +/* callback */ +void camera_manager_list_cameras_with_cbk(camera_manager_t *, + camera_manager_list_camera_cbk); + +/* list view */ +size_t camera_manager_list_cameras_view(camera_manager_t *, + const managed_camera_t **); + +/* Reference counted copies */ +void camera_manager_camera_list_grab(camera_manager_t *, + managed_camera_t *); +void camera_manager_camera_list_drop(managed_camera_t *, size_t); + +/* Raw pointers copies */ +void camera_manager_camera_list_borrow(camera_manager_t *, camera_t *); + +void camera_manager_get_camera(camera_manager_t *, const char *, + managed_camera_t *camera); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */
\ No newline at end of file diff --git a/include/libcamera_c/meson.build b/include/libcamera_c/meson.build new file mode 100644 index 00000000..e71caa41 --- /dev/null +++ b/include/libcamera_c/meson.build @@ -0,0 +1,12 @@ + +libcamera_c_include_dir = 'libcamera' / 'libcamera_c' + +libcamera_c_includes = include_directories('.') + +libcamera_c_headers = files([ + 'camera_c.h', + 'camera_manager_c.h' +]) + +install_headers(libcamera_c_headers, + subdir : libcamera_c_include_dir)
\ No newline at end of file diff --git a/include/libcamera_c/request_c.h b/include/libcamera_c/request_c.h new file mode 100644 index 00000000..0b114563 --- /dev/null +++ b/include/libcamera_c/request_c.h @@ -0,0 +1,25 @@ +#pragma once + +#ifdef __cplusplus +#include <memory> + +#include <libcamera.h> + +typedef std::unique_ptr<libcamera::Request> request_t; + +extern "C" { + +#else /* __cplusplus */ + +/* Request wrapped in a unique_ptr */ +typedef struct request { +#define LIBCAMERA_UNIQUE_PTR 8 + char padding[LIBCAMERA_UNIQUE_PTR]; +} request_t; +#endif + +void request_drop(request_t *); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */
\ No newline at end of file diff --git a/include/meson.build b/include/meson.build index 19b93a7b..06e83e84 100644 --- a/include/meson.build +++ b/include/meson.build @@ -4,3 +4,4 @@ include_build_dir = meson.current_build_dir() subdir('android') subdir('libcamera') +subdir('libcamera_c') diff --git a/src/apps/c_apps/c_main.c b/src/apps/c_apps/c_main.c new file mode 100644 index 00000000..a44c3d50 --- /dev/null +++ b/src/apps/c_apps/c_main.c @@ -0,0 +1,130 @@ +#include "camera_c.h" +#include "camera_manager_c.h" +#include "request_c.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +[[maybe_unused]] +static void list_camera_cbk(camera_t camera) +{ + printf("Camera name: %s\n", camera_id(camera)); +} + +static void managed_camera_cleanup(managed_camera_t **cameras) +{ + if (!*cameras) + return; + + camera_manager_camera_list_drop(*cameras, 2); + free(*cameras); +} + +int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[]) +{ + camera_manager_t *mngr = camera_manager_create(); + camera_manager_start(mngr); + + printf(" === Unwrap the camera list with callbacks === \n"); + + /* + * Inspect the camera list with callbacks. + + * No memory transfer, the callback has access to members one by one + */ + camera_manager_list_cameras_with_cbk(mngr, list_camera_cbk); + printf("\n"); + + printf(" === View the camera list memory (doesn't work) === \n"); + /* + * View the libcamera::CameraManager::cameras() memory. + * + * This doesn't work and segfaults as CameraManager::cameras() return a new vector instance + * instead of refrencing to its owned copy. + */ + { + const managed_camera_t *cameras; + size_t num_cameras = camera_manager_list_cameras_view(mngr, + &cameras); + + for (size_t i = 0; i < num_cameras; ++i) { + printf("Camera name: %s\n", " nope.. ");//shared_ptr_camera_id(cameras[i])); + } + } + printf("\n"); + + printf(" === Get a list of cameras increasing the ref count (grab) === \n"); + /* + * Borrow the shared_ptr into memory owned by application and increase the reference count + * + * We need to explicitly drop references and release memory + */ + char camera_name[100]; + { + size_t num_cameras = camera_manager_num_cameras(mngr); + + __attribute__((cleanup(managed_camera_cleanup))) + managed_camera_t *cameras = (managed_camera_t *)calloc(num_cameras, + sizeof(*cameras)); + + camera_manager_camera_list_grab(mngr, cameras); + + for (size_t i = 0; i < num_cameras; ++i) { + printf("Camera name: %s\n", shared_ptr_camera_id(&cameras[i])); + } + + const char *name = shared_ptr_camera_id(&cameras[0]); + memcpy(camera_name, name, strlen(name)); + } + printf("\n"); + + printf(" === Get a list of raw camera references (borrow) === \n"); + /* + * Copy the raw Camera pointers in application's memory. + * + * No reference handling needed, but memory has to be released + */ + { + size_t num_cameras = camera_manager_num_cameras(mngr); + camera_t *cameras = (camera_t *)calloc(num_cameras, + sizeof(*cameras)); + + camera_manager_camera_list_borrow(mngr, cameras); + for (size_t i = 0; i < num_cameras; ++i) { + printf("Camera name: %s\n", camera_id(cameras[i])); + } + + free(cameras); + + } + + managed_camera_t camera = {}; + printf("Camera name: %s\n", camera_name); + camera_manager_get_camera(mngr, camera_name, &camera); + + camera_configuration_t config = {}; + enum stream_roles roles[] = { VIEWFINDER }; + camera_generate_configuration(&camera, roles, 1, &config); + + camera_acquire(&camera); + camera_configure(&camera, &config); + + request_t requests[8] = {}; + + for (size_t i = 0; i < 8; ++i) { + camera_create_request(&camera, &requests[i]); + } + + /* Cleanup */ + for (size_t i = 0; i < 8; ++i) + request_drop(&requests[i]); + camera_drop_configuration(&config); + camera_release(&camera); + camera_put(&camera); + + camera_manager_stop(mngr); + camera_manager_delete(mngr); + + return 0; +}
\ No newline at end of file diff --git a/src/apps/c_apps/meson.build b/src/apps/c_apps/meson.build new file mode 100644 index 00000000..c5b0b3b9 --- /dev/null +++ b/src/apps/c_apps/meson.build @@ -0,0 +1,8 @@ + +c_cam_sources = files([ + 'c_main.c', +]) + +c_cam = executable('c_cam', c_cam_sources, + link_with : libcamera_c_abi, + dependencies : libcamera_c) diff --git a/src/apps/meson.build b/src/apps/meson.build index af632b9a..4b0b1598 100644 --- a/src/apps/meson.build +++ b/src/apps/meson.build @@ -12,6 +12,8 @@ endif libtiff = dependency('libtiff-4', required : false) +subdir('c_apps') + subdir('common') subdir('lc-compliance') diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 87e6717e..38671d2b 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -362,7 +362,7 @@ void CameraManager::stop() * * \return List of all available cameras */ -std::vector<std::shared_ptr<Camera>> CameraManager::cameras() const +const std::vector<std::shared_ptr<Camera>> &CameraManager::cameras() const { const Private *const d = _d(); diff --git a/src/libcamera_c/camera_c.cpp b/src/libcamera_c/camera_c.cpp new file mode 100644 index 00000000..eb95937e --- /dev/null +++ b/src/libcamera_c/camera_c.cpp @@ -0,0 +1,69 @@ +#include <camera_c.h> +#include "libcamera/stream.h" + +using namespace libcamera; + +const char *camera_id(camera_t camera) +{ + Camera *c = (Camera *)camera; + + return c->id().c_str(); +} + +const char *shared_ptr_camera_id(const managed_camera_t *shrd) +{ + Camera *c = (*shrd).get(); + + return c->id().c_str(); +} + +void camera_put(managed_camera_t *shrd) +{ + (*shrd).reset(); +} + +void camera_generate_configuration(managed_camera_t *shrd, enum stream_roles *c_roles, + size_t num_roles, camera_configuration_t *config) +{ + Span<StreamRole> roles = Span<StreamRole>((StreamRole *)c_roles, num_roles); + Camera *c = (*shrd).get(); + + using namespace std; + cout << "usage count: " << shrd->use_count() << endl; + cout << "sizeof unique: " << sizeof(*config) << endl; + + *config = c->generateConfiguration(roles); +} + +void camera_drop_configuration(camera_configuration_t *config) +{ + (*config).reset(); +} + +void camera_acquire(managed_camera_t *shrd) +{ + Camera *c = (*shrd).get(); + + c->acquire(); +} + +void camera_release(managed_camera_t *shrd) +{ + Camera *c = (*shrd).get(); + + c->release(); +} + +void camera_configure(managed_camera_t *shrd, camera_configuration_t *config) +{ + Camera *c = (*shrd).get(); + + c->configure((*config).get()); +} + +void camera_create_request(managed_camera_t *shrd, request_t *request) +{ + Camera *c = (*shrd).get(); + + (*request) = c->createRequest(); +}
\ No newline at end of file diff --git a/src/libcamera_c/camera_manager_c.cpp b/src/libcamera_c/camera_manager_c.cpp new file mode 100644 index 00000000..ee7ea41e --- /dev/null +++ b/src/libcamera_c/camera_manager_c.cpp @@ -0,0 +1,114 @@ +#include "camera_manager_c.h" + +#include "camera_c.h" + +#include <libcamera.h> + +using namespace libcamera; + +camera_manager_t *camera_manager_create() +{ + return (camera_manager_t *)new CameraManager(); +} + +void camera_manager_delete(camera_manager_t *mngr) +{ + CameraManager *manager = (CameraManager *)mngr; + delete manager; +} + +int camera_manager_start(camera_manager_t *mngr) +{ + CameraManager *manager = (CameraManager *)mngr; + + return manager->start(); +} + +void camera_manager_stop(camera_manager_t *mngr) +{ + CameraManager *manager = (CameraManager *)mngr; + + manager->stop(); +} + +size_t camera_manager_num_cameras(camera_manager_t *mngr) +{ + CameraManager *manager = (CameraManager *)mngr; + + return manager->cameras().size(); +} + +void camera_manager_list_cameras_with_cbk(camera_manager_t *mngr, + camera_manager_list_camera_cbk cbk) +{ + CameraManager *manager = (CameraManager *)mngr; + + /* Unroll the std::vector<SharedPtr<Camera>> by calling cbk for each element. */ + auto &&cameras = manager->cameras(); + for (auto const &camera : cameras) { + cbk((camera_t)camera.get()); + } +} + +size_t camera_manager_list_cameras_view(camera_manager_t *mngr, + const managed_camera_t **cameras) +{ + CameraManager *manager = (CameraManager *)mngr; + + /* b0rken! manager->cameras() is temporary */ + (*cameras) = manager->cameras().data(); + return manager->cameras().size(); +} + +void camera_manager_camera_list_grab(camera_manager_t *mngr, + managed_camera_t *cameras) +{ + CameraManager *manager = (CameraManager *)mngr; + + auto &&camera_list = manager->cameras(); + + size_t i = 0; + for (auto &camera : camera_list) { + std::cout << "Use count: " << camera.use_count() << std::endl; + cameras[i++] = camera; + std::cout << "Use count: " << camera.use_count() << std::endl; + std::cout << "Use count: " << cameras[i-1].use_count() << std::endl; + } +} + +void camera_manager_camera_list_drop(managed_camera_t *cameras, + size_t num_cameras) +{ + for (size_t i = 0; i < num_cameras; ++i) { + auto &camera = cameras[i]; + + std::cout << "Use count: " << camera.use_count() << std::endl; + + /* Drop reference count */ + camera.reset(); + } +} + +void camera_manager_camera_list_borrow(camera_manager_t *mngr, + camera_t *cameras) +{ + CameraManager *manager = (CameraManager *)mngr; + + auto &&camera_list = manager->cameras(); + size_t i = 0; + for (auto const &camera : camera_list) { + cameras[i++] = (camera_t)camera.get(); + } +} + +void camera_manager_get_camera(camera_manager_t *mngr, const char *id, + managed_camera_t *camera) +{ + CameraManager *manager = (CameraManager *)mngr; + + using namespace std; + cout << "get camera: " << id << endl; + *camera = manager->get(std::string(id)); + if (!(*camera)) + cout << "ARGH!" << endl; +}
\ No newline at end of file diff --git a/src/libcamera_c/meson.build b/src/libcamera_c/meson.build new file mode 100644 index 00000000..4e063410 --- /dev/null +++ b/src/libcamera_c/meson.build @@ -0,0 +1,30 @@ + +c_includes = [ + libcamera_includes, + libcamera_c_includes, +] + +libcamera_c_sources = files([ + 'camera_c.cpp', + 'camera_manager_c.cpp', + 'request_c.cpp', +]) + +libcamera_c_deps = [ + libcamera_public, +] + +libcamera_c_abi = shared_library('libcamera_c', + [ + libcamera_c_sources, + ], + include_directories : c_includes, + dependencies : libcamera_c_deps) + + +libcamera_c = declare_dependency(sources : [ + libcamera_c_headers, + ], + include_directories : libcamera_c_includes, + dependencies : libcamera_public, + link_with : libcamera_c_abi) diff --git a/src/libcamera_c/request_c.cpp b/src/libcamera_c/request_c.cpp new file mode 100644 index 00000000..3fdf52d9 --- /dev/null +++ b/src/libcamera_c/request_c.cpp @@ -0,0 +1,8 @@ +#include "request_c.h" + +using namespace libcamera; + +void request_drop(request_t *request) +{ + (*request).reset(); +}
\ No newline at end of file diff --git a/src/meson.build b/src/meson.build index 76198e95..4d14ac00 100644 --- a/src/meson.build +++ b/src/meson.build @@ -50,6 +50,7 @@ endif # libcamera must be built first as a dependency to the other components. subdir('libcamera') +subdir('libcamera_c') subdir('android') subdir('ipa') |