Files
Jetson/wrapper/recordv2/k4a_shim.cpp
T
AngePierreandClaude Opus 5 cabca69c4d wrapper: build libk4arecord_v2.so — the library the recorder actually dlopens
The recorder does not load the stock libk4a/libk4arecord. It dlopens a single
custom libk4arecord_v2.so: the wrapper's MKV-writing sources linked to a
pure-data shim (k4a_shim.cpp) instead of libk4a, so recording has no OrbbecSDK
dependency. That target is FTF's own (wrapper/recordv2/), absent from the stock
wrapper the Orin carried — so ship it and inject+build it, the same pattern as
the recorder in the SDK examples tree. Idempotent; only added when missing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 17:26:06 +02:00

386 lines
11 KiB
C++

// Copyright (c) French Touch Factory. All Rights Reserved.
//
// k4a_shim — implementation des objets k4a_image_t / k4a_capture_t SANS OrbbecSDK.
//
// Pourquoi : libk4a.so implemente ces deux types au-dessus d'OrbbecSDK v1.10.18
// (k4a_capture_create -> ob_create_frameset, k4a_image_create_from_buffer ->
// ob_create_frame_from_buffer). Le recorder capture deja via OrbbecSDK v2, et le
// chemin d'ecriture MKV ne fait que relire buffer/size/format/timestamp de ces
// objets : l'aller-retour par la v1 n'apporte rien et impose de charger un second
// SDK dans le process (d'ou le hack RTLD_DEEPBIND, cf. le recorder).
//
// Ici les deux types sont de simples conteneurs de donnees comptes par reference.
// Semantique reproduite a l'identique de l'API Azure Kinect :
// - create* -> refcount = 1, appartient a l'appelant
// - capture_set_* -> la capture prend SA propre reference
// - capture_get_* -> rend une NOUVELLE reference (l'appelant doit release)
// - release -> decremente ; a 0, appelle le buffer_release_cb fourni
//
// Les quatre fonctions k4a_device_* / k4a_calibration_get_from_raw ne sont
// presentes que pour satisfaire l'editeur de liens : record.cpp ne les appelle
// que si un k4a_device_t est passe a k4a_record_create(), et le recorder passe
// nullptr (il attache lui-meme le JSON de calibration lu via la v2).
#include <k4a/k4a.h>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <new>
namespace {
struct ShimImage
{
std::atomic<int> refcount;
k4a_image_format_t format;
int width_pixels;
int height_pixels;
int stride_bytes;
uint8_t *buffer;
size_t size;
k4a_memory_destroy_cb_t *release_cb;
void *release_cb_context;
uint64_t device_timestamp_usec;
uint64_t system_timestamp_nsec;
};
struct ShimCapture
{
std::atomic<int> refcount;
ShimImage *color;
ShimImage *depth;
ShimImage *ir;
float temperature_c;
};
inline ShimImage *as_image(k4a_image_t h)
{
return reinterpret_cast<ShimImage *>(h);
}
inline ShimCapture *as_capture(k4a_capture_t h)
{
return reinterpret_cast<ShimCapture *>(h);
}
inline void image_add_ref(ShimImage *i)
{
if (i != nullptr)
{
i->refcount.fetch_add(1, std::memory_order_relaxed);
}
}
// Rend la reference. A zero : rend le buffer a son proprietaire via le callback
// fourni a la creation, puis detruit le conteneur.
void image_dec_ref(ShimImage *i)
{
if (i == nullptr)
{
return;
}
if (i->refcount.fetch_sub(1, std::memory_order_acq_rel) == 1)
{
if (i->release_cb != nullptr)
{
i->release_cb(i->buffer, i->release_cb_context);
}
delete i;
}
}
// Remplace un des trois emplacements d'une capture en respectant les references :
// on prend la nouvelle avant de rendre l'ancienne, au cas ou ce soit la meme.
void capture_set_slot(ShimImage **slot, k4a_image_t image_handle)
{
ShimImage *incoming = as_image(image_handle);
image_add_ref(incoming);
ShimImage *previous = *slot;
*slot = incoming;
image_dec_ref(previous);
}
k4a_image_t capture_get_slot(ShimImage *slot)
{
image_add_ref(slot);
return reinterpret_cast<k4a_image_t>(slot);
}
} // namespace
extern "C" {
// ---- images ----------------------------------------------------------------
k4a_result_t k4a_image_create_from_buffer(k4a_image_format_t format,
int width_pixels,
int height_pixels,
int stride_bytes,
uint8_t *buffer,
size_t buffer_size,
k4a_memory_destroy_cb_t *buffer_release_cb,
void *buffer_release_cb_context,
k4a_image_t *image_handle)
{
if (image_handle == nullptr || buffer == nullptr)
{
return K4A_RESULT_FAILED;
}
ShimImage *i = new (std::nothrow) ShimImage();
if (i == nullptr)
{
return K4A_RESULT_FAILED;
}
i->refcount.store(1, std::memory_order_relaxed);
i->format = format;
i->width_pixels = width_pixels;
i->height_pixels = height_pixels;
i->stride_bytes = stride_bytes;
i->buffer = buffer;
i->size = buffer_size;
i->release_cb = buffer_release_cb;
i->release_cb_context = buffer_release_cb_context;
i->device_timestamp_usec = 0;
i->system_timestamp_nsec = 0;
*image_handle = reinterpret_cast<k4a_image_t>(i);
return K4A_RESULT_SUCCEEDED;
}
uint8_t *k4a_image_get_buffer(k4a_image_t image_handle)
{
ShimImage *i = as_image(image_handle);
return (i != nullptr) ? i->buffer : nullptr;
}
size_t k4a_image_get_size(k4a_image_t image_handle)
{
ShimImage *i = as_image(image_handle);
return (i != nullptr) ? i->size : 0;
}
k4a_image_format_t k4a_image_get_format(k4a_image_t image_handle)
{
ShimImage *i = as_image(image_handle);
return (i != nullptr) ? i->format : K4A_IMAGE_FORMAT_CUSTOM;
}
int k4a_image_get_width_pixels(k4a_image_t image_handle)
{
ShimImage *i = as_image(image_handle);
return (i != nullptr) ? i->width_pixels : 0;
}
int k4a_image_get_height_pixels(k4a_image_t image_handle)
{
ShimImage *i = as_image(image_handle);
return (i != nullptr) ? i->height_pixels : 0;
}
int k4a_image_get_stride_bytes(k4a_image_t image_handle)
{
ShimImage *i = as_image(image_handle);
return (i != nullptr) ? i->stride_bytes : 0;
}
uint64_t k4a_image_get_device_timestamp_usec(k4a_image_t image_handle)
{
ShimImage *i = as_image(image_handle);
return (i != nullptr) ? i->device_timestamp_usec : 0;
}
void k4a_image_set_device_timestamp_usec(k4a_image_t image_handle, uint64_t timestamp_usec)
{
ShimImage *i = as_image(image_handle);
if (i != nullptr)
{
i->device_timestamp_usec = timestamp_usec;
}
}
uint64_t k4a_image_get_system_timestamp_nsec(k4a_image_t image_handle)
{
ShimImage *i = as_image(image_handle);
return (i != nullptr) ? i->system_timestamp_nsec : 0;
}
void k4a_image_set_system_timestamp_nsec(k4a_image_t image_handle, uint64_t timestamp_nsec)
{
ShimImage *i = as_image(image_handle);
if (i != nullptr)
{
i->system_timestamp_nsec = timestamp_nsec;
}
}
void k4a_image_reference(k4a_image_t image_handle)
{
image_add_ref(as_image(image_handle));
}
void k4a_image_release(k4a_image_t image_handle)
{
image_dec_ref(as_image(image_handle));
}
// ---- captures --------------------------------------------------------------
k4a_result_t k4a_capture_create(k4a_capture_t *capture_handle)
{
if (capture_handle == nullptr)
{
return K4A_RESULT_FAILED;
}
ShimCapture *c = new (std::nothrow) ShimCapture();
if (c == nullptr)
{
return K4A_RESULT_FAILED;
}
c->refcount.store(1, std::memory_order_relaxed);
c->color = nullptr;
c->depth = nullptr;
c->ir = nullptr;
c->temperature_c = 0.0f;
*capture_handle = reinterpret_cast<k4a_capture_t>(c);
return K4A_RESULT_SUCCEEDED;
}
void k4a_capture_reference(k4a_capture_t capture_handle)
{
ShimCapture *c = as_capture(capture_handle);
if (c != nullptr)
{
c->refcount.fetch_add(1, std::memory_order_relaxed);
}
}
void k4a_capture_release(k4a_capture_t capture_handle)
{
ShimCapture *c = as_capture(capture_handle);
if (c == nullptr)
{
return;
}
if (c->refcount.fetch_sub(1, std::memory_order_acq_rel) == 1)
{
image_dec_ref(c->color);
image_dec_ref(c->depth);
image_dec_ref(c->ir);
delete c;
}
}
void k4a_capture_set_color_image(k4a_capture_t capture_handle, k4a_image_t image_handle)
{
ShimCapture *c = as_capture(capture_handle);
if (c != nullptr)
{
capture_set_slot(&c->color, image_handle);
}
}
void k4a_capture_set_depth_image(k4a_capture_t capture_handle, k4a_image_t image_handle)
{
ShimCapture *c = as_capture(capture_handle);
if (c != nullptr)
{
capture_set_slot(&c->depth, image_handle);
}
}
void k4a_capture_set_ir_image(k4a_capture_t capture_handle, k4a_image_t image_handle)
{
ShimCapture *c = as_capture(capture_handle);
if (c != nullptr)
{
capture_set_slot(&c->ir, image_handle);
}
}
k4a_image_t k4a_capture_get_color_image(k4a_capture_t capture_handle)
{
ShimCapture *c = as_capture(capture_handle);
return (c != nullptr) ? capture_get_slot(c->color) : nullptr;
}
k4a_image_t k4a_capture_get_depth_image(k4a_capture_t capture_handle)
{
ShimCapture *c = as_capture(capture_handle);
return (c != nullptr) ? capture_get_slot(c->depth) : nullptr;
}
k4a_image_t k4a_capture_get_ir_image(k4a_capture_t capture_handle)
{
ShimCapture *c = as_capture(capture_handle);
return (c != nullptr) ? capture_get_slot(c->ir) : nullptr;
}
void k4a_capture_set_temperature_c(k4a_capture_t capture_handle, float temperature_c)
{
ShimCapture *c = as_capture(capture_handle);
if (c != nullptr)
{
c->temperature_c = temperature_c;
}
}
float k4a_capture_get_temperature_c(k4a_capture_t capture_handle)
{
ShimCapture *c = as_capture(capture_handle);
return (c != nullptr) ? c->temperature_c : 0.0f;
}
// ---- stubs de lien ---------------------------------------------------------
// record.cpp ne touche a un k4a_device_t que si k4a_record_create() en recoit un.
// Le recorder passe nullptr, donc ces chemins sont morts. On echoue proprement
// plutot que de mentir sur des donnees qu'on ne peut pas fournir.
k4a_buffer_result_t k4a_device_get_raw_calibration(k4a_device_t device_handle,
uint8_t *data,
size_t *data_size)
{
(void)device_handle;
(void)data;
(void)data_size;
return K4A_BUFFER_RESULT_FAILED;
}
k4a_buffer_result_t k4a_device_get_serialnum(k4a_device_t device_handle,
char *serial_number,
size_t *serial_number_size)
{
(void)device_handle;
(void)serial_number;
(void)serial_number_size;
return K4A_BUFFER_RESULT_FAILED;
}
k4a_result_t k4a_device_get_version(k4a_device_t device_handle, k4a_hardware_version_t *version)
{
(void)device_handle;
(void)version;
return K4A_RESULT_FAILED;
}
k4a_result_t k4a_calibration_get_from_raw(char *raw_calibration,
size_t raw_calibration_size,
const k4a_depth_mode_t depth_mode,
const k4a_color_resolution_t color_resolution,
k4a_calibration_t *calibration)
{
(void)raw_calibration;
(void)raw_calibration_size;
(void)depth_mode;
(void)color_resolution;
(void)calibration;
return K4A_RESULT_FAILED;
}
} // extern "C"