Compare commits

...

10 Commits

Author SHA1 Message Date
Maik Jurischka
2b769bfe5e clang optimizations 2025-12-29 15:49:00 +01:00
Maik Jurischka
bb9b5cc619 re-organize folder structure 2025-12-19 13:08:28 +01:00
Maik Jurischka
a2d2f256cf add license information 2025-12-19 09:57:28 +01:00
Maik Jurischka
e8444b09e5 add license information 2025-12-19 09:56:03 +01:00
Maik Jurischka
530d447717 add license information 2025-12-19 09:49:21 +01:00
Maik Jurischka
0fd3fe4ce6 add license information 2025-12-19 09:49:11 +01:00
Maik Jurischka
1c61e76eb4 add credits 2025-12-19 09:39:14 +01:00
Maik Jurischka
6fdae6be7b add credits 2025-12-19 09:38:30 +01:00
Maik Jurischka
a6cf510607 add eHDR controls 2025-12-19 09:12:54 +01:00
Maik Jurischka
e729354c8f add hint for VizionSDK dependency 2025-12-19 07:46:29 +01:00
14 changed files with 548 additions and 67 deletions

View File

@@ -11,6 +11,9 @@ set(VIZIONSDK_LIB_DIR "${VIZIONSDK_ROOT}/lib")
# Add VizionSDK include directory # Add VizionSDK include directory
include_directories(${VIZIONSDK_INCLUDE_DIR}) include_directories(${VIZIONSDK_INCLUDE_DIR})
# Add project include directory
include_directories(${CMAKE_SOURCE_DIR}/include)
# ---------------- GStreamer integration ---------------- # ---------------- GStreamer integration ----------------
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0) pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
@@ -36,11 +39,11 @@ find_library(VIZIONSDK_LIBRARY
# Create executable # Create executable
add_executable(vizionStreamer add_executable(vizionStreamer
main.cpp src/main.cpp
SocketServer.cpp src/SocketServer.cpp
CameraController.cpp src/CameraController.cpp
GStreamerPipeline.cpp src/GStreamerPipeline.cpp
StreamingEngine.cpp src/StreamingEngine.cpp
) )
# Link libraries # Link libraries

37
LICENSE Normal file
View File

@@ -0,0 +1,37 @@
VizionStreamer
Copyright (c) 2025 Maik Jurischka
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
You are free to:
- Share — copy and redistribute the material in any medium or format
- Adapt — remix, transform, and build upon the material
Under the following terms:
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
- NonCommercial — You may not use the material for commercial purposes.
- ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
Full license text: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
===============================================================================
THIRD-PARTY DEPENDENCIES:
This software uses the following third-party libraries:
1. VizionSDK
Copyright (c) 2025 TechNexion Ltd.
Licensed under MIT License
https://github.com/TechNexion-Vision/vizionsdk/blob/main/LICENSE
2. GStreamer
Licensed under LGPL
https://gstreamer.freedesktop.org/
===============================================================================
DISCLAIMER:
This software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.

View File

@@ -2,6 +2,8 @@
High-performance video streaming application for Technexion cameras with GStreamer integration and Unix Domain Socket control interface. High-performance video streaming application for Technexion cameras with GStreamer integration and Unix Domain Socket control interface.
Depends on: https://github.com/TechNexion-Vision/vizionsdk
## Features ## Features
- **Continuous Frame Acquisition**: Dedicated thread for frame capture from VizionSDK - **Continuous Frame Acquisition**: Dedicated thread for frame capture from VizionSDK
@@ -131,7 +133,7 @@ firefox http://localhost:8080
## Socket Control API ## Socket Control API
Full API documentation: [SOCKET_API.md](SOCKET_API.md) Full API documentation: [SOCKET_API.md](docs/SOCKET_API.md)
**Socket Path**: `/tmp/vizion_control.sock` **Socket Path**: `/tmp/vizion_control.sock`
@@ -151,6 +153,12 @@ Full API documentation: [SOCKET_API.md](SOCKET_API.md)
- `set_sharpness` - Adjust sharpness - `set_sharpness` - Adjust sharpness
- `set_gamma` - Adjust gamma - `set_gamma` - Adjust gamma
- `set_gain` - Adjust gain - `set_gain` - Adjust gain
- `set_ehdr_mode` - Enable/disable eHDR (compatible cameras only)
- `set_ehdr_exposure_min` - Set eHDR minimum exposure frames
- `set_ehdr_exposure_max` - Set eHDR maximum exposure frames
- `set_ehdr_ratio_min` - Set eHDR minimum exposure ratio
- `set_ehdr_ratio_max` - Set eHDR maximum exposure ratio
- `get_ehdr_status` - Get current eHDR settings
### Example ### Example
@@ -218,23 +226,32 @@ sudo apt install build-essential cmake pkg-config socat \
``` ```
vizionStreamer/ vizionStreamer/
├── main.cpp # Main application
├── SocketServer.{h,cpp} # Unix domain socket server
├── CameraController.{h,cpp} # Command processing & camera control
├── StreamingEngine.{h,cpp} # Acquisition loop & streaming
├── GStreamerPipeline.{h,cpp} # GStreamer pipeline wrapper
├── CMakeLists.txt # Build configuration ├── CMakeLists.txt # Build configuration
├── config/ ├── LICENSE # Project license
│ └── VxConfig.conf # VizionSDK configuration ├── README.md # This file
├── scripts/ # Control scripts ├── include/ # Public header files
── README.md ── vizionstreamer/
├── start_stream.sh ├── CameraController.h
├── stop_stream.sh ├── SocketServer.h
├── get_status.sh ├── StreamingEngine.h
├── set_pipeline_*.sh └── GStreamerPipeline.h
│ └── get_formats.sh ├── src/ # Implementation files
├── SOCKET_API.md # Complete API documentation │ ├── main.cpp
└── README.md # This file │ ├── CameraController.cpp
│ ├── SocketServer.cpp
│ ├── StreamingEngine.cpp
│ └── GStreamerPipeline.cpp
├── config/ # Configuration files
│ └── VxConfig.conf
├── docs/ # Documentation
│ └── SOCKET_API.md
└── scripts/ # Control scripts
├── README.md
├── start_stream.sh
├── stop_stream.sh
├── get_status.sh
├── set_pipeline_*.sh
└── get_formats.sh
``` ```
## Configuration Files ## Configuration Files
@@ -280,11 +297,42 @@ Typical performance:
## License ## License
See VizionSDK license terms. **VizionStreamer**
Copyright (c) 2025 Maik Jurischka
This work is licensed under the **Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License** (CC BY-NC-SA 4.0).
### You are free to:
- **Share** — copy and redistribute the material in any medium or format
- **Adapt** — remix, transform, and build upon the material
### Under the following terms:
- **Attribution** — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
- **NonCommercial** — You may not use the material for commercial purposes.
- **ShareAlike** — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
**Full license text**: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
### Disclaimer
This software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.
### Third-Party Dependencies
This software uses the following dependencies:
- **VizionSDK**
Copyright (c) 2025 TechNexion Ltd.
Licensed under MIT License
https://github.com/TechNexion-Vision/vizionsdk/blob/main/LICENSE
- **GStreamer**
Licensed under LGPL
https://gstreamer.freedesktop.org/
## Support ## Support
For issues and questions, refer to: For issues and questions, refer to:
- [SOCKET_API.md](SOCKET_API.md) - Complete API reference - [SOCKET_API.md](docs/SOCKET_API.md) - Complete API reference
- [scripts/README.md](scripts/README.md) - Script usage guide - [scripts/README.md](scripts/README.md) - Script usage guide
- VizionSDK documentation at `/opt/vizionsdk/` - VizionSDK documentation at https://developer.technexion.com/docs/vision-software/vizionsdk/

View File

@@ -2,6 +2,9 @@
VizionStreamer can be controlled via a Unix Domain Socket interface. This allows external applications to configure camera parameters and stream settings at runtime. VizionStreamer can be controlled via a Unix Domain Socket interface. This allows external applications to configure camera parameters and stream settings at runtime.
**Copyright (c) 2025 Maik Jurischka**
Licensed under CC BY-NC-SA 4.0 - https://creativecommons.org/licenses/by-nc-sa/4.0/
## Socket Connection ## Socket Connection
- **Socket Path**: `/tmp/vizion_control.sock` - **Socket Path**: `/tmp/vizion_control.sock`
@@ -433,6 +436,168 @@ Adjust camera gain.
--- ---
### 15. Set eHDR Mode
Enable or disable eHDR (Enhanced High Dynamic Range) mode.
**Note:** eHDR features are only available on specific camera models: VCI-AR0821/AR0822, VCS-AR0821/AR0822, VLS3-AR0821/AR0822, VLS-GM2-AR0821/AR0822, and TEVS-AR0821/AR0822.
**Command:**
```json
{
"command": "set_ehdr_mode",
"params": {
"mode": "0"
}
}
```
**Parameters:**
- `mode`: "0" to enable eHDR, "1" to disable eHDR
**Response:**
```json
{
"status": "success",
"message": "eHDR mode set successfully"
}
```
---
### 16. Set eHDR Exposure Minimum
Set the minimum number of exposure frames for eHDR.
**Command:**
```json
{
"command": "set_ehdr_exposure_min",
"params": {
"value": "1"
}
}
```
**Parameters:**
- `value`: Minimum exposure frames (range: 1-4, default: 1)
**Response:**
```json
{
"status": "success",
"message": "eHDR exposure min set successfully"
}
```
---
### 17. Set eHDR Exposure Maximum
Set the maximum number of exposure frames for eHDR.
**Command:**
```json
{
"command": "set_ehdr_exposure_max",
"params": {
"value": "4"
}
}
```
**Parameters:**
- `value`: Maximum exposure frames (range: 1-4, default: 4)
**Response:**
```json
{
"status": "success",
"message": "eHDR exposure max set successfully"
}
```
---
### 18. Set eHDR Ratio Minimum
Set the minimum exposure ratio for eHDR.
**Command:**
```json
{
"command": "set_ehdr_ratio_min",
"params": {
"value": "12"
}
}
```
**Parameters:**
- `value`: Minimum exposure ratio (range: 1-128, default: 12)
**Response:**
```json
{
"status": "success",
"message": "eHDR ratio min set successfully"
}
```
---
### 19. Set eHDR Ratio Maximum
Set the maximum exposure ratio for eHDR.
**Command:**
```json
{
"command": "set_ehdr_ratio_max",
"params": {
"value": "24"
}
}
```
**Parameters:**
- `value`: Maximum exposure ratio (range: 1-128, default: 24)
**Response:**
```json
{
"status": "success",
"message": "eHDR ratio max set successfully"
}
```
---
### 20. Get eHDR Status
Retrieve all current eHDR settings.
**Command:**
```json
{
"command": "get_ehdr_status"
}
```
**Response:**
```json
{
"status": "success",
"ehdr_mode": 0,
"exposure_min": 1,
"exposure_max": 4,
"ratio_min": 12,
"ratio_max": 24
}
```
---
## Usage Examples ## Usage Examples
### Complete Workflow Example ### Complete Workflow Example
@@ -448,6 +613,13 @@ echo '{"command":"set_format","params":{"width":"1920","height":"1080","framerat
echo '{"command":"set_exposure","params":{"mode":"auto"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock 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 echo '{"command":"set_brightness","params":{"value":"50"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
# 3a. (Optional) Configure eHDR settings (for compatible cameras)
echo '{"command":"set_ehdr_mode","params":{"mode":"0"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
echo '{"command":"set_ehdr_exposure_min","params":{"value":"1"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
echo '{"command":"set_ehdr_exposure_max","params":{"value":"4"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
echo '{"command":"set_ehdr_ratio_min","params":{"value":"12"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
echo '{"command":"set_ehdr_ratio_max","params":{"value":"24"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
# 4. Start streaming # 4. Start streaming
echo '{"command":"start_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock echo '{"command":"start_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
@@ -499,6 +671,27 @@ echo '{"command":"get_status"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
echo '{"command":"stop_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock echo '{"command":"stop_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
``` ```
### eHDR Control Examples
```bash
# Enable eHDR mode
echo '{"command":"set_ehdr_mode","params":{"mode":"0"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
# Disable eHDR mode
echo '{"command":"set_ehdr_mode","params":{"mode":"1"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
# Configure eHDR exposure range
echo '{"command":"set_ehdr_exposure_min","params":{"value":"1"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
echo '{"command":"set_ehdr_exposure_max","params":{"value":"4"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
# Configure eHDR ratio range
echo '{"command":"set_ehdr_ratio_min","params":{"value":"12"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
echo '{"command":"set_ehdr_ratio_max","params":{"value":"24"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
# Get current eHDR settings
echo '{"command":"get_ehdr_status"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
```
### Using `nc` (netcat with Unix socket support) ### Using `nc` (netcat with Unix socket support)
```bash ```bash
@@ -535,6 +728,14 @@ print(send_command("set_format", {
})) }))
print(send_command("set_exposure", {"mode": "auto"})) print(send_command("set_exposure", {"mode": "auto"}))
print(send_command("start_stream")) print(send_command("start_stream"))
# eHDR control examples (for compatible cameras)
print(send_command("set_ehdr_mode", {"mode": "0"})) # Enable eHDR
print(send_command("set_ehdr_exposure_min", {"value": "1"}))
print(send_command("set_ehdr_exposure_max", {"value": "4"}))
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
``` ```
### Using C++ ### Using C++
@@ -569,6 +770,13 @@ std::string sendCommand(const std::string& command) {
int main() { int main() {
std::cout << sendCommand(R"({"command":"get_formats"})") << std::endl; std::cout << sendCommand(R"({"command":"get_formats"})") << std::endl;
std::cout << sendCommand(R"({"command":"set_brightness","params":{"value":"50"}})") << std::endl; std::cout << sendCommand(R"({"command":"set_brightness","params":{"value":"50"}})") << std::endl;
// eHDR control examples (for compatible cameras)
std::cout << sendCommand(R"({"command":"set_ehdr_mode","params":{"mode":"0"}})") << std::endl;
std::cout << sendCommand(R"({"command":"set_ehdr_exposure_min","params":{"value":"1"}})") << std::endl;
std::cout << sendCommand(R"({"command":"set_ehdr_exposure_max","params":{"value":"4"}})") << std::endl;
std::cout << sendCommand(R"({"command":"get_ehdr_status"})") << std::endl;
return 0; return 0;
} }
``` ```
@@ -587,6 +795,20 @@ The valid ranges for camera parameters depend on the specific camera model. You
- Exposure: 1-10000 (in auto mode, value is ignored) - Exposure: 1-10000 (in auto mode, value is ignored)
- White Balance Temperature: 2800-6500 Kelvin - White Balance Temperature: 2800-6500 Kelvin
**eHDR ranges (for compatible cameras only):**
- eHDR Mode: 0 (enable) or 1 (disable)
- eHDR Exposure Min: 1-4 (default: 1)
- eHDR Exposure Max: 1-4 (default: 4)
- eHDR Ratio Min: 1-128 (default: 12)
- eHDR Ratio Max: 1-128 (default: 24)
**Compatible eHDR Camera Models:**
- VCI-AR0821/AR0822
- VCS-AR0821/AR0822
- VLS3-AR0821/AR0822
- VLS-GM2-AR0821/AR0822
- TEVS-AR0821/AR0822
## Error Handling ## Error Handling
Always check the `status` field in the response: Always check the `status` field in the response:
@@ -661,3 +883,5 @@ curl http://192.168.1.100:8080 > stream.mjpg
- Invalid parameter values will return an error response - Invalid parameter values will return an error response
- GStreamer pipeline errors will be reported when starting the stream - GStreamer pipeline errors will be reported when starting the stream
- Default pipeline: `videoconvert ! autovideosink` (display locally) - 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)

View File

@@ -1,7 +1,15 @@
/*
* VizionStreamer - Camera Control Interface
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#pragma once #pragma once
#include <vizionsdk/VizionSDK.h> #include <vizionsdk/VizionSDK.h>
#include "StreamingEngine.h" #include "vizionstreamer/StreamingEngine.h"
#include <memory> #include <memory>
#include <string> #include <string>
#include <mutex> #include <mutex>
@@ -33,12 +41,21 @@ private:
std::string handleStartStream(); std::string handleStartStream();
std::string handleStopStream(); std::string handleStopStream();
std::string handleSetPipeline(const std::string& pipeline); std::string handleSetPipeline(const std::string& pipeline);
std::string handleSetEHDRMode(const std::string& value);
std::string handleSetEHDRExposureMin(const std::string& value);
std::string handleSetEHDRExposureMax(const std::string& value);
std::string handleSetEHDRRatioMin(const std::string& value);
std::string handleSetEHDRRatioMax(const std::string& value);
std::string handleGetEHDRStatus();
// Helper functions // Helper functions
VX_IMAGE_FORMAT stringToFormat(const std::string& format); static VX_IMAGE_FORMAT stringToFormat(const std::string& format);
std::string formatToString(VX_IMAGE_FORMAT format);
std::string createErrorResponse(const std::string& error); static std::string formatToString(VX_IMAGE_FORMAT format);
std::string createSuccessResponse(const std::string& message = "");
static std::string createErrorResponse(const std::string& error);
static std::string createSuccessResponse(const std::string& message = "");
std::shared_ptr<VxCamera> camera_; std::shared_ptr<VxCamera> camera_;
std::shared_ptr<StreamingEngine> streamingEngine_; std::shared_ptr<StreamingEngine> streamingEngine_;

View File

@@ -1,3 +1,11 @@
/*
* VizionStreamer - GStreamer Pipeline Interface
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#pragma once #pragma once
#include <gst/gst.h> #include <gst/gst.h>

View File

@@ -1,3 +1,11 @@
/*
* VizionStreamer - Unix Socket Server Interface
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#pragma once #pragma once
#include <string> #include <string>
@@ -19,7 +27,7 @@ public:
private: private:
void serverLoop(); void serverLoop();
void handleClient(int clientFd); void handleClient(int clientFd) const;
std::string socketPath_; std::string socketPath_;
int serverFd_; int serverFd_;

View File

@@ -1,7 +1,15 @@
/*
* VizionStreamer - Streaming Engine Interface
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#pragma once #pragma once
#include <vizionsdk/VizionSDK.h> #include <vizionsdk/VizionSDK.h>
#include "GStreamerPipeline.h" #include "vizionstreamer/GStreamerPipeline.h"
#include <memory> #include <memory>
#include <thread> #include <thread>
#include <atomic> #include <atomic>

View File

@@ -2,6 +2,9 @@
Diese Scripts ermöglichen die schnelle Steuerung von VizionStreamer über die Unix Domain Socket API. Diese Scripts ermöglichen die schnelle Steuerung von VizionStreamer über die Unix Domain Socket API.
**Copyright (c) 2025 Maik Jurischka**
Lizenziert unter CC BY-NC-SA 4.0 - https://creativecommons.org/licenses/by-nc-sa/4.0/
## Voraussetzung ## Voraussetzung
VizionStreamer muss laufen: VizionStreamer muss laufen:

View File

@@ -1,4 +1,12 @@
#include "CameraController.h" /*
* VizionStreamer - Camera Control Implementation
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#include "vizionstreamer/CameraController.h"
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
@@ -18,9 +26,9 @@ std::string CameraController::processCommand(const std::string& jsonCommand) {
return createErrorResponse("Missing command field"); return createErrorResponse("Missing command field");
} }
const size_t colonPos = jsonCommand.find(":", cmdPos); const size_t colonPos = jsonCommand.find(':', cmdPos);
const size_t quoteStart = jsonCommand.find("\"", colonPos); const size_t quoteStart = jsonCommand.find('\"', colonPos);
const size_t quoteEnd = jsonCommand.find("\"", quoteStart + 1); const size_t quoteEnd = jsonCommand.find('\"', quoteStart + 1);
if (quoteStart == std::string::npos || quoteEnd == std::string::npos) { if (quoteStart == std::string::npos || quoteEnd == std::string::npos) {
return createErrorResponse("Invalid command format"); return createErrorResponse("Invalid command format");
@@ -33,10 +41,10 @@ std::string CameraController::processCommand(const std::string& jsonCommand) {
const size_t pos = jsonCommand.find("\"" + paramName + "\""); const size_t pos = jsonCommand.find("\"" + paramName + "\"");
if (pos == std::string::npos) return ""; if (pos == std::string::npos) return "";
const size_t colonPos = jsonCommand.find(":", pos); const size_t colonPos = jsonCommand.find(':', pos);
if (size_t valueStart = jsonCommand.find_first_not_of(" \t\n\r", colonPos + 1); jsonCommand[valueStart] == '\"') { if (size_t valueStart = jsonCommand.find_first_not_of(" \t\n\r", colonPos + 1); jsonCommand[valueStart] == '\"') {
size_t valueEnd = jsonCommand.find("\"", valueStart + 1); size_t valueEnd = jsonCommand.find('\"', valueStart + 1);
return jsonCommand.substr(valueStart + 1, valueEnd - valueStart - 1); return jsonCommand.substr(valueStart + 1, valueEnd - valueStart - 1);
} else { } else {
size_t valueEnd = jsonCommand.find_first_of(",}", valueStart); size_t valueEnd = jsonCommand.find_first_of(",}", valueStart);
@@ -74,6 +82,18 @@ std::string CameraController::processCommand(const std::string& jsonCommand) {
return handleStopStream(); return handleStopStream();
} else if (command == "set_pipeline") { } else if (command == "set_pipeline") {
return handleSetPipeline(getParam("pipeline")); return handleSetPipeline(getParam("pipeline"));
} else if (command == "set_ehdr_mode") {
return handleSetEHDRMode(getParam("mode"));
} else if (command == "set_ehdr_exposure_min") {
return handleSetEHDRExposureMin(getParam("value"));
} else if (command == "set_ehdr_exposure_max") {
return handleSetEHDRExposureMax(getParam("value"));
} else if (command == "set_ehdr_ratio_min") {
return handleSetEHDRRatioMin(getParam("value"));
} else if (command == "set_ehdr_ratio_max") {
return handleSetEHDRRatioMax(getParam("value"));
} else if (command == "get_ehdr_status") {
return handleGetEHDRStatus();
} else { } else {
return createErrorResponse("Unknown command: " + command); return createErrorResponse("Unknown command: " + command);
} }
@@ -86,7 +106,7 @@ std::string CameraController::handleSetFormat(const std::string& width, const st
} }
try { try {
VxFormat fmt; VxFormat fmt{};
fmt.width = std::stoi(width); fmt.width = std::stoi(width);
fmt.height = std::stoi(height); fmt.height = std::stoi(height);
fmt.framerate = std::stoi(framerate); fmt.framerate = std::stoi(framerate);
@@ -111,13 +131,13 @@ std::string CameraController::handleGetFormats() {
} }
std::ostringstream oss; std::ostringstream oss;
oss << "{\"status\":\"success\",\"formats\":["; oss << R"({"status":"success","formats":[)";
for (size_t i = 0; i < fmtList.size(); i++) { for (size_t i = 0; i < fmtList.size(); i++) {
if (i > 0) oss << ","; if (i > 0) oss << ",";
oss << "{\"width\":" << fmtList[i].width oss << "{\"width\":" << fmtList[i].width
<< ",\"height\":" << fmtList[i].height << ",\"height\":" << fmtList[i].height
<< ",\"framerate\":" << fmtList[i].framerate << ",\"framerate\":" << fmtList[i].framerate
<< ",\"format\":\"" << formatToString(fmtList[i].format) << "\"}"; << R"(,"format":")" << formatToString(fmtList[i].format) << "\"}";
} }
oss << "]}"; oss << "]}";
return oss.str(); return oss.str();
@@ -233,10 +253,93 @@ std::string CameraController::handleSetGain(const std::string& value) {
} }
} }
std::string CameraController::handleSetEHDRMode(const std::string& value) {
try {
const int mode = std::stoi(value);
if (VxSetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_IMAGE_EHDR_MODE, mode) != 0) {
return createErrorResponse("Failed to set eHDR mode");
}
return createSuccessResponse("eHDR mode set successfully");
} catch (const std::exception& e) {
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
}
}
std::string CameraController::handleSetEHDRExposureMin(const std::string& value) {
try {
const int minExp = std::stoi(value);
if (VxSetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_EHDR_EXPOSURE_MIN_NUMBER, minExp) != 0) {
return createErrorResponse("Failed to set eHDR exposure min");
}
return createSuccessResponse("eHDR exposure min set successfully");
} catch (const std::exception& e) {
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
}
}
std::string CameraController::handleSetEHDRExposureMax(const std::string& value) {
try {
const int maxExp = std::stoi(value);
if (VxSetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_EHDR_EXPOSURE_MAX_NUMBER, maxExp) != 0) {
return createErrorResponse("Failed to set eHDR exposure max");
}
return createSuccessResponse("eHDR exposure max set successfully");
} catch (const std::exception& e) {
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
}
}
std::string CameraController::handleSetEHDRRatioMin(const std::string& value) {
try {
const int minRatio = std::stoi(value);
if (VxSetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_EHDR_RATIO_MIN, minRatio) != 0) {
return createErrorResponse("Failed to set eHDR ratio min");
}
return createSuccessResponse("eHDR ratio min set successfully");
} catch (const std::exception& e) {
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
}
}
std::string CameraController::handleSetEHDRRatioMax(const std::string& value) {
try {
const int maxRatio = std::stoi(value);
if (VxSetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_EHDR_RATIO_MAX, maxRatio) != 0) {
return createErrorResponse("Failed to set eHDR ratio max");
}
return createSuccessResponse("eHDR ratio max set successfully");
} catch (const std::exception& e) {
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
}
}
std::string CameraController::handleGetEHDRStatus() {
int mode = 0, flag = 0;
int expMin = 0, expMax = 0;
int ratioMin = 0, ratioMax = 0;
if (VxGetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_IMAGE_EHDR_MODE, mode, flag) != 0) {
return createErrorResponse("Failed to get eHDR mode");
}
VxGetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_EHDR_EXPOSURE_MIN_NUMBER, expMin, flag);
VxGetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_EHDR_EXPOSURE_MAX_NUMBER, expMax, flag);
VxGetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_EHDR_RATIO_MIN, ratioMin, flag);
VxGetISPImageProcessing(camera_, VX_ISP_IMAGE_PROPERTIES::ISP_EHDR_RATIO_MAX, ratioMax, flag);
std::ostringstream oss;
oss << R"({"status":"success","ehdr_mode":)" << mode
<< ",\"exposure_min\":" << expMin
<< ",\"exposure_max\":" << expMax
<< ",\"ratio_min\":" << ratioMin
<< ",\"ratio_max\":" << ratioMax << "}";
return oss.str();
}
std::string CameraController::handleGetStatus() { std::string CameraController::handleGetStatus() {
std::ostringstream oss; std::ostringstream oss;
oss << "{\"status\":\"success\",\"streaming\":" << (streamingEngine_->isRunning() ? "true" : "false") oss << R"({"status":"success","streaming":)" << (streamingEngine_->isRunning() ? "true" : "false")
<< ",\"pipeline\":\"" << gstPipeline_ << "\"}"; << R"(,"pipeline":")" << gstPipeline_ << "\"}";
return oss.str(); return oss.str();
} }
@@ -285,7 +388,7 @@ VX_IMAGE_FORMAT CameraController::stringToFormat(const std::string& format) {
return VX_IMAGE_FORMAT::NONE; return VX_IMAGE_FORMAT::NONE;
} }
std::string CameraController::formatToString(VX_IMAGE_FORMAT format) { std::string CameraController::formatToString(const VX_IMAGE_FORMAT format) {
switch (format) { switch (format) {
case VX_IMAGE_FORMAT::YUY2: return "YUY2"; case VX_IMAGE_FORMAT::YUY2: return "YUY2";
case VX_IMAGE_FORMAT::UYVY: return "UYVY"; case VX_IMAGE_FORMAT::UYVY: return "UYVY";
@@ -298,12 +401,12 @@ std::string CameraController::formatToString(VX_IMAGE_FORMAT format) {
} }
std::string CameraController::createErrorResponse(const std::string& error) { std::string CameraController::createErrorResponse(const std::string& error) {
return "{\"status\":\"error\",\"message\":\"" + error + "\"}"; return R"({"status":"error","message":")" + error + "\"}";
} }
std::string CameraController::createSuccessResponse(const std::string& message) { std::string CameraController::createSuccessResponse(const std::string& message) {
if (message.empty()) { if (message.empty()) {
return "{\"status\":\"success\"}"; return R"({"status":"success"})";
} }
return "{\"status\":\"success\",\"message\":\"" + message + "\"}"; return R"({"status":"success","message":")" + message + "\"}";
} }

View File

@@ -1,4 +1,12 @@
#include "GStreamerPipeline.h" /*
* VizionStreamer - GStreamer Pipeline Implementation
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#include "vizionstreamer/GStreamerPipeline.h"
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#include <utility> #include <utility>

View File

@@ -1,4 +1,12 @@
#include "SocketServer.h" /*
* VizionStreamer - Unix Socket Server Implementation
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#include "vizionstreamer/SocketServer.h"
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
@@ -19,10 +27,8 @@ bool SocketServer::start(CommandCallback callback) {
commandCallback_ = std::move(callback); commandCallback_ = std::move(callback);
// Remove existing socket file if it exists
unlink(socketPath_.c_str()); unlink(socketPath_.c_str());
// Create Unix domain socket
serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0); serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0);
if (serverFd_ < 0) { if (serverFd_ < 0) {
std::cerr << "Failed to create socket" << std::endl; std::cerr << "Failed to create socket" << std::endl;
@@ -62,14 +68,12 @@ void SocketServer::stop() {
running_ = false; running_ = false;
// Close server socket to unblock accept()
if (serverFd_ >= 0) { if (serverFd_ >= 0) {
shutdown(serverFd_, SHUT_RDWR); shutdown(serverFd_, SHUT_RDWR);
close(serverFd_); close(serverFd_);
serverFd_ = -1; serverFd_ = -1;
} }
// Wait for server thread to finish
if (serverThread_ && serverThread_->joinable()) { if (serverThread_ && serverThread_->joinable()) {
serverThread_->join(); serverThread_->join();
} }
@@ -93,7 +97,7 @@ void SocketServer::serverLoop() {
} }
} }
void SocketServer::handleClient(const int clientFd) { void SocketServer::handleClient(const int clientFd) const {
char buffer[4096]; char buffer[4096];
const ssize_t bytesRead = recv(clientFd, buffer, sizeof(buffer) - 1, 0); const ssize_t bytesRead = recv(clientFd, buffer, sizeof(buffer) - 1, 0);
@@ -101,10 +105,8 @@ void SocketServer::handleClient(const int clientFd) {
buffer[bytesRead] = '\0'; buffer[bytesRead] = '\0';
const std::string command(buffer); const std::string command(buffer);
// Call the command callback
const std::string response = commandCallback_(command); const std::string response = commandCallback_(command);
// Send response back to client
send(clientFd, response.c_str(), response.length(), 0); send(clientFd, response.c_str(), response.length(), 0);
} }
} }

View File

@@ -1,10 +1,18 @@
#include "StreamingEngine.h" /*
* VizionStreamer - Streaming Engine Implementation
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#include "vizionstreamer/StreamingEngine.h"
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>
#include <utility> #include <utility>
StreamingEngine::StreamingEngine(std::shared_ptr<VxCamera> camera) StreamingEngine::StreamingEngine(std::shared_ptr<VxCamera> camera)
: camera_(std::move(camera)), running_(false), bufferSize_(0) { : camera_(std::move(camera)), running_(false), currentFormat_(), bufferSize_(0) {
gstPipeline_ = std::make_unique<GStreamerPipeline>(""); gstPipeline_ = std::make_unique<GStreamerPipeline>("");
} }

View File

@@ -1,10 +1,18 @@
/*
* VizionStreamer - Main Application
* Copyright (c) 2025 Maik Jurischka
*
* Licensed under CC BY-NC-SA 4.0
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <csignal> #include <csignal>
#include <atomic> #include <atomic>
#include <vizionsdk/VizionSDK.h> #include <vizionsdk/VizionSDK.h>
#include "SocketServer.h" #include "vizionstreamer/SocketServer.h"
#include "CameraController.h" #include "vizionstreamer/CameraController.h"
std::atomic<bool> g_running(true); std::atomic<bool> g_running(true);
@@ -71,10 +79,8 @@ int main() {
std::cout << "Initial format: " << fmtList[0].width << "x" << fmtList[0].height std::cout << "Initial format: " << fmtList[0].width << "x" << fmtList[0].height
<< " @ " << fmtList[0].framerate << " fps" << std::endl; << " @ " << fmtList[0].framerate << " fps" << std::endl;
// Create camera controller
const auto controller = std::make_shared<CameraController>(cam); const auto controller = std::make_shared<CameraController>(cam);
// Start Unix domain socket server
const std::string socketPath = "/tmp/vizion_control.sock"; const std::string socketPath = "/tmp/vizion_control.sock";
SocketServer server(socketPath); SocketServer server(socketPath);
@@ -88,8 +94,9 @@ int main() {
std::cout << "\n========================================" << std::endl; std::cout << "\n========================================" << std::endl;
std::cout << "VizionStreamer Ready" << std::endl; std::cout << "VizionStreamer Ready" << std::endl;
std::cout << "Author: Maik Jurischka <m.jurischka@scidre.de" << std::endl; std::cout << "Author: Maik Jurischka <maik@skadilabs.de>" << std::endl;
std::cout << "========================================" << std::endl; std::cout << "License: CC BY-NC-SA 4.0 -> https://creativecommons.org/licenses/by-nc-sa/4.0/" << std::endl;
std::cout << "========================================" << std::endl << std::endl;
std::cout << "Control socket: " << socketPath << std::endl; std::cout << "Control socket: " << socketPath << std::endl;
std::cout << "Default pipeline: videoconvert ! autovideosink" << std::endl; std::cout << "Default pipeline: videoconvert ! autovideosink" << std::endl;
std::cout << "\nQuick start:" << std::endl; std::cout << "\nQuick start:" << std::endl;
@@ -98,15 +105,12 @@ int main() {
std::cout << R"( echo '{"command":"set_pipeline","params":{"pipeline":"YOUR_PIPELINE"}}' | socat - UNIX-CONNECT:)" << socketPath << std::endl; std::cout << R"( echo '{"command":"set_pipeline","params":{"pipeline":"YOUR_PIPELINE"}}' | socat - UNIX-CONNECT:)" << socketPath << std::endl;
std::cout << "\nPress Ctrl+C to exit.\n" << std::endl; std::cout << "\nPress Ctrl+C to exit.\n" << std::endl;
// Main loop - keep running until signaled to stop
while (g_running) { while (g_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
// Cleanup
std::cout << "Shutting down..." << std::endl; std::cout << "Shutting down..." << std::endl;
// Stop streaming engine if running
if (controller->getStreamingEngine()->isRunning()) { if (controller->getStreamingEngine()->isRunning()) {
controller->getStreamingEngine()->stop(); controller->getStreamingEngine()->stop();
} }