Compare commits

...

16 Commits
v0.14 ... v0.17

Author SHA1 Message Date
Devaev Maxim
6029408564 Bump version: 0.16 → 0.17 2018-10-04 01:33:30 +03:00
Devaev Maxim
8734834341 refactoring 2018-10-04 01:32:02 +03:00
Devaev Maxim
809f86955d refactoring 2018-10-04 01:29:38 +03:00
Devaev Maxim
2f557617d8 --add-x-timings -> --extra-stream-headers 2018-10-04 01:07:06 +03:00
Devaev Maxim
35c8196103 extra headers 2018-10-04 00:59:59 +03:00
Devaev Maxim
c71df1bb25 fixed time rounding 2018-10-03 20:46:13 +03:00
Devaev Maxim
bc107d2870 eps 2018-10-03 20:37:39 +03:00
Devaev Maxim
294ed36b8f clients count in /ping 2018-10-03 19:29:19 +03:00
Devaev Maxim
e01c7640b7 Bump version: 0.15 → 0.16 2018-10-02 23:30:27 +03:00
Devaev Maxim
90125dcce4 refactoring 2018-10-02 23:28:50 +03:00
Devaev Maxim
a0c87c1c04 configurable input channel 2018-10-02 23:28:35 +03:00
Devaev Maxim
8924cdcac4 removed newline 2018-10-02 13:57:28 +03:00
Devaev Maxim
0d396e3f0a Bump version: 0.14 → 0.15 2018-10-01 18:15:52 +03:00
Devaev Maxim
28daefc5ff refactoring 2018-10-01 18:12:43 +03:00
Devaev Maxim
895db6a8c9 logging: flush stdout 2018-10-01 18:12:43 +03:00
Maxim Devaev
73b894419a Update README.md 2018-10-01 07:01:58 +03:00
16 changed files with 126 additions and 72 deletions

View File

@@ -1,7 +1,7 @@
[bumpversion]
commit = True
tag = True
current_version = 0.14
current_version = 0.17
parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)?
serialize =
{major}.{minor}

View File

@@ -3,7 +3,7 @@
pkgname=ustreamer
pkgver=0.14
pkgver=0.17
pkgrel=1
pkgdesc="Lightweight and fast MJPG-HTTP streamer"
url="https://github.com/pi-kvm/ustreamer"

View File

@@ -17,7 +17,7 @@
| Возможность сервить файлы встроенным<br>HTTP-сервером, настройки авторизации | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет <sup>4</sup> | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть |
Сносочки:
* ```1``` Для mjpg-streamer существует [мой патч](https://github.com/jacksonliam/mjpg-streamer/pull/164), предотвращающий зависание при отключении устройства и добавляющий поддержку DV-таймингов, однако трансляция при этом все равно прерывается. В данный момент этот патч не принят в апстрим, и я даже не гарантирую его стопроцентную работоспособность. Код mjpg-streamer очень плохо структурирован и чрезвычайно запутан, и я мог что-то упустить. Собственно, это одна из причин, почему µStreamer написан с нуля.
* ```1``` Для mjpg-streamer существует [мой патч](https://github.com/jacksonliam/mjpg-streamer/pull/164), предотвращающий зависание при отключении устройства и добавляющий поддержку DV-таймингов, однако трансляция при этом все равно прерывается. В данный момент этот патч не принят в апстрим, и я даже не гарантирую его стопроцентную работоспособность. Код mjpg-streamer очень плохо структурирован и чрезвычайно запутан, и я мог что-то упустить. Собственно, это одна из причин, почему µStreamer был написан с нуля.
* ```2``` Это фича позволяет в несколько раз снизить объем исходящего трафика при трансляции HDMI, однако увеличивает загрузку процессора и добавляет небольшую задержку. Суть в том, что HDMI - полностью цифровой интерфейс, и новый захваченный фрейм может быть идентичен предыдущему в точности до байта. В этом случае нет нужды передавать одну и ту же картинку по сети несколько раз в секунду. При использовании опции `--drop-same-frames=20`, µStreamer будет дропать все одинаковые фреймы, но не более 20. Новый фрейм сравнивается с предыдущим сначала по длине, а затем помощью ```memcmp()```.
@@ -46,7 +46,7 @@ $ ./ustreamer --help
-----
# Использование
Будучи запущенным без аргументов, ```ustremaer``` попробует открыть устройство ```/dev/video0``` с разрешением 640x480 и начать трансляцию на ```http://localhost:8080```. Это поведение может быть изменено с помощью опций ```--device```, ```--host``` и ```--port```. Пример вещания на всю сеть по 80 порту:
Будучи запущенным без аргументов, ```ustreamer``` попробует открыть устройство ```/dev/video0``` с разрешением 640x480 и начать трансляцию на ```http://localhost:8080```. Это поведение может быть изменено с помощью опций ```--device```, ```--host``` и ```--port```. Пример вещания на всю сеть по 80 порту:
```
# ./ustreamer --device=/dev/video1 --host=0.0.0.0 --port=80
```

View File

@@ -21,4 +21,4 @@
#pragma once
#define VERSION "0.14"
#define VERSION "0.17"

View File

@@ -185,6 +185,7 @@ void device_close(struct device_t *dev) {
static int _device_open_check_cap(struct device_t *dev) {
struct v4l2_capability cap;
int input = dev->input; // Needs pointer to int for ioctl()
MEMSET_ZERO(cap);
@@ -204,10 +205,16 @@ static int _device_open_check_cap(struct device_t *dev) {
return -1;
}
LOG_INFO("Using input channel: %d", input);
if (xioctl(dev->run->fd, VIDIOC_S_INPUT, &input) < 0) {
LOG_ERROR("Can't set input channel");
return -1;
}
if (dev->standard != V4L2_STD_UNKNOWN) {
LOG_INFO("Using TV standard: %s", _standard_to_string(dev->standard));
if (xioctl(dev->run->fd, VIDIOC_S_STD, &dev->standard) < 0) {
LOG_PERROR("Can't set video standard");
LOG_ERROR("Can't set video standard");
return -1;
}
} else {

View File

@@ -64,6 +64,7 @@ struct device_runtime_t {
struct device_t {
char *path;
unsigned input;
unsigned width;
unsigned height;
unsigned format;

View File

@@ -131,7 +131,7 @@ void encoder_prepare_for_device(struct encoder_t *encoder, struct device_t *dev)
int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, const unsigned index) {
assert(encoder->type != ENCODER_TYPE_UNKNOWN);
dev->run->pictures[index].encode_begin_time = now_monotonic_ms();
dev->run->pictures[index].encode_begin_time = get_now_monotonic();
if (encoder->type == ENCODER_TYPE_CPU) {
jpeg_encoder_compress_buffer(dev, index, encoder->quality);
@@ -144,7 +144,7 @@ int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev, con
}
# endif
dev->run->pictures[index].encode_end_time = now_monotonic_ms();
dev->run->pictures[index].encode_end_time = get_now_monotonic();
return 0;

View File

@@ -115,7 +115,7 @@ int http_server_listen(struct http_server_t *server) {
LOG_DEBUG("Binding HTTP to [%s]:%d ...", server->host, server->port);
evhttp_set_timeout(server->run->http, server->timeout);
if (evhttp_bind_socket(server->run->http, server->host, server->port) != 0) {
if (evhttp_bind_socket(server->run->http, server->host, server->port) < 0) {
LOG_PERROR("Can't listen HTTP on [%s]:%d", server->host, server->port)
return -1;
}
@@ -174,10 +174,14 @@ static void _http_callback_ping(struct evhttp_request *request, void *v_server)
assert(evbuffer_add_printf(buf,
"{\"stream\": {\"resolution\":"
" {\"width\": %u, \"height\": %u},"
" \"fps\": %u, \"online\": %s}}",
" \"fps\": %u, \"eps\": %u,"
" \"online\": %s, \"clients\": %u}}",
(server->fake_width ? server->fake_width : server->run->exposed->width),
(server->fake_height ? server->fake_height : server->run->exposed->height),
server->run->exposed->fps, (server->run->exposed->online ? "true" : "false")
server->run->exposed->fps, // frame per second (capturing)
server->run->exposed->eps, // expose per second (server)
(server->run->exposed->online ? "true" : "false"),
server->run->stream_clients_count
));
ADD_HEADER("Content-Type", "application/json");
evhttp_send_reply(request, HTTP_OK, "OK", buf);
@@ -204,16 +208,16 @@ static void _http_callback_snapshot(struct evhttp_request *request, void *v_serv
# define ADD_TIME_HEADER(_key, _value) \
{ sprintf(time_buf, "%.06Lf", _value); ADD_HEADER(_key, time_buf); }
ADD_TIME_HEADER("X-Timestamp", now_real_ms());
ADD_TIME_HEADER("X-Timestamp", get_now_real());
if (server->add_x_timings) {
ADD_TIME_HEADER("X-UStreamer-Grab-Time", EXPOSED(picture.grab_time));
ADD_TIME_HEADER("X-UStreamer-Encode-Begin-Time", EXPOSED(picture.encode_begin_time));
ADD_TIME_HEADER("X-UStreamer-Encode-End-Time", EXPOSED(picture.encode_end_time));
ADD_TIME_HEADER("X-UStreamer-Expose-Begin-Time", EXPOSED(expose_begin_time));
ADD_TIME_HEADER("X-UStreamer-Expose-End-Time", EXPOSED(expose_end_time));
ADD_TIME_HEADER("X-UStreamer-Send-Time", now_monotonic_ms());
}
ADD_HEADER("X-UStreamer-Online", (EXPOSED(online) ? "true" : "false"));
ADD_TIME_HEADER("X-UStreamer-Grab-Time", EXPOSED(picture.grab_time));
ADD_TIME_HEADER("X-UStreamer-Encode-Begin-Time", EXPOSED(picture.encode_begin_time));
ADD_TIME_HEADER("X-UStreamer-Encode-End-Time", EXPOSED(picture.encode_end_time));
ADD_TIME_HEADER("X-UStreamer-Expose-Begin-Time", EXPOSED(expose_begin_time));
ADD_TIME_HEADER("X-UStreamer-Expose-Cmp-Time", EXPOSED(expose_cmp_time));
ADD_TIME_HEADER("X-UStreamer-Expose-End-Time", EXPOSED(expose_end_time));
ADD_TIME_HEADER("X-UStreamer-Send-Time", get_now_monotonic());
# undef ADD_TIME_HEADER
@@ -310,23 +314,27 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
"X-Timestamp: %.06Lf" RN
"%s",
EXPOSED(picture.size) * sizeof(*EXPOSED(picture.data)),
now_real_ms(), (client->server->add_x_timings ? "" : RN)
get_now_real(), (client->server->extra_stream_headers ? "" : RN)
));
if (client->server->add_x_timings) {
if (client->server->extra_stream_headers) {
assert(evbuffer_add_printf(buf,
"X-UStreamer-Online: %s" RN
"X-UStreamer-Grab-Time: %.06Lf" RN
"X-UStreamer-Encode-Begin-Time: %.06Lf" RN
"X-UStreamer-Encode-End-Time: %.06Lf" RN
"X-UStreamer-Expose-Begin-Time: %.06Lf" RN
"X-UStreamer-Expose-Cmp-Time: %.06Lf" RN
"X-UStreamer-Expose-End-Time: %.06Lf" RN
"X-UStreamer-Send-Time: %.06Lf" RN
RN,
(EXPOSED(online) ? "true" : "false"),
EXPOSED(picture.grab_time),
EXPOSED(picture.encode_begin_time),
EXPOSED(picture.encode_end_time),
EXPOSED(expose_begin_time),
EXPOSED(expose_cmp_time),
EXPOSED(expose_end_time),
now_monotonic_ms()
get_now_monotonic()
));
}
@@ -398,6 +406,9 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
struct http_server_t *server = (struct http_server_t *)v_server;
bool updated = false;
bool queue_send = false;
long long now;
static unsigned eps = 0;
static long long eps_second = 0;
#define LOCK_STREAM \
A_PTHREAD_M_LOCK(&server->run->stream->mutex);
@@ -423,6 +434,13 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
}
if (queue_send) {
if ((now = floor_ms(get_now_monotonic())) != eps_second) {
server->run->exposed->eps = eps;
eps = 0;
eps_second = now;
}
eps += 1;
_http_queue_send_stream(server, updated);
}
@@ -436,7 +454,7 @@ static bool _expose_new_picture(struct http_server_t *server) {
assert(STREAM(picture.size) > 0);
EXPOSED(fps) = STREAM(fps);
EXPOSED(expose_begin_time) = now_monotonic_ms();
EXPOSED(expose_begin_time) = get_now_monotonic();
# define MEM_STREAM_TO_EXPOSED \
EXPOSED(picture.data), STREAM(picture.data), \
@@ -449,10 +467,20 @@ static bool _expose_new_picture(struct http_server_t *server) {
&& EXPOSED(picture.size) == STREAM(picture.size)
&& !memcmp(MEM_STREAM_TO_EXPOSED)
) {
LOG_PERF("HTTP: dropped same frame number %u", EXPOSED(dropped));
EXPOSED(expose_cmp_time) = get_now_monotonic();
EXPOSED(expose_end_time) = EXPOSED(expose_cmp_time);
LOG_PERF(
"HTTP: dropped same frame number %u; comparsion time = %.06Lf",
EXPOSED(dropped), EXPOSED(expose_cmp_time) - EXPOSED(expose_begin_time)
);
EXPOSED(dropped) += 1;
EXPOSED(expose_end_time) = now_monotonic_ms();
return false; // Not updated
} else {
EXPOSED(expose_cmp_time) = get_now_monotonic();
LOG_PERF(
"HTTP: passed same frame check (frames are differ); comparsion time = %.06Lf",
EXPOSED(expose_cmp_time) - EXPOSED(expose_begin_time)
);
}
}
@@ -475,7 +503,8 @@ static bool _expose_new_picture(struct http_server_t *server) {
EXPOSED(height) = STREAM(height);
EXPOSED(online) = true;
EXPOSED(dropped) = 0;
EXPOSED(expose_end_time) = now_monotonic_ms();
EXPOSED(expose_cmp_time) = EXPOSED(expose_begin_time);
EXPOSED(expose_end_time) = get_now_monotonic();
# undef STREAM
# undef EXPOSED
@@ -485,7 +514,8 @@ static bool _expose_new_picture(struct http_server_t *server) {
static bool _expose_blank_picture(struct http_server_t *server) {
# define EXPOSED(_next) server->run->exposed->_next
EXPOSED(expose_begin_time) = now_monotonic_ms();
EXPOSED(expose_begin_time) = get_now_monotonic();
EXPOSED(expose_cmp_time) = EXPOSED(expose_begin_time);
if (EXPOSED(online) || EXPOSED(picture.size) == 0) {
if (EXPOSED(picture.allocated) < BLANK_JPG_SIZE) {
@@ -514,13 +544,13 @@ static bool _expose_blank_picture(struct http_server_t *server) {
if (EXPOSED(dropped) < server->run->drop_same_frames_blank) {
LOG_PERF("HTTP: dropped same frame (BLANK) number %u", EXPOSED(dropped));
EXPOSED(dropped) += 1;
EXPOSED(expose_end_time) = now_monotonic_ms();
EXPOSED(expose_end_time) = get_now_monotonic();
return false; // Not updated
}
updated:
EXPOSED(dropped) = 0;
EXPOSED(expose_end_time) = now_monotonic_ms();
EXPOSED(expose_end_time) = get_now_monotonic();
return true; // Updated
# undef EXPOSED

View File

@@ -45,7 +45,9 @@ struct exposed_t {
unsigned fps;
bool online;
unsigned dropped;
unsigned eps;
long double expose_begin_time;
long double expose_cmp_time;
long double expose_end_time;
};
@@ -64,7 +66,7 @@ struct http_server_t {
char *host;
unsigned port;
unsigned drop_same_frames;
bool add_x_timings;
bool extra_stream_headers;
unsigned fake_width;
unsigned fake_height;
unsigned timeout;

View File

@@ -54,65 +54,72 @@ pthread_mutex_t log_mutex;
#define LOGGING_UNLOCK assert(!pthread_mutex_unlock(&log_mutex))
#define SEP_INFO(_x_ch) { \
#define SEP_INFO(_ch) { \
LOGGING_LOCK; \
for (int _i = 0; _i < 80; ++_i) { \
putchar(_x_ch); \
putchar(_ch); \
} \
putchar('\n'); \
fflush(stdout); \
LOGGING_UNLOCK; \
}
#define SEP_DEBUG(_x_ch) { \
#define SEP_DEBUG(_ch) { \
if (log_level >= LOG_LEVEL_DEBUG) { \
SEP_INFO(_x_ch); \
SEP_INFO(_ch); \
} \
}
#define LOG_ERROR(_x_msg, ...) { \
#define LOG_PRINTF_NOLOCK(_label, _msg, ...) { \
printf("-- " _label " [%.03Lf tid=%ld] -- " _msg "\n", get_now_monotonic(), syscall(SYS_gettid), ##__VA_ARGS__); \
fflush(stdout); \
}
#define LOG_ERROR(_msg, ...) { \
LOGGING_LOCK; \
printf("-- ERROR [%.03Lf tid=%ld] -- " _x_msg "\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__); \
LOG_PRINTF_NOLOCK("ERROR", _msg, ##__VA_ARGS__); \
LOGGING_UNLOCK; \
}
#define LOG_PERROR(_x_msg, ...) { \
#define LOG_PERROR(_msg, ...) { \
char _buf[1024] = ""; \
strerror_r(errno, _buf, 1024); \
LOGGING_LOCK; \
printf("-- ERROR [%.03Lf tid=%ld] -- " _x_msg ": %s\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__, _buf); \
printf("-- ERROR [%.03Lf tid=%ld] -- " _msg ": %s\n", get_now_monotonic(), syscall(SYS_gettid), ##__VA_ARGS__, _buf); \
fflush(stdout); \
LOGGING_UNLOCK; \
}
#define LOG_INFO(_x_msg, ...) { \
#define LOG_INFO(_msg, ...) { \
LOGGING_LOCK; \
printf("-- INFO [%.03Lf tid=%ld] -- " _x_msg "\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__); \
LOG_PRINTF_NOLOCK("INFO ", _msg, ##__VA_ARGS__); \
LOGGING_UNLOCK; \
}
#define LOG_INFO_NOLOCK(_x_msg, ...) { \
printf("-- INFO [%.03Lf tid=%ld] -- " _x_msg "\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__); \
#define LOG_INFO_NOLOCK(_msg, ...) { \
LOG_PRINTF_NOLOCK("INFO ", _msg, ##__VA_ARGS__); \
}
#define LOG_PERF(_x_msg, ...) { \
#define LOG_PERF(_msg, ...) { \
if (log_level >= LOG_LEVEL_PERF) { \
LOGGING_LOCK; \
printf("-- PERF [%.03Lf tid=%ld] -- " _x_msg "\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__); \
LOG_PRINTF_NOLOCK("PERF ", _msg, ##__VA_ARGS__); \
LOGGING_UNLOCK; \
} \
}
#define LOG_VERBOSE(_x_msg, ...) { \
#define LOG_VERBOSE(_msg, ...) { \
if (log_level >= LOG_LEVEL_VERBOSE) { \
LOGGING_LOCK; \
printf("-- VERB [%.03Lf tid=%ld] -- " _x_msg "\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__); \
LOG_PRINTF_NOLOCK("VERB ", _msg, ##__VA_ARGS__); \
LOGGING_UNLOCK; \
} \
}
#define LOG_DEBUG(_x_msg, ...) { \
#define LOG_DEBUG(_msg, ...) { \
if (log_level >= LOG_LEVEL_DEBUG) { \
LOGGING_LOCK; \
printf("-- DEBUG [%.03Lf tid=%ld] -- " _x_msg "\n", now_monotonic_ms(), syscall(SYS_gettid), ##__VA_ARGS__); \
LOG_PRINTF_NOLOCK("DEBUG", _msg, ##__VA_ARGS__); \
LOGGING_UNLOCK; \
} \
}

View File

@@ -40,9 +40,10 @@
#include "http.h"
static const char _short_opts[] = "d:x:y:f:a:e:z:tn:w:q:c:s:p:r:h";
static const char _short_opts[] = "d:i:x:y:f:a:e:z:tn:w:q:c:s:p:r:h";
static const struct option _long_opts[] = {
{"device", required_argument, NULL, 'd'},
{"input", required_argument, NULL, 'i'},
{"width", required_argument, NULL, 'x'},
{"height", required_argument, NULL, 'y'},
{"format", required_argument, NULL, 'f'},
@@ -63,7 +64,7 @@ static const struct option _long_opts[] = {
{"host", required_argument, NULL, 's'},
{"port", required_argument, NULL, 'p'},
{"drop-same-frames", required_argument, NULL, 'r'},
{"add-x-timings", no_argument, NULL, 2000},
{"extra-stream-headers", no_argument, NULL, 2000},
{"fake-width", required_argument, NULL, 2001},
{"fake-height", required_argument, NULL, 2002},
{"server-timeout", required_argument, NULL, 2003},
@@ -83,9 +84,10 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
printf("Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com>\n\n");
printf("Capturing options:\n");
printf("------------------\n");
printf(" -d|--device </dev/path> -- Path to V4L2 device. Default: %s\n\n", dev->path);
printf(" -x|--width <N> -- Initial image width. Default: %d\n\n", dev->width);
printf(" -y|--height <N> -- Initial image height. Default: %d\n\n", dev->height);
printf(" -d|--device </dev/path> -- Path to V4L2 device. Default: %s.\n\n", dev->path);
printf(" -i|--input <N> -- Input channel. Default: %u.\n\n", dev->input);
printf(" -x|--width <N> -- Initial image width. Default: %d.\n\n", dev->width);
printf(" -y|--height <N> -- Initial image height. Default: %d.\n\n", dev->height);
printf(" -f|--format <fmt> -- Image format.\n");
printf(" Available: %s; default: YUYV.\n\n", FORMATS_STR);
printf(" -a|--tv-standard <std> -- Force TV standard.\n");
@@ -117,7 +119,7 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
printf(" It can significantly reduce the outgoing traffic, but will increase\n");
printf(" the CPU loading. Don't use this option with analog signal sources\n");
printf(" or webcams, it's useless. Default: disabled.\n\n");
printf(" --add-x-timings -- Add X-UStreamer-*-Time headers to the /stream and /snapshot handles.\n");
printf(" --extra-stream-headers -- Add X-UStreamer-* headers to /stream handle (like /snapshot).\n");
printf(" Default: disabled.\n\n");
printf(" --fake-width <N> -- Override image width for /ping. Default: disabled\n\n");
printf(" --fake-height <N> -- Override image height for /ping. Default: disabled.\n\n");
@@ -156,6 +158,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
while ((ch = getopt_long(argc, argv, _short_opts, _long_opts, &index)) >= 0) {
switch (ch) {
case 'd': OPT_SET(dev->path, optarg);
case 'i': OPT_UNSIGNED(dev->input, "--input", 0, 128);
case 'x': OPT_UNSIGNED(dev->width, "--width", 320, 1920);
case 'y': OPT_UNSIGNED(dev->height, "--height", 180, 1200);
# pragma GCC diagnostic ignored "-Wsign-compare"
@@ -179,7 +182,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
case 's': OPT_SET(server->host, optarg);
case 'p': OPT_UNSIGNED(server->port, "--port", 1, 65535);
case 'r': OPT_UNSIGNED(server->drop_same_frames, "--drop-same-frames", 0, 30);
case 2000: OPT_SET(server->add_x_timings, true);
case 2000: OPT_SET(server->extra_stream_headers, true);
case 2001: OPT_UNSIGNED(server->fake_width, "--fake-width", 0, 1920);
case 2002: OPT_UNSIGNED(server->fake_height, "--fake-height", 0, 1200);
case 2003: OPT_UNSIGNED(server->timeout, "--server-timeout", 1, 60);

View File

@@ -29,12 +29,12 @@
#include "formatters.h"
#define CASE_TO_STRING(_val) \
case _val: { return #_val; }
#define CASE_TO_STRING(_value) \
case _value: { return #_value; }
#define CASE_ASSERT(_msg, _val) default: { \
#define CASE_ASSERT(_msg, _value) default: { \
char *_buf; A_CALLOC(_buf, 128); \
sprintf(_buf, _msg ": 0x%08x", _val); \
sprintf(_buf, _msg ": 0x%08x", _value); \
assert(0 && _buf); \
}

View File

@@ -35,7 +35,7 @@
#define LOG_OMX_ERROR(_error, _msg, ...) { \
LOGGING_LOCK; \
printf("-- ERROR [%.03Lf tid=%ld] -- " _msg ": %s\n", now_monotonic_ms(), \
printf("-- ERROR [%.03Lf tid=%ld] -- " _msg ": %s\n", get_now_monotonic(), \
syscall(SYS_gettid), ##__VA_ARGS__, omx_error_to_string(_error)); \
LOGGING_UNLOCK; \
}

View File

@@ -162,7 +162,8 @@ void stream_loop(struct stream_t *stream) {
LOG_DEBUG("Frame is ready");
struct v4l2_buffer buf_info;
long double now = now_monotonic_ms();
long double now = get_now_monotonic();
long long now_second = floor_ms(now);
if (_stream_grab_buffer(stream->dev, &buf_info) < 0) {
break;
@@ -196,11 +197,11 @@ void stream_loop(struct stream_t *stream) {
}
fluency_passed = 0;
if ((long long)now != fps_second) {
if (now_second != fps_second) {
LOG_PERF("Oldest worker complete, encoding FPS = %u", fps);
stream->fps = fps;
fps = 0;
fps_second = (long long)now;
fps_second = now_second;
}
fps += 1;

View File

@@ -49,8 +49,8 @@
#define A_CALLOC(_dest, _nmemb) assert((_dest = calloc(_nmemb, sizeof(*(_dest)))))
#define A_REALLOC(_dest, _nmemb) assert((_dest = realloc(_dest, _nmemb * sizeof(*(_dest)))))
#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 MEMSET_ZERO(_obj) memset(&(_obj), 0, sizeof(_obj))
#define MEMSET_ZERO_PTR(_ptr) memset(_ptr, 0, sizeof(*(_ptr)))
#define INLINE inline __attribute__((always_inline))
@@ -61,7 +61,11 @@ INLINE unsigned max_u(unsigned a, unsigned b) {
return (a > b ? a : b);
}
INLINE void now_ms(clockid_t clk_id, time_t *sec, long *msec) {
INLINE long long floor_ms(long double now) {
return (long long) now - (now < (long long) now); // floor()
}
INLINE void get_now(clockid_t clk_id, time_t *sec, long *msec) {
struct timespec spec;
assert(!clock_gettime(clk_id, &spec));
@@ -74,18 +78,18 @@ INLINE void now_ms(clockid_t clk_id, time_t *sec, long *msec) {
}
}
INLINE long double now_monotonic_ms(void) {
INLINE long double get_now_monotonic(void) {
time_t sec;
long msec;
now_ms(CLOCK_MONOTONIC_RAW, &sec, &msec);
get_now(CLOCK_MONOTONIC_RAW, &sec, &msec);
return (long double)sec + ((long double)msec) / 1000;
}
INLINE long double now_real_ms(void) {
INLINE long double get_now_real(void) {
time_t sec;
long msec;
now_ms(CLOCK_REALTIME, &sec, &msec);
get_now(CLOCK_REALTIME, &sec, &msec);
return (long double)sec + ((long double)msec) / 1000;
}

View File

@@ -71,7 +71,6 @@ def main():
*****************************************************************************/
""").strip() + "\n\n\n" + text
with open(dest, "w") as h_file:
h_file.write(text)