http skel

This commit is contained in:
Devaev Maxim 2018-09-18 02:13:42 +03:00
parent 912443eafb
commit 8039d60ad5
10 changed files with 158 additions and 57 deletions

View File

@ -1,4 +1,4 @@
LIBS = -lm -ljpeg -pthread LIBS = -lm -ljpeg -pthread -levent
CC = gcc CC = gcc
CFLAGS = -c -O3 -Wall -Wextra CFLAGS = -c -O3 -Wall -Wextra
LDFLAGS = LDFLAGS =

View File

@ -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); static int _capture_handle_event(struct device_t *dev);
void captured_picture_init(struct captured_picture_t *captured) { struct captured_picture_t *captured_picture_init() {
memset(captured, 0, sizeof(struct captured_picture_t)); struct captured_picture_t *captured;
A_CALLOC(captured, 1, sizeof(*captured));
MEMSET_ZERO_PTR(captured);
A_PTHREAD_M_INIT(&captured->mutex); A_PTHREAD_M_INIT(&captured->mutex);
return captured;
} }
void captured_picture_destroy(struct captured_picture_t *captured) { void captured_picture_destroy(struct captured_picture_t *captured) {
A_PTHREAD_M_DESTROY(&captured->mutex); A_PTHREAD_M_DESTROY(&captured->mutex);
free(captured);
} }
#ifdef DUMP_CAPTURED_JPEGS #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 ..."); LOG_DEBUG("Allocation memory for captured (result) picture ...");
A_CALLOC(captured->picture.data, dev->run->max_picture_size, sizeof(*captured->picture.data)); 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) { while (!*global_stop) {
SEP_DEBUG('-'); 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, dev->run->pictures[last_worker->ctx.index].data,
captured->picture.size * sizeof(*captured->picture.data) captured->picture.size * sizeof(*captured->picture.data)
); );
captured->updated = true;
A_PTHREAD_M_UNLOCK(&captured->mutex); A_PTHREAD_M_UNLOCK(&captured->mutex);
last_worker = last_worker->order_next; 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) { 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->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf_info->memory = V4L2_MEMORY_MMAP; buf_info->memory = V4L2_MEMORY_MMAP;

View File

@ -55,10 +55,12 @@ struct captured_picture_t {
struct picture_t picture; struct picture_t picture;
unsigned width; unsigned width;
unsigned height; unsigned height;
bool updated;
pthread_mutex_t mutex; 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 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); void capture_loop(struct device_t *dev, struct captured_picture_t *captured, sig_atomic_t *volatile global_stop);

View File

@ -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); static const char *_standard_to_string(const v4l2_std_id standard);
void device_init(struct device_t *dev, struct device_runtime_t *run) { struct device_t *device_init() {
memset(dev, 0, sizeof(struct device_t)); struct device_t *dev;
memset(run, 0, sizeof(struct device_runtime_t)); 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->path = (char *)DEFAULT_DEVICE;
dev->width = 640; dev->width = 640;
@ -61,9 +69,12 @@ void device_init(struct device_t *dev, struct device_runtime_t *run) {
dev->jpeg_quality = 80; dev->jpeg_quality = 80;
dev->timeout = 1; dev->timeout = 1;
dev->error_timeout = 1; dev->error_timeout = 1;
return dev;
}
dev->run = run; void device_destroy(struct device_t *dev) {
dev->run->fd = -1; free(dev->run);
free(dev);
} }
int device_parse_format(const char *const str) { int device_parse_format(const char *const str) {

View File

@ -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); int device_parse_format(const char *const str);
v4l2_std_id device_parse_standard(const char *const str); v4l2_std_id device_parse_standard(const char *const str);

28
src/http.c Normal file
View 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
View 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);

View File

@ -14,34 +14,38 @@
#include "tools.h" #include "tools.h"
#include "device.h" #include "device.h"
#include "capture.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[] = { static const struct option _long_opts[] = {
{"help", no_argument, NULL, 'h'}, {"device", required_argument, NULL, 'd'},
{"device", required_argument, NULL, 'd'}, {"format", required_argument, NULL, 'f'},
{"format", required_argument, NULL, 'f'}, {"tv-standard", required_argument, NULL, 'a'},
{"tv-standard", required_argument, NULL, 's'}, {"every-frame", required_argument, NULL, 'e'},
{"every-frame", required_argument, NULL, 'e'}, {"min-frame-size", required_argument, NULL, 'z'},
{"min-frame-size", required_argument, NULL, 'z'}, {"dv-timings", no_argument, NULL, 't'},
{"dv-timings", no_argument, NULL, 't'}, {"buffers", required_argument, NULL, 'n'},
{"buffers", required_argument, NULL, 'n'}, {"jpeg-quality", required_argument, NULL, 'q'},
{"jpeg-quality", required_argument, NULL, 'q'}, {"width", required_argument, NULL, 1000},
{"width", required_argument, NULL, 1000}, {"height", required_argument, NULL, 1001},
{"height", required_argument, NULL, 1001}, {"device-timeout", required_argument, NULL, 1002},
{"v4l2-timeout", required_argument, NULL, 1002}, {"device-error-timeout", required_argument, NULL, 1003},
{"v4l2-error-timeout", required_argument, NULL, 1003},
{"debug", no_argument, NULL, 5000}, {"host", required_argument, NULL, 's'},
{"log-level", required_argument, NULL, 5001}, {"port", required_argument, NULL, 'p'},
{NULL, 0, NULL, 0},
{"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"); 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) \ # define OPT_ARG(_dest) \
{ _dest = optarg; break; } { _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) \ # define OPT_UNSIGNED(_dest, _name, _min) \
{ int _tmp = strtol(optarg, NULL, 0); \ { int _tmp = strtol(optarg, NULL, 0); \
if (errno || _tmp < _min) \ 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; } _dest = _tmp; break; }
# define OPT_PARSE(_dest, _func, _invalid, _name) \ # define OPT_PARSE(_dest, _func, _invalid, _name) \
{ if ((_dest = _func(optarg)) == _invalid) \ { if ((_dest = _func(optarg)) == _invalid) \
{ printf("Unknown " _name ": %s\n", optarg); exit(EXIT_FAILURE); } \ { printf("Unknown " _name ": %s\n", optarg); return -1; } \
break; } break; }
int index; int index;
@ -65,13 +69,12 @@ static void _parse_options(int argc, char *argv[], struct device_t *dev) {
log_level = LOG_LEVEL_INFO; log_level = LOG_LEVEL_INFO;
while ((ch = getopt_long(argc, argv, _short_opts, _long_opts, &index)) >= 0) { while ((ch = getopt_long(argc, argv, _short_opts, _long_opts, &index)) >= 0) {
switch (ch) { switch (ch) {
case 0: break;
case 'd': OPT_ARG(dev->path); case 'd': OPT_ARG(dev->path);
# pragma GCC diagnostic ignored "-Wsign-compare" # pragma GCC diagnostic ignored "-Wsign-compare"
# pragma GCC diagnostic push # pragma GCC diagnostic push
case 'f': OPT_PARSE(dev->format, device_parse_format, FORMAT_UNKNOWN, "pixel format"); case 'f': OPT_PARSE(dev->format, device_parse_format, FORMAT_UNKNOWN, "pixel format");
# pragma GCC diagnostic pop # 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 'e': OPT_UNSIGNED(dev->every_frame, "--every-frame", 1);
case 'z': OPT_UNSIGNED(dev->min_frame_size, "--min-frame-size", 0); case 'z': OPT_UNSIGNED(dev->min_frame_size, "--min-frame-size", 0);
case 't': OPT_TRUE(dev->dv_timings); 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 1001: OPT_UNSIGNED(dev->height, "--height", 180);
case 1002: OPT_UNSIGNED(dev->timeout, "--timeout", 1); case 1002: OPT_UNSIGNED(dev->timeout, "--timeout", 1);
case 1003: OPT_UNSIGNED(dev->error_timeout, "--error-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 5000: log_level = LOG_LEVEL_DEBUG; break;
case 5001: OPT_UNSIGNED(log_level, "--log-level", 0); case 5001: OPT_UNSIGNED(log_level, "--log-level", 0);
case 'h': _help(EXIT_SUCCESS); break; case 0: break;
default: _help(EXIT_FAILURE); 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_UNSIGNED
# undef OPT_TRUE # undef OPT_TRUE
# undef OPT_ARG # undef OPT_ARG
return 0;
} }
struct threads_context { struct thread_context {
struct device_t *dev; struct device_t *dev;
struct captured_picture_t *captured; struct captured_picture_t *captured;
sig_atomic_t *volatile global_stop; struct http_server_t *server;
}; };
static void *_capture_loop_thread(void *v_ctx) { static volatile sig_atomic_t _global_stop = 0;
struct threads_context *ctx = (struct threads_context *)v_ctx;
sigset_t mask;
static void _block_thread_signals() {
sigset_t mask;
assert(!sigemptyset(&mask)); assert(!sigemptyset(&mask));
assert(!sigaddset(&mask, SIGINT)); assert(!sigaddset(&mask, SIGINT));
assert(!sigaddset(&mask, SIGTERM)); assert(!sigaddset(&mask, SIGTERM));
assert(!pthread_sigmask(SIG_BLOCK, &mask, NULL)); 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; 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) { static void _signal_handler(int signum) {
LOG_INFO("===== Stopping by %s =====", strsignal(signum)); LOG_INFO("===== Stopping by %s =====", strsignal(signum));
_global_stop = 1; _global_stop = 1;
} }
static void _init_signal_handlers() { static void _install_signal_handlers() {
struct sigaction sig_act; struct sigaction sig_act;
MEMSET_ZERO(sig_act); MEMSET_ZERO(sig_act);
@ -137,19 +155,33 @@ static void _init_signal_handlers() {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct device_t dev; struct device_t *dev;
struct device_runtime_t run; struct captured_picture_t *captured;
struct captured_picture_t captured; struct http_server_t *server;
struct threads_context ctx = {&dev, &captured, (sig_atomic_t *volatile)&_global_stop};
pthread_t capture_loop_tid;
device_init(&dev, &run); dev = device_init();
_parse_options(argc, argv, &dev); captured = captured_picture_init();
_init_signal_handlers(); server = http_server_init();
captured_picture_init(&captured); if (_parse_options(argc, argv, dev, server) == 0) {
A_PTHREAD_CREATE(&capture_loop_tid, _capture_loop_thread, (void *)&ctx); _install_signal_handlers();
A_PTHREAD_JOIN(capture_loop_tid);
captured_picture_destroy(&captured); 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; return 0;
} }

View File

@ -68,6 +68,7 @@ unsigned log_level;
#define A_CALLOC(_dest, _nmemb, _size) assert((_dest = calloc(_nmemb, _size))) #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(_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)) #define INLINE inline __attribute__((always_inline))

BIN
vgcore.8195 Normal file

Binary file not shown.