add Unix Socket API
This commit is contained in:
@@ -20,7 +20,11 @@ find_library(VIZIONSDK_LIBRARY
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Create executable
|
# Create executable
|
||||||
add_executable(vizionStreamer main.cpp)
|
add_executable(vizionStreamer
|
||||||
|
main.cpp
|
||||||
|
SocketServer.cpp
|
||||||
|
CameraController.cpp
|
||||||
|
)
|
||||||
|
|
||||||
# Link VizionSDK library
|
# Link VizionSDK library
|
||||||
target_link_libraries(vizionStreamer PRIVATE ${VIZIONSDK_LIBRARY})
|
target_link_libraries(vizionStreamer PRIVATE ${VIZIONSDK_LIBRARY})
|
||||||
|
|||||||
295
CameraController.cpp
Normal file
295
CameraController.cpp
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
#include "CameraController.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
CameraController::CameraController(std::shared_ptr<VxCamera> camera)
|
||||||
|
: camera_(camera), streaming_(false) {}
|
||||||
|
|
||||||
|
std::string CameraController::processCommand(const std::string& jsonCommand) {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
// Simple JSON parsing (basic implementation)
|
||||||
|
// Format: {"command":"name","params":{...}}
|
||||||
|
|
||||||
|
size_t cmdPos = jsonCommand.find("\"command\"");
|
||||||
|
if (cmdPos == std::string::npos) {
|
||||||
|
return createErrorResponse("Missing command field");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t colonPos = jsonCommand.find(":", cmdPos);
|
||||||
|
size_t quoteStart = jsonCommand.find("\"", colonPos);
|
||||||
|
size_t quoteEnd = jsonCommand.find("\"", quoteStart + 1);
|
||||||
|
|
||||||
|
if (quoteStart == std::string::npos || quoteEnd == std::string::npos) {
|
||||||
|
return createErrorResponse("Invalid command format");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string command = jsonCommand.substr(quoteStart + 1, quoteEnd - quoteStart - 1);
|
||||||
|
|
||||||
|
// Helper lambda to extract parameter value
|
||||||
|
auto getParam = [&jsonCommand](const std::string& paramName) -> std::string {
|
||||||
|
size_t pos = jsonCommand.find("\"" + paramName + "\"");
|
||||||
|
if (pos == std::string::npos) return "";
|
||||||
|
|
||||||
|
size_t colonPos = jsonCommand.find(":", pos);
|
||||||
|
size_t valueStart = jsonCommand.find_first_not_of(" \t\n\r", colonPos + 1);
|
||||||
|
|
||||||
|
if (jsonCommand[valueStart] == '\"') {
|
||||||
|
size_t valueEnd = jsonCommand.find("\"", valueStart + 1);
|
||||||
|
return jsonCommand.substr(valueStart + 1, valueEnd - valueStart - 1);
|
||||||
|
} else {
|
||||||
|
size_t valueEnd = jsonCommand.find_first_of(",}", valueStart);
|
||||||
|
return jsonCommand.substr(valueStart, valueEnd - valueStart);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Route commands
|
||||||
|
if (command == "set_format") {
|
||||||
|
return handleSetFormat(getParam("width"), getParam("height"),
|
||||||
|
getParam("framerate"), getParam("format"));
|
||||||
|
} else if (command == "get_formats") {
|
||||||
|
return handleGetFormats();
|
||||||
|
} else if (command == "set_exposure") {
|
||||||
|
return handleSetExposure(getParam("mode"), getParam("value"));
|
||||||
|
} else if (command == "set_whitebalance") {
|
||||||
|
return handleSetWhiteBalance(getParam("mode"), getParam("temperature"));
|
||||||
|
} else if (command == "set_brightness") {
|
||||||
|
return handleSetBrightness(getParam("value"));
|
||||||
|
} else if (command == "set_contrast") {
|
||||||
|
return handleSetContrast(getParam("value"));
|
||||||
|
} else if (command == "set_saturation") {
|
||||||
|
return handleSetSaturation(getParam("value"));
|
||||||
|
} else if (command == "set_sharpness") {
|
||||||
|
return handleSetSharpness(getParam("value"));
|
||||||
|
} else if (command == "set_gamma") {
|
||||||
|
return handleSetGamma(getParam("value"));
|
||||||
|
} else if (command == "set_gain") {
|
||||||
|
return handleSetGain(getParam("value"));
|
||||||
|
} else if (command == "get_status") {
|
||||||
|
return handleGetStatus();
|
||||||
|
} else if (command == "start_stream") {
|
||||||
|
return handleStartStream();
|
||||||
|
} else if (command == "stop_stream") {
|
||||||
|
return handleStopStream();
|
||||||
|
} else {
|
||||||
|
return createErrorResponse("Unknown command: " + command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetFormat(const std::string& width, const std::string& height,
|
||||||
|
const std::string& framerate, const std::string& format) {
|
||||||
|
if (streaming_) {
|
||||||
|
return createErrorResponse("Cannot change format while streaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
VxFormat fmt;
|
||||||
|
fmt.width = std::stoi(width);
|
||||||
|
fmt.height = std::stoi(height);
|
||||||
|
fmt.framerate = std::stoi(framerate);
|
||||||
|
fmt.format = stringToFormat(format);
|
||||||
|
fmt.mediatypeIdx = 0;
|
||||||
|
|
||||||
|
if (VxSetFormat(camera_, fmt) != 0) {
|
||||||
|
return createErrorResponse("Failed to set format");
|
||||||
|
}
|
||||||
|
|
||||||
|
return createSuccessResponse("Format set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleGetFormats() {
|
||||||
|
std::vector<VxFormat> fmtList;
|
||||||
|
if (VxGetFormatList(camera_, fmtList) != 0) {
|
||||||
|
return createErrorResponse("Failed to get format list");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "{\"status\":\"success\",\"formats\":[";
|
||||||
|
for (size_t i = 0; i < fmtList.size(); i++) {
|
||||||
|
if (i > 0) oss << ",";
|
||||||
|
oss << "{\"width\":" << fmtList[i].width
|
||||||
|
<< ",\"height\":" << fmtList[i].height
|
||||||
|
<< ",\"framerate\":" << fmtList[i].framerate
|
||||||
|
<< ",\"format\":\"" << formatToString(fmtList[i].format) << "\"}";
|
||||||
|
}
|
||||||
|
oss << "]}";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetExposure(const std::string& mode, const std::string& value) {
|
||||||
|
try {
|
||||||
|
int flag = (mode == "auto") ? 1 : 0;
|
||||||
|
long expValue = value.empty() ? 0 : std::stol(value);
|
||||||
|
|
||||||
|
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_EXPOSURE,
|
||||||
|
expValue, flag) != 0) {
|
||||||
|
return createErrorResponse("Failed to set exposure");
|
||||||
|
}
|
||||||
|
|
||||||
|
return createSuccessResponse("Exposure set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetWhiteBalance(const std::string& mode, const std::string& temperature) {
|
||||||
|
try {
|
||||||
|
int flag = (mode == "auto") ? 1 : 0;
|
||||||
|
long tempValue = temperature.empty() ? 0 : std::stol(temperature);
|
||||||
|
|
||||||
|
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_WHITEBALANCE,
|
||||||
|
tempValue, flag) != 0) {
|
||||||
|
return createErrorResponse("Failed to set white balance");
|
||||||
|
}
|
||||||
|
|
||||||
|
return createSuccessResponse("White balance set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetBrightness(const std::string& value) {
|
||||||
|
try {
|
||||||
|
long val = std::stol(value);
|
||||||
|
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_BRIGHTNESS,
|
||||||
|
val, 0) != 0) {
|
||||||
|
return createErrorResponse("Failed to set brightness");
|
||||||
|
}
|
||||||
|
return createSuccessResponse("Brightness set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetContrast(const std::string& value) {
|
||||||
|
try {
|
||||||
|
long val = std::stol(value);
|
||||||
|
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_CONTRAST,
|
||||||
|
val, 0) != 0) {
|
||||||
|
return createErrorResponse("Failed to set contrast");
|
||||||
|
}
|
||||||
|
return createSuccessResponse("Contrast set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetSaturation(const std::string& value) {
|
||||||
|
try {
|
||||||
|
long val = std::stol(value);
|
||||||
|
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_SATURATION,
|
||||||
|
val, 0) != 0) {
|
||||||
|
return createErrorResponse("Failed to set saturation");
|
||||||
|
}
|
||||||
|
return createSuccessResponse("Saturation set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetSharpness(const std::string& value) {
|
||||||
|
try {
|
||||||
|
long val = std::stol(value);
|
||||||
|
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_SHARPNESS,
|
||||||
|
val, 0) != 0) {
|
||||||
|
return createErrorResponse("Failed to set sharpness");
|
||||||
|
}
|
||||||
|
return createSuccessResponse("Sharpness set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetGamma(const std::string& value) {
|
||||||
|
try {
|
||||||
|
long val = std::stol(value);
|
||||||
|
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_GAMMA,
|
||||||
|
val, 0) != 0) {
|
||||||
|
return createErrorResponse("Failed to set gamma");
|
||||||
|
}
|
||||||
|
return createSuccessResponse("Gamma set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleSetGain(const std::string& value) {
|
||||||
|
try {
|
||||||
|
long val = std::stol(value);
|
||||||
|
if (VxSetUVCImageProcessing(camera_, VX_UVC_IMAGE_PROPERTIES::UVC_IMAGE_GAIN,
|
||||||
|
val, 0) != 0) {
|
||||||
|
return createErrorResponse("Failed to set gain");
|
||||||
|
}
|
||||||
|
return createSuccessResponse("Gain set successfully");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return createErrorResponse(std::string("Invalid parameters: ") + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleGetStatus() {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "{\"status\":\"success\",\"streaming\":" << (streaming_ ? "true" : "false") << "}";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleStartStream() {
|
||||||
|
if (streaming_) {
|
||||||
|
return createErrorResponse("Already streaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VxStartStreaming(camera_) != 0) {
|
||||||
|
return createErrorResponse("Failed to start streaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
streaming_ = true;
|
||||||
|
return createSuccessResponse("Streaming started");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::handleStopStream() {
|
||||||
|
if (!streaming_) {
|
||||||
|
return createErrorResponse("Not streaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VxStopStreaming(camera_) != 0) {
|
||||||
|
return createErrorResponse("Failed to stop streaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
streaming_ = false;
|
||||||
|
return createSuccessResponse("Streaming stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
VX_IMAGE_FORMAT CameraController::stringToFormat(const std::string& format) {
|
||||||
|
if (format == "YUY2") return VX_IMAGE_FORMAT::YUY2;
|
||||||
|
if (format == "UYVY") return VX_IMAGE_FORMAT::UYVY;
|
||||||
|
if (format == "NV12") return VX_IMAGE_FORMAT::NV12;
|
||||||
|
if (format == "MJPG") return VX_IMAGE_FORMAT::MJPG;
|
||||||
|
if (format == "BGR") return VX_IMAGE_FORMAT::BGR;
|
||||||
|
if (format == "RGB") return VX_IMAGE_FORMAT::RGB;
|
||||||
|
return VX_IMAGE_FORMAT::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::formatToString(VX_IMAGE_FORMAT format) {
|
||||||
|
switch (format) {
|
||||||
|
case VX_IMAGE_FORMAT::YUY2: return "YUY2";
|
||||||
|
case VX_IMAGE_FORMAT::UYVY: return "UYVY";
|
||||||
|
case VX_IMAGE_FORMAT::NV12: return "NV12";
|
||||||
|
case VX_IMAGE_FORMAT::MJPG: return "MJPG";
|
||||||
|
case VX_IMAGE_FORMAT::BGR: return "BGR";
|
||||||
|
case VX_IMAGE_FORMAT::RGB: return "RGB";
|
||||||
|
default: return "NONE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::createErrorResponse(const std::string& error) {
|
||||||
|
return "{\"status\":\"error\",\"message\":\"" + error + "\"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CameraController::createSuccessResponse(const std::string& message) {
|
||||||
|
if (message.empty()) {
|
||||||
|
return "{\"status\":\"success\"}";
|
||||||
|
}
|
||||||
|
return "{\"status\":\"success\",\"message\":\"" + message + "\"}";
|
||||||
|
}
|
||||||
41
CameraController.h
Normal file
41
CameraController.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vizionsdk/VizionSDK.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
class CameraController {
|
||||||
|
public:
|
||||||
|
explicit CameraController(std::shared_ptr<VxCamera> camera);
|
||||||
|
|
||||||
|
// Process JSON command and return JSON response
|
||||||
|
std::string processCommand(const std::string& jsonCommand);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Command handlers
|
||||||
|
std::string handleSetFormat(const std::string& width, const std::string& height,
|
||||||
|
const std::string& framerate, const std::string& format);
|
||||||
|
std::string handleGetFormats();
|
||||||
|
std::string handleSetExposure(const std::string& mode, const std::string& value);
|
||||||
|
std::string handleSetWhiteBalance(const std::string& mode, const std::string& temperature);
|
||||||
|
std::string handleSetBrightness(const std::string& value);
|
||||||
|
std::string handleSetContrast(const std::string& value);
|
||||||
|
std::string handleSetSaturation(const std::string& value);
|
||||||
|
std::string handleSetSharpness(const std::string& value);
|
||||||
|
std::string handleSetGamma(const std::string& value);
|
||||||
|
std::string handleSetGain(const std::string& value);
|
||||||
|
std::string handleGetStatus();
|
||||||
|
std::string handleStartStream();
|
||||||
|
std::string handleStopStream();
|
||||||
|
|
||||||
|
// Helper functions
|
||||||
|
VX_IMAGE_FORMAT stringToFormat(const std::string& format);
|
||||||
|
std::string formatToString(VX_IMAGE_FORMAT format);
|
||||||
|
std::string createErrorResponse(const std::string& error);
|
||||||
|
std::string createSuccessResponse(const std::string& message = "");
|
||||||
|
|
||||||
|
std::shared_ptr<VxCamera> camera_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
bool streaming_;
|
||||||
|
};
|
||||||
514
SOCKET_API.md
Normal file
514
SOCKET_API.md
Normal file
@@ -0,0 +1,514 @@
|
|||||||
|
# VizionStreamer Socket Control API
|
||||||
|
|
||||||
|
VizionStreamer can be controlled via a Unix Domain Socket interface. This allows external applications to configure camera parameters and stream settings at runtime.
|
||||||
|
|
||||||
|
## Socket Connection
|
||||||
|
|
||||||
|
- **Socket Path**: `/tmp/vizion_control.sock`
|
||||||
|
- **Protocol**: Unix Domain Socket (SOCK_STREAM)
|
||||||
|
- **Message Format**: JSON
|
||||||
|
|
||||||
|
## Command Format
|
||||||
|
|
||||||
|
All commands follow this JSON structure:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "command_name",
|
||||||
|
"params": {
|
||||||
|
"param1": "value1",
|
||||||
|
"param2": "value2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Format
|
||||||
|
|
||||||
|
All responses follow this JSON structure:
|
||||||
|
|
||||||
|
**Success Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Optional success message"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": "Error description"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available Commands
|
||||||
|
|
||||||
|
### 1. Get Available Formats
|
||||||
|
|
||||||
|
Retrieve all supported video formats.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "get_formats"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"formats": [
|
||||||
|
{
|
||||||
|
"width": 1920,
|
||||||
|
"height": 1080,
|
||||||
|
"framerate": 30,
|
||||||
|
"format": "YUY2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"width": 1280,
|
||||||
|
"height": 720,
|
||||||
|
"framerate": 60,
|
||||||
|
"format": "MJPG"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Supported Formats:** YUY2, UYVY, NV12, MJPG, BGR, RGB
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Set Video Format
|
||||||
|
|
||||||
|
Change the video format (resolution, framerate, pixel format).
|
||||||
|
|
||||||
|
**Note:** Cannot be changed while streaming is active.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_format",
|
||||||
|
"params": {
|
||||||
|
"width": "1920",
|
||||||
|
"height": "1080",
|
||||||
|
"framerate": "30",
|
||||||
|
"format": "YUY2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Format set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Start Streaming
|
||||||
|
|
||||||
|
Start video streaming from the camera.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "start_stream"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Streaming started"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Stop Streaming
|
||||||
|
|
||||||
|
Stop video streaming.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "stop_stream"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Streaming stopped"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Get Status
|
||||||
|
|
||||||
|
Get current streaming status.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "get_status"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"streaming": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. Set Exposure
|
||||||
|
|
||||||
|
Configure camera exposure settings.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_exposure",
|
||||||
|
"params": {
|
||||||
|
"mode": "manual",
|
||||||
|
"value": "100"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `mode`: "auto" or "manual"
|
||||||
|
- `value`: Exposure value (only used in manual mode)
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Exposure set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. Set White Balance
|
||||||
|
|
||||||
|
Configure white balance settings.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_whitebalance",
|
||||||
|
"params": {
|
||||||
|
"mode": "auto",
|
||||||
|
"temperature": "4500"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `mode`: "auto" or "manual"
|
||||||
|
- `temperature`: Color temperature in Kelvin (only used in manual mode)
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "White balance set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. Set Brightness
|
||||||
|
|
||||||
|
Adjust camera brightness.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_brightness",
|
||||||
|
"params": {
|
||||||
|
"value": "50"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Brightness set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9. Set Contrast
|
||||||
|
|
||||||
|
Adjust camera contrast.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_contrast",
|
||||||
|
"params": {
|
||||||
|
"value": "32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Contrast set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10. Set Saturation
|
||||||
|
|
||||||
|
Adjust color saturation.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_saturation",
|
||||||
|
"params": {
|
||||||
|
"value": "64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Saturation set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 11. Set Sharpness
|
||||||
|
|
||||||
|
Adjust image sharpness.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_sharpness",
|
||||||
|
"params": {
|
||||||
|
"value": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Sharpness set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 12. Set Gamma
|
||||||
|
|
||||||
|
Adjust gamma correction.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_gamma",
|
||||||
|
"params": {
|
||||||
|
"value": "100"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Gamma set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 13. Set Gain
|
||||||
|
|
||||||
|
Adjust camera gain.
|
||||||
|
|
||||||
|
**Command:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "set_gain",
|
||||||
|
"params": {
|
||||||
|
"value": "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"message": "Gain set successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Using `socat`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get available formats
|
||||||
|
echo '{"command":"get_formats"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
|
||||||
|
|
||||||
|
# Set video format
|
||||||
|
echo '{"command":"set_format","params":{"width":"1920","height":"1080","framerate":"30","format":"YUY2"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
|
||||||
|
|
||||||
|
# Start streaming
|
||||||
|
echo '{"command":"start_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
|
||||||
|
|
||||||
|
# Set exposure to auto
|
||||||
|
echo '{"command":"set_exposure","params":{"mode":"auto"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
|
||||||
|
|
||||||
|
# Set brightness
|
||||||
|
echo '{"command":"set_brightness","params":{"value":"50"}}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
|
||||||
|
|
||||||
|
# Get status
|
||||||
|
echo '{"command":"get_status"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
|
||||||
|
|
||||||
|
# Stop streaming
|
||||||
|
echo '{"command":"stop_stream"}' | socat - UNIX-CONNECT:/tmp/vizion_control.sock
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using `nc` (netcat with Unix socket support)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo '{"command":"get_formats"}' | nc -U /tmp/vizion_control.sock
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Python
|
||||||
|
|
||||||
|
```python
|
||||||
|
import socket
|
||||||
|
import json
|
||||||
|
|
||||||
|
def send_command(command, params=None):
|
||||||
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
sock.connect('/tmp/vizion_control.sock')
|
||||||
|
|
||||||
|
cmd = {"command": command}
|
||||||
|
if params:
|
||||||
|
cmd["params"] = params
|
||||||
|
|
||||||
|
sock.send(json.dumps(cmd).encode())
|
||||||
|
response = sock.recv(4096).decode()
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
return json.loads(response)
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
print(send_command("get_formats"))
|
||||||
|
print(send_command("set_format", {
|
||||||
|
"width": "1920",
|
||||||
|
"height": "1080",
|
||||||
|
"framerate": "30",
|
||||||
|
"format": "YUY2"
|
||||||
|
}))
|
||||||
|
print(send_command("set_exposure", {"mode": "auto"}))
|
||||||
|
print(send_command("start_stream"))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using C++
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
std::string sendCommand(const std::string& command) {
|
||||||
|
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strcpy(addr.sun_path, "/tmp/vizion_control.sock");
|
||||||
|
|
||||||
|
connect(sock, (struct sockaddr*)&addr, sizeof(addr));
|
||||||
|
send(sock, command.c_str(), command.length(), 0);
|
||||||
|
|
||||||
|
char buffer[4096];
|
||||||
|
int bytesRead = recv(sock, buffer, sizeof(buffer) - 1, 0);
|
||||||
|
buffer[bytesRead] = '\0';
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
return std::string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example usage
|
||||||
|
int main() {
|
||||||
|
std::cout << sendCommand(R"({"command":"get_formats"})") << std::endl;
|
||||||
|
std::cout << sendCommand(R"({"command":"set_brightness","params":{"value":"50"}})") << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameter Value Ranges
|
||||||
|
|
||||||
|
The valid ranges for camera parameters depend on the specific camera model. You can query the camera capabilities through the VizionSDK API or experimentally determine valid ranges.
|
||||||
|
|
||||||
|
**Typical ranges (camera-dependent):**
|
||||||
|
- Brightness: 0-255
|
||||||
|
- Contrast: 0-255
|
||||||
|
- Saturation: 0-255
|
||||||
|
- Sharpness: 0-255
|
||||||
|
- Gamma: 72-500
|
||||||
|
- Gain: 0-100
|
||||||
|
- Exposure: 1-10000 (in auto mode, value is ignored)
|
||||||
|
- White Balance Temperature: 2800-6500 Kelvin
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
Always check the `status` field in the response:
|
||||||
|
|
||||||
|
```python
|
||||||
|
response = send_command("set_format", {...})
|
||||||
|
if response["status"] == "error":
|
||||||
|
print(f"Command failed: {response['message']}")
|
||||||
|
else:
|
||||||
|
print("Command successful")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Thread Safety
|
||||||
|
|
||||||
|
The socket server handles one client connection at a time. Commands are processed sequentially with mutex protection to ensure thread safety with the camera operations.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- The socket file is automatically created when VizionStreamer starts
|
||||||
|
- The socket file is removed when VizionStreamer exits cleanly
|
||||||
|
- Format changes require streaming to be stopped first
|
||||||
|
- Some parameters may not be supported on all camera models
|
||||||
|
- Invalid parameter values will return an error response
|
||||||
111
SocketServer.cpp
Normal file
111
SocketServer.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#include "SocketServer.h"
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
SocketServer::SocketServer(const std::string& socketPath)
|
||||||
|
: socketPath_(socketPath), serverFd_(-1), running_(false) {}
|
||||||
|
|
||||||
|
SocketServer::~SocketServer() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketServer::start(CommandCallback callback) {
|
||||||
|
if (running_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandCallback_ = callback;
|
||||||
|
|
||||||
|
// Remove existing socket file if it exists
|
||||||
|
unlink(socketPath_.c_str());
|
||||||
|
|
||||||
|
// Create Unix domain socket
|
||||||
|
serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (serverFd_ < 0) {
|
||||||
|
std::cerr << "Failed to create socket" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind socket
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, socketPath_.c_str(), sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
if (bind(serverFd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||||
|
std::cerr << "Failed to bind socket: " << strerror(errno) << std::endl;
|
||||||
|
close(serverFd_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for connections
|
||||||
|
if (listen(serverFd_, 5) < 0) {
|
||||||
|
std::cerr << "Failed to listen on socket" << std::endl;
|
||||||
|
close(serverFd_);
|
||||||
|
unlink(socketPath_.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
running_ = true;
|
||||||
|
serverThread_ = std::make_unique<std::thread>(&SocketServer::serverLoop, this);
|
||||||
|
|
||||||
|
std::cout << "Socket server started on " << socketPath_ << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketServer::stop() {
|
||||||
|
if (!running_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
running_ = false;
|
||||||
|
|
||||||
|
// Close server socket to unblock accept()
|
||||||
|
if (serverFd_ >= 0) {
|
||||||
|
shutdown(serverFd_, SHUT_RDWR);
|
||||||
|
close(serverFd_);
|
||||||
|
serverFd_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for server thread to finish
|
||||||
|
if (serverThread_ && serverThread_->joinable()) {
|
||||||
|
serverThread_->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(socketPath_.c_str());
|
||||||
|
std::cout << "Socket server stopped" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketServer::serverLoop() {
|
||||||
|
while (running_) {
|
||||||
|
int clientFd = accept(serverFd_, nullptr, nullptr);
|
||||||
|
if (clientFd < 0) {
|
||||||
|
if (running_) {
|
||||||
|
std::cerr << "Accept failed: " << strerror(errno) << std::endl;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClient(clientFd);
|
||||||
|
close(clientFd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketServer::handleClient(int clientFd) {
|
||||||
|
char buffer[4096];
|
||||||
|
ssize_t bytesRead = recv(clientFd, buffer, sizeof(buffer) - 1, 0);
|
||||||
|
|
||||||
|
if (bytesRead > 0) {
|
||||||
|
buffer[bytesRead] = '\0';
|
||||||
|
std::string command(buffer);
|
||||||
|
|
||||||
|
// Call the command callback
|
||||||
|
std::string response = commandCallback_(command);
|
||||||
|
|
||||||
|
// Send response back to client
|
||||||
|
send(clientFd, response.c_str(), response.length(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
SocketServer.h
Normal file
29
SocketServer.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class SocketServer {
|
||||||
|
public:
|
||||||
|
using CommandCallback = std::function<std::string(const std::string&)>;
|
||||||
|
|
||||||
|
explicit SocketServer(const std::string& socketPath);
|
||||||
|
~SocketServer();
|
||||||
|
|
||||||
|
bool start(CommandCallback callback);
|
||||||
|
void stop();
|
||||||
|
bool isRunning() const { return running_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void serverLoop();
|
||||||
|
void handleClient(int clientFd);
|
||||||
|
|
||||||
|
std::string socketPath_;
|
||||||
|
int serverFd_;
|
||||||
|
std::atomic<bool> running_;
|
||||||
|
std::unique_ptr<std::thread> serverThread_;
|
||||||
|
CommandCallback commandCallback_;
|
||||||
|
};
|
||||||
56
main.cpp
56
main.cpp
@@ -1,9 +1,22 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <csignal>
|
||||||
|
#include <atomic>
|
||||||
#include <vizionsdk/VizionSDK.h>
|
#include <vizionsdk/VizionSDK.h>
|
||||||
|
#include "SocketServer.h"
|
||||||
|
#include "CameraController.h"
|
||||||
|
|
||||||
|
std::atomic<bool> g_running(true);
|
||||||
|
|
||||||
|
void signalHandler(int signal) {
|
||||||
|
std::cout << "\nReceived signal " << signal << ", shutting down..." << std::endl;
|
||||||
|
g_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
// TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
|
|
||||||
int main() {
|
int main() {
|
||||||
|
// Setup signal handlers for clean shutdown
|
||||||
|
signal(SIGINT, signalHandler);
|
||||||
|
signal(SIGTERM, signalHandler);
|
||||||
|
|
||||||
// List available cameras
|
// List available cameras
|
||||||
std::vector<std::string> devList;
|
std::vector<std::string> devList;
|
||||||
@@ -26,7 +39,7 @@ int main() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get and set format
|
// Get and set default format
|
||||||
std::vector<VxFormat> fmtList;
|
std::vector<VxFormat> fmtList;
|
||||||
if (VxGetFormatList(cam, fmtList) != 0) {
|
if (VxGetFormatList(cam, fmtList) != 0) {
|
||||||
std::cout << "Failed to get format list" << std::endl;
|
std::cout << "Failed to get format list" << std::endl;
|
||||||
@@ -40,31 +53,38 @@ int main() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start streaming
|
std::cout << "Initial format: " << fmtList[0].width << "x" << fmtList[0].height
|
||||||
if (VxStartStreaming(cam) != 0) {
|
<< " @ " << fmtList[0].framerate << " fps" << std::endl;
|
||||||
std::cout << "Failed to start streaming" << std::endl;
|
|
||||||
|
// Create camera controller
|
||||||
|
auto controller = std::make_shared<CameraController>(cam);
|
||||||
|
|
||||||
|
// Start Unix domain socket server
|
||||||
|
const std::string socketPath = "/tmp/vizion_control.sock";
|
||||||
|
SocketServer server(socketPath);
|
||||||
|
|
||||||
|
if (!server.start([controller](const std::string& cmd) {
|
||||||
|
return controller->processCommand(cmd);
|
||||||
|
})) {
|
||||||
|
std::cout << "Failed to start socket server" << std::endl;
|
||||||
VxClose(cam);
|
VxClose(cam);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture 5 frames
|
std::cout << "\nVizion Streamer is running." << std::endl;
|
||||||
std::shared_ptr<uint8_t[]> buffer(new uint8_t[fmtList[0].width * fmtList[0].height * 3]);
|
std::cout << "Control socket: " << socketPath << std::endl;
|
||||||
int dataSize;
|
std::cout << "Press Ctrl+C to exit.\n" << std::endl;
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
// Main loop - keep running until signaled to stop
|
||||||
VX_CAPTURE_RESULT result = VxGetImage(cam, buffer.get(), &dataSize, 1000);
|
while (g_running) {
|
||||||
if (result == VX_CAPTURE_RESULT::VX_SUCCESS) {
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
std::cout << "Successfully captured frame " << i + 1 << " of size: " << dataSize << " bytes" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cout << "Failed to capture frame " << i + 1 << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
VxStopStreaming(cam);
|
std::cout << "Shutting down..." << std::endl;
|
||||||
|
server.stop();
|
||||||
VxClose(cam);
|
VxClose(cam);
|
||||||
|
|
||||||
|
std::cout << "Shutdown complete." << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
// TIP See CLion help at <a href="https://www.jetbrains.com/help/clion/">jetbrains.com/help/clion/</a>. Also, you can try interactive lessons for CLion by selecting 'Help | Learn IDE Features' from the main menu.
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user