From cc97528eca056d969eb9043cf06c7b2ffdc5ba91 Mon Sep 17 00:00:00 2001 From: Maik Jurischka Date: Thu, 29 Jan 2026 12:27:37 +0100 Subject: [PATCH] add SharedMemoryWriter support - without gstreamer --- docs/SOCKET_API.md | 98 ++++++++++++++++++++++++++++++++++++++--- src/StreamingEngine.cpp | 44 ++++++++++++------ 2 files changed, 122 insertions(+), 20 deletions(-) diff --git a/docs/SOCKET_API.md b/docs/SOCKET_API.md index 4f7235b..e685372 100644 --- a/docs/SOCKET_API.md +++ b/docs/SOCKET_API.md @@ -600,10 +600,14 @@ Retrieve all current eHDR settings. ### 21. Enable Shared Memory -Enable shared memory output for direct frame access by external processes. This creates a shared memory region at `/dev/shm/` where frames are written in parallel to the GStreamer pipeline. +Enable shared memory output for direct frame access by external processes. This creates a shared memory region at `/dev/shm/` where frames are written. **Note:** Cannot be enabled while streaming is active. Must be enabled before starting the stream. +**Important:** Shared memory can be used **with or without** GStreamer: +- **With GStreamer:** Frames are written to both GStreamer pipeline and shared memory +- **Without GStreamer:** Set pipeline to empty string `""` - frames are only written to shared memory + **Command:** ```json { @@ -698,7 +702,7 @@ Query the current shared memory configuration. ## Usage Examples -### Complete Workflow Example +### Complete Workflow Example (GStreamer + Shared Memory) ```bash # 1. Set GStreamer pipeline for UDP streaming @@ -721,7 +725,7 @@ echo '{"command":"set_ehdr_ratio_max","params":{"value":"24"}}' | socat - UNIX-C # 3b. (Optional) Enable shared memory output echo '{"command":"enable_shared_memory","params":{"name":"/vizion_frame","buffer_size":"8294528"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock -# 4. Start streaming +# 4. Start streaming (both GStreamer and shared memory active) echo '{"command":"start_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock # 5. Check status @@ -735,6 +739,36 @@ echo '{"command":"stop_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock echo '{"command":"disable_shared_memory"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock ``` +### Shared Memory Only Workflow (No GStreamer) + +```bash +# 1. Disable GStreamer pipeline +echo '{"command":"set_pipeline","params":{"pipeline":""}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# 2. Set video format +echo '{"command":"set_format","params":{"width":"1920","height":"1080","framerate":"30","format":"YUY2"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# 3. Configure camera settings +echo '{"command":"set_exposure","params":{"mode":"auto"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock +echo '{"command":"set_brightness","params":{"value":"50"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# 4. Enable shared memory +echo '{"command":"enable_shared_memory","params":{"name":"/vizion_frame","buffer_size":"8294528"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# 5. Start streaming (shared memory only) +echo '{"command":"start_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock +# Output: "GStreamer pipeline disabled (using shared memory only)" + +# 6. Check that shared memory is being updated +ls -l /dev/shm/vizion_frame # Watch file modification time + +# 7. Stop streaming +echo '{"command":"stop_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# 8. Disable shared memory +echo '{"command":"disable_shared_memory"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock +``` + ### GStreamer Pipeline Examples ```bash @@ -819,6 +853,35 @@ ls -lh /dev/shm/vizion_frame watch -n 0.1 'ls -l /dev/shm/vizion_frame' ``` +### Shared Memory WITHOUT GStreamer (Shared Memory Only) + +To use shared memory without GStreamer, disable the GStreamer pipeline by setting it to an empty string: + +```bash +# 1. Disable GStreamer pipeline +echo '{"command":"set_pipeline","params":{"pipeline":""}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# 2. Enable shared memory +echo '{"command":"enable_shared_memory","params":{"name":"/vizion_frame","buffer_size":"8294528"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# 3. Start streaming (frames will only go to shared memory) +echo '{"command":"start_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# Output: "GStreamer pipeline disabled (using shared memory only)" + +# 4. Stop streaming +echo '{"command":"stop_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock + +# 5. Optionally re-enable GStreamer for next session +echo '{"command":"set_pipeline","params":{"pipeline":"videoconvert ! autovideosink"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock +``` + +**Benefits of Shared Memory Only Mode:** +- Lower CPU usage (no GStreamer overhead) +- Lower memory bandwidth (no duplicate frame copies to GStreamer) +- Suitable for headless systems or custom processing pipelines +- Multiple external processes can still read from shared memory simultaneously + ### Using `nc` (netcat with Unix socket support) ```bash @@ -864,7 +927,7 @@ print(send_command("set_ehdr_ratio_min", {"value": "12"})) print(send_command("set_ehdr_ratio_max", {"value": "24"})) print(send_command("get_ehdr_status")) # Get current eHDR settings -# Shared memory control examples +# Shared memory control examples (with GStreamer) print(send_command("enable_shared_memory", { "name": "/vizion_frame", "buffer_size": "8294528" @@ -874,6 +937,17 @@ print(send_command("start_stream")) # ... streaming active, external process can read /dev/shm/vizion_frame ... print(send_command("stop_stream")) print(send_command("disable_shared_memory")) + +# Shared memory only (without GStreamer) +print(send_command("set_pipeline", {"pipeline": ""})) # Disable GStreamer +print(send_command("enable_shared_memory", { + "name": "/vizion_frame", + "buffer_size": "8294528" +})) +print(send_command("start_stream")) # Frames only go to shared memory +# Output: "GStreamer pipeline disabled (using shared memory only)" +print(send_command("stop_stream")) +print(send_command("disable_shared_memory")) ``` ### Using C++ @@ -915,7 +989,7 @@ int main() { std::cout << sendCommand(R"({"command":"set_ehdr_exposure_max","params":{"value":"4"}})") << std::endl; std::cout << sendCommand(R"({"command":"get_ehdr_status"})") << std::endl; - // Shared memory control examples + // Shared memory control examples (with GStreamer) std::cout << sendCommand(R"({"command":"enable_shared_memory","params":{"name":"/vizion_frame","buffer_size":"8294528"}})") << std::endl; std::cout << sendCommand(R"({"command":"get_shared_memory_status"})") << std::endl; std::cout << sendCommand(R"({"command":"start_stream"})") << std::endl; @@ -923,6 +997,14 @@ int main() { std::cout << sendCommand(R"({"command":"stop_stream"})") << std::endl; std::cout << sendCommand(R"({"command":"disable_shared_memory"})") << std::endl; + // Shared memory only (without GStreamer) + std::cout << sendCommand(R"({"command":"set_pipeline","params":{"pipeline":""}})") << std::endl; // Disable GStreamer + std::cout << sendCommand(R"({"command":"enable_shared_memory","params":{"name":"/vizion_frame","buffer_size":"8294528"}})") << std::endl; + std::cout << sendCommand(R"({"command":"start_stream"})") << std::endl; // Frames only go to shared memory + // Output: "GStreamer pipeline disabled (using shared memory only)" + std::cout << sendCommand(R"({"command":"stop_stream"})") << std::endl; + std::cout << sendCommand(R"({"command":"disable_shared_memory"})") << std::endl; + return 0; } ``` @@ -1316,7 +1398,11 @@ finally: - Default pipeline: `videoconvert ! autovideosink` (display locally) - eHDR features require compatible camera models (VCI/VCS/VLS3/VLS-GM2/TEVS-AR0821/AR0822) - eHDR settings may be reset to defaults when the camera starts streaming (driver behavior) -- Shared memory output is independent of GStreamer pipeline (both run in parallel) +- Shared memory output can run with or without GStreamer pipeline: + - **With GStreamer:** Both outputs active (parallel operation) + - **Without GStreamer:** Set pipeline to `""` for shared memory only (lower CPU/memory usage) - Shared memory must be enabled before starting the stream +- At least one output (GStreamer or shared memory) must be configured to start streaming - Shared memory files are automatically cleaned up when disabled or on clean exit - Multiple processes can read from the same shared memory region simultaneously +- Shared memory only mode is recommended for headless systems or custom processing applications diff --git a/src/StreamingEngine.cpp b/src/StreamingEngine.cpp index ac16f5f..ca64350 100644 --- a/src/StreamingEngine.cpp +++ b/src/StreamingEngine.cpp @@ -35,8 +35,14 @@ bool StreamingEngine::start(const std::string& gstPipeline) { return false; } - // Set pipeline description - gstPipeline_->setPipelineDescription(gstPipeline); + // Check if at least one output is configured + const bool useGStreamer = !gstPipeline.empty(); + const bool useSharedMemory = (shmWriter_ && shmWriter_->isCreated()); + + if (!useGStreamer && !useSharedMemory) { + std::cerr << "No output configured. Enable GStreamer pipeline or shared memory first." << std::endl; + return false; + } // Start camera streaming if (VxStartStreaming(camera_) != 0) { @@ -58,11 +64,17 @@ bool StreamingEngine::start(const std::string& gstPipeline) { bufferSize_ = calculatedBufferSize; buffer_ = std::make_unique(bufferSize_); - // Start GStreamer pipeline - if (!gstPipeline_->start()) { - std::cerr << "Failed to start GStreamer pipeline" << std::endl; - VxStopStreaming(camera_); - return false; + // Start GStreamer pipeline if configured + if (useGStreamer) { + gstPipeline_->setPipelineDescription(gstPipeline); + if (!gstPipeline_->start()) { + std::cerr << "Failed to start GStreamer pipeline" << std::endl; + VxStopStreaming(camera_); + return false; + } + std::cout << "GStreamer pipeline started" << std::endl; + } else { + std::cout << "GStreamer pipeline disabled (using shared memory only)" << std::endl; } // Start acquisition thread @@ -85,8 +97,10 @@ void StreamingEngine::stop() { acquisitionThread_->join(); } - // Stop GStreamer pipeline - gstPipeline_->stop(); + // Stop GStreamer pipeline if running + if (gstPipeline_->isRunning()) { + gstPipeline_->stop(); + } // Stop camera streaming VxStopStreaming(camera_); @@ -131,11 +145,13 @@ void StreamingEngine::acquisitionLoop() { default: formatStr = "UNKNOWN"; break; } - // Push frame to GStreamer pipeline - if (!gstPipeline_->pushBuffer(buffer_.get(), dataSize, - currentFormat_.width, currentFormat_.height, - formatStr)) { - std::cerr << "Failed to push frame to GStreamer pipeline" << std::endl; + // Push frame to GStreamer pipeline if active + if (gstPipeline_->isRunning()) { + if (!gstPipeline_->pushBuffer(buffer_.get(), dataSize, + currentFormat_.width, currentFormat_.height, + formatStr)) { + std::cerr << "Failed to push frame to GStreamer pipeline" << std::endl; + } } // Push frame to shared memory if enabled