mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-27 04:06:30 +00:00
common fps counter
This commit is contained in:
@@ -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;
|
||||
|
||||
60
src/libs/fps.c
Normal file
60
src/libs/fps.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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 <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#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);
|
||||
}
|
||||
43
src/libs/fps.h
Normal file
43
src/libs/fps.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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 <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) { \
|
||||
|
||||
Reference in New Issue
Block a user