From a0b35fdec94ec683dcb782288c8333d434e9fa9e Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sat, 4 Jul 2026 23:55:21 +0200 Subject: [PATCH 1/8] Update flatcc dependency to master to fix compilation with gcc 15 --- fbs/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fbs/CMakeLists.txt b/fbs/CMakeLists.txt index 0e228c7..832fdb3 100644 --- a/fbs/CMakeLists.txt +++ b/fbs/CMakeLists.txt @@ -7,8 +7,8 @@ else () endif () ExternalProject_Add(flatcc-native - URL https://github.com/dvidelabs/flatcc/archive/v0.6.1.tar.gz - URL_HASH SHA512=46ba5ca75facc7d3360dba797d24ae7bfe539a854a48831e1c7b96528cf9594d8bea22b267678fd7c6d742b6636d9e52930987119b4c6b2e38d4abe89b990cae + GIT_REPOSITORY https://github.com/dvidelabs/flatcc.git + GIT_TAG 29201734bf2d12713a7a1a035d31e5123aac9c93 DOWNLOAD_EXTRACT_TIMESTAMP TRUE CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} @@ -53,8 +53,8 @@ else () endif () ExternalProject_Add(flatcc-target - URL https://github.com/dvidelabs/flatcc/archive/v0.6.1.tar.gz - URL_HASH SHA512=46ba5ca75facc7d3360dba797d24ae7bfe539a854a48831e1c7b96528cf9594d8bea22b267678fd7c6d742b6636d9e52930987119b4c6b2e38d4abe89b990cae + GIT_REPOSITORY https://github.com/dvidelabs/flatcc.git + GIT_TAG 29201734bf2d12713a7a1a035d31e5123aac9c93 DOWNLOAD_EXTRACT_TIMESTAMP TRUE CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} From 9e88e92f141ffee5e818ea737bed9b5b41845942 Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sat, 4 Jul 2026 23:56:15 +0200 Subject: [PATCH 2/8] Fix memory allocation calloc call gcc warning --- unicapture/backends/libdile_vt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unicapture/backends/libdile_vt.c b/unicapture/backends/libdile_vt.c index 0851ec8..d156e0e 100644 --- a/unicapture/backends/libdile_vt.c +++ b/unicapture/backends/libdile_vt.c @@ -150,9 +150,9 @@ int capture_init(cap_backend_config_t* config, void** state_p) } INFO("[DILE_VT] vfbs: %d; planes: %d", this->vfbcap.numVfbs, this->vfbcap.numPlanes); - uint32_t** ptr = calloc(sizeof(uint32_t*), this->vfbcap.numVfbs); + uint32_t** ptr = calloc(this->vfbcap.numVfbs, sizeof(uint32_t*)); for (uint32_t vfb = 0; vfb < this->vfbcap.numVfbs; vfb++) { - ptr[vfb] = calloc(sizeof(uint32_t), this->vfbcap.numPlanes); + ptr[vfb] = calloc(this->vfbcap.numPlanes, sizeof(uint32_t)); } this->vfbprop.ptr = ptr; From 6ee69d267cca86ec4040594197ac798512fd586d Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sat, 4 Jul 2026 23:56:39 +0200 Subject: [PATCH 3/8] Optimize blending process in YUV420 semi-planar format using libyuv --- unicapture/unicapture.c | 51 +++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/unicapture/unicapture.c b/unicapture/unicapture.c index d771b83..8e533a9 100644 --- a/unicapture/unicapture.c +++ b/unicapture/unicapture.c @@ -129,6 +129,7 @@ void* unicapture_run(void* data) frame_info_t blended_frame = { PIXFMT_INVALID }; frame_info_t final_frame = { PIXFMT_INVALID }; + uint8_t* blend_alpha_y = NULL; this->vsync_thread_running = true; pthread_create(&this->vsync_thread, NULL, unicapture_vsync_handler, this); @@ -222,6 +223,8 @@ void* unicapture_run(void* data) } if (target_format == PIXFMT_YUV420_SEMI_PLANAR) { + const int uv_height = height / 2; + blended_frame.planes[0].buffer = realloc(blended_frame.planes[0].buffer, width * height); blended_frame.planes[0].stride = width; blended_frame.planes[1].buffer = realloc(blended_frame.planes[1].buffer, width * height / 2); @@ -230,23 +233,36 @@ void* unicapture_run(void* data) blended_frame.width = width; blended_frame.pixel_format = PIXFMT_YUV420_SEMI_PLANAR; - for (int i = 0; i < width * height; i++) { - blended_frame.planes[0].buffer[i] = blend(ui_frame_converted.planes[0].buffer[i], - video_frame_converted.planes[0].buffer[i], ui_frame.planes[0].buffer[i * 4 + 3]); - } - - int alpha_idx = 0; - for (int i = 0; i < height / 2; i++) { - for (int j = 0; j < width; j += 2) { - int idx = i * width + j; - blended_frame.planes[1].buffer[idx] = blend(ui_frame_converted.planes[1].buffer[idx], - video_frame_converted.planes[1].buffer[idx], ui_frame.planes[0].buffer[alpha_idx + 3]); - blended_frame.planes[1].buffer[idx + 1] = blend(ui_frame_converted.planes[1].buffer[idx + 1], - video_frame_converted.planes[1].buffer[idx + 1], ui_frame.planes[0].buffer[alpha_idx + 3]); - alpha_idx += 8; - } - alpha_idx += ui_frame.planes[0].stride; - } + blend_alpha_y = realloc(blend_alpha_y, width * height); + + ARGBExtractAlpha(ui_frame.planes[0].buffer, + ui_frame.planes[0].stride, + blend_alpha_y, + width, + width, + height); + + BlendPlane(ui_frame_converted.planes[0].buffer, + ui_frame_converted.planes[0].stride, + video_frame_converted.planes[0].buffer, + video_frame_converted.planes[0].stride, + blend_alpha_y, + width, + blended_frame.planes[0].buffer, + blended_frame.planes[0].stride, + width, + height); + + BlendPlane(ui_frame_converted.planes[1].buffer, + ui_frame_converted.planes[1].stride, + video_frame_converted.planes[1].buffer, + video_frame_converted.planes[1].stride, + blend_alpha_y, + width * 2, + blended_frame.planes[1].buffer, + blended_frame.planes[1].stride, + width, + uv_height); } converter_run(&final_converter, &blended_frame, &final_frame, target_format); } else if (ui_frame_converted.pixel_format != PIXFMT_INVALID) { @@ -342,6 +358,7 @@ void* unicapture_run(void* data) blended_frame.planes[i].buffer = NULL; } } + free(blend_alpha_y); converter_release(&ui_converter); converter_release(&video_converter); From 795fbe14a20ca8e787461ee30ecd145f1429312e Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sun, 5 Jul 2026 00:07:08 +0200 Subject: [PATCH 4/8] Optimize frame conversion by skipping unnecessary processing for matching pixel formats --- unicapture/unicapture.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/unicapture/unicapture.c b/unicapture/unicapture.c index 8e533a9..5892c88 100644 --- a/unicapture/unicapture.c +++ b/unicapture/unicapture.c @@ -264,7 +264,11 @@ void* unicapture_run(void* data) width, uv_height); } - converter_run(&final_converter, &blended_frame, &final_frame, target_format); + if (blended_frame.pixel_format == target_format) { + final_frame = blended_frame; + } else { + converter_run(&final_converter, &blended_frame, &final_frame, target_format); + } } else if (ui_frame_converted.pixel_format != PIXFMT_INVALID) { converter_run(&final_converter, &ui_frame_converted, &final_frame, target_format); } else if (video_frame_converted.pixel_format != PIXFMT_INVALID) { From 39fd234cfb24e97392d5f38b4d94d9b8b30f0330 Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sun, 5 Jul 2026 00:23:56 +0200 Subject: [PATCH 5/8] Optimize buffer handling in vtcapture --- unicapture/backends/libvtcapture.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/unicapture/backends/libvtcapture.cpp b/unicapture/backends/libvtcapture.cpp index aed0188..8e86c88 100644 --- a/unicapture/backends/libvtcapture.cpp +++ b/unicapture/backends/libvtcapture.cpp @@ -1,4 +1,5 @@ #include +#include // snprintf() #include // calloc() #include // usleep() @@ -24,6 +25,7 @@ typedef struct _vtcapture_backend_state { _LibVtCaptureBufferInfo buff; _LibVtCaptureProperties props; char* curr_buff; + bool buff_valid; bool terminate; bool quirk_force_capture; } vtcapture_backend_state_t; @@ -115,7 +117,7 @@ int capture_start(void* state) const VT_CALLER_T* caller = "hyperion-webos_service"; vtcapture_backend_state_t* self = (vtcapture_backend_state_t*)state; - sprintf(self->client, "%s", "00"); + snprintf(self->client, sizeof(self->client), "%s", "00"); if ((ret = vtCapture_init(self->driver, caller, self->client)) == 17) { @@ -182,6 +184,7 @@ int capture_start(void* state) plane.activeregion.a, plane.activeregion.b, plane.activeregion.c, plane.activeregion.d); self->terminate = false; + self->buff_valid = false; INFO("vtcapture initialization finished."); @@ -213,6 +216,7 @@ int capture_terminate(void* state) vtcapture_backend_state_t* self = (vtcapture_backend_state_t*)state; self->terminate = true; + self->buff_valid = false; vtCapture_stop(self->driver, self->client); vtCapture_postprocess(self->driver, self->client); @@ -224,10 +228,9 @@ int capture_terminate(void* state) int capture_acquire_frame(void* state, frame_info_t* frame) { vtcapture_backend_state_t* self = (vtcapture_backend_state_t*)state; - _LibVtCaptureBufferInfo buff; int ret = 0; - if ((ret = vtCapture_currentCaptureBuffInfo(self->driver, &buff)) != 0) { + if (!self->buff_valid && (ret = vtCapture_currentCaptureBuffInfo(self->driver, &self->buff)) != 0) { ERR("vtCapture_currentCaptureBuffInfo() failed: %d", ret); return -1; @@ -236,12 +239,13 @@ int capture_acquire_frame(void* state, frame_info_t* frame) frame->pixel_format = PIXFMT_YUV420_SEMI_PLANAR; // ToDo: I guess?! frame->width = self->width; frame->height = self->height; - frame->planes[0].buffer = reinterpret_cast(buff.start_addr0); + frame->planes[0].buffer = reinterpret_cast(self->buff.start_addr0); frame->planes[0].stride = self->stride; - frame->planes[1].buffer = reinterpret_cast(buff.start_addr1); + frame->planes[1].buffer = reinterpret_cast(self->buff.start_addr1); frame->planes[1].stride = self->stride; self->curr_buff = self->buff.start_addr0; + self->buff_valid = false; return 0; } @@ -305,6 +309,7 @@ int capture_wait(void* state) } self->curr_buff = self->buff.start_addr0; + self->buff_valid = true; return 0; } From 652feda87a68cc628ab7a32992ed32bcc8e7970d Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sun, 5 Jul 2026 00:24:10 +0200 Subject: [PATCH 6/8] Optimize buffer management in converter and unicapture --- unicapture/converter.c | 54 +++++++++++---- unicapture/converter.h | 2 + unicapture/unicapture.c | 142 ++++++++++++++++++++++++---------------- 3 files changed, 130 insertions(+), 68 deletions(-) diff --git a/unicapture/converter.c b/unicapture/converter.c index 34f7a9f..6eeeb7f 100644 --- a/unicapture/converter.c +++ b/unicapture/converter.c @@ -1,11 +1,29 @@ #include "converter.h" #include +#include #include +static int converter_reserve(converter_t* converter, int idx, size_t size) +{ + if (converter->capacities[idx] >= size) { + return 0; + } + + uint8_t* buffer = realloc(converter->buffers[idx], size); + if (!buffer) { + return -1; + } + + converter->buffers[idx] = buffer; + converter->capacities[idx] = size; + return 0; +} + void converter_init(converter_t* this) { for (int i = 0; i < MAX_PLANES; i++) { this->buffers[i] = NULL; + this->capacities[i] = 0; } } @@ -14,7 +32,9 @@ int converter_release(converter_t* converter) for (int i = 0; i < MAX_PLANES; i++) { if (converter->buffers[i] != NULL) { free(converter->buffers[i]); + converter->buffers[i] = NULL; } + converter->capacities[i] = 0; } return 0; } @@ -41,7 +61,9 @@ int converter_run(converter_t* this, frame_info_t* input, frame_info_t* output, output->planes[i].stride = input->planes[i].stride; if (input->planes[i].buffer) { - this->buffers[i] = realloc(this->buffers[i], size); + if (converter_reserve(this, i, size) != 0) { + return -1; + } memcpy(this->buffers[i], input->planes[i].buffer, size); output->planes[i].buffer = this->buffers[i]; } @@ -53,7 +75,9 @@ int converter_run(converter_t* this, frame_info_t* input, frame_info_t* output, output->width = input->width; output->height = input->height; - this->buffers[0] = realloc(this->buffers[0], output->width * output->height * 4); + if (converter_reserve(this, 0, output->width * output->height * 4) != 0) { + return -1; + } output->planes[0].buffer = this->buffers[0]; output->planes[0].stride = output->width * 4; @@ -85,8 +109,10 @@ int converter_run(converter_t* this, frame_info_t* input, frame_info_t* output, output->width, output->height); } else if (input->pixel_format == PIXFMT_YUV422_SEMI_PLANAR) { - this->buffers[1] = realloc(this->buffers[1], input->width / 2 * input->height); - this->buffers[2] = realloc(this->buffers[2], input->width / 2 * input->height); + if (converter_reserve(this, 1, input->width / 2 * input->height) != 0 + || converter_reserve(this, 2, input->width / 2 * input->height) != 0) { + return -1; + } SplitUVPlane( input->planes[1].buffer, input->planes[1].stride, @@ -118,8 +144,10 @@ int converter_run(converter_t* this, frame_info_t* input, frame_info_t* output, return 0; } if (target_format == PIXFMT_YUV420_SEMI_PLANAR && input->pixel_format == PIXFMT_ARGB) { - this->buffers[0] = realloc(this->buffers[0], input->width * input->height); - this->buffers[1] = realloc(this->buffers[1], input->width * input->height / 2); + if (converter_reserve(this, 0, input->width * input->height) != 0 + || converter_reserve(this, 1, input->width * input->height / 2) != 0) { + return -1; + } output->width = input->width; output->height = input->height; @@ -140,7 +168,9 @@ int converter_run(converter_t* this, frame_info_t* input, frame_info_t* output, return 0; } if (target_format == PIXFMT_RGB && input->pixel_format == PIXFMT_ARGB) { - this->buffers[0] = realloc(this->buffers[0], input->width * input->height * 3); + if (converter_reserve(this, 0, input->width * input->height * 3) != 0) { + return -1; + } output->width = input->width; output->height = input->height; @@ -158,10 +188,12 @@ int converter_run(converter_t* this, frame_info_t* input, frame_info_t* output, } if (target_format == PIXFMT_YUV420_SEMI_PLANAR && input->pixel_format == PIXFMT_YUV422_SEMI_PLANAR) { - this->buffers[0] = realloc(this->buffers[0], input->planes[0].stride * input->height); // Y - this->buffers[1] = realloc(this->buffers[1], input->width / 2 * input->height); // U - this->buffers[2] = realloc(this->buffers[2], input->width / 2 * input->height); // V - this->buffers[3] = realloc(this->buffers[3], input->width / 2 * input->height); // UV + if (converter_reserve(this, 0, input->planes[0].stride * input->height) != 0 // Y + || converter_reserve(this, 1, input->width / 2 * input->height) != 0 // U + || converter_reserve(this, 2, input->width / 2 * input->height) != 0 // V + || converter_reserve(this, 3, input->width / 2 * input->height) != 0) { // UV + return -1; + } SplitUVPlane( input->planes[1].buffer, input->planes[1].stride, diff --git a/unicapture/converter.h b/unicapture/converter.h index d56d933..a853eae 100644 --- a/unicapture/converter.h +++ b/unicapture/converter.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "unicapture.h" @@ -7,6 +8,7 @@ typedef struct _converter { // Temporary conversion memory buffers uint8_t* buffers[4]; + size_t capacities[4]; } converter_t; void converter_init(converter_t* converter); diff --git a/unicapture/unicapture.c b/unicapture/unicapture.c index 5892c88..cafc3ab 100644 --- a/unicapture/unicapture.c +++ b/unicapture/unicapture.c @@ -15,6 +15,22 @@ return -2; \ } +static int reserve_buffer(uint8_t** buffer, size_t* capacity, size_t size) +{ + if (*capacity >= size) { + return 0; + } + + uint8_t* new_buffer = realloc(*buffer, size); + if (!new_buffer) { + return -1; + } + + *buffer = new_buffer; + *capacity = size; + return 0; +} + int unicapture_init_backend(cap_backend_config_t* config, capture_backend_t* backend, const char* name) { char* error; @@ -129,7 +145,9 @@ void* unicapture_run(void* data) frame_info_t blended_frame = { PIXFMT_INVALID }; frame_info_t final_frame = { PIXFMT_INVALID }; + size_t blended_frame_capacities[MAX_PLANES] = { 0 }; uint8_t* blend_alpha_y = NULL; + size_t blend_alpha_y_capacity = 0; this->vsync_thread_running = true; pthread_create(&this->vsync_thread, NULL, unicapture_vsync_handler, this); @@ -206,68 +224,77 @@ void* unicapture_run(void* data) const int height = video_frame_converted.height; if (target_format == PIXFMT_RGB || target_format == PIXFMT_ARGB) { - blended_frame.planes[0].buffer = realloc(blended_frame.planes[0].buffer, width * height * 4); - blended_frame.planes[0].stride = width * 4; - blended_frame.pixel_format = PIXFMT_ARGB; - blended_frame.width = width; - blended_frame.height = height; - - ARGBBlend(ui_frame_converted.planes[0].buffer, - ui_frame_converted.planes[0].stride, - video_frame_converted.planes[0].buffer, - video_frame_converted.planes[0].stride, - blended_frame.planes[0].buffer, - 4 * width, - width, - height); + if (reserve_buffer(&blended_frame.planes[0].buffer, &blended_frame_capacities[0], width * height * 4) != 0) { + got_frame = false; + WARN("Unable to allocate ARGB blend buffer"); + } else { + blended_frame.planes[0].stride = width * 4; + blended_frame.pixel_format = PIXFMT_ARGB; + blended_frame.width = width; + blended_frame.height = height; + + ARGBBlend(ui_frame_converted.planes[0].buffer, + ui_frame_converted.planes[0].stride, + video_frame_converted.planes[0].buffer, + video_frame_converted.planes[0].stride, + blended_frame.planes[0].buffer, + 4 * width, + width, + height); + } } - if (target_format == PIXFMT_YUV420_SEMI_PLANAR) { + if (got_frame && target_format == PIXFMT_YUV420_SEMI_PLANAR) { const int uv_height = height / 2; - blended_frame.planes[0].buffer = realloc(blended_frame.planes[0].buffer, width * height); - blended_frame.planes[0].stride = width; - blended_frame.planes[1].buffer = realloc(blended_frame.planes[1].buffer, width * height / 2); - blended_frame.planes[1].stride = width; - blended_frame.height = height; - blended_frame.width = width; - blended_frame.pixel_format = PIXFMT_YUV420_SEMI_PLANAR; - - blend_alpha_y = realloc(blend_alpha_y, width * height); - - ARGBExtractAlpha(ui_frame.planes[0].buffer, - ui_frame.planes[0].stride, - blend_alpha_y, - width, - width, - height); - - BlendPlane(ui_frame_converted.planes[0].buffer, - ui_frame_converted.planes[0].stride, - video_frame_converted.planes[0].buffer, - video_frame_converted.planes[0].stride, - blend_alpha_y, - width, - blended_frame.planes[0].buffer, - blended_frame.planes[0].stride, - width, - height); - - BlendPlane(ui_frame_converted.planes[1].buffer, - ui_frame_converted.planes[1].stride, - video_frame_converted.planes[1].buffer, - video_frame_converted.planes[1].stride, - blend_alpha_y, - width * 2, - blended_frame.planes[1].buffer, - blended_frame.planes[1].stride, - width, - uv_height); + if (reserve_buffer(&blended_frame.planes[0].buffer, &blended_frame_capacities[0], width * height) != 0 + || reserve_buffer(&blended_frame.planes[1].buffer, &blended_frame_capacities[1], width * height / 2) != 0 + || reserve_buffer(&blend_alpha_y, &blend_alpha_y_capacity, width * height) != 0) { + got_frame = false; + WARN("Unable to allocate NV12 blend buffers"); + } else { + blended_frame.planes[0].stride = width; + blended_frame.planes[1].stride = width; + blended_frame.height = height; + blended_frame.width = width; + blended_frame.pixel_format = PIXFMT_YUV420_SEMI_PLANAR; + + ARGBExtractAlpha(ui_frame.planes[0].buffer, + ui_frame.planes[0].stride, + blend_alpha_y, + width, + width, + height); + + BlendPlane(ui_frame_converted.planes[0].buffer, + ui_frame_converted.planes[0].stride, + video_frame_converted.planes[0].buffer, + video_frame_converted.planes[0].stride, + blend_alpha_y, + width, + blended_frame.planes[0].buffer, + blended_frame.planes[0].stride, + width, + height); + + BlendPlane(ui_frame_converted.planes[1].buffer, + ui_frame_converted.planes[1].stride, + video_frame_converted.planes[1].buffer, + video_frame_converted.planes[1].stride, + blend_alpha_y, + width * 2, + blended_frame.planes[1].buffer, + blended_frame.planes[1].stride, + width, + uv_height); + } } - if (blended_frame.pixel_format == target_format) { - final_frame = blended_frame; - } else { - converter_run(&final_converter, &blended_frame, &final_frame, target_format); + if (got_frame) { + if (blended_frame.pixel_format == target_format) { + final_frame = blended_frame; + } else { + converter_run(&final_converter, &blended_frame, &final_frame, target_format); + } } } else if (ui_frame_converted.pixel_format != PIXFMT_INVALID) { converter_run(&final_converter, &ui_frame_converted, &final_frame, target_format); @@ -360,6 +387,7 @@ void* unicapture_run(void* data) if (blended_frame.planes[i].buffer != NULL) { free(blended_frame.planes[i].buffer); blended_frame.planes[i].buffer = NULL; + blended_frame_capacities[i] = 0; } } free(blend_alpha_y); From f315ae3a3ff85254c4cf5ad2e8c27284e8db71de Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sun, 5 Jul 2026 00:43:42 +0200 Subject: [PATCH 7/8] Optimize frame conversion by reusing frames for matching pixel formats --- unicapture/unicapture.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/unicapture/unicapture.c b/unicapture/unicapture.c index cafc3ab..e6a3bd1 100644 --- a/unicapture/unicapture.c +++ b/unicapture/unicapture.c @@ -31,6 +31,11 @@ static int reserve_buffer(uint8_t** buffer, size_t* capacity, size_t size) return 0; } +static void borrow_frame(frame_info_t* output, const frame_info_t* input) +{ + *output = *input; +} + int unicapture_init_backend(cap_backend_config_t* config, capture_backend_t* backend, const char* name) { char* error; @@ -202,16 +207,23 @@ void* unicapture_run(void* data) uint64_t frame_acquired = getticks_us(); pixel_format_t target_format = this->target_format; + pixel_format_t blend_format = (target_format == PIXFMT_RGB || target_format == PIXFMT_ARGB) ? PIXFMT_ARGB : PIXFMT_YUV420_SEMI_PLANAR; // Convert frame to suitable video formats if (ui_frame.pixel_format != PIXFMT_INVALID) { - converter_run(&ui_converter, &ui_frame, &ui_frame_converted, - (target_format == PIXFMT_RGB || target_format == PIXFMT_ARGB) ? PIXFMT_ARGB : PIXFMT_YUV420_SEMI_PLANAR); + if (ui_frame.pixel_format == blend_format) { + borrow_frame(&ui_frame_converted, &ui_frame); + } else { + converter_run(&ui_converter, &ui_frame, &ui_frame_converted, blend_format); + } } if (video_frame.pixel_format != PIXFMT_INVALID) { - converter_run(&video_converter, &video_frame, &video_frame_converted, - (target_format == PIXFMT_RGB || target_format == PIXFMT_ARGB) ? PIXFMT_ARGB : PIXFMT_YUV420_SEMI_PLANAR); + if (video_frame.pixel_format == blend_format) { + borrow_frame(&video_frame_converted, &video_frame); + } else { + converter_run(&video_converter, &video_frame, &video_frame_converted, blend_format); + } } uint64_t frame_converted = getticks_us(); @@ -297,9 +309,17 @@ void* unicapture_run(void* data) } } } else if (ui_frame_converted.pixel_format != PIXFMT_INVALID) { - converter_run(&final_converter, &ui_frame_converted, &final_frame, target_format); + if (ui_frame_converted.pixel_format == target_format) { + borrow_frame(&final_frame, &ui_frame_converted); + } else { + converter_run(&final_converter, &ui_frame_converted, &final_frame, target_format); + } } else if (video_frame_converted.pixel_format != PIXFMT_INVALID) { - converter_run(&final_converter, &video_frame_converted, &final_frame, target_format); + if (video_frame_converted.pixel_format == target_format) { + borrow_frame(&final_frame, &video_frame_converted); + } else { + converter_run(&final_converter, &video_frame_converted, &final_frame, target_format); + } } else { got_frame = false; WARN("No valid frame to send..."); @@ -329,7 +349,7 @@ void* unicapture_run(void* data) if (this->callback_nv12 != NULL && target_format == PIXFMT_YUV420_SEMI_PLANAR) { this->callback_nv12(this->callback_data, final_frame.width, final_frame.height, final_frame.planes[0].buffer, - final_frame.planes[1].buffer, final_frame.width, final_frame.width); + final_frame.planes[1].buffer, final_frame.planes[0].stride, final_frame.planes[1].stride); } uint64_t frame_sent = getticks_us(); From 63544e35d05b7f39f8d0ab977f56b215b23fb165 Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sun, 5 Jul 2026 00:43:54 +0200 Subject: [PATCH 8/8] Optimize message writing by using writev --- src/hyperion_client.c | 51 +++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/src/hyperion_client.c b/src/hyperion_client.c index f732a0b..4722d08 100644 --- a/src/hyperion_client.c +++ b/src/hyperion_client.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,7 @@ static int _connect_unix_socket(const char* hostname); static int _connect_inet_socket(const char* hostname, int port); static int _send_message(const void* buffer, size_t size); +static int _write_message(const void* buffer, size_t size); static bool _parse_reply(hyperionnet_Reply_table_t reply); static int sockfd; @@ -88,8 +90,8 @@ int hyperion_set_nv12_image(const uint8_t* y, const uint8_t* uv, int width, int { flatbuffers_builder_t B; flatcc_builder_init(&B); - flatbuffers_uint8_vec_ref_t yData = flatcc_builder_create_type_vector(&B, y, width * height); - flatbuffers_uint8_vec_ref_t uvData = flatcc_builder_create_type_vector(&B, uv, width * height / 2); + flatbuffers_uint8_vec_ref_t yData = flatcc_builder_create_type_vector(&B, y, stride_y * height); + flatbuffers_uint8_vec_ref_t uvData = flatcc_builder_create_type_vector(&B, uv, stride_uv * height / 2); hyperionnet_RawImage_ref_t nv12Img = hyperionnet_NV12Image_create(&B, yData, uvData, width, height, stride_y, stride_uv); hyperionnet_Image_ref_t imageReq = hyperionnet_Image_create(&B, hyperionnet_ImageType_as_NV12Image(nv12Img), -1); hyperionnet_Request_create_as_root(&B, hyperionnet_Command_as_Image(imageReq)); @@ -112,23 +114,27 @@ int hyperion_set_register(const char* origin, int priority) size_t size; void* buf = flatcc_builder_finalize_buffer(&B, &size); - uint8_t header[4] = { + int ret = _write_message(buf, size); + + free(buf); + flatcc_builder_clear(&B); + return ret; +} + +int _write_message(const void* buffer, size_t size) +{ + const uint8_t header[] = { (uint8_t)((size >> 24) & 0xFF), (uint8_t)((size >> 16) & 0xFF), (uint8_t)((size >> 8) & 0xFF), - (uint8_t)(size & 0xFF), + (uint8_t)(size & 0xFF) + }; + const struct iovec iov[] = { + { (void*)header, sizeof(header) }, + { (void*)buffer, size } }; - // write message - int ret = 0; - if (write(sockfd, header, 4) < 0) - ret = -1; - if (write(sockfd, buf, size) < 0) - ret = -1; - - free(buf); - flatcc_builder_clear(&B); - return ret; + return writev(sockfd, iov, 2) == (ssize_t)(sizeof(header) + size) ? 0 : -1; } int _send_message(const void* buffer, size_t size) @@ -142,20 +148,7 @@ int _send_message(const void* buffer, size_t size) return hyperion_set_register(_origin, _priority); } - const uint8_t header[] = { - (uint8_t)((size >> 24) & 0xFF), - (uint8_t)((size >> 16) & 0xFF), - (uint8_t)((size >> 8) & 0xFF), - (uint8_t)(size & 0xFF) - }; - - // write message - int ret = 0; - if (write(sockfd, header, 4) < 0) - ret = -1; - if (write(sockfd, buffer, size) < 0) - ret = -1; - return ret; + return _write_message(buffer, size); } bool _parse_reply(hyperionnet_Reply_table_t reply) @@ -267,4 +260,4 @@ int _connect_unix_socket(const char* hostname) _connected = true; return 0; -} \ No newline at end of file +}