mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-19 16:26:30 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c404c49c6d | ||
|
|
481e359153 | ||
|
|
04114bba86 |
@@ -1,7 +1,7 @@
|
||||
[bumpversion]
|
||||
commit = True
|
||||
tag = True
|
||||
current_version = 6.18
|
||||
current_version = 6.19
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
||||
serialize =
|
||||
{major}.{minor}
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
|
||||
// A number of frames per 1 channel:
|
||||
// - https://github.com/xiph/opus/blob/7b05f44/src/opus_demo.c#L368
|
||||
#define _HZ_TO_FRAMES(_hz) (6 * (_hz) / 50) // 120ms
|
||||
// #define _HZ_TO_FRAMES(_hz) (6 * (_hz) / 50) // 120ms
|
||||
#define _HZ_TO_FRAMES(_hz) ((_hz) / 50) // 20ms
|
||||
#define _HZ_TO_BUF16(_hz) (_HZ_TO_FRAMES(_hz) * 2) // One stereo frame = (16bit L) + (16bit R)
|
||||
#define _HZ_TO_BUF8(_hz) (_HZ_TO_BUF16(_hz) * sizeof(s16))
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Manpage for ustreamer-dump.
|
||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||
.TH USTREAMER-DUMP 1 "version 6.18" "January 2021"
|
||||
.TH USTREAMER-DUMP 1 "version 6.19" "January 2021"
|
||||
|
||||
.SH NAME
|
||||
ustreamer-dump \- Dump uStreamer's memory sink to file
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" Manpage for ustreamer.
|
||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||
.TH USTREAMER 1 "version 6.18" "November 2020"
|
||||
.TH USTREAMER 1 "version 6.19" "November 2020"
|
||||
|
||||
.SH NAME
|
||||
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
pkgname=ustreamer
|
||||
pkgver=6.18
|
||||
pkgver=6.19
|
||||
pkgrel=1
|
||||
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
||||
url="https://github.com/pikvm/ustreamer"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ustreamer
|
||||
PKG_VERSION:=6.18
|
||||
PKG_VERSION:=6.19
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ def _find_sources(suffix: str) -> list[str]:
|
||||
if __name__ == "__main__":
|
||||
setup(
|
||||
name="ustreamer",
|
||||
version="6.18",
|
||||
version="6.19",
|
||||
description="uStreamer tools",
|
||||
author="Maxim Devaev",
|
||||
author_email="mdevaev@gmail.com",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
|
||||
#define US_VERSION_MAJOR 6
|
||||
#define US_VERSION_MINOR 18
|
||||
#define US_VERSION_MINOR 19
|
||||
|
||||
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
||||
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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 "bev.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <event2/util.h>
|
||||
#include <event2/bufferevent.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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
|
||||
|
||||
|
||||
char *us_bufferevent_format_reason(short what);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "unix.h"
|
||||
#include "tools.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include <event2/http.h>
|
||||
#include <event2/util.h>
|
||||
#include <event2/keyvalq_struct.h>
|
||||
#include <event2/bufferevent.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -25,9 +25,17 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <event2/http.h>
|
||||
#include <event2/util.h>
|
||||
#include <event2/keyvalq_struct.h>
|
||||
|
||||
#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);
|
||||
@@ -1,52 +0,0 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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 "uri.h"
|
||||
|
||||
#include <event2/util.h>
|
||||
#include <event2/http.h>
|
||||
#include <event2/keyvalq_struct.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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 <event2/keyvalq_struct.h>
|
||||
|
||||
#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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user