// 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 #include #include #include #include namespace { struct ShimImage { std::atomic 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 refcount; ShimImage *color; ShimImage *depth; ShimImage *ir; float temperature_c; }; inline ShimImage *as_image(k4a_image_t h) { return reinterpret_cast(h); } inline ShimCapture *as_capture(k4a_capture_t h) { return reinterpret_cast(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(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(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(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"