From 70fa6548fe7d830a01aad796f1d12aaef539df02 Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Sat, 30 Mar 2024 12:15:59 +0200 Subject: [PATCH] common fps counter --- src/dump/main.c | 16 +++------- src/libs/fps.c | 60 +++++++++++++++++++++++++++++++++++++ src/libs/fps.h | 43 ++++++++++++++++++++++++++ src/ustreamer/http/server.c | 40 +++++++++++-------------- src/ustreamer/http/server.h | 9 +++--- src/ustreamer/stream.c | 18 ++++------- 6 files changed, 135 insertions(+), 51 deletions(-) create mode 100644 src/libs/fps.c create mode 100644 src/libs/fps.h diff --git a/src/dump/main.c b/src/dump/main.c index 1e896f5..afe99c8 100644 --- a/src/dump/main.c +++ b/src/dump/main.c @@ -36,6 +36,7 @@ #include "../libs/logging.h" #include "../libs/frame.h" #include "../libs/memsink.h" +#include "../libs/fps.h" #include "../libs/signal.h" #include "../libs/options.h" @@ -221,16 +222,13 @@ static int _dump_sink( const useconds_t interval_us = interval * 1000000; us_frame_s *frame = us_frame_init(); + us_fps_s *fps = us_fps_init("SINK"); us_memsink_s *sink = NULL; if ((sink = us_memsink_init_opened("input", sink_name, false, 0, false, 0, sink_timeout)) == NULL) { goto error; } - unsigned fps = 0; - unsigned fps_accum = 0; - long long fps_second = 0; - long double last_ts = 0; while (!_g_stop) { @@ -240,7 +238,6 @@ static int _dump_sink( key_required = false; const long double now = us_get_now_monotonic(); - const long long now_second = us_floor_ms(now); char fourcc_str[8]; US_LOG_VERBOSE("Frame: %s - %ux%u -- online=%d, key=%d, kr=%d, gop=%u, latency=%.3Lf, backlog=%.3Lf, size=%zu", @@ -254,13 +251,7 @@ static int _dump_sink( US_LOG_DEBUG(" stride=%u, grab_ts=%.3Lf, encode_begin_ts=%.3Lf, encode_end_ts=%.3Lf", frame->stride, frame->grab_ts, frame->encode_begin_ts, frame->encode_end_ts); - if (now_second != fps_second) { - fps = fps_accum; - fps_accum = 0; - fps_second = now_second; - US_LOG_PERF_FPS("A new second has come; captured_fps=%u", fps); - } - fps_accum += 1; + us_fps_bump(fps); if (ctx->v_output != NULL) { ctx->write(ctx->v_output, frame); @@ -287,6 +278,7 @@ static int _dump_sink( error: US_DELETE(sink, us_memsink_destroy); + us_fps_destroy(fps); us_frame_destroy(frame); US_LOG_INFO("Bye-bye"); return retval; diff --git a/src/libs/fps.c b/src/libs/fps.c new file mode 100644 index 0000000..ed7b6ee --- /dev/null +++ b/src/libs/fps.c @@ -0,0 +1,60 @@ +/***************************************************************************** +# # +# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # +# # +# Copyright (C) 2018-2024 Maxim Devaev # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +*****************************************************************************/ + + +#include "fps.h" + +#include "types.h" +#include "tools.h" +#include "logging.h" + + +us_fps_s *us_fps_init(const char *name) { + us_fps_s *fps; + US_CALLOC(fps, 1); + fps->name = us_strdup(name); + return fps; +} + +void us_fps_destroy(us_fps_s *fps) { + free(fps->name); + free(fps); +} + +void us_fps_bump(us_fps_s *fps) { + const sll now_sec_ts = us_floor_ms(us_get_now_monotonic()); + if (now_sec_ts != fps->ts) { + US_LOG_PERF_FPS("FPS: %s: %u", fps->name, fps->accum); + atomic_store(&fps->current, fps->accum); + fps->accum = 0; + fps->ts = now_sec_ts; + } + ++fps->accum; +} + +void us_fps_reset(us_fps_s *fps) { + us_fps_bump(fps); // Just show the log record + fps->accum = 0; +} + +uint us_fps_get(us_fps_s *fps) { + return atomic_load(&fps->current); +} diff --git a/src/libs/fps.h b/src/libs/fps.h new file mode 100644 index 0000000..c203c52 --- /dev/null +++ b/src/libs/fps.h @@ -0,0 +1,43 @@ +/***************************************************************************** +# # +# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # +# # +# Copyright (C) 2018-2024 Maxim Devaev # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +*****************************************************************************/ + + +#pragma once + +#include + +#include "types.h" + + +typedef struct { + char *name; + uint accum; + ldf ts; + atomic_uint current; +} us_fps_s; + + +us_fps_s *us_fps_init(const char *name); +void us_fps_destroy(us_fps_s *fps); + +void us_fps_bump(us_fps_s *fps); +void us_fps_reset(us_fps_s *fps); +uint us_fps_get(us_fps_s *fps); diff --git a/src/ustreamer/http/server.c b/src/ustreamer/http/server.c index 3a4c1d0..030d544 100644 --- a/src/ustreamer/http/server.c +++ b/src/ustreamer/http/server.c @@ -120,6 +120,7 @@ us_server_s *us_server_init(us_stream_s *stream) { us_server_exposed_s *exposed; US_CALLOC(exposed, 1); exposed->frame = us_frame_init(); + exposed->queued_fps = us_fps_init("MJPEG-QUEUED"); us_server_runtime_s *run; US_CALLOC(run, 1); @@ -168,6 +169,7 @@ void us_server_destroy(us_server_s *server) { }); US_LIST_ITERATE(run->stream_clients, client, { // cppcheck-suppress constStatement + us_fps_destroy(client->fps); free(client->key); free(client->hostport); free(client); @@ -175,6 +177,7 @@ void us_server_destroy(us_server_s *server) { US_DELETE(run->auth_token, free); + us_fps_destroy(run->exposed->queued_fps); us_frame_destroy(run->exposed->frame); free(run->exposed); free(server->run); @@ -514,7 +517,7 @@ static void _http_callback_state(struct evhttp_request *request, void *v_server) us_bool_to_string(online), stream->cap->desired_fps, captured_fps, - ex->queued_fps, + us_fps_get(ex->queued_fps), run->stream_clients_count ); @@ -523,7 +526,7 @@ static void _http_callback_state(struct evhttp_request *request, void *v_server) "\"%" PRIx64 "\": {\"fps\": %u, \"extra_headers\": %s, \"advance_headers\": %s," " \"dual_final_frames\": %s, \"zero_data\": %s, \"key\": \"%s\"}%s", client->id, - client->fps, + us_fps_get(client->fps), us_bool_to_string(client->extra_headers), us_bool_to_string(client->advance_headers), us_bool_to_string(client->dual_final_frames), @@ -590,6 +593,13 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server client->hostport = _http_get_client_hostport(request); client->id = us_get_now_id(); + { + char *name; + US_ASPRINTF(name, "MJPEG-CLIENT-%" PRIx64, client->id); + client->fps = us_fps_init(name); + free(name); + } + US_LIST_APPEND_C(run->stream_clients, client, run->stream_clients_count); if (run->stream_clients_count == 1) { @@ -626,15 +636,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c us_server_s *const server = client->server; us_server_exposed_s *const ex = server->run->exposed; - const ldf now_ts = us_get_now_monotonic(); - const sll now_sec_ts = us_floor_ms(now_ts); - - if (now_sec_ts != client->fps_ts) { - client->fps = client->fps_accum; - client->fps_accum = 0; - client->fps_ts = now_sec_ts; - } - client->fps_accum += 1; + us_fps_bump(client->fps); struct evbuffer *buf; _A_EVBUFFER_NEW(buf); @@ -716,6 +718,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c us_get_now_real(), (client->extra_headers ? "" : RN) ); + const ldf now_ts = us_get_now_monotonic(); if (client->extra_headers) { _A_EVBUFFER_ADD_PRINTF(buf, "X-UStreamer-Online: %s" RN @@ -736,7 +739,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c ex->dropped, ex->frame->width, ex->frame->height, - client->fps, + us_fps_get(client->fps), ex->frame->grab_ts, ex->frame->encode_begin_ts, ex->frame->encode_end_ts, @@ -793,6 +796,7 @@ static void _http_callback_stream_error(struct bufferevent *buf_event, short wha struct evhttp_connection *conn = evhttp_request_get_connection(client->request); US_DELETE(conn, evhttp_connection_free); + us_fps_destroy(client->fps); free(client->key); free(client->hostport); free(client); @@ -839,17 +843,9 @@ static void _http_send_stream(us_server_s *server, bool stream_updated, bool fra }); if (queued) { - static uint queued_fps_accum = 0; - static sll queued_fps_ts = 0; - const sll now_sec_ts = us_floor_ms(us_get_now_monotonic()); - if (now_sec_ts != queued_fps_ts) { - ex->queued_fps = queued_fps_accum; - queued_fps_accum = 0; - queued_fps_ts = now_sec_ts; - } - queued_fps_accum += 1; + us_fps_bump(ex->queued_fps); } else if (!has_clients) { - ex->queued_fps = 0; + us_fps_reset(ex->queued_fps); } } diff --git a/src/ustreamer/http/server.h b/src/ustreamer/http/server.h index 7c2b896..1907aad 100644 --- a/src/ustreamer/http/server.h +++ b/src/ustreamer/http/server.h @@ -31,6 +31,7 @@ #include "../../libs/types.h" #include "../../libs/frame.h" #include "../../libs/list.h" +#include "../../libs/fps.h" #include "../encoder.h" #include "../stream.h" @@ -50,9 +51,8 @@ typedef struct us_stream_client_sx { bool need_initial; bool need_first_frame; bool updated_prev; - uint fps_accum; - sll fps_ts; - uint fps; + + us_fps_s *fps; US_LIST_STRUCT(struct us_stream_client_sx); } us_stream_client_s; @@ -67,8 +67,7 @@ typedef struct us_snapshot_client_sx { typedef struct { us_frame_s *frame; - uint captured_fps; - uint queued_fps; + us_fps_s *queued_fps; uint dropped; ldf expose_begin_ts; ldf expose_cmp_ts; diff --git a/src/ustreamer/stream.c b/src/ustreamer/stream.c index 7b366b5..0c9e662 100644 --- a/src/ustreamer/stream.c +++ b/src/ustreamer/stream.c @@ -42,6 +42,7 @@ #include "../libs/memsink.h" #include "../libs/capture.h" #include "../libs/unjpeg.h" +#include "../libs/fps.h" #ifdef WITH_V4P # include "../libs/drm/drm.h" #endif @@ -175,9 +176,7 @@ void us_stream_loop(us_stream_s *stream) { # endif # undef CREATE_WORKER - uint captured_fps_accum = 0; - sll captured_fps_ts = 0; - uint captured_fps = 0; + us_fps_s *fps = us_fps_init("CAP"); US_LOG_INFO("Capturing ..."); @@ -190,16 +189,9 @@ void us_stream_loop(us_stream_s *stream) { default: goto close; // Any error } - const sll now_sec_ts = us_floor_ms(us_get_now_monotonic()); - if (now_sec_ts != captured_fps_ts) { - captured_fps = captured_fps_accum; - captured_fps_accum = 0; - captured_fps_ts = now_sec_ts; - US_LOG_PERF_FPS("A new second has come; captured_fps=%u", captured_fps); - } - captured_fps_accum += 1; + us_fps_bump(fps); + _stream_set_capture_state(stream, cap->run->width, cap->run->height, true, us_fps_get(fps)); - _stream_set_capture_state(stream, cap->run->width, cap->run->height, true, captured_fps); # ifdef WITH_GPIO us_gpio_set_stream_online(true); # endif @@ -229,6 +221,8 @@ void us_stream_loop(us_stream_s *stream) { } close: + us_fps_destroy(fps); + atomic_store(&threads_stop, true); # define DELETE_WORKER(x_ctx) if (x_ctx != NULL) { \