mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-18 02:55:46 +00:00
first implementation of --soft-fps
This commit is contained in:
parent
77b5e6eabc
commit
fb6331b64a
@ -84,6 +84,7 @@ struct device_t *device_init() {
|
||||
dev->standard = V4L2_STD_UNKNOWN;
|
||||
dev->n_buffers = max_u(sysconf(_SC_NPROCESSORS_ONLN), 1) + 1;
|
||||
dev->n_workers = dev->n_buffers;
|
||||
dev->soft_fps = 30;
|
||||
dev->timeout = 1;
|
||||
dev->error_delay = 1;
|
||||
dev->run = run;
|
||||
|
||||
@ -72,6 +72,7 @@ struct device_t {
|
||||
bool dv_timings;
|
||||
unsigned n_buffers;
|
||||
unsigned n_workers;
|
||||
unsigned soft_fps;
|
||||
unsigned every_frame;
|
||||
unsigned min_frame_size;
|
||||
bool persistent;
|
||||
|
||||
31
src/http.c
31
src/http.c
@ -63,7 +63,6 @@ struct http_server_t *http_server_init(struct stream_t *stream) {
|
||||
struct http_server_runtime_t *run;
|
||||
struct http_server_t *server;
|
||||
struct exposed_t *exposed;
|
||||
struct timeval refresh_interval;
|
||||
|
||||
A_CALLOC(exposed, 1);
|
||||
|
||||
@ -90,17 +89,15 @@ struct http_server_t *http_server_init(struct stream_t *stream) {
|
||||
assert(!evhttp_set_cb(run->http, "/snapshot", _http_callback_snapshot, (void *)server));
|
||||
assert(!evhttp_set_cb(run->http, "/stream", _http_callback_stream, (void *)server));
|
||||
|
||||
refresh_interval.tv_sec = 0;
|
||||
refresh_interval.tv_usec = 30000; // ~30 refreshes per second
|
||||
assert((run->refresh = event_new(run->base, -1, EV_PERSIST, _http_exposed_refresh, server)));
|
||||
assert(!event_add(run->refresh, &refresh_interval));
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void http_server_destroy(struct http_server_t *server) {
|
||||
event_del(server->run->refresh);
|
||||
event_free(server->run->refresh);
|
||||
if (server->run->refresh) {
|
||||
event_del(server->run->refresh);
|
||||
event_free(server->run->refresh);
|
||||
}
|
||||
|
||||
evhttp_free(server->run->http);
|
||||
event_base_free(server->run->base);
|
||||
libevent_global_shutdown();
|
||||
@ -112,6 +109,13 @@ void http_server_destroy(struct http_server_t *server) {
|
||||
}
|
||||
|
||||
int http_server_listen(struct http_server_t *server) {
|
||||
struct timeval refresh_interval;
|
||||
|
||||
refresh_interval.tv_sec = 0;
|
||||
refresh_interval.tv_usec = 1000000 / (server->run->stream->dev->soft_fps * 2);
|
||||
assert((server->run->refresh = event_new(server->run->base, -1, EV_PERSIST, _http_exposed_refresh, server)));
|
||||
assert(!event_add(server->run->refresh, &refresh_interval));
|
||||
|
||||
server->run->drop_same_frames_blank = max_u(server->drop_same_frames, server->run->drop_same_frames_blank);
|
||||
|
||||
LOG_DEBUG("Binding HTTP to [%s]:%d ...", server->host, server->port);
|
||||
@ -473,7 +477,7 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
|
||||
if (queue_send) {
|
||||
if (server->drop_same_frames) {
|
||||
// Хром всегда показывает не новый пришедший фрейм, а предыдущий.
|
||||
// При updated == false нужно еще один раз послать предыдущий фрейм
|
||||
// При updated == false нужно еще один раз послать последний значимый фрейм.
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=527446
|
||||
|
||||
static bool updated_prev = false;
|
||||
@ -513,7 +517,7 @@ static bool _expose_new_picture(struct http_server_t *server) {
|
||||
) {
|
||||
EXPOSED(expose_cmp_time) = get_now_monotonic();
|
||||
EXPOSED(expose_end_time) = EXPOSED(expose_cmp_time);
|
||||
LOG_PERF(
|
||||
LOG_VERBOSE(
|
||||
"HTTP: dropped same frame number %u; comparsion time = %.06Lf",
|
||||
EXPOSED(dropped), EXPOSED(expose_cmp_time) - EXPOSED(expose_begin_time)
|
||||
);
|
||||
@ -521,7 +525,7 @@ static bool _expose_new_picture(struct http_server_t *server) {
|
||||
return false; // Not updated
|
||||
} else {
|
||||
EXPOSED(expose_cmp_time) = get_now_monotonic();
|
||||
LOG_PERF(
|
||||
LOG_VERBOSE(
|
||||
"HTTP: passed same frame check (frames are differ); comparsion time = %.06Lf",
|
||||
EXPOSED(expose_cmp_time) - EXPOSED(expose_begin_time)
|
||||
);
|
||||
@ -550,6 +554,11 @@ static bool _expose_new_picture(struct http_server_t *server) {
|
||||
EXPOSED(expose_cmp_time) = EXPOSED(expose_begin_time);
|
||||
EXPOSED(expose_end_time) = get_now_monotonic();
|
||||
|
||||
LOG_VERBOSE(
|
||||
"HTTP: exposed new frame; full exposition time = %.06Lf",
|
||||
EXPOSED(expose_end_time) - EXPOSED(expose_begin_time)
|
||||
);
|
||||
|
||||
# undef STREAM
|
||||
# undef EXPOSED
|
||||
return true; // Updated
|
||||
|
||||
@ -48,6 +48,7 @@ static const struct option _long_opts[] = {
|
||||
{"height", required_argument, NULL, 'y'},
|
||||
{"format", required_argument, NULL, 'f'},
|
||||
{"tv-standard", required_argument, NULL, 'a'},
|
||||
{"soft-fps", required_argument, NULL, 'm'},
|
||||
{"every-frame", required_argument, NULL, 'e'},
|
||||
{"min-frame-size", required_argument, NULL, 'z'},
|
||||
{"dv-timings", no_argument, NULL, 't'},
|
||||
@ -106,6 +107,7 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
|
||||
printf(" Available: %s; default: YUYV.\n\n", FORMATS_STR);
|
||||
printf(" -a|--tv-standard <std> -- Force TV standard.\n");
|
||||
printf(" Available: %s; default: disabled.\n\n", STANDARDS_STR);
|
||||
printf(" -m|--soft-fps <N> -- Soft FPS limit; default: %u.\n\n", dev->soft_fps);
|
||||
printf(" -e|--every-frame <N> -- Drop all input frames except specified. Default: disabled.\n\n");
|
||||
printf(" -z|--min-frame-size <N> -- Drop frames smaller then this limit.\n");
|
||||
printf(" Useful if the device produces small-sized garbage frames.\n\n");
|
||||
@ -181,6 +183,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
case 'f': OPT_PARSE(dev->format, device_parse_format, FORMAT_UNKNOWN, "pixel format");
|
||||
# pragma GCC diagnostic pop
|
||||
case 'a': OPT_PARSE(dev->standard, device_parse_standard, STANDARD_UNKNOWN, "TV standard");
|
||||
case 'm': OPT_UNSIGNED(dev->soft_fps, "--soft-fps", 1, 30);
|
||||
case 'e': OPT_UNSIGNED(dev->every_frame, "--every-frame", 1, 30);
|
||||
case 'z': OPT_UNSIGNED(dev->min_frame_size, "--min-frame-size", 0, 8192);
|
||||
case 't': OPT_SET(dev->dv_timings, true);
|
||||
|
||||
17
src/stream.c
17
src/stream.c
@ -321,17 +321,26 @@ static void _stream_expose_picture(struct stream_t *stream, unsigned buf_index)
|
||||
}
|
||||
|
||||
static long double _stream_get_fluency_delay(struct device_t *dev, struct workers_pool_t *pool) {
|
||||
long double delay = 0;
|
||||
long double comp_time = 0;
|
||||
long double min_delay;
|
||||
long double soft_delay;
|
||||
|
||||
for (unsigned number = 0; number < dev->run->n_workers; ++number) {
|
||||
A_PTHREAD_M_LOCK(&pool->workers[number].last_comp_time_mutex);
|
||||
if (pool->workers[number].last_comp_time > 0) {
|
||||
delay += pool->workers[number].last_comp_time;
|
||||
comp_time += pool->workers[number].last_comp_time;
|
||||
}
|
||||
A_PTHREAD_M_UNLOCK(&pool->workers[number].last_comp_time_mutex);
|
||||
}
|
||||
// Среднее арифметическое деленное на количество воркеров
|
||||
return delay / dev->run->n_workers / dev->run->n_workers;
|
||||
comp_time = comp_time / dev->run->n_workers; // Среднее время работы воркеров
|
||||
|
||||
min_delay = comp_time / dev->run->n_workers; // Минимальное время работы размазывается на N воркеров
|
||||
soft_delay = ((long double)1) / dev->soft_fps; // Искусственное время задержки на основе желаемого FPS
|
||||
|
||||
if (min_delay > 0) {
|
||||
return (min_delay > soft_delay ? min_delay : soft_delay);
|
||||
}
|
||||
return min_delay;
|
||||
}
|
||||
|
||||
static int _stream_init_loop(struct device_t *dev, struct workers_pool_t *pool) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user