From 04114bba868533a399df712005a179bcfcec0af0 Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Sun, 15 Dec 2024 11:34:41 +0200 Subject: [PATCH] refactoring --- src/ustreamer/http/bev.c | 65 ------------------ src/ustreamer/http/bev.h | 26 ------- src/ustreamer/http/server.c | 75 +++----------------- src/ustreamer/http/server.h | 6 -- src/ustreamer/http/{unix.c => tools.c} | 95 +++++++++++++++++++++++++- src/ustreamer/http/{unix.h => tools.h} | 10 ++- src/ustreamer/http/uri.c | 52 -------------- src/ustreamer/http/uri.h | 31 --------- src/ustreamer/options.c | 2 +- src/ustreamer/stream.c | 33 +++++---- src/ustreamer/stream.h | 3 + 11 files changed, 136 insertions(+), 262 deletions(-) delete mode 100644 src/ustreamer/http/bev.c delete mode 100644 src/ustreamer/http/bev.h rename src/ustreamer/http/{unix.c => tools.c} (56%) rename src/ustreamer/http/{unix.h => tools.h} (82%) delete mode 100644 src/ustreamer/http/uri.c delete mode 100644 src/ustreamer/http/uri.h diff --git a/src/ustreamer/http/bev.c b/src/ustreamer/http/bev.c deleted file mode 100644 index 2a9a23a..0000000 --- a/src/ustreamer/http/bev.c +++ /dev/null @@ -1,65 +0,0 @@ -/***************************************************************************** -# # -# 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 "bev.h" - -#include -#include - -#include -#include - -#include "../../libs/tools.h" - - -char *us_bufferevent_format_reason(short what) { - char *reason; - US_CALLOC(reason, 2048); - - // evutil_socket_error_to_string() is not thread-safe - char *const perror_str = us_errno_to_string(EVUTIL_SOCKET_ERROR()); - bool first = true; - - strncat(reason, perror_str, 1023); - free(perror_str); - strcat(reason, " ("); - -# define FILL_REASON(x_bev, x_name) { \ - if (what & x_bev) { \ - if (first) { \ - first = false; \ - } else { \ - strcat(reason, ","); \ - } \ - strcat(reason, x_name); \ - } \ - } - FILL_REASON(BEV_EVENT_READING, "reading"); - FILL_REASON(BEV_EVENT_WRITING, "writing"); - FILL_REASON(BEV_EVENT_ERROR, "error"); - FILL_REASON(BEV_EVENT_TIMEOUT, "timeout"); - FILL_REASON(BEV_EVENT_EOF, "eof"); // cppcheck-suppress unreadVariable -# undef FILL_REASON - - strcat(reason, ")"); - return reason; -} diff --git a/src/ustreamer/http/bev.h b/src/ustreamer/http/bev.h deleted file mode 100644 index 57c5782..0000000 --- a/src/ustreamer/http/bev.h +++ /dev/null @@ -1,26 +0,0 @@ -/***************************************************************************** -# # -# 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 - - -char *us_bufferevent_format_reason(short what); diff --git a/src/ustreamer/http/server.c b/src/ustreamer/http/server.c index b90d8db..229969e 100644 --- a/src/ustreamer/http/server.c +++ b/src/ustreamer/http/server.c @@ -56,7 +56,6 @@ #include "../../libs/tools.h" #include "../../libs/threading.h" #include "../../libs/logging.h" -#include "../../libs/process.h" #include "../../libs/frame.h" #include "../../libs/base64.h" #include "../../libs/list.h" @@ -68,9 +67,7 @@ # include "../gpio/gpio.h" #endif -#include "bev.h" -#include "unix.h" -#include "uri.h" +#include "tools.h" #include "mime.h" #include "static.h" #ifdef WITH_SYSTEMD @@ -98,9 +95,6 @@ static void _http_send_snapshot(us_server_s *server); static bool _expose_frame(us_server_s *server, const us_frame_s *frame); -static const char *_http_get_header(struct evhttp_request *request, const char *key); -static char *_http_get_client_hostport(struct evhttp_request *request); - #define _LOG_ERROR(x_msg, ...) US_LOG_ERROR("HTTP: " x_msg, ##__VA_ARGS__) #define _LOG_PERROR(x_msg, ...) US_LOG_PERROR("HTTP: " x_msg, ##__VA_ARGS__) @@ -203,8 +197,6 @@ int us_server_listen(us_server_s *server) { } us_frame_copy(stream->run->blank->jpeg, ex->frame); - ex->notify_last_width = ex->frame->width; - ex->notify_last_height = ex->frame->height; { struct timeval interval = {0}; @@ -282,8 +274,8 @@ static int _http_preprocess_request(struct evhttp_request *request, us_server_s atomic_store(&server->stream->run->http->last_request_ts, us_get_now_monotonic()); if (server->allow_origin[0] != '\0') { - const char *const cors_headers = _http_get_header(request, "Access-Control-Request-Headers"); - const char *const cors_method = _http_get_header(request, "Access-Control-Request-Method"); + const char *const cors_headers = us_evhttp_get_header(request, "Access-Control-Request-Headers"); + const char *const cors_method = us_evhttp_get_header(request, "Access-Control-Request-Method"); _A_ADD_HEADER(request, "Access-Control-Allow-Origin", server->allow_origin); _A_ADD_HEADER(request, "Access-Control-Allow-Credentials", "true"); @@ -301,7 +293,7 @@ static int _http_preprocess_request(struct evhttp_request *request, us_server_s } if (run->auth_token != NULL) { - const char *const token = _http_get_header(request, "Authorization"); + const char *const token = us_evhttp_get_header(request, "Authorization"); if (token == NULL || strcmp(token, run->auth_token) != 0) { _A_ADD_HEADER(request, "WWW-Authenticate", "Basic realm=\"Restricted area\""); evhttp_send_reply(request, 401, "Unauthorized", NULL); @@ -593,7 +585,7 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server struct evkeyvalq params; evhttp_parse_query(evhttp_request_get_uri(request), ¶ms); -# define PARSE_PARAM(x_type, x_name) client->x_name = us_uri_get_##x_type(¶ms, #x_name) +# define PARSE_PARAM(x_type, x_name) client->x_name = us_evkeyvalq_get_##x_type(¶ms, #x_name) PARSE_PARAM(string, key); PARSE_PARAM(true, extra_headers); PARSE_PARAM(true, advance_headers); @@ -602,7 +594,7 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server # undef PARSE_PARAM evhttp_clear_headers(¶ms); - client->hostport = _http_get_client_hostport(request); + client->hostport = us_evhttp_get_hostport(request); client->id = us_get_now_id(); { @@ -682,8 +674,8 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c _A_EVBUFFER_ADD_PRINTF(buf, "HTTP/1.0 200 OK" RN); if (client->server->allow_origin[0] != '\0') { - const char *const cors_headers = _http_get_header(client->request, "Access-Control-Request-Headers"); - const char *const cors_method = _http_get_header(client->request, "Access-Control-Request-Method"); + const char *const cors_headers = us_evhttp_get_header(client->request, "Access-Control-Request-Headers"); + const char *const cors_method = us_evhttp_get_header(client->request, "Access-Control-Request-Method"); _A_EVBUFFER_ADD_PRINTF(buf, "Access-Control-Allow-Origin: %s" RN @@ -957,21 +949,6 @@ static void _http_refresher(int fd, short what, void *v_server) { _http_send_stream(server, stream_updated, frame_updated); _http_send_snapshot(server); - - if ( - frame_updated - && server->notify_parent - && ( - ex->notify_last_online != ex->frame->online - || ex->notify_last_width != ex->frame->width - || ex->notify_last_height != ex->frame->height - ) - ) { - ex->notify_last_online = ex->frame->online; - ex->notify_last_width = ex->frame->width; - ex->notify_last_height = ex->frame->height; - us_process_notify_parent(); - } } static bool _expose_frame(us_server_s *server, const us_frame_s *frame) { @@ -1016,39 +993,3 @@ static bool _expose_frame(us_server_s *server, const us_frame_s *frame) { ex->frame->online, (ex->expose_end_ts - ex->expose_begin_ts)); return true; // Updated } - -static const char *_http_get_header(struct evhttp_request *request, const char *key) { - return evhttp_find_header(evhttp_request_get_input_headers(request), key); -} - -static char *_http_get_client_hostport(struct evhttp_request *request) { - char *addr = NULL; - unsigned short port = 0; - struct evhttp_connection *conn = evhttp_request_get_connection(request); - if (conn != NULL) { - char *peer; - evhttp_connection_get_peer(conn, &peer, &port); - addr = us_strdup(peer); - } - - const char *xff = _http_get_header(request, "X-Forwarded-For"); - if (xff != NULL) { - US_DELETE(addr, free); - assert((addr = strndup(xff, 1024)) != NULL); - for (uint index = 0; addr[index]; ++index) { - if (addr[index] == ',') { - addr[index] = '\0'; - break; - } - } - } - - if (addr == NULL) { - addr = us_strdup("???"); - } - - char *hostport; - US_ASPRINTF(hostport, "[%s]:%u", addr, port); - free(addr); - return hostport; -} diff --git a/src/ustreamer/http/server.h b/src/ustreamer/http/server.h index a207a9d..2d886f7 100644 --- a/src/ustreamer/http/server.h +++ b/src/ustreamer/http/server.h @@ -72,10 +72,6 @@ typedef struct { ldf expose_begin_ts; ldf expose_cmp_ts; ldf expose_end_ts; - - bool notify_last_online; - uint notify_last_width; - uint notify_last_height; } us_server_exposed_s; typedef struct { @@ -121,8 +117,6 @@ typedef struct us_server_sx { uint fake_width; uint fake_height; - bool notify_parent; - us_server_runtime_s *run; } us_server_s; diff --git a/src/ustreamer/http/unix.c b/src/ustreamer/http/tools.c similarity index 56% rename from src/ustreamer/http/unix.c rename to src/ustreamer/http/tools.c index 5fe321a..e1ff565 100644 --- a/src/ustreamer/http/unix.c +++ b/src/ustreamer/http/tools.c @@ -20,7 +20,7 @@ *****************************************************************************/ -#include "unix.h" +#include "tools.h" #include #include @@ -33,6 +33,8 @@ #include #include +#include +#include #include "../../libs/types.h" #include "../../libs/tools.h" @@ -79,3 +81,94 @@ evutil_socket_t us_evhttp_bind_unix(struct evhttp *http, const char *path, bool } return fd; } + +const char *us_evhttp_get_header(struct evhttp_request *request, const char *key) { + return evhttp_find_header(evhttp_request_get_input_headers(request), key); +} + +char *us_evhttp_get_hostport(struct evhttp_request *request) { + char *addr = NULL; + unsigned short port = 0; + struct evhttp_connection *conn = evhttp_request_get_connection(request); + if (conn != NULL) { + char *peer; + evhttp_connection_get_peer(conn, &peer, &port); + addr = us_strdup(peer); + } + + const char *xff = us_evhttp_get_header(request, "X-Forwarded-For"); + if (xff != NULL) { + US_DELETE(addr, free); + assert((addr = strndup(xff, 1024)) != NULL); + for (uint index = 0; addr[index]; ++index) { + if (addr[index] == ',') { + addr[index] = '\0'; + break; + } + } + } + + if (addr == NULL) { + addr = us_strdup("???"); + } + + char *hostport; + US_ASPRINTF(hostport, "[%s]:%u", addr, port); + free(addr); + return hostport; +} + +bool us_evkeyvalq_get_true(struct evkeyvalq *params, const char *key) { + const char *value_str = evhttp_find_header(params, key); + if (value_str != NULL) { + if ( + value_str[0] == '1' + || !evutil_ascii_strcasecmp(value_str, "true") + || !evutil_ascii_strcasecmp(value_str, "yes") + ) { + return true; + } + } + return false; +} + +char *us_evkeyvalq_get_string(struct evkeyvalq *params, const char *key) { + const char *const value_str = evhttp_find_header(params, key); + if (value_str != NULL) { + return evhttp_encode_uri(value_str); + } + return NULL; +} + +char *us_bufferevent_format_reason(short what) { + char *reason; + US_CALLOC(reason, 2048); + + // evutil_socket_error_to_string() is not thread-safe + char *const perror_str = us_errno_to_string(EVUTIL_SOCKET_ERROR()); + bool first = true; + + strncat(reason, perror_str, 1023); + free(perror_str); + strcat(reason, " ("); + +# define FILL_REASON(x_bev, x_name) { \ + if (what & x_bev) { \ + if (first) { \ + first = false; \ + } else { \ + strcat(reason, ","); \ + } \ + strcat(reason, x_name); \ + } \ + } + FILL_REASON(BEV_EVENT_READING, "reading"); + FILL_REASON(BEV_EVENT_WRITING, "writing"); + FILL_REASON(BEV_EVENT_ERROR, "error"); + FILL_REASON(BEV_EVENT_TIMEOUT, "timeout"); + FILL_REASON(BEV_EVENT_EOF, "eof"); // cppcheck-suppress unreadVariable +# undef FILL_REASON + + strcat(reason, ")"); + return reason; +} diff --git a/src/ustreamer/http/unix.h b/src/ustreamer/http/tools.h similarity index 82% rename from src/ustreamer/http/unix.h rename to src/ustreamer/http/tools.h index bb7a2bb..0c9fc59 100644 --- a/src/ustreamer/http/unix.h +++ b/src/ustreamer/http/tools.h @@ -25,9 +25,17 @@ #include #include -#include +#include #include "../../libs/types.h" evutil_socket_t us_evhttp_bind_unix(struct evhttp *http, const char *path, bool rm, mode_t mode); + +const char *us_evhttp_get_header(struct evhttp_request *request, const char *key); +char *us_evhttp_get_hostport(struct evhttp_request *request); + +bool us_evkeyvalq_get_true(struct evkeyvalq *params, const char *key); +char *us_evkeyvalq_get_string(struct evkeyvalq *params, const char *key); + +char *us_bufferevent_format_reason(short what); diff --git a/src/ustreamer/http/uri.c b/src/ustreamer/http/uri.c deleted file mode 100644 index 0456394..0000000 --- a/src/ustreamer/http/uri.c +++ /dev/null @@ -1,52 +0,0 @@ -/***************************************************************************** -# # -# 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 "uri.h" - -#include -#include -#include - -#include "../../libs/types.h" - - -bool us_uri_get_true(struct evkeyvalq *params, const char *key) { - const char *value_str = evhttp_find_header(params, key); - if (value_str != NULL) { - if ( - value_str[0] == '1' - || !evutil_ascii_strcasecmp(value_str, "true") - || !evutil_ascii_strcasecmp(value_str, "yes") - ) { - return true; - } - } - return false; -} - -char *us_uri_get_string(struct evkeyvalq *params, const char *key) { - const char *const value_str = evhttp_find_header(params, key); - if (value_str != NULL) { - return evhttp_encode_uri(value_str); - } - return NULL; -} diff --git a/src/ustreamer/http/uri.h b/src/ustreamer/http/uri.h deleted file mode 100644 index 5aa5811..0000000 --- a/src/ustreamer/http/uri.h +++ /dev/null @@ -1,31 +0,0 @@ -/***************************************************************************** -# # -# 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 "../../libs/types.h" - - -bool us_uri_get_true(struct evkeyvalq *params, const char *key); -char *us_uri_get_string(struct evkeyvalq *params, const char *key); diff --git a/src/ustreamer/options.c b/src/ustreamer/options.c index bde3315..a0bfa00 100644 --- a/src/ustreamer/options.c +++ b/src/ustreamer/options.c @@ -494,7 +494,7 @@ int options_parse(us_options_s *options, us_capture_s *cap, us_encoder_s *enc, u # ifdef WITH_SETPROCTITLE case _O_PROCESS_NAME_PREFIX: OPT_SET(process_name_prefix, optarg); # endif - case _O_NOTIFY_PARENT: OPT_SET(server->notify_parent, true); + case _O_NOTIFY_PARENT: OPT_SET(stream->notify_parent, true); case _O_LOG_LEVEL: OPT_NUMBER("--log-level", us_g_log_level, US_LOG_LEVEL_INFO, US_LOG_LEVEL_DEBUG, 0); case _O_PERF: OPT_SET(us_g_log_level, US_LOG_LEVEL_PERF); diff --git a/src/ustreamer/stream.c b/src/ustreamer/stream.c index 94036e0..221525b 100644 --- a/src/ustreamer/stream.c +++ b/src/ustreamer/stream.c @@ -85,6 +85,7 @@ static us_capture_hwbuf_s *_get_latest_hw(us_queue_s *queue); static bool _stream_has_jpeg_clients_cached(us_stream_s *stream); static bool _stream_has_any_clients_cached(us_stream_s *stream); static int _stream_init_loop(us_stream_s *stream); +static void _stream_update_captured_fpsi(us_stream_s *stream, const us_frame_s *frame, bool bump); #ifdef WITH_V4P static void _stream_drm_ensure_no_signal(us_stream_s *stream); #endif @@ -122,15 +123,15 @@ us_stream_s *us_stream_init(us_capture_s *cap, us_encoder_s *enc) { stream->h264_gop = 30; stream->run = run; - us_blank_draw(run->blank, "< NO SIGNAL >", cap->width, cap->height); - us_fpsi_meta_s meta = {0}; - us_fpsi_frame_to_meta(run->blank->raw, &meta); - us_fpsi_update(http->captured_fpsi, false, &meta); + us_stream_update_blank(stream, cap); // Init blank return stream; } void us_stream_update_blank(us_stream_s *stream, const us_capture_s *cap) { - us_blank_draw(stream->run->blank, "< NO SIGNAL >", cap->width, cap->height); + us_stream_runtime_s *const run = stream->run; + us_blank_draw(run->blank, "< NO SIGNAL >", cap->width, cap->height); + us_fpsi_frame_to_meta(run->blank->raw, &run->notify_meta); // Initial "unchanged" meta + _stream_update_captured_fpsi(stream, run->blank->raw, false); } void us_stream_destroy(us_stream_s *stream) { @@ -204,9 +205,7 @@ void us_stream_loop(us_stream_s *stream) { default: goto close; // Any error } - us_fpsi_meta_s meta = {0}; - us_fpsi_frame_to_meta(&hw->raw, &meta); - us_fpsi_update(run->http->captured_fpsi, true, &meta); + _stream_update_captured_fpsi(stream, &hw->raw, true); # ifdef WITH_GPIO us_gpio_set_stream_online(true); @@ -580,10 +579,7 @@ static int _stream_init_loop(us_stream_s *stream) { } us_blank_draw(run->blank, "< NO SIGNAL >", width, height); - us_fpsi_meta_s meta = {0}; - us_fpsi_frame_to_meta(run->blank->raw, &meta); - us_fpsi_update(run->http->captured_fpsi, false, &meta); - + _stream_update_captured_fpsi(stream, run->blank->raw, false); _stream_expose_jpeg(stream, run->blank->jpeg); _stream_expose_raw(stream, run->blank->raw); _stream_encode_expose_h264(stream, run->blank->raw, true); @@ -598,6 +594,19 @@ static int _stream_init_loop(us_stream_s *stream) { return -1; } +static void _stream_update_captured_fpsi(us_stream_s *stream, const us_frame_s *frame, bool bump) { + us_stream_runtime_s *const run = stream->run; + + us_fpsi_meta_s meta = {0}; + us_fpsi_frame_to_meta(run->blank->raw, &meta); + us_fpsi_update(run->http->captured_fpsi, false, &meta); + + if (stream->notify_parent && !memcmp(&run->notify_meta, &meta, sizeof(us_fpsi_meta_s))) { + memcpy(&run->notify_meta, &meta, sizeof(us_fpsi_meta_s)); + us_process_notify_parent(); + } +} + #ifdef WITH_V4P static void _stream_drm_ensure_no_signal(us_stream_s *stream) { if (stream->drm == NULL) { diff --git a/src/ustreamer/stream.h b/src/ustreamer/stream.h index 4be5f51..8c98037 100644 --- a/src/ustreamer/stream.h +++ b/src/ustreamer/stream.h @@ -68,6 +68,8 @@ typedef struct { us_blank_s *blank; + us_fpsi_meta_s notify_meta; + atomic_bool stop; } us_stream_runtime_s; @@ -75,6 +77,7 @@ typedef struct { us_capture_s *cap; us_encoder_s *enc; + bool notify_parent; bool slowdown; uint error_delay; uint exit_on_no_clients;