initial commit
This commit is contained in:
46
.gitignore
vendored
Normal file
46
.gitignore
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/cmake,visualstudiocode
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake,visualstudiocode
|
||||||
|
|
||||||
|
### CMake ###
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
### CMake Patch ###
|
||||||
|
# External projects
|
||||||
|
*-prefix/
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/*.code-snippets
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Built Visual Studio Code Extensions
|
||||||
|
*.vsix
|
||||||
|
|
||||||
|
### VisualStudioCode Patch ###
|
||||||
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
.ionide
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/cmake,visualstudiocode
|
||||||
|
|
||||||
|
#build path
|
||||||
|
build/*
|
||||||
|
|
||||||
|
# opencv lib
|
||||||
|
opencv-mobile-4.9.0-armlinux/*
|
||||||
63
.vscode/settings.json
vendored
Normal file
63
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"array": "cpp",
|
||||||
|
"atomic": "cpp",
|
||||||
|
"bit": "cpp",
|
||||||
|
"*.tcc": "cpp",
|
||||||
|
"cctype": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"clocale": "cpp",
|
||||||
|
"cmath": "cpp",
|
||||||
|
"complex": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"cstdarg": "cpp",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"cstdint": "cpp",
|
||||||
|
"cstdio": "cpp",
|
||||||
|
"cstdlib": "cpp",
|
||||||
|
"cstring": "cpp",
|
||||||
|
"ctime": "cpp",
|
||||||
|
"cwchar": "cpp",
|
||||||
|
"cwctype": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"set": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"exception": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"functional": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"memory_resource": "cpp",
|
||||||
|
"numeric": "cpp",
|
||||||
|
"optional": "cpp",
|
||||||
|
"random": "cpp",
|
||||||
|
"ratio": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"system_error": "cpp",
|
||||||
|
"tuple": "cpp",
|
||||||
|
"type_traits": "cpp",
|
||||||
|
"utility": "cpp",
|
||||||
|
"fstream": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"iomanip": "cpp",
|
||||||
|
"iosfwd": "cpp",
|
||||||
|
"iostream": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"ostream": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"streambuf": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"cinttypes": "cpp",
|
||||||
|
"typeinfo": "cpp",
|
||||||
|
"shared_mutex": "cpp",
|
||||||
|
"cfenv": "cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
27
CMakeLists.txt
Normal file
27
CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.8)
|
||||||
|
project(capture)
|
||||||
|
|
||||||
|
# 设定编译参数
|
||||||
|
set(CMAKE_CXX_STANDARD 11) # 指定 C++ 版本
|
||||||
|
set(CMAKE_BUILD_TYPE "Debug") # 调试使用 Debug
|
||||||
|
|
||||||
|
set(main main.cc
|
||||||
|
capture.cc)
|
||||||
|
|
||||||
|
set(LOGC logc/log.c)
|
||||||
|
set(TOML tomlc99/toml.c)
|
||||||
|
|
||||||
|
|
||||||
|
# 查找并添加 OpenCV 的头文件目录
|
||||||
|
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.9.0-armlinux/lib/cmake/opencv4)
|
||||||
|
find_package(OpenCV REQUIRED)
|
||||||
|
|
||||||
|
set(ZMQ zmq)
|
||||||
|
set(PTHREAD pthread)
|
||||||
|
|
||||||
|
message(STATUS " version: ${OpenCV_VERSION}")
|
||||||
|
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
|
||||||
|
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
add_executable(capture ${main} ${TOML} ${LOGC})
|
||||||
|
target_link_libraries(capture ${PTHREAD} ${ZMQ} ${OpenCV_LIBS})
|
||||||
104
capture.cc
Normal file
104
capture.cc
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include "capture.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <opencv2/highgui.hpp>
|
||||||
|
#include <zmq.hpp>
|
||||||
|
#include "logc/log.h"
|
||||||
|
|
||||||
|
capture::capture(int camera_index, int zmq_port, int width_set, int height_set, int fps_set)
|
||||||
|
{
|
||||||
|
index = camera_index;
|
||||||
|
port = zmq_port;
|
||||||
|
width = width_set;
|
||||||
|
height = height_set;
|
||||||
|
fps = fps_set;
|
||||||
|
|
||||||
|
log_info("trying open camera %d", index);
|
||||||
|
|
||||||
|
cap = new cv::VideoCapture(index, cv::CAP_V4L2);
|
||||||
|
cap->set(cv::CAP_PROP_FRAME_WIDTH, width);
|
||||||
|
cap->set(cv::CAP_PROP_FRAME_HEIGHT, height);
|
||||||
|
cap->set(cv::CAP_PROP_FPS, fps);
|
||||||
|
|
||||||
|
if (!cap->isOpened())
|
||||||
|
{
|
||||||
|
log_error("Error opening video stream in %d", index);
|
||||||
|
status = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_info("Successful opening video stream in %d", index);
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
context = new zmq::context_t(1);
|
||||||
|
socket = new zmq::socket_t(*context, ZMQ_PUB);
|
||||||
|
|
||||||
|
char zmq_bind_port[10] = {0};
|
||||||
|
sprintf(zmq_bind_port, "%d", port);
|
||||||
|
strcat(zmq_bind_addr, zmq_bind_port);
|
||||||
|
log_info("set camera %d zmq address %s", index, zmq_bind_addr);
|
||||||
|
socket->bind(zmq_bind_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void capture::start(void)
|
||||||
|
{
|
||||||
|
if (this->is_open())
|
||||||
|
{
|
||||||
|
log_info("start camera %d capture thread", index);
|
||||||
|
thread = new std::thread(&capture::run, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_error("camera %d have not been inited, exit", index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void capture::run(void)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
*cap >> frame;
|
||||||
|
if (frame.empty())
|
||||||
|
{
|
||||||
|
log_error("empty frame");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保图像是连续的
|
||||||
|
if (!frame.isContinuous())
|
||||||
|
{
|
||||||
|
frame = frame.clone().reshape(1, frame.total());
|
||||||
|
}
|
||||||
|
|
||||||
|
// cv::imshow(zmq_bind_addr, frame);
|
||||||
|
|
||||||
|
// 将帧编码后发送
|
||||||
|
std::vector<uchar> buff;
|
||||||
|
cv::imencode(".jpg", frame, buff);
|
||||||
|
zmq::message_t message(buff.size());
|
||||||
|
memcpy(message.data(), buff.data(), buff.size());
|
||||||
|
socket->send(message, zmq::send_flags::none);
|
||||||
|
|
||||||
|
// 发送帧的元数据(宽度、高度、类型等)
|
||||||
|
// 这里简单起见,只发送宽度和高度(假设类型为 CV_8UC3)
|
||||||
|
// zmq::message_t header_msg(sizeof(int) * 2);
|
||||||
|
// int *header_data = static_cast<int *>(header_msg.data());
|
||||||
|
// header_data[0] = frame.cols;
|
||||||
|
// header_data[1] = frame.rows;
|
||||||
|
// socket.send(header_msg, zmq::send_flags::sndmore);
|
||||||
|
|
||||||
|
// 发送帧数据
|
||||||
|
// zmq::message_t frame_msg((size_t)frame.total() * frame.elemSize());
|
||||||
|
// memcpy(frame_msg.data(), frame.data, frame.total() * frame.elemSize());
|
||||||
|
// socket->send(frame_msg, zmq::send_flags::none);
|
||||||
|
// 在这里添加一些延迟,以控制帧率
|
||||||
|
cv::waitKey(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool capture::is_open(void)
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
31
capture.h
Normal file
31
capture.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef _CAPTURE_H__
|
||||||
|
#define _CAPTURE_H__
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <iostream>
|
||||||
|
#include <opencv2/highgui.hpp>
|
||||||
|
#include <zmq.hpp>
|
||||||
|
|
||||||
|
class capture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int index;
|
||||||
|
int port;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int fps;
|
||||||
|
bool status = false;
|
||||||
|
char zmq_bind_addr[40] = "tcp://*:";
|
||||||
|
std::thread *thread;
|
||||||
|
cv::VideoCapture *cap;
|
||||||
|
cv::Mat frame;
|
||||||
|
zmq::context_t *context;
|
||||||
|
zmq::socket_t *socket;
|
||||||
|
|
||||||
|
capture(int camera_index, int zmq_port, int width_set = 320, int height_set = 240, int fps_set = 20);
|
||||||
|
void start(void);
|
||||||
|
void run(void);
|
||||||
|
bool is_open(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
10
config.toml
Normal file
10
config.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[server]
|
||||||
|
|
||||||
|
server_0_index = 0
|
||||||
|
server_0_port = 5555
|
||||||
|
|
||||||
|
server_1_index = 2
|
||||||
|
server_1_port = 5556
|
||||||
|
|
||||||
|
server_2_index = 4
|
||||||
|
server_2_port = 5557
|
||||||
3
download_opencv.sh
Normal file
3
download_opencv.sh
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# 直接下载预编译好的 opencv 库
|
||||||
|
wget https://github.com/nihui/opencv-mobile/releases/latest/download/opencv-mobile-4.9.0-armlinux.zip
|
||||||
|
unzip opencv-mobile-4.9.0-armlinux.zip
|
||||||
19
logc/LICENSE
Normal file
19
logc/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020 rxi
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE 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.
|
||||||
83
logc/README.md
Normal file
83
logc/README.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# log.c
|
||||||
|
A simple logging library implemented in C99
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
**[log.c](src/log.c?raw=1)** and **[log.h](src/log.h?raw=1)** should be dropped
|
||||||
|
into an existing project and compiled along with it. The library provides 6
|
||||||
|
function-like macros for logging:
|
||||||
|
|
||||||
|
```c
|
||||||
|
log_trace(const char *fmt, ...);
|
||||||
|
log_debug(const char *fmt, ...);
|
||||||
|
log_info(const char *fmt, ...);
|
||||||
|
log_warn(const char *fmt, ...);
|
||||||
|
log_error(const char *fmt, ...);
|
||||||
|
log_fatal(const char *fmt, ...);
|
||||||
|
```
|
||||||
|
|
||||||
|
Each function takes a printf format string followed by additional arguments:
|
||||||
|
|
||||||
|
```c
|
||||||
|
log_trace("Hello %s", "world")
|
||||||
|
```
|
||||||
|
|
||||||
|
Resulting in a line with the given format printed to stderr:
|
||||||
|
|
||||||
|
```
|
||||||
|
20:18:26 TRACE src/main.c:11: Hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### log_set_quiet(bool enable)
|
||||||
|
Quiet-mode can be enabled by passing `true` to the `log_set_quiet()` function.
|
||||||
|
While this mode is enabled the library will not output anything to `stderr`, but
|
||||||
|
will continue to write to files and callbacks if any are set.
|
||||||
|
|
||||||
|
|
||||||
|
#### log_set_level(int level)
|
||||||
|
The current logging level can be set by using the `log_set_level()` function.
|
||||||
|
All logs below the given level will not be written to `stderr`. By default the
|
||||||
|
level is `LOG_TRACE`, such that nothing is ignored.
|
||||||
|
|
||||||
|
|
||||||
|
#### log_add_fp(FILE *fp, int level)
|
||||||
|
One or more file pointers where the log will be written can be provided to the
|
||||||
|
library by using the `log_add_fp()` function. The data written to the file
|
||||||
|
output is of the following format:
|
||||||
|
|
||||||
|
```
|
||||||
|
2047-03-11 20:18:26 TRACE src/main.c:11: Hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
Any messages below the given `level` are ignored. If the library failed to add a
|
||||||
|
file pointer a value less-than-zero is returned.
|
||||||
|
|
||||||
|
|
||||||
|
#### log_add_callback(log_LogFn fn, void *udata, int level)
|
||||||
|
One or more callback functions which are called with the log data can be
|
||||||
|
provided to the library by using the `log_add_callback()` function. A callback
|
||||||
|
function is passed a `log_Event` structure containing the `line` number,
|
||||||
|
`filename`, `fmt` string, `va` printf va\_list, `level` and the given `udata`.
|
||||||
|
|
||||||
|
|
||||||
|
#### log_set_lock(log_LockFn fn, void *udata)
|
||||||
|
If the log will be written to from multiple threads a lock function can be set.
|
||||||
|
The function is passed the boolean `true` if the lock should be acquired or
|
||||||
|
`false` if the lock should be released and the given `udata` value.
|
||||||
|
|
||||||
|
|
||||||
|
#### const char* log_level_string(int level)
|
||||||
|
Returns the name of the given log level as a string.
|
||||||
|
|
||||||
|
|
||||||
|
#### LOG_USE_COLOR
|
||||||
|
If the library is compiled with `-DLOG_USE_COLOR` ANSI color escape codes will
|
||||||
|
be used when printing.
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
This library is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the MIT license. See [LICENSE](LICENSE) for details.
|
||||||
168
logc/log.c
Normal file
168
logc/log.c
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 rxi
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#define MAX_CALLBACKS 32
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
log_LogFn fn;
|
||||||
|
void *udata;
|
||||||
|
int level;
|
||||||
|
} Callback;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
void *udata;
|
||||||
|
log_LockFn lock;
|
||||||
|
int level;
|
||||||
|
bool quiet;
|
||||||
|
Callback callbacks[MAX_CALLBACKS];
|
||||||
|
} L;
|
||||||
|
|
||||||
|
|
||||||
|
static const char *level_strings[] = {
|
||||||
|
"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef LOG_USE_COLOR
|
||||||
|
static const char *level_colors[] = {
|
||||||
|
"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void stdout_callback(log_Event *ev) {
|
||||||
|
char buf[16];
|
||||||
|
buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
|
||||||
|
#ifdef LOG_USE_COLOR
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
|
||||||
|
buf, level_colors[ev->level], level_strings[ev->level],
|
||||||
|
ev->file, ev->line);
|
||||||
|
#else
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %-5s %s:%d: ",
|
||||||
|
buf, level_strings[ev->level], ev->file, ev->line);
|
||||||
|
#endif
|
||||||
|
vfprintf(ev->udata, ev->fmt, ev->ap);
|
||||||
|
fprintf(ev->udata, "\n");
|
||||||
|
fflush(ev->udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void file_callback(log_Event *ev) {
|
||||||
|
char buf[64];
|
||||||
|
buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %-5s %s:%d: ",
|
||||||
|
buf, level_strings[ev->level], ev->file, ev->line);
|
||||||
|
vfprintf(ev->udata, ev->fmt, ev->ap);
|
||||||
|
fprintf(ev->udata, "\n");
|
||||||
|
fflush(ev->udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void lock(void) {
|
||||||
|
if (L.lock) { L.lock(true, L.udata); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void unlock(void) {
|
||||||
|
if (L.lock) { L.lock(false, L.udata); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* log_level_string(int level) {
|
||||||
|
return level_strings[level];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_set_lock(log_LockFn fn, void *udata) {
|
||||||
|
L.lock = fn;
|
||||||
|
L.udata = udata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_set_level(int level) {
|
||||||
|
L.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_set_quiet(bool enable) {
|
||||||
|
L.quiet = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int log_add_callback(log_LogFn fn, void *udata, int level) {
|
||||||
|
for (int i = 0; i < MAX_CALLBACKS; i++) {
|
||||||
|
if (!L.callbacks[i].fn) {
|
||||||
|
L.callbacks[i] = (Callback) { fn, udata, level };
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int log_add_fp(FILE *fp, int level) {
|
||||||
|
return log_add_callback(file_callback, fp, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void init_event(log_Event *ev, void *udata) {
|
||||||
|
if (!ev->time) {
|
||||||
|
time_t t = time(NULL);
|
||||||
|
ev->time = localtime(&t);
|
||||||
|
}
|
||||||
|
ev->udata = udata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void log_log(int level, const char *file, int line, const char *fmt, ...) {
|
||||||
|
log_Event ev = {
|
||||||
|
.fmt = fmt,
|
||||||
|
.file = file,
|
||||||
|
.line = line,
|
||||||
|
.level = level,
|
||||||
|
};
|
||||||
|
|
||||||
|
lock();
|
||||||
|
|
||||||
|
if (!L.quiet && level >= L.level) {
|
||||||
|
init_event(&ev, stderr);
|
||||||
|
va_start(ev.ap, fmt);
|
||||||
|
stdout_callback(&ev);
|
||||||
|
va_end(ev.ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
|
||||||
|
Callback *cb = &L.callbacks[i];
|
||||||
|
if (level >= cb->level) {
|
||||||
|
init_event(&ev, cb->udata);
|
||||||
|
va_start(ev.ap, fmt);
|
||||||
|
cb->fn(&ev);
|
||||||
|
va_end(ev.ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
57
logc/log.h
Normal file
57
logc/log.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2020 rxi
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the MIT license. See `log.c` for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LOG_H
|
||||||
|
#define LOG_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define LOG_VERSION "0.1.0"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
va_list ap;
|
||||||
|
const char *fmt;
|
||||||
|
const char *file;
|
||||||
|
struct tm *time;
|
||||||
|
void *udata;
|
||||||
|
int line;
|
||||||
|
int level;
|
||||||
|
} log_Event;
|
||||||
|
|
||||||
|
typedef void (*log_LogFn)(log_Event *ev);
|
||||||
|
typedef void (*log_LockFn)(bool lock, void *udata);
|
||||||
|
|
||||||
|
enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
|
||||||
|
|
||||||
|
#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
|
||||||
|
const char* log_level_string(int level);
|
||||||
|
void log_set_lock(log_LockFn fn, void *udata);
|
||||||
|
void log_set_level(int level);
|
||||||
|
void log_set_quiet(bool enable);
|
||||||
|
int log_add_callback(log_LogFn fn, void *udata, int level);
|
||||||
|
int log_add_fp(FILE *fp, int level);
|
||||||
|
|
||||||
|
void log_log(int level, const char *file, int line, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
97
main.cc
Normal file
97
main.cc
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include <opencv2/opencv.hpp>
|
||||||
|
#include <zmq.hpp>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include "logc/log.h"
|
||||||
|
#include "tomlc99/toml.h"
|
||||||
|
#include "capture.h"
|
||||||
|
|
||||||
|
#define config_file_path "../config.toml"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char errbuf[200];
|
||||||
|
|
||||||
|
fp = fopen(config_file_path, "r");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
log_error("can not open conifg file");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
toml_table_t *conf = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (!conf)
|
||||||
|
{
|
||||||
|
log_error("cannot parse - %s", errbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
toml_table_t *server = toml_table_in(conf, "server");
|
||||||
|
if (!server)
|
||||||
|
{
|
||||||
|
log_error("missing [server]");
|
||||||
|
}
|
||||||
|
|
||||||
|
toml_datum_t server_0_index = toml_int_in(server, "server_0_index");
|
||||||
|
toml_datum_t server_1_index = toml_int_in(server, "server_1_index");
|
||||||
|
toml_datum_t server_2_index = toml_int_in(server, "server_2_index");
|
||||||
|
toml_datum_t server_0_port = toml_int_in(server, "server_0_port");
|
||||||
|
toml_datum_t server_1_port = toml_int_in(server, "server_1_port");
|
||||||
|
toml_datum_t server_2_port = toml_int_in(server, "server_2_port");
|
||||||
|
|
||||||
|
capture cap0(server_0_index.u.i, server_0_port.u.i);
|
||||||
|
capture cap1(server_1_index.u.i, server_1_port.u.i, 320, 240, 25);
|
||||||
|
capture cap2(server_2_index.u.i, server_2_port.u.i);
|
||||||
|
|
||||||
|
cap0.start();
|
||||||
|
// cap1.start();
|
||||||
|
cap2.start();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
usleep(1);
|
||||||
|
}
|
||||||
|
// while (true)
|
||||||
|
// {
|
||||||
|
// cap >> frame;
|
||||||
|
// if (frame.empty())
|
||||||
|
// {
|
||||||
|
// std::cerr << "Empty frame" << std::endl;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 确保图像是连续的
|
||||||
|
// if (!frame.isContinuous())
|
||||||
|
// {
|
||||||
|
// frame = frame.clone().reshape(1, frame.total());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // std::cout << frame.cols << ":" << frame.rows << std::endl;
|
||||||
|
|
||||||
|
// // cv::imshow("realtime", frame);
|
||||||
|
|
||||||
|
// // 发送帧的元数据(宽度、高度、类型等)
|
||||||
|
// // 这里简单起见,只发送宽度和高度(假设类型为 CV_8UC3)
|
||||||
|
// zmq::message_t header_msg(sizeof(int) * 2);
|
||||||
|
// int *header_data = static_cast<int *>(header_msg.data());
|
||||||
|
// header_data[0] = frame.cols;
|
||||||
|
// header_data[1] = frame.rows;
|
||||||
|
// // socket.send(header_msg, zmq::send_flags::sndmore);
|
||||||
|
|
||||||
|
// // 发送帧数据
|
||||||
|
// zmq::message_t frame_msg((size_t)frame.total() * frame.elemSize());
|
||||||
|
// memcpy(frame_msg.data(), frame.data, frame.total() * frame.elemSize());
|
||||||
|
// socket.send(frame_msg, zmq::send_flags::none);
|
||||||
|
// // 在这里添加一些延迟,以控制帧率
|
||||||
|
// cv::waitKey(1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 关闭视频捕获和 ZMQ 套接字
|
||||||
|
// cap.release();
|
||||||
|
// socket.close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
2392
tomlc99/toml.c
Normal file
2392
tomlc99/toml.c
Normal file
File diff suppressed because it is too large
Load Diff
175
tomlc99/toml.h
Normal file
175
tomlc99/toml.h
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) CK Tan
|
||||||
|
https://github.com/cktan/tomlc99
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE 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.
|
||||||
|
*/
|
||||||
|
#ifndef TOML_H
|
||||||
|
#define TOML_H
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable : 4996)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define TOML_EXTERN extern "C"
|
||||||
|
#else
|
||||||
|
#define TOML_EXTERN extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct toml_timestamp_t toml_timestamp_t;
|
||||||
|
typedef struct toml_table_t toml_table_t;
|
||||||
|
typedef struct toml_array_t toml_array_t;
|
||||||
|
typedef struct toml_datum_t toml_datum_t;
|
||||||
|
|
||||||
|
/* Parse a file. Return a table on success, or 0 otherwise.
|
||||||
|
* Caller must toml_free(the-return-value) after use.
|
||||||
|
*/
|
||||||
|
TOML_EXTERN toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz);
|
||||||
|
|
||||||
|
/* Parse a string containing the full config.
|
||||||
|
* Return a table on success, or 0 otherwise.
|
||||||
|
* Caller must toml_free(the-return-value) after use.
|
||||||
|
*/
|
||||||
|
TOML_EXTERN toml_table_t *toml_parse(char *conf, /* NUL terminated, please. */
|
||||||
|
char *errbuf, int errbufsz);
|
||||||
|
|
||||||
|
/* Free the table returned by toml_parse() or toml_parse_file(). Once
|
||||||
|
* this function is called, any handles accessed through this tab
|
||||||
|
* directly or indirectly are no longer valid.
|
||||||
|
*/
|
||||||
|
TOML_EXTERN void toml_free(toml_table_t *tab);
|
||||||
|
|
||||||
|
/* Timestamp types. The year, month, day, hour, minute, second, z
|
||||||
|
* fields may be NULL if they are not relevant. e.g. In a DATE
|
||||||
|
* type, the hour, minute, second and z fields will be NULLs.
|
||||||
|
*/
|
||||||
|
struct toml_timestamp_t {
|
||||||
|
struct { /* internal. do not use. */
|
||||||
|
int year, month, day;
|
||||||
|
int hour, minute, second, millisec;
|
||||||
|
char z[10];
|
||||||
|
} __buffer;
|
||||||
|
int *year, *month, *day;
|
||||||
|
int *hour, *minute, *second, *millisec;
|
||||||
|
char *z;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
* Enhanced access methods
|
||||||
|
*/
|
||||||
|
struct toml_datum_t {
|
||||||
|
int ok;
|
||||||
|
union {
|
||||||
|
toml_timestamp_t *ts; /* ts must be freed after use */
|
||||||
|
char *s; /* string value. s must be freed after use */
|
||||||
|
int b; /* bool value */
|
||||||
|
int64_t i; /* int value */
|
||||||
|
double d; /* double value */
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* on arrays: */
|
||||||
|
/* ... retrieve size of array. */
|
||||||
|
TOML_EXTERN int toml_array_nelem(const toml_array_t *arr);
|
||||||
|
/* ... retrieve values using index. */
|
||||||
|
TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t *arr, int idx);
|
||||||
|
TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t *arr, int idx);
|
||||||
|
TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t *arr, int idx);
|
||||||
|
TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t *arr, int idx);
|
||||||
|
TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t *arr, int idx);
|
||||||
|
/* ... retrieve array or table using index. */
|
||||||
|
TOML_EXTERN toml_array_t *toml_array_at(const toml_array_t *arr, int idx);
|
||||||
|
TOML_EXTERN toml_table_t *toml_table_at(const toml_array_t *arr, int idx);
|
||||||
|
|
||||||
|
/* on tables: */
|
||||||
|
/* ... retrieve the key in table at keyidx. Return 0 if out of range. */
|
||||||
|
TOML_EXTERN const char *toml_key_in(const toml_table_t *tab, int keyidx);
|
||||||
|
/* ... returns 1 if key exists in tab, 0 otherwise */
|
||||||
|
TOML_EXTERN int toml_key_exists(const toml_table_t *tab, const char *key);
|
||||||
|
/* ... retrieve values using key. */
|
||||||
|
TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t *arr,
|
||||||
|
const char *key);
|
||||||
|
TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key);
|
||||||
|
TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t *arr, const char *key);
|
||||||
|
TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t *arr,
|
||||||
|
const char *key);
|
||||||
|
TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t *arr,
|
||||||
|
const char *key);
|
||||||
|
/* .. retrieve array or table using key. */
|
||||||
|
TOML_EXTERN toml_array_t *toml_array_in(const toml_table_t *tab,
|
||||||
|
const char *key);
|
||||||
|
TOML_EXTERN toml_table_t *toml_table_in(const toml_table_t *tab,
|
||||||
|
const char *key);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
* lesser used
|
||||||
|
*/
|
||||||
|
/* Return the array kind: 't'able, 'a'rray, 'v'alue, 'm'ixed */
|
||||||
|
TOML_EXTERN char toml_array_kind(const toml_array_t *arr);
|
||||||
|
|
||||||
|
/* For array kind 'v'alue, return the type of values
|
||||||
|
i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp, 'm'ixed
|
||||||
|
0 if unknown
|
||||||
|
*/
|
||||||
|
TOML_EXTERN char toml_array_type(const toml_array_t *arr);
|
||||||
|
|
||||||
|
/* Return the key of an array */
|
||||||
|
TOML_EXTERN const char *toml_array_key(const toml_array_t *arr);
|
||||||
|
|
||||||
|
/* Return the number of key-values in a table */
|
||||||
|
TOML_EXTERN int toml_table_nkval(const toml_table_t *tab);
|
||||||
|
|
||||||
|
/* Return the number of arrays in a table */
|
||||||
|
TOML_EXTERN int toml_table_narr(const toml_table_t *tab);
|
||||||
|
|
||||||
|
/* Return the number of sub-tables in a table */
|
||||||
|
TOML_EXTERN int toml_table_ntab(const toml_table_t *tab);
|
||||||
|
|
||||||
|
/* Return the key of a table*/
|
||||||
|
TOML_EXTERN const char *toml_table_key(const toml_table_t *tab);
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
* misc
|
||||||
|
*/
|
||||||
|
TOML_EXTERN int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret);
|
||||||
|
TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]);
|
||||||
|
TOML_EXTERN void toml_set_memutil(void *(*xxmalloc)(size_t),
|
||||||
|
void (*xxfree)(void *));
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------
|
||||||
|
* deprecated
|
||||||
|
*/
|
||||||
|
/* A raw value, must be processed by toml_rto* before using. */
|
||||||
|
typedef const char *toml_raw_t;
|
||||||
|
TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key);
|
||||||
|
TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t *arr, int idx);
|
||||||
|
TOML_EXTERN int toml_rtos(toml_raw_t s, char **ret);
|
||||||
|
TOML_EXTERN int toml_rtob(toml_raw_t s, int *ret);
|
||||||
|
TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t *ret);
|
||||||
|
TOML_EXTERN int toml_rtod(toml_raw_t s, double *ret);
|
||||||
|
TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double *ret, char *buf, int buflen);
|
||||||
|
TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t *ret);
|
||||||
|
|
||||||
|
#endif /* TOML_H */
|
||||||
Reference in New Issue
Block a user