summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacopo Mondi <jacopo.mondi@ideasonboard.com>2025-02-17 17:31:14 +0100
committerJacopo Mondi <jacopo.mondi@ideasonboard.com>2025-02-21 18:13:24 +0100
commitc05950646ac5e4f9ec128b5535d8266451c69073 (patch)
treec48f4150b8e3435509fb8e7ee8b7d10116dea55e
parent9834402f81bb1fc597b0b9dcdf7cdceda09083b4 (diff)
HACK: play with C ABI
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
-rw-r--r--include/libcamera/camera_manager.h2
-rw-r--r--include/libcamera_c/camera_c.h61
-rw-r--r--include/libcamera_c/camera_manager_c.h52
-rw-r--r--include/libcamera_c/meson.build12
-rw-r--r--include/libcamera_c/request_c.h25
-rw-r--r--include/meson.build1
-rw-r--r--src/apps/c_apps/c_main.c130
-rw-r--r--src/apps/c_apps/meson.build8
-rw-r--r--src/apps/meson.build2
-rw-r--r--src/libcamera/camera_manager.cpp2
-rw-r--r--src/libcamera_c/camera_c.cpp69
-rw-r--r--src/libcamera_c/camera_manager_c.cpp114
-rw-r--r--src/libcamera_c/meson.build30
-rw-r--r--src/libcamera_c/request_c.cpp8
-rw-r--r--src/meson.build1
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')