From fb6331b64a2ec70fb202879c29b5b09b35144a48 Mon Sep 17 00:00:00 2001 From: Devaev Maxim Date: Fri, 2 Nov 2018 02:32:28 +0300 Subject: [PATCH] first implementation of --soft-fps --- src/device.c | 1 + src/device.h | 1 + src/http.c | 31 ++++++++++++++++++++----------- src/main.c | 3 +++ src/stream.c | 17 +++++++++++++---- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/device.c b/src/device.c index 1003f0e..6a8e83b 100644 --- a/src/device.c +++ b/src/device.c @@ -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; diff --git a/src/device.h b/src/device.h index 443b5e2..9c6449c 100644 --- a/src/device.h +++ b/src/device.h @@ -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; diff --git a/src/http.c b/src/http.c index e3bab5a..8fcee74 100644 --- a/src/http.c +++ b/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 diff --git a/src/main.c b/src/main.c index 52d7aa5..23f0166 100644 --- a/src/main.c +++ b/src/main.c @@ -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 -- Force TV standard.\n"); printf(" Available: %s; default: disabled.\n\n", STANDARDS_STR); + printf(" -m|--soft-fps -- Soft FPS limit; default: %u.\n\n", dev->soft_fps); printf(" -e|--every-frame -- Drop all input frames except specified. Default: disabled.\n\n"); printf(" -z|--min-frame-size -- 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); diff --git a/src/stream.c b/src/stream.c index 9702ac9..f3bedba 100644 --- a/src/stream.c +++ b/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) {