From efc4e0be4f63af862f8c81175a4a645108b17d97 Mon Sep 17 00:00:00 2001 From: Henk Wiedig Date: Mon, 18 Nov 2024 20:42:52 +0100 Subject: [PATCH] add ExternalSurfaceWidget --- CMakeLists.txt | 2 +- config_osd.json | 7 +++++ src/osd.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ src/osd.hpp | 6 ++++ 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62f94dc..d498c5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ find_package(spdlog REQUIRED) find_package(nlohmann_json 3 REQUIRED) add_executable(${PROJECT_NAME} ${SOURCE_FILES}) -target_link_libraries(${PROJECT_NAME} rockchip_mpp pthread drm m cairo spdlog::spdlog nlohmann_json::nlohmann_json) +target_link_libraries(${PROJECT_NAME} rockchip_mpp pthread drm m cairo spdlog::spdlog nlohmann_json::nlohmann_json rt) # Embed gstreamer find_package(PkgConfig REQUIRED) diff --git a/config_osd.json b/config_osd.json index 205da2e..bc07026 100644 --- a/config_osd.json +++ b/config_osd.json @@ -2,6 +2,13 @@ "format": "0.0.1", "assets_dir": "/usr/local/share/pixelpilot/", "widgets": [ + { + "name": "msposd", + "type": "ExternalSurfaceWidget", + "x": 0, + "y": 0, + "facts": [] + }, { "name": "WFB RSSI chart", "type": "BarChartWidget", diff --git a/src/osd.cpp b/src/osd.cpp index ce1bfa1..a5d8cb7 100644 --- a/src/osd.cpp +++ b/src/osd.cpp @@ -950,6 +950,83 @@ class DebugWidget: public Widget { } }; +class ExternalSurfaceWidget: public Widget { +public: + ExternalSurfaceWidget(int pos_x, int pos_y, std::string shm_name ): Widget(pos_x, pos_y), shm_name(shm_name) {}; + + virtual void init_shm(cairo_t *cr) { + SPDLOG_INFO("creating shm region {}", shm_name); + + cairo_surface_t *target = cairo_get_target(cr); + int width = cairo_image_surface_get_width(target); + int height = cairo_image_surface_get_height(target); + + // Calculate total shared memory size + shm_size = sizeof(SharedMemoryRegion) + (width * height * 4); // Metadata + Image data + + // Create shared memory region + int shm_fd = shm_open(shm_name.c_str(), O_CREAT | O_RDWR, 0666); + if (shm_fd == -1) { + perror("Failed to create shared memory"); + return; + } + + if (ftruncate(shm_fd, shm_size) == -1) { + perror("Failed to set shared memory size"); + shm_unlink(shm_name.c_str()); + return; + } + + // Map shared memory to process address space + auto *shm_region = static_cast( + mmap(0, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0) + ); + if (shm_region == MAP_FAILED) { + perror("Failed to map shared memory"); + shm_unlink(shm_name.c_str()); + return; + } + + // Write metadata + shm_region->width = width; + shm_region->height = height; + + // Create Cairo surface for the image data + shm_surface = cairo_image_surface_create_for_data( + shm_region->data, CAIRO_FORMAT_ARGB32, width, height, width * 4 + ); + + // Store pointer for cleanup + shm_data = reinterpret_cast(shm_region); + } + + + virtual void draw(cairo_t *cr) { + + if (! shm_surface) + init_shm(cr); + auto [x, y] = xy(cr); + cairo_set_source_surface(cr, shm_surface, x, y); // Position at (0, 0) + cairo_paint(cr); // Paint shm_surface onto base_surface + } + + ~ExternalSurfaceWidget() { + SPDLOG_INFO("bye, bye, shm region {}", shm_name); + if (shm_surface) { + cairo_surface_destroy(shm_surface); + } + if (shm_data) { + munmap(shm_data, shm_size); + } + shm_unlink(shm_name.c_str()); + } + +protected: + cairo_surface_t *shm_surface = nullptr; + unsigned char *shm_data = nullptr; + size_t shm_size; + std::string shm_name; +}; class Osd { public: @@ -993,6 +1070,9 @@ class Osd { if (type == "TextWidget") { addWidget(new TextWidget(x, y, widget_j.at("text").template get()), matchers); + } + else if (type == "ExternalSurfaceWidget") { + addWidget(new ExternalSurfaceWidget(x, y, name), matchers); } else if (type == "TplTextWidget") { auto tpl = widget_j.at("template").template get(); addWidget(new TplTextWidget(x, y, tpl, (uint)matchers.size()), matchers); diff --git a/src/osd.hpp b/src/osd.hpp index 7de5c86..903f2c0 100644 --- a/src/osd.hpp +++ b/src/osd.hpp @@ -14,6 +14,12 @@ typedef struct { extern int osd_thread_signal; +struct SharedMemoryRegion { + uint16_t width; // Image width + uint16_t height; // Image height + unsigned char data[]; // Flexible array member for image data +}; + void *__OSD_THREAD__(void *param); #endif