Compare commits

...

7 Commits
v1.12 ... v1.14

Author SHA1 Message Date
Devaev Maxim
dcc90341c9 Bump version: 1.13 → 1.14 2020-05-03 06:32:59 +03:00
Devaev Maxim
7e102c88cd log static errors as verbose 2020-05-03 06:17:43 +03:00
Devaev Maxim
e131a3ba49 typo 2020-04-30 17:27:55 +03:00
Devaev Maxim
e393be4c63 Bump version: 1.12 → 1.13 2020-03-04 03:04:44 +03:00
Devaev Maxim
cf4f5f5b2a notify parent using SIGUSR2 2020-03-04 03:04:28 +03:00
Maxim Devaev
1190059359 Update README.ru.md 2020-02-25 16:06:25 +03:00
Maxim Devaev
910b27feb4 Update README.md 2020-02-25 16:05:58 +03:00
12 changed files with 87 additions and 25 deletions

View File

@@ -1,7 +1,7 @@
[bumpversion] [bumpversion]
commit = True commit = True
tag = True tag = True
current_version = 1.12 current_version = 1.14
parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)? parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)?
serialize = serialize =
{major}.{minor} {major}.{minor}

View File

@@ -32,6 +32,10 @@ If you're going to live-stream from your backyard webcam and need to control it,
# Building # Building
You'll need ```make```, ```gcc```, ```libevent``` with ```pthreads``` support, ```libjpeg8```/```libjpeg-turbo```, ```libuuid``` and ```libbsd``` (only for Linux). You'll need ```make```, ```gcc```, ```libevent``` with ```pthreads``` support, ```libjpeg8```/```libjpeg-turbo```, ```libuuid``` and ```libbsd``` (only for Linux).
* Arch: `sudo pacman -S libevent libjpeg-turbo libutil-linux libbsd`.
* Raspbian: `sudo apt install libevent-dev libevent-pthreads-2.1-6-dev libjpeg8-dev uuid-dev libbsd-dev`.
* Debian: `sudo apt install build-essential libevent-dev libjpeg62-turbo-dev uuid-dev libbsd-dev`.
On Raspberry Pi you can build the program with OpenMAX IL. To do this pass option ```WITH_OMX=1``` to ```make```. To enable GPIO support install [wiringPi](http://wiringpi.com) and pass option ```WITH_GPIO=1```. If the compiler reports about a missing function ```pthread_get_name_np()``` (or similar), add option ```WITH_PTHREAD_NP=0``` (it's enabled by default). For the similar error with ```setproctitle()``` add option ```WITH_SETPROCTITLE=0```. On Raspberry Pi you can build the program with OpenMAX IL. To do this pass option ```WITH_OMX=1``` to ```make```. To enable GPIO support install [wiringPi](http://wiringpi.com) and pass option ```WITH_GPIO=1```. If the compiler reports about a missing function ```pthread_get_name_np()``` (or similar), add option ```WITH_PTHREAD_NP=0``` (it's enabled by default). For the similar error with ```setproctitle()``` add option ```WITH_SETPROCTITLE=0```.
``` ```

View File

@@ -32,6 +32,10 @@
# Сборка # Сборка
Для сборки вам понадобятся ```make```, ```gcc```, ```libevent``` с поддержкой ```pthreads```, ```libjpeg8```/```libjpeg-turbo```, ```libuuid``` и ```libbsd``` (только для Linux). Для сборки вам понадобятся ```make```, ```gcc```, ```libevent``` с поддержкой ```pthreads```, ```libjpeg8```/```libjpeg-turbo```, ```libuuid``` и ```libbsd``` (только для Linux).
* Arch: `sudo pacman -S libevent libjpeg-turbo libutil-linux libbsd`.
* Raspbian: `sudo apt install libevent-dev libevent-pthreads-2.1-6-dev libjpeg8-dev uuid-dev libbsd-dev`.
* Debian: `sudo apt install build-essential libevent-dev libjpeg62-turbo-dev uuid-dev libbsd-dev`.
На Raspberry Pi программу можно собрать с поддержкой OpenMAX IL. Для этого передайте ```make``` параметр ```WITH_OMX=1```. Для включения сборки с поддержкой GPIO установите [wiringPi](http://wiringpi.com) и добавьте параметр ```WITH_GPIO=1```. Если при сборке компилятор ругается на отсутствие функции ```pthread_get_name_np()``` или другой подобной, добавьте параметр ```WITH_PTHREAD_NP=0``` (по умолчанию он включен). При аналогичной ошибке с функцией ```setproctitle()``` добавьте параметр ```WITH_SETPROCTITLE=0```. На Raspberry Pi программу можно собрать с поддержкой OpenMAX IL. Для этого передайте ```make``` параметр ```WITH_OMX=1```. Для включения сборки с поддержкой GPIO установите [wiringPi](http://wiringpi.com) и добавьте параметр ```WITH_GPIO=1```. Если при сборке компилятор ругается на отсутствие функции ```pthread_get_name_np()``` или другой подобной, добавьте параметр ```WITH_PTHREAD_NP=0``` (по умолчанию он включен). При аналогичной ошибке с функцией ```setproctitle()``` добавьте параметр ```WITH_SETPROCTITLE=0```.
``` ```

View File

@@ -3,7 +3,7 @@
pkgname=ustreamer pkgname=ustreamer
pkgver=1.12 pkgver=1.14
pkgrel=1 pkgrel=1
pkgdesc="Lightweight and fast MJPG-HTTP streamer" pkgdesc="Lightweight and fast MJPG-HTTP streamer"
url="https://github.com/pikvm/ustreamer" url="https://github.com/pikvm/ustreamer"

View File

@@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=ustreamer PKG_NAME:=ustreamer
PKG_VERSION:=1.12 PKG_VERSION:=1.14
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com> PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>

View File

@@ -23,5 +23,5 @@
#pragma once #pragma once
#ifndef VERSION #ifndef VERSION
# define VERSION "1.12" # define VERSION "1.14"
#endif #endif

View File

@@ -50,6 +50,7 @@
#include "../tools.h" #include "../tools.h"
#include "../threading.h" #include "../threading.h"
#include "../logging.h" #include "../logging.h"
#include "../process.h"
#include "../picture.h" #include "../picture.h"
#include "../encoder.h" #include "../encoder.h"
#include "../stream.h" #include "../stream.h"
@@ -176,6 +177,9 @@ int http_server_listen(struct http_server_t *server) {
EXPOSED(expose_begin_ts) = get_now_monotonic(); EXPOSED(expose_begin_ts) = get_now_monotonic();
EXPOSED(expose_cmp_ts) = EXPOSED(expose_begin_ts); EXPOSED(expose_cmp_ts) = EXPOSED(expose_begin_ts);
EXPOSED(expose_end_ts) = EXPOSED(expose_begin_ts); EXPOSED(expose_end_ts) = EXPOSED(expose_begin_ts);
// See _http_exposed_refresh()
EXPOSED(notify_last_width) = EXPOSED(picture->width);
EXPOSED(notify_last_height) = EXPOSED(picture->height);
# undef EXPOSED # undef EXPOSED
{ {
@@ -791,6 +795,25 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
# undef UNLOCK_STREAM # undef UNLOCK_STREAM
_http_queue_send_stream(server, stream_updated, picture_updated); _http_queue_send_stream(server, stream_updated, picture_updated);
# define EXPOSED(_next) server->run->exposed->_next
if (
picture_updated
&& server->notify_parent
&& (
EXPOSED(notify_last_online) != EXPOSED(online)
|| EXPOSED(notify_last_width) != EXPOSED(picture->width)
|| EXPOSED(notify_last_height) != EXPOSED(picture->height)
)
) {
EXPOSED(notify_last_online) = EXPOSED(online);
EXPOSED(notify_last_width) = EXPOSED(picture->width);
EXPOSED(notify_last_height) = EXPOSED(picture->height);
process_notify_parent();
}
# undef EXPOSED
} }
static bool _expose_new_picture_unsafe(struct http_server_t *server) { static bool _expose_new_picture_unsafe(struct http_server_t *server) {

View File

@@ -65,6 +65,10 @@ struct exposed_t {
long double expose_cmp_ts; long double expose_cmp_ts;
long double expose_end_ts; long double expose_end_ts;
long double last_as_blank_ts; long double last_as_blank_ts;
bool notify_last_online;
unsigned notify_last_width;
unsigned notify_last_height;
}; };
struct http_server_runtime_t { struct http_server_runtime_t {
@@ -100,6 +104,8 @@ struct http_server_t {
unsigned fake_width; unsigned fake_width;
unsigned fake_height; unsigned fake_height;
bool notify_parent;
struct http_server_runtime_t *run; struct http_server_runtime_t *run;
}; };

View File

@@ -30,7 +30,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "../tools.h" #include "../tools.h"
// #include "../logging.h" #include "../logging.h"
#include "path.h" #include "path.h"
@@ -42,6 +42,7 @@ char *find_static_file_path(const char *root_path, const char *request_path) {
simplified_path = simplify_request_path(request_path); simplified_path = simplify_request_path(request_path);
if (simplified_path[0] == '\0') { if (simplified_path[0] == '\0') {
LOG_VERBOSE("HTTP: Invalid request path %s to static", request_path);
goto error; goto error;
} }
@@ -50,13 +51,14 @@ char *find_static_file_path(const char *root_path, const char *request_path) {
# define LOAD_STAT { \ # define LOAD_STAT { \
if (lstat(path, &st) < 0) { \ if (lstat(path, &st) < 0) { \
/* LOG_PERROR("Can't stat() file %s", path); */ \ LOG_VERBOSE_PERROR("HTTP: Can't stat() static path %s", path); \
goto error; \ goto error; \
} \ } \
} }
LOAD_STAT; LOAD_STAT;
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
LOG_VERBOSE("HTTP: Requested static path %s is a directory, trying %s/index.html", path, path);
strcat(path, "/index.html"); strcat(path, "/index.html");
LOAD_STAT; LOAD_STAT;
} }
@@ -64,12 +66,12 @@ char *find_static_file_path(const char *root_path, const char *request_path) {
# undef LOAD_STAT # undef LOAD_STAT
if (!S_ISREG(st.st_mode)) { if (!S_ISREG(st.st_mode)) {
// LOG_ERROR("Not a regulary file: %s", path); LOG_VERBOSE("HTTP: Not a regular file: %s", path);
goto error; goto error;
} }
if (access(path, R_OK) < 0) { if (access(path, R_OK) < 0) {
// LOG_PERROR("Can't access() R_OK file %s", path); LOG_VERBOSE_PERROR("HTTP: Can't access() R_OK file %s", path);
goto error; goto error;
} }

View File

@@ -88,14 +88,14 @@ pthread_mutex_t log_mutex;
#define LOG_PRINTF_NOLOCK(_label_color, _label, _msg_color, _msg, ...) { \ #define LOG_PRINTF_NOLOCK(_label_color, _label, _msg_color, _msg, ...) { \
char _buf[MAX_THREAD_NAME] = {0}; \ char _tname_buf[MAX_THREAD_NAME] = {0}; \
thread_get_name(_buf); \ thread_get_name(_tname_buf); \
if (log_colored) { \ if (log_colored) { \
printf(COLOR_GRAY "-- " _label_color _label COLOR_GRAY " [%.03Lf %9s]" " -- " COLOR_RESET _msg_color _msg COLOR_RESET, \ printf(COLOR_GRAY "-- " _label_color _label COLOR_GRAY " [%.03Lf %9s]" " -- " COLOR_RESET _msg_color _msg COLOR_RESET, \
get_now_monotonic(), _buf, ##__VA_ARGS__); \ get_now_monotonic(), _tname_buf, ##__VA_ARGS__); \
} else { \ } else { \
printf("-- " _label " [%.03Lf %9s] -- " _msg, \ printf("-- " _label " [%.03Lf %9s] -- " _msg, \
get_now_monotonic(), _buf, ##__VA_ARGS__); \ get_now_monotonic(), _tname_buf, ##__VA_ARGS__); \
} \ } \
putchar('\n'); \ putchar('\n'); \
fflush(stdout); \ fflush(stdout); \
@@ -112,9 +112,9 @@ pthread_mutex_t log_mutex;
} }
#define LOG_PERROR(_msg, ...) { \ #define LOG_PERROR(_msg, ...) { \
char _buf[1024] = {0}; \ char _perror_buf[1024] = {0}; \
char *_ptr = errno_to_string(_buf, 1024); \ char *_perror_ptr = errno_to_string(_perror_buf, 1024); \
LOG_ERROR(_msg ": %s", ##__VA_ARGS__, _ptr); \ LOG_ERROR(_msg ": %s", ##__VA_ARGS__, _perror_ptr); \
} }
#define LOG_INFO(_msg, ...) { \ #define LOG_INFO(_msg, ...) { \
@@ -143,6 +143,14 @@ pthread_mutex_t log_mutex;
} \ } \
} }
#define LOG_VERBOSE_PERROR(_msg, ...) { \
if (log_level >= LOG_LEVEL_VERBOSE) { \
char _perror_buf[1024] = {0}; \
char *_perror_ptr = errno_to_string(_perror_buf, 1024); \
LOG_PRINTF(COLOR_BLUE, "VERB ", COLOR_BLUE, _msg ": %s", ##__VA_ARGS__, _perror_ptr); \
} \
}
#define LOG_DEBUG(_msg, ...) { \ #define LOG_DEBUG(_msg, ...) { \
if (log_level >= LOG_LEVEL_DEBUG) { \ if (log_level >= LOG_LEVEL_DEBUG) { \
LOG_PRINTF(COLOR_GRAY, "DEBUG", COLOR_GRAY, _msg, ##__VA_ARGS__); \ LOG_PRINTF(COLOR_GRAY, "DEBUG", COLOR_GRAY, _msg, ##__VA_ARGS__); \

View File

@@ -110,6 +110,7 @@ enum _OPT_VALUES {
#ifdef WITH_SETPROCTITLE #ifdef WITH_SETPROCTITLE
_O_PROCESS_NAME_PREFIX, _O_PROCESS_NAME_PREFIX,
#endif #endif
_O_NOTIFY_PARENT,
_O_LOG_LEVEL, _O_LOG_LEVEL,
_O_PERF, _O_PERF,
@@ -180,6 +181,7 @@ static const struct option _LONG_OPTS[] = {
#ifdef WITH_SETPROCTITLE #ifdef WITH_SETPROCTITLE
{"process-name-prefix", required_argument, NULL, _O_PROCESS_NAME_PREFIX}, {"process-name-prefix", required_argument, NULL, _O_PROCESS_NAME_PREFIX},
#endif #endif
{"notify-parent", no_argument, NULL, _O_NOTIFY_PARENT},
{"log-level", required_argument, NULL, _O_LOG_LEVEL}, {"log-level", required_argument, NULL, _O_LOG_LEVEL},
{"perf", no_argument, NULL, _O_PERF}, {"perf", no_argument, NULL, _O_PERF},
@@ -396,6 +398,7 @@ int options_parse(struct options_t *options, struct device_t *dev, struct encode
# ifdef WITH_SETPROCTITLE # ifdef WITH_SETPROCTITLE
case _O_PROCESS_NAME_PREFIX: OPT_SET(process_name_prefix, optarg); case _O_PROCESS_NAME_PREFIX: OPT_SET(process_name_prefix, optarg);
# endif # endif
case _O_NOTIFY_PARENT: OPT_SET(server->notify_parent, true);
case _O_LOG_LEVEL: OPT_NUMBER("--log-level", log_level, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, 0); case _O_LOG_LEVEL: OPT_NUMBER("--log-level", log_level, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, 0);
case _O_PERF: OPT_SET(log_level, LOG_LEVEL_PERF); case _O_PERF: OPT_SET(log_level, LOG_LEVEL_PERF);
@@ -612,7 +615,7 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
printf(" or webcams, it's useless. Default: disabled.\n\n"); printf(" or webcams, it's useless. Default: disabled.\n\n");
printf(" -l|--slowdown ────────────── Slowdown capturing to 1 FPS or less when no stream clients are connected.\n"); printf(" -l|--slowdown ────────────── Slowdown capturing to 1 FPS or less when no stream clients are connected.\n");
printf(" Useful to reduce CPU consumption. Default: disabled.\n\n"); printf(" Useful to reduce CPU consumption. Default: disabled.\n\n");
printf(" -R|--fake-resolution <WxH> ─ Override image resolution for state. Default: disabled.\n\n"); printf(" -R|--fake-resolution <WxH> ─ Override image resolution for the /state. Default: disabled.\n\n");
printf(" --server-timeout <sec> ───── Timeout for client connections. Default: %u.\n\n", server->timeout); printf(" --server-timeout <sec> ───── Timeout for client connections. Default: %u.\n\n", server->timeout);
#ifdef WITH_GPIO #ifdef WITH_GPIO
printf("GPIO options:\n"); printf("GPIO options:\n");
@@ -633,6 +636,8 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
#ifdef WITH_SETPROCTITLE #ifdef WITH_SETPROCTITLE
printf(" --process-name-prefix <str> ── Set process name prefix which will be displayed in the process list\n"); printf(" --process-name-prefix <str> ── Set process name prefix which will be displayed in the process list\n");
printf(" like '<str>: ustreamer --blah-blah-blah'. Default: disabled.\n\n"); printf(" like '<str>: ustreamer --blah-blah-blah'. Default: disabled.\n\n");
printf(" --notify-parent ────────────── Send SIGUSR2 to the parent process when the stream parameters are changed.\n");
printf(" Checking changes is performed for the online flag and image resolution.\n\n");
#endif #endif
printf("Logging options:\n"); printf("Logging options:\n");
printf("════════════════\n"); printf("════════════════\n");

View File

@@ -22,6 +22,12 @@
#pragma once #pragma once
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#if defined(__linux__) #if defined(__linux__)
# define HAS_PDEATHSIG # define HAS_PDEATHSIG
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
@@ -32,19 +38,14 @@
#endif #endif
#ifdef HAS_PDEATHSIG
# include <signal.h>
# include <unistd.h>
#endif
#ifdef WITH_SETPROCTITLE #ifdef WITH_SETPROCTITLE
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
# if defined(__linux__) # if defined(__linux__)
# include <bsd/unistd.h> # include <bsd/unistd.h>
# include <sys/types.h>
# elif (defined(__FreeBSD__) || defined(__DragonFly__)) # elif (defined(__FreeBSD__) || defined(__DragonFly__))
# include <unistd.h> //# include <unistd.h>
# include <sys/types.h> //# include <sys/types.h>
# elif (defined(__NetBSD__) || defined(__OpenBSD__)) // setproctitle() placed in stdlib.h # elif (defined(__NetBSD__) || defined(__OpenBSD__)) // setproctitle() placed in stdlib.h
# else # else
# error setproctitle() not implemented, you can disable it using WITH_SETPROCTITLE=0 # error setproctitle() not implemented, you can disable it using WITH_SETPROCTITLE=0
@@ -72,6 +73,7 @@ extern char **environ;
#ifdef HAS_PDEATHSIG #ifdef HAS_PDEATHSIG
INLINE int process_track_parent_death(void) { INLINE int process_track_parent_death(void) {
pid_t parent = getppid();
int signum = SIGTERM; int signum = SIGTERM;
# if defined(__linux__) # if defined(__linux__)
int retval = prctl(PR_SET_PDEATHSIG, signum); int retval = prctl(PR_SET_PDEATHSIG, signum);
@@ -85,8 +87,8 @@ INLINE int process_track_parent_death(void) {
return -1; return -1;
} }
if (kill(getppid(), 0) < 0) { if (kill(parent, 0) < 0) {
LOG_PERROR("The parent process is already dead"); LOG_PERROR("The parent process %d is already dead", parent);
return -1; return -1;
} }
@@ -128,3 +130,11 @@ INLINE void process_set_name_prefix(int argc, char *argv[], const char *prefix)
free(cmdline); free(cmdline);
} }
#endif #endif
INLINE void process_notify_parent(void) {
pid_t parent = getppid();
if (kill(parent, SIGUSR2) < 0) {
LOG_PERROR("Can't send SIGUSR2 to the parent process %d", parent);
}
}