mirror of
https://github.com/pikvm/ustreamer.git
synced 2025-12-23 18:50:00 +00:00
http skel
This commit is contained in:
parent
912443eafb
commit
8039d60ad5
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
||||
LIBS = -lm -ljpeg -pthread
|
||||
LIBS = -lm -ljpeg -pthread -levent
|
||||
CC = gcc
|
||||
CFLAGS = -c -O3 -Wall -Wextra
|
||||
LDFLAGS =
|
||||
|
||||
@ -32,13 +32,19 @@ static int _capture_release_buffer(struct device_t *dev, struct v4l2_buffer *buf
|
||||
static int _capture_handle_event(struct device_t *dev);
|
||||
|
||||
|
||||
void captured_picture_init(struct captured_picture_t *captured) {
|
||||
memset(captured, 0, sizeof(struct captured_picture_t));
|
||||
struct captured_picture_t *captured_picture_init() {
|
||||
struct captured_picture_t *captured;
|
||||
|
||||
A_CALLOC(captured, 1, sizeof(*captured));
|
||||
MEMSET_ZERO_PTR(captured);
|
||||
|
||||
A_PTHREAD_M_INIT(&captured->mutex);
|
||||
return captured;
|
||||
}
|
||||
|
||||
void captured_picture_destroy(struct captured_picture_t *captured) {
|
||||
A_PTHREAD_M_DESTROY(&captured->mutex);
|
||||
free(captured);
|
||||
}
|
||||
|
||||
#ifdef DUMP_CAPTURED_JPEGS
|
||||
@ -83,6 +89,9 @@ void capture_loop(struct device_t *dev, struct captured_picture_t *captured, sig
|
||||
LOG_DEBUG("Allocation memory for captured (result) picture ...");
|
||||
A_CALLOC(captured->picture.data, dev->run->max_picture_size, sizeof(*captured->picture.data));
|
||||
|
||||
captured->width = dev->run->width;
|
||||
captured->height = dev->run->height;
|
||||
|
||||
while (!*global_stop) {
|
||||
SEP_DEBUG('-');
|
||||
|
||||
@ -99,6 +108,7 @@ void capture_loop(struct device_t *dev, struct captured_picture_t *captured, sig
|
||||
dev->run->pictures[last_worker->ctx.index].data,
|
||||
captured->picture.size * sizeof(*captured->picture.data)
|
||||
);
|
||||
captured->updated = true;
|
||||
A_PTHREAD_M_UNLOCK(&captured->mutex);
|
||||
|
||||
last_worker = last_worker->order_next;
|
||||
@ -418,7 +428,7 @@ static int _capture_control(struct device_t *dev, const bool enable) {
|
||||
}
|
||||
|
||||
static int _capture_grab_buffer(struct device_t *dev, struct v4l2_buffer *buf_info) {
|
||||
memset(buf_info, 0, sizeof(struct v4l2_buffer));
|
||||
MEMSET_ZERO_PTR(buf_info);
|
||||
buf_info->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf_info->memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
|
||||
@ -55,10 +55,12 @@ struct captured_picture_t {
|
||||
struct picture_t picture;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
bool updated;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
|
||||
void captured_picture_init(struct captured_picture_t *captured);
|
||||
struct captured_picture_t *captured_picture_init();
|
||||
void captured_picture_destroy(struct captured_picture_t *captured);
|
||||
|
||||
void capture_loop(struct device_t *dev, struct captured_picture_t *captured, sig_atomic_t *volatile global_stop);
|
||||
|
||||
21
src/device.c
21
src/device.c
@ -48,9 +48,17 @@ static const char *_format_to_string_null(const unsigned format);
|
||||
static const char *_standard_to_string(const v4l2_std_id standard);
|
||||
|
||||
|
||||
void device_init(struct device_t *dev, struct device_runtime_t *run) {
|
||||
memset(dev, 0, sizeof(struct device_t));
|
||||
memset(run, 0, sizeof(struct device_runtime_t));
|
||||
struct device_t *device_init() {
|
||||
struct device_t *dev;
|
||||
struct device_runtime_t *run;
|
||||
|
||||
A_CALLOC(dev, 1, sizeof(*dev));
|
||||
MEMSET_ZERO_PTR(dev);
|
||||
|
||||
A_CALLOC(run, 1, sizeof(*run));
|
||||
MEMSET_ZERO_PTR(run);
|
||||
dev->run = run;
|
||||
dev->run->fd = -1;
|
||||
|
||||
dev->path = (char *)DEFAULT_DEVICE;
|
||||
dev->width = 640;
|
||||
@ -61,9 +69,12 @@ void device_init(struct device_t *dev, struct device_runtime_t *run) {
|
||||
dev->jpeg_quality = 80;
|
||||
dev->timeout = 1;
|
||||
dev->error_timeout = 1;
|
||||
return dev;
|
||||
}
|
||||
|
||||
dev->run = run;
|
||||
dev->run->fd = -1;
|
||||
void device_destroy(struct device_t *dev) {
|
||||
free(dev->run);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
int device_parse_format(const char *const str) {
|
||||
|
||||
@ -49,7 +49,8 @@ struct device_t {
|
||||
};
|
||||
|
||||
|
||||
void device_init(struct device_t *dev, struct device_runtime_t *run);
|
||||
struct device_t *device_init();
|
||||
void device_destroy(struct device_t *dev);
|
||||
|
||||
int device_parse_format(const char *const str);
|
||||
v4l2_std_id device_parse_standard(const char *const str);
|
||||
|
||||
28
src/http.c
Normal file
28
src/http.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include "capture.h"
|
||||
#include "tools.h"
|
||||
#include "http.h"
|
||||
|
||||
|
||||
static const char DEFAULT_HOST[] = "localhost";
|
||||
|
||||
|
||||
struct http_server_t *http_server_init() {
|
||||
struct http_server_t *server;
|
||||
|
||||
A_CALLOC(server, 1, sizeof(*server));
|
||||
MEMSET_ZERO_PTR(server);
|
||||
|
||||
server->host = (char *)DEFAULT_HOST;
|
||||
server->port = 8080;
|
||||
return server;
|
||||
}
|
||||
|
||||
void http_server_destroy(struct http_server_t *server) {
|
||||
free(server);
|
||||
}
|
||||
|
||||
void http_server_loop(struct http_server_t *server, struct captured_picture_t *captured, sig_atomic_t *volatile global_stop) {
|
||||
// TODO: implement server here
|
||||
}
|
||||
16
src/http.h
Normal file
16
src/http.h
Normal file
@ -0,0 +1,16 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include "tools.h"
|
||||
#include "capture.h"
|
||||
|
||||
|
||||
struct http_server_t {
|
||||
char *host;
|
||||
unsigned port;
|
||||
};
|
||||
|
||||
|
||||
struct http_server_t *http_server_init();
|
||||
void http_server_destroy(struct http_server_t *server);
|
||||
|
||||
void http_server_loop(struct http_server_t *server, struct captured_picture_t *captured, sig_atomic_t *volatile global_stop);
|
||||
124
src/main.c
124
src/main.c
@ -14,34 +14,38 @@
|
||||
#include "tools.h"
|
||||
#include "device.h"
|
||||
#include "capture.h"
|
||||
#include "http.h"
|
||||
|
||||
|
||||
static const char _short_opts[] = "hd:f:s:e:tn:q:";
|
||||
static const char _short_opts[] = "d:f:a:e:tn:q:s:p:h";
|
||||
static const struct option _long_opts[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"device", required_argument, NULL, 'd'},
|
||||
{"format", required_argument, NULL, 'f'},
|
||||
{"tv-standard", required_argument, NULL, 's'},
|
||||
{"every-frame", required_argument, NULL, 'e'},
|
||||
{"min-frame-size", required_argument, NULL, 'z'},
|
||||
{"dv-timings", no_argument, NULL, 't'},
|
||||
{"buffers", required_argument, NULL, 'n'},
|
||||
{"jpeg-quality", required_argument, NULL, 'q'},
|
||||
{"width", required_argument, NULL, 1000},
|
||||
{"height", required_argument, NULL, 1001},
|
||||
{"v4l2-timeout", required_argument, NULL, 1002},
|
||||
{"v4l2-error-timeout", required_argument, NULL, 1003},
|
||||
{"debug", no_argument, NULL, 5000},
|
||||
{"log-level", required_argument, NULL, 5001},
|
||||
{NULL, 0, NULL, 0},
|
||||
{"device", required_argument, NULL, 'd'},
|
||||
{"format", required_argument, NULL, 'f'},
|
||||
{"tv-standard", required_argument, NULL, 'a'},
|
||||
{"every-frame", required_argument, NULL, 'e'},
|
||||
{"min-frame-size", required_argument, NULL, 'z'},
|
||||
{"dv-timings", no_argument, NULL, 't'},
|
||||
{"buffers", required_argument, NULL, 'n'},
|
||||
{"jpeg-quality", required_argument, NULL, 'q'},
|
||||
{"width", required_argument, NULL, 1000},
|
||||
{"height", required_argument, NULL, 1001},
|
||||
{"device-timeout", required_argument, NULL, 1002},
|
||||
{"device-error-timeout", required_argument, NULL, 1003},
|
||||
|
||||
{"host", required_argument, NULL, 's'},
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
|
||||
{"debug", no_argument, NULL, 5000},
|
||||
{"log-level", required_argument, NULL, 5001},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static void _help(int exit_code) {
|
||||
static void _help() {
|
||||
printf("No manual yet\n");
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
static void _parse_options(int argc, char *argv[], struct device_t *dev) {
|
||||
static int _parse_options(int argc, char *argv[], struct device_t *dev, struct http_server_t *server) {
|
||||
# define OPT_ARG(_dest) \
|
||||
{ _dest = optarg; break; }
|
||||
|
||||
@ -51,12 +55,12 @@ static void _parse_options(int argc, char *argv[], struct device_t *dev) {
|
||||
# define OPT_UNSIGNED(_dest, _name, _min) \
|
||||
{ int _tmp = strtol(optarg, NULL, 0); \
|
||||
if (errno || _tmp < _min) \
|
||||
{ printf("Invalid value for '%s=%u'; minimal=%u\n", _name, _tmp, _min); exit(EXIT_FAILURE); } \
|
||||
{ printf("Invalid value for '%s=%u'; minimal=%u\n", _name, _tmp, _min); return -1; } \
|
||||
_dest = _tmp; break; }
|
||||
|
||||
# define OPT_PARSE(_dest, _func, _invalid, _name) \
|
||||
{ if ((_dest = _func(optarg)) == _invalid) \
|
||||
{ printf("Unknown " _name ": %s\n", optarg); exit(EXIT_FAILURE); } \
|
||||
{ printf("Unknown " _name ": %s\n", optarg); return -1; } \
|
||||
break; }
|
||||
|
||||
int index;
|
||||
@ -65,13 +69,12 @@ static void _parse_options(int argc, char *argv[], struct device_t *dev) {
|
||||
log_level = LOG_LEVEL_INFO;
|
||||
while ((ch = getopt_long(argc, argv, _short_opts, _long_opts, &index)) >= 0) {
|
||||
switch (ch) {
|
||||
case 0: break;
|
||||
case 'd': OPT_ARG(dev->path);
|
||||
# pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
# pragma GCC diagnostic push
|
||||
case 'f': OPT_PARSE(dev->format, device_parse_format, FORMAT_UNKNOWN, "pixel format");
|
||||
# pragma GCC diagnostic pop
|
||||
case 's': OPT_PARSE(dev->standard, device_parse_standard, STANDARD_UNKNOWN, "TV standard");
|
||||
case 'a': OPT_PARSE(dev->standard, device_parse_standard, STANDARD_UNKNOWN, "TV standard");
|
||||
case 'e': OPT_UNSIGNED(dev->every_frame, "--every-frame", 1);
|
||||
case 'z': OPT_UNSIGNED(dev->min_frame_size, "--min-frame-size", 0);
|
||||
case 't': OPT_TRUE(dev->dv_timings);
|
||||
@ -81,10 +84,14 @@ static void _parse_options(int argc, char *argv[], struct device_t *dev) {
|
||||
case 1001: OPT_UNSIGNED(dev->height, "--height", 180);
|
||||
case 1002: OPT_UNSIGNED(dev->timeout, "--timeout", 1);
|
||||
case 1003: OPT_UNSIGNED(dev->error_timeout, "--error-timeout", 1);
|
||||
|
||||
case 's': server->host = optarg; break;
|
||||
case 'p': OPT_UNSIGNED(server->port, "--port", 1);
|
||||
|
||||
case 5000: log_level = LOG_LEVEL_DEBUG; break;
|
||||
case 5001: OPT_UNSIGNED(log_level, "--log-level", 0);
|
||||
case 'h': _help(EXIT_SUCCESS); break;
|
||||
default: _help(EXIT_FAILURE); break;
|
||||
case 0: break;
|
||||
case 'h': default: _help(); return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,35 +99,46 @@ static void _parse_options(int argc, char *argv[], struct device_t *dev) {
|
||||
# undef OPT_UNSIGNED
|
||||
# undef OPT_TRUE
|
||||
# undef OPT_ARG
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct threads_context {
|
||||
struct thread_context {
|
||||
struct device_t *dev;
|
||||
struct captured_picture_t *captured;
|
||||
sig_atomic_t *volatile global_stop;
|
||||
struct http_server_t *server;
|
||||
};
|
||||
|
||||
static void *_capture_loop_thread(void *v_ctx) {
|
||||
struct threads_context *ctx = (struct threads_context *)v_ctx;
|
||||
sigset_t mask;
|
||||
static volatile sig_atomic_t _global_stop = 0;
|
||||
|
||||
static void _block_thread_signals() {
|
||||
sigset_t mask;
|
||||
assert(!sigemptyset(&mask));
|
||||
assert(!sigaddset(&mask, SIGINT));
|
||||
assert(!sigaddset(&mask, SIGTERM));
|
||||
assert(!pthread_sigmask(SIG_BLOCK, &mask, NULL));
|
||||
}
|
||||
|
||||
capture_loop(ctx->dev, ctx->captured, (sig_atomic_t *volatile)ctx->global_stop);
|
||||
static void *_capture_loop_thread(void *v_ctx) {
|
||||
struct thread_context *ctx = (struct thread_context *)v_ctx;
|
||||
_block_thread_signals();
|
||||
capture_loop(ctx->dev, ctx->captured, (sig_atomic_t *volatile)&_global_stop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static volatile sig_atomic_t _global_stop = 0;
|
||||
static void *_server_loop_thread(void *v_ctx) {
|
||||
struct thread_context *ctx = (struct thread_context *)v_ctx;
|
||||
_block_thread_signals();
|
||||
http_server_loop(ctx->server, ctx->captured, (sig_atomic_t *volatile)&_global_stop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _signal_handler(int signum) {
|
||||
LOG_INFO("===== Stopping by %s =====", strsignal(signum));
|
||||
_global_stop = 1;
|
||||
}
|
||||
|
||||
static void _init_signal_handlers() {
|
||||
static void _install_signal_handlers() {
|
||||
struct sigaction sig_act;
|
||||
|
||||
MEMSET_ZERO(sig_act);
|
||||
@ -137,19 +155,33 @@ static void _init_signal_handlers() {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct device_t dev;
|
||||
struct device_runtime_t run;
|
||||
struct captured_picture_t captured;
|
||||
struct threads_context ctx = {&dev, &captured, (sig_atomic_t *volatile)&_global_stop};
|
||||
pthread_t capture_loop_tid;
|
||||
struct device_t *dev;
|
||||
struct captured_picture_t *captured;
|
||||
struct http_server_t *server;
|
||||
|
||||
device_init(&dev, &run);
|
||||
_parse_options(argc, argv, &dev);
|
||||
_init_signal_handlers();
|
||||
dev = device_init();
|
||||
captured = captured_picture_init();
|
||||
server = http_server_init();
|
||||
|
||||
captured_picture_init(&captured);
|
||||
A_PTHREAD_CREATE(&capture_loop_tid, _capture_loop_thread, (void *)&ctx);
|
||||
A_PTHREAD_JOIN(capture_loop_tid);
|
||||
captured_picture_destroy(&captured);
|
||||
if (_parse_options(argc, argv, dev, server) == 0) {
|
||||
_install_signal_handlers();
|
||||
|
||||
pthread_t capture_loop_tid;
|
||||
pthread_t server_loop_tid;
|
||||
struct thread_context ctx;
|
||||
|
||||
ctx.dev = dev;
|
||||
ctx.captured = captured;
|
||||
ctx.server = server;
|
||||
|
||||
A_PTHREAD_CREATE(&capture_loop_tid, _capture_loop_thread, (void *)&ctx);
|
||||
A_PTHREAD_CREATE(&server_loop_tid, _server_loop_thread, (void *)&ctx);
|
||||
A_PTHREAD_JOIN(capture_loop_tid);
|
||||
A_PTHREAD_JOIN(server_loop_tid);
|
||||
}
|
||||
|
||||
http_server_destroy(server);
|
||||
captured_picture_destroy(captured);
|
||||
device_destroy(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -68,6 +68,7 @@ unsigned log_level;
|
||||
|
||||
#define A_CALLOC(_dest, _nmemb, _size) assert((_dest = calloc(_nmemb, _size)))
|
||||
#define MEMSET_ZERO(_x_obj) memset(&(_x_obj), 0, sizeof(_x_obj))
|
||||
#define MEMSET_ZERO_PTR(_x_ptr) memset(_x_ptr, 0, sizeof(*(_x_ptr)))
|
||||
|
||||
|
||||
#define INLINE inline __attribute__((always_inline))
|
||||
|
||||
BIN
vgcore.8195
Normal file
BIN
vgcore.8195
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user