mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-27 12:16:31 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90f09b197e | ||
|
|
687e97d523 | ||
|
|
c1675001fa | ||
|
|
69cc45a2a0 | ||
|
|
ece96b5834 | ||
|
|
383ed7530b | ||
|
|
7f620c758f | ||
|
|
fb50eea526 | ||
|
|
63f757a9da | ||
|
|
4ec02d46b9 | ||
|
|
527afb66df | ||
|
|
5502758a7e | ||
|
|
faa1776407 | ||
|
|
3d7fb8c8dd | ||
|
|
b5f814d71e | ||
|
|
6eafd4156a | ||
|
|
df1e4eaa06 | ||
|
|
d2bef81b03 | ||
|
|
7b3dffd072 | ||
|
|
1a6e9998fb | ||
|
|
9ab9561803 |
@@ -1,7 +1,7 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
current_version = 5.17
|
current_version = 5.23
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
||||||
serialize =
|
serialize =
|
||||||
{major}.{minor}
|
{major}.{minor}
|
||||||
|
|||||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
patreon: pikvm
|
patreon: pikvm
|
||||||
#custom: https://www.paypal.me/mdevaev
|
custom: https://paypal.me/pikvm
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
[[Русская версия]](README.ru.md)
|
[[Русская версия]](README.ru.md)
|
||||||
|
|
||||||
µStreamer is a lightweight and very quick server to stream [MJPEG](https://en.wikipedia.org/wiki/Motion_JPEG) video from any V4L2 device to the net. All new browsers have native support of this video format, as well as most video players such as mplayer, VLC etc.
|
µStreamer is a lightweight and very quick server to stream [MJPEG](https://en.wikipedia.org/wiki/Motion_JPEG) video from any V4L2 device to the net. All new browsers have native support of this video format, as well as most video players such as mplayer, VLC etc.
|
||||||
µStreamer is a part of the [Pi-KVM](https://github.com/pikvm/pikvm) project designed to stream [VGA](https://www.amazon.com/dp/B0126O0RDC) and [HDMI](https://auvidea.com/b101-hdmi-to-csi-2-bridge-15-pin-fpc/) screencast hardware data with the highest resolution and FPS possible.
|
µStreamer is a part of the [PiKVM](https://github.com/pikvm/pikvm) project designed to stream [VGA](https://www.amazon.com/dp/B0126O0RDC) and [HDMI](https://auvidea.com/b101-hdmi-to-csi-2-bridge-15-pin-fpc/) screencast hardware data with the highest resolution and FPS possible.
|
||||||
|
|
||||||
µStreamer is very similar to [mjpg-streamer](https://github.com/jacksonliam/mjpg-streamer) with ```input_uvc.so``` and ```output_http.so``` plugins, however, there are some major differences. The key ones are:
|
µStreamer is very similar to [mjpg-streamer](https://github.com/jacksonliam/mjpg-streamer) with ```input_uvc.so``` and ```output_http.so``` plugins, however, there are some major differences. The key ones are:
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
[[English version]](README.md)
|
[[English version]](README.md)
|
||||||
|
|
||||||
|
|
||||||
µStreamer - это маленький и очень быстрый сервер, который позволяет организовать трансляцию видео в формате [MJPEG](https://en.wikipedia.org/wiki/Motion_JPEG) с любого устройства V4L2 в сеть. Этот формат нативно поддерживается всеми современными браузерами и большинством приложений для просмотра видео (mplayer, VLC и так далее). µStreamer был разработан в рамках проекта [Pi-KVM](https://github.com/pikvm/pikvm) специально для стриминга с устройств видеозахвата [VGA](https://www.amazon.com/dp/B0126O0RDC) и [HDMI](https://auvidea.com/b101-hdmi-to-csi-2-bridge-15-pin-fpc/) с максимально возможным разрешением и FPS, которые только позволяет железо.
|
µStreamer - это маленький и очень быстрый сервер, который позволяет организовать трансляцию видео в формате [MJPEG](https://en.wikipedia.org/wiki/Motion_JPEG) с любого устройства V4L2 в сеть. Этот формат нативно поддерживается всеми современными браузерами и большинством приложений для просмотра видео (mplayer, VLC и так далее). µStreamer был разработан в рамках проекта [PiKVM](https://github.com/pikvm/pikvm) специально для стриминга с устройств видеозахвата [VGA](https://www.amazon.com/dp/B0126O0RDC) и [HDMI](https://auvidea.com/b101-hdmi-to-csi-2-bridge-15-pin-fpc/) с максимально возможным разрешением и FPS, которые только позволяет железо.
|
||||||
|
|
||||||
Функционально µStreamer очень похож на [mjpg-streamer](https://github.com/jacksonliam/mjpg-streamer) при использовании им плагинов ```input_uvc.so``` и ```output_http.so```, однако имеет ряд серьезных отличий. Основные приведены в этой таблице:
|
Функционально µStreamer очень похож на [mjpg-streamer](https://github.com/jacksonliam/mjpg-streamer) при использовании им плагинов ```input_uvc.so``` и ```output_http.so```, однако имеет ряд серьезных отличий. Основные приведены в этой таблице:
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
#define US_JLOG_ERROR(x_prefix, x_msg, ...) JANUS_LOG(LOG_ERR, "== %s/%-9s -- " x_msg "\n", US_PLUGIN_NAME, x_prefix, ##__VA_ARGS__)
|
#define US_JLOG_ERROR(x_prefix, x_msg, ...) JANUS_LOG(LOG_ERR, "== %s/%-9s -- " x_msg "\n", US_PLUGIN_NAME, x_prefix, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define US_JLOG_PERROR(x_prefix, x_msg, ...) { \
|
#define US_JLOG_PERROR(x_prefix, x_msg, ...) { \
|
||||||
char m_perror_buf[1024] = {0}; \
|
char *const m_perror_str = us_errno_to_string(errno); \
|
||||||
char *m_perror_ptr = us_errno_to_string(errno, m_perror_buf, 1023); \
|
JANUS_LOG(LOG_ERR, "[%s/%-9s] " x_msg ": %s\n", US_PLUGIN_NAME, x_prefix, ##__VA_ARGS__, m_perror_str); \
|
||||||
JANUS_LOG(LOG_ERR, "[%s/%-9s] " x_msg ": %s\n", US_PLUGIN_NAME, x_prefix, ##__VA_ARGS__, m_perror_ptr); \
|
free(m_perror_str); \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ us_queue_s *us_queue_init(unsigned capacity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void us_queue_destroy(us_queue_s *queue) {
|
void us_queue_destroy(us_queue_s *queue) {
|
||||||
|
US_COND_DESTROY(queue->empty_cond);
|
||||||
|
US_COND_DESTROY(queue->full_cond);
|
||||||
|
US_MUTEX_DESTROY(queue->mutex);
|
||||||
free(queue->items);
|
free(queue->items);
|
||||||
free(queue);
|
free(queue);
|
||||||
}
|
}
|
||||||
@@ -73,7 +76,7 @@ int us_queue_put(us_queue_s *queue, void *item, long double timeout) {
|
|||||||
++queue->in;
|
++queue->in;
|
||||||
queue->in %= queue->capacity;
|
queue->in %= queue->capacity;
|
||||||
US_MUTEX_UNLOCK(queue->mutex);
|
US_MUTEX_UNLOCK(queue->mutex);
|
||||||
assert(!pthread_cond_broadcast(&queue->empty_cond));
|
US_COND_BROADCAST(queue->empty_cond);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +88,7 @@ int us_queue_get(us_queue_s *queue, void **item, long double timeout) {
|
|||||||
++queue->out;
|
++queue->out;
|
||||||
queue->out %= queue->capacity;
|
queue->out %= queue->capacity;
|
||||||
US_MUTEX_UNLOCK(queue->mutex);
|
US_MUTEX_UNLOCK(queue->mutex);
|
||||||
assert(!pthread_cond_broadcast(&queue->full_cond));
|
US_COND_BROADCAST(queue->full_cond);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ FROM archlinux/archlinux:base-devel
|
|||||||
RUN mkdir -p /etc/pacman.d/hooks \
|
RUN mkdir -p /etc/pacman.d/hooks \
|
||||||
&& ln -s /dev/null /etc/pacman.d/hooks/30-systemd-tmpfiles.hook
|
&& ln -s /dev/null /etc/pacman.d/hooks/30-systemd-tmpfiles.hook
|
||||||
|
|
||||||
RUN echo "Server = http://mirror.yandex.ru/archlinux/\$repo/os/\$arch" > /etc/pacman.d/mirrorlist
|
RUN echo 'Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch' > /etc/pacman.d/mirrorlist
|
||||||
|
|
||||||
RUN pacman -Syu --noconfirm \
|
RUN pacman -Syu --noconfirm \
|
||||||
&& pacman -S --needed --noconfirm \
|
&& pacman -S --needed --noconfirm \
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer-dump.
|
.\" Manpage for ustreamer-dump.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER-DUMP 1 "version 5.17" "January 2021"
|
.TH USTREAMER-DUMP 1 "version 5.23" "January 2021"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer-dump \- Dump uStreamer's memory sink to file
|
ustreamer-dump \- Dump uStreamer's memory sink to file
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer.
|
.\" Manpage for ustreamer.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER 1 "version 5.17" "November 2020"
|
.TH USTREAMER 1 "version 5.23" "November 2020"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
||||||
@@ -10,7 +10,7 @@ ustreamer \- stream MJPEG video from any V4L2 device to the network
|
|||||||
.RI [OPTIONS]
|
.RI [OPTIONS]
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
µStreamer (\fBustreamer\fP) is a lightweight and very quick server to stream MJPEG video from any V4L2 device to the network. All new browsers have native support of this video format, as well as most video players such as mplayer, VLC etc. µStreamer is a part of the Pi-KVM project designed to stream VGA and HDMI screencast hardware data with the highest resolution and FPS possible.
|
µStreamer (\fBustreamer\fP) is a lightweight and very quick server to stream MJPEG video from any V4L2 device to the network. All new browsers have native support of this video format, as well as most video players such as mplayer, VLC etc. µStreamer is a part of the PiKVM project designed to stream VGA and HDMI screencast hardware data with the highest resolution and FPS possible.
|
||||||
|
|
||||||
.SH USAGE
|
.SH USAGE
|
||||||
Without arguments, \fBustreamer\fR will try to open \fB/dev/video0\fR with 640x480 resolution and start streaming on \fBhttp://127\.0\.0\.1:8080\fR\. You can override this behavior using parameters \fB\-\-device\fR, \fB\-\-host\fR and \fB\-\-port\fR\. For example, to stream to the world, run: \fBustreamer --device=/dev/video1 --host=0.0.0.0 --port=80\fR
|
Without arguments, \fBustreamer\fR will try to open \fB/dev/video0\fR with 640x480 resolution and start streaming on \fBhttp://127\.0\.0\.1:8080\fR\. You can override this behavior using parameters \fB\-\-device\fR, \fB\-\-host\fR and \fB\-\-port\fR\. For example, to stream to the world, run: \fBustreamer --device=/dev/video1 --host=0.0.0.0 --port=80\fR
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
pkgname=ustreamer
|
pkgname=ustreamer
|
||||||
pkgver=5.17
|
pkgver=5.23
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
||||||
url="https://github.com/pikvm/ustreamer"
|
url="https://github.com/pikvm/ustreamer"
|
||||||
@@ -22,8 +22,8 @@ if [ -e /usr/bin/python3 ]; then
|
|||||||
makedepends+=(python-setuptools)
|
makedepends+=(python-setuptools)
|
||||||
fi
|
fi
|
||||||
if [ -e /usr/include/janus/plugins/plugin.h ];then
|
if [ -e /usr/include/janus/plugins/plugin.h ];then
|
||||||
depends+=(janus-gateway-pikvm alsa-lib opus)
|
depends+=(janus-gateway alsa-lib opus)
|
||||||
makedepends+=(janus-gateway-pikvm alsa-lib opus)
|
makedepends+=(janus-gateway alsa-lib opus)
|
||||||
_options="$_options WITH_JANUS=1"
|
_options="$_options WITH_JANUS=1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=ustreamer
|
PKG_NAME:=ustreamer
|
||||||
PKG_VERSION:=5.17
|
PKG_VERSION:=5.23
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from setuptools import Extension
|
from setuptools import Extension
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
def _find_sources(suffix: str) -> List[str]:
|
def _find_sources(suffix: str) -> list[str]:
|
||||||
sources: List[str] = []
|
sources: list[str] = []
|
||||||
for (root_path, _, names) in os.walk("src"):
|
for (root_path, _, names) in os.walk("src"):
|
||||||
for name in names:
|
for name in names:
|
||||||
if name.endswith(suffix):
|
if name.endswith(suffix):
|
||||||
@@ -19,7 +17,7 @@ def _find_sources(suffix: str) -> List[str]:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
setup(
|
setup(
|
||||||
name="ustreamer",
|
name="ustreamer",
|
||||||
version="5.17",
|
version="5.23",
|
||||||
description="uStreamer tools",
|
description="uStreamer tools",
|
||||||
author="Maxim Devaev",
|
author="Maxim Devaev",
|
||||||
author_email="mdevaev@gmail.com",
|
author_email="mdevaev@gmail.com",
|
||||||
|
|||||||
@@ -151,12 +151,12 @@ int main(int argc, char *argv[]) {
|
|||||||
case _O_COUNT: OPT_NUMBER("--count", count, 0, LLONG_MAX, 0);
|
case _O_COUNT: OPT_NUMBER("--count", count, 0, LLONG_MAX, 0);
|
||||||
case _O_INTERVAL: OPT_LDOUBLE("--interval", interval, 0, 60);
|
case _O_INTERVAL: OPT_LDOUBLE("--interval", interval, 0, 60);
|
||||||
|
|
||||||
case _O_LOG_LEVEL: OPT_NUMBER("--log-level", us_log_level, US_LOG_LEVEL_INFO, US_LOG_LEVEL_DEBUG, 0);
|
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_log_level, US_LOG_LEVEL_PERF);
|
case _O_PERF: OPT_SET(us_g_log_level, US_LOG_LEVEL_PERF);
|
||||||
case _O_VERBOSE: OPT_SET(us_log_level, US_LOG_LEVEL_VERBOSE);
|
case _O_VERBOSE: OPT_SET(us_g_log_level, US_LOG_LEVEL_VERBOSE);
|
||||||
case _O_DEBUG: OPT_SET(us_log_level, US_LOG_LEVEL_DEBUG);
|
case _O_DEBUG: OPT_SET(us_g_log_level, US_LOG_LEVEL_DEBUG);
|
||||||
case _O_FORCE_LOG_COLORS: OPT_SET(us_log_colored, true);
|
case _O_FORCE_LOG_COLORS: OPT_SET(us_g_log_colored, true);
|
||||||
case _O_NO_LOG_COLORS: OPT_SET(us_log_colored, false);
|
case _O_NO_LOG_COLORS: OPT_SET(us_g_log_colored, false);
|
||||||
|
|
||||||
case _O_HELP: _help(stdout); return 0;
|
case _O_HELP: _help(stdout); return 0;
|
||||||
case _O_VERSION: puts(US_VERSION); return 0;
|
case _O_VERSION: puts(US_VERSION); return 0;
|
||||||
@@ -195,12 +195,9 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
|
|
||||||
static void _signal_handler(int signum) {
|
static void _signal_handler(int signum) {
|
||||||
switch (signum) {
|
char *const name = us_signum_to_string(signum);
|
||||||
case SIGTERM: US_LOG_INFO_NOLOCK("===== Stopping by SIGTERM ====="); break;
|
US_LOG_INFO_NOLOCK("===== Stopping by %s =====", name);
|
||||||
case SIGINT: US_LOG_INFO_NOLOCK("===== Stopping by SIGINT ====="); break;
|
free(name);
|
||||||
case SIGPIPE: US_LOG_INFO_NOLOCK("===== Stopping by SIGPIPE ====="); break;
|
|
||||||
default: US_LOG_INFO_NOLOCK("===== Stopping by %d =====", signum); break;
|
|
||||||
}
|
|
||||||
_g_stop = true;
|
_g_stop = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +327,7 @@ static void _help(FILE *fp) {
|
|||||||
SAY(" --log-level <N> ──── Verbosity level of messages from 0 (info) to 3 (debug).");
|
SAY(" --log-level <N> ──── Verbosity level of messages from 0 (info) to 3 (debug).");
|
||||||
SAY(" Enabling debugging messages can slow down the program.");
|
SAY(" Enabling debugging messages can slow down the program.");
|
||||||
SAY(" Available levels: 0 (info), 1 (performance), 2 (verbose), 3 (debug).");
|
SAY(" Available levels: 0 (info), 1 (performance), 2 (verbose), 3 (debug).");
|
||||||
SAY(" Default: %d.\n", us_log_level);
|
SAY(" Default: %d.\n", us_g_log_level);
|
||||||
SAY(" --perf ───────────── Enable performance messages (same as --log-level=1). Default: disabled.\n");
|
SAY(" --perf ───────────── Enable performance messages (same as --log-level=1). Default: disabled.\n");
|
||||||
SAY(" --verbose ────────── Enable verbose messages and lower (same as --log-level=2). Default: disabled.\n");
|
SAY(" --verbose ────────── Enable verbose messages and lower (same as --log-level=2). Default: disabled.\n");
|
||||||
SAY(" --debug ──────────── Enable debug messages and lower (same as --log-level=3). Default: disabled.\n");
|
SAY(" --debug ──────────── Enable debug messages and lower (same as --log-level=3). Default: disabled.\n");
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define US_VERSION_MAJOR 5
|
#define US_VERSION_MAJOR 5
|
||||||
#define US_VERSION_MINOR 17
|
#define US_VERSION_MINOR 23
|
||||||
|
|
||||||
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
||||||
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
|
|
||||||
enum us_log_level_t us_log_level;
|
enum us_log_level_t us_g_log_level;
|
||||||
|
|
||||||
bool us_log_colored;
|
bool us_g_log_colored;
|
||||||
|
|
||||||
pthread_mutex_t us_log_mutex;
|
pthread_mutex_t us_g_log_mutex;
|
||||||
|
|||||||
@@ -45,23 +45,23 @@ enum us_log_level_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern enum us_log_level_t us_log_level;
|
extern enum us_log_level_t us_g_log_level;
|
||||||
|
|
||||||
extern bool us_log_colored;
|
extern bool us_g_log_colored;
|
||||||
|
|
||||||
extern pthread_mutex_t us_log_mutex;
|
extern pthread_mutex_t us_g_log_mutex;
|
||||||
|
|
||||||
|
|
||||||
#define US_LOGGING_INIT { \
|
#define US_LOGGING_INIT { \
|
||||||
us_log_level = US_LOG_LEVEL_INFO; \
|
us_g_log_level = US_LOG_LEVEL_INFO; \
|
||||||
us_log_colored = isatty(2); \
|
us_g_log_colored = isatty(2); \
|
||||||
US_MUTEX_INIT(us_log_mutex); \
|
US_MUTEX_INIT(us_g_log_mutex); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define US_LOGGING_DESTROY US_MUTEX_DESTROY(us_log_mutex)
|
#define US_LOGGING_DESTROY US_MUTEX_DESTROY(us_g_log_mutex)
|
||||||
|
|
||||||
#define US_LOGGING_LOCK US_MUTEX_LOCK(us_log_mutex)
|
#define US_LOGGING_LOCK US_MUTEX_LOCK(us_g_log_mutex)
|
||||||
#define US_LOGGING_UNLOCK US_MUTEX_UNLOCK(us_log_mutex)
|
#define US_LOGGING_UNLOCK US_MUTEX_UNLOCK(us_g_log_mutex)
|
||||||
|
|
||||||
|
|
||||||
#define US_COLOR_GRAY "\x1b[30;1m"
|
#define US_COLOR_GRAY "\x1b[30;1m"
|
||||||
@@ -84,7 +84,7 @@ extern pthread_mutex_t us_log_mutex;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define US_SEP_DEBUG(x_ch) { \
|
#define US_SEP_DEBUG(x_ch) { \
|
||||||
if (us_log_level >= US_LOG_LEVEL_DEBUG) { \
|
if (us_g_log_level >= US_LOG_LEVEL_DEBUG) { \
|
||||||
US_SEP_INFO(x_ch); \
|
US_SEP_INFO(x_ch); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ extern pthread_mutex_t us_log_mutex;
|
|||||||
#define US_LOG_PRINTF_NOLOCK(x_label_color, x_label, x_msg_color, x_msg, ...) { \
|
#define US_LOG_PRINTF_NOLOCK(x_label_color, x_label, x_msg_color, x_msg, ...) { \
|
||||||
char m_tname_buf[US_MAX_THREAD_NAME] = {0}; \
|
char m_tname_buf[US_MAX_THREAD_NAME] = {0}; \
|
||||||
us_thread_get_name(m_tname_buf); \
|
us_thread_get_name(m_tname_buf); \
|
||||||
if (us_log_colored) { \
|
if (us_g_log_colored) { \
|
||||||
fprintf(stderr, US_COLOR_GRAY "-- " x_label_color x_label US_COLOR_GRAY \
|
fprintf(stderr, US_COLOR_GRAY "-- " x_label_color x_label US_COLOR_GRAY \
|
||||||
" [%.03Lf %9s]" " -- " US_COLOR_RESET x_msg_color x_msg US_COLOR_RESET, \
|
" [%.03Lf %9s]" " -- " US_COLOR_RESET x_msg_color x_msg US_COLOR_RESET, \
|
||||||
us_get_now_monotonic(), m_tname_buf, ##__VA_ARGS__); \
|
us_get_now_monotonic(), m_tname_buf, ##__VA_ARGS__); \
|
||||||
@@ -116,9 +116,9 @@ extern pthread_mutex_t us_log_mutex;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define US_LOG_PERROR(x_msg, ...) { \
|
#define US_LOG_PERROR(x_msg, ...) { \
|
||||||
char m_perror_buf[1024] = {0}; \
|
char *const m_perror_str = us_errno_to_string(errno); \
|
||||||
char *m_perror_ptr = us_errno_to_string(errno, m_perror_buf, 1024); \
|
US_LOG_ERROR(x_msg ": %s", ##__VA_ARGS__, m_perror_str); \
|
||||||
US_LOG_ERROR(x_msg ": %s", ##__VA_ARGS__, m_perror_ptr); \
|
free(m_perror_str); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define US_LOG_INFO(x_msg, ...) { \
|
#define US_LOG_INFO(x_msg, ...) { \
|
||||||
@@ -130,33 +130,33 @@ extern pthread_mutex_t us_log_mutex;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define US_LOG_PERF(x_msg, ...) { \
|
#define US_LOG_PERF(x_msg, ...) { \
|
||||||
if (us_log_level >= US_LOG_LEVEL_PERF) { \
|
if (us_g_log_level >= US_LOG_LEVEL_PERF) { \
|
||||||
US_LOG_PRINTF(US_COLOR_CYAN, "PERF ", US_COLOR_CYAN, x_msg, ##__VA_ARGS__); \
|
US_LOG_PRINTF(US_COLOR_CYAN, "PERF ", US_COLOR_CYAN, x_msg, ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define US_LOG_PERF_FPS(x_msg, ...) { \
|
#define US_LOG_PERF_FPS(x_msg, ...) { \
|
||||||
if (us_log_level >= US_LOG_LEVEL_PERF) { \
|
if (us_g_log_level >= US_LOG_LEVEL_PERF) { \
|
||||||
US_LOG_PRINTF(US_COLOR_YELLOW, "PERF ", US_COLOR_YELLOW, x_msg, ##__VA_ARGS__); \
|
US_LOG_PRINTF(US_COLOR_YELLOW, "PERF ", US_COLOR_YELLOW, x_msg, ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define US_LOG_VERBOSE(x_msg, ...) { \
|
#define US_LOG_VERBOSE(x_msg, ...) { \
|
||||||
if (us_log_level >= US_LOG_LEVEL_VERBOSE) { \
|
if (us_g_log_level >= US_LOG_LEVEL_VERBOSE) { \
|
||||||
US_LOG_PRINTF(US_COLOR_BLUE, "VERB ", US_COLOR_BLUE, x_msg, ##__VA_ARGS__); \
|
US_LOG_PRINTF(US_COLOR_BLUE, "VERB ", US_COLOR_BLUE, x_msg, ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define US_LOG_VERBOSE_PERROR(x_msg, ...) { \
|
#define US_LOG_VERBOSE_PERROR(x_msg, ...) { \
|
||||||
if (us_log_level >= US_LOG_LEVEL_VERBOSE) { \
|
if (us_g_log_level >= US_LOG_LEVEL_VERBOSE) { \
|
||||||
char m_perror_buf[1024] = {0}; \
|
char *m_perror_str = us_errno_to_string(errno); \
|
||||||
char *m_perror_ptr = us_errno_to_string(errno, m_perror_buf, 1023); \
|
US_LOG_PRINTF(US_COLOR_BLUE, "VERB ", US_COLOR_BLUE, x_msg ": %s", ##__VA_ARGS__, m_perror_str); \
|
||||||
US_LOG_PRINTF(US_COLOR_BLUE, "VERB ", US_COLOR_BLUE, x_msg ": %s", ##__VA_ARGS__, m_perror_ptr); \
|
free(m_perror_str); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define US_LOG_DEBUG(x_msg, ...) { \
|
#define US_LOG_DEBUG(x_msg, ...) { \
|
||||||
if (us_log_level >= US_LOG_LEVEL_DEBUG) { \
|
if (us_g_log_level >= US_LOG_LEVEL_DEBUG) { \
|
||||||
US_LOG_PRINTF(US_COLOR_GRAY, "DEBUG", US_COLOR_GRAY, x_msg, ##__VA_ARGS__); \
|
US_LOG_PRINTF(US_COLOR_GRAY, "DEBUG", US_COLOR_GRAY, x_msg, ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,8 @@
|
|||||||
#define US_COND_INIT(x_cond) assert(!pthread_cond_init(&(x_cond), NULL))
|
#define US_COND_INIT(x_cond) assert(!pthread_cond_init(&(x_cond), NULL))
|
||||||
#define US_COND_DESTROY(x_cond) assert(!pthread_cond_destroy(&(x_cond)))
|
#define US_COND_DESTROY(x_cond) assert(!pthread_cond_destroy(&(x_cond)))
|
||||||
#define US_COND_SIGNAL(x_cond) assert(!pthread_cond_signal(&(x_cond)))
|
#define US_COND_SIGNAL(x_cond) assert(!pthread_cond_signal(&(x_cond)))
|
||||||
#define US_COND_WAIT_TRUE(x_var, x_cond, x_mutex) { while(!(x_var)) assert(!pthread_cond_wait(&(x_cond), &(x_mutex))); }
|
#define US_COND_BROADCAST(x_cond) assert(!pthread_cond_broadcast(&(x_cond)))
|
||||||
|
#define US_COND_WAIT_FOR(x_var, x_cond, x_mutex) { while(!(x_var)) assert(!pthread_cond_wait(&(x_cond), &(x_mutex))); }
|
||||||
|
|
||||||
|
|
||||||
#ifdef WITH_PTHREAD_NP
|
#ifdef WITH_PTHREAD_NP
|
||||||
|
|||||||
@@ -38,6 +38,12 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
|
|
||||||
|
#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
|
||||||
|
# define HAS_SIGABBREV_NP
|
||||||
|
#else
|
||||||
|
# include <signal.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
# error WTF dude? Asserts are good things!
|
# error WTF dude? Asserts are good things!
|
||||||
@@ -181,15 +187,34 @@ INLINE int us_flock_timedwait_monotonic(int fd, long double timeout) {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE char *us_errno_to_string(int error, char *buf, size_t size) {
|
INLINE char *us_errno_to_string(int error) {
|
||||||
assert(buf != NULL);
|
|
||||||
assert(size > 0);
|
|
||||||
locale_t locale = newlocale(LC_MESSAGES_MASK, "C", NULL);
|
locale_t locale = newlocale(LC_MESSAGES_MASK, "C", NULL);
|
||||||
const char *str = "!!! newlocale() error !!!";
|
char *buf;
|
||||||
strncpy(buf, (locale ? strerror_l(error, locale) : str), size - 1);
|
|
||||||
buf[size - 1] = '\0';
|
|
||||||
if (locale) {
|
if (locale) {
|
||||||
|
buf = us_strdup(strerror_l(error, locale));
|
||||||
freelocale(locale);
|
freelocale(locale);
|
||||||
|
} else {
|
||||||
|
buf = us_strdup("!!! newlocale() error !!!");
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE char *us_signum_to_string(int signum) {
|
||||||
|
# ifdef HAS_SIGABBREV_NP
|
||||||
|
const char *const name = sigabbrev_np(signum);
|
||||||
|
# else
|
||||||
|
const char *const name = (
|
||||||
|
signum == SIGTERM ? "TERM" :
|
||||||
|
signum == SIGINT ? "INT" :
|
||||||
|
signum == SIGPIPE ? "PIPE" :
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
# endif
|
||||||
|
char *buf;
|
||||||
|
if (name != NULL) {
|
||||||
|
US_ASPRINTF(buf, "SIG%s", name);
|
||||||
|
} else {
|
||||||
|
US_ASPRINTF(buf, "SIG[%d]", signum);
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
|
|
||||||
|
|
||||||
us_gpio_s us_gpio = {
|
us_gpio_s us_g_gpio = {
|
||||||
.path = "/dev/gpiochip0",
|
.path = "/dev/gpiochip0",
|
||||||
.consumer_prefix = "ustreamer",
|
.consumer_prefix = "ustreamer",
|
||||||
|
|
||||||
@@ -51,42 +51,42 @@ static void _gpio_output_destroy(us_gpio_output_s *output);
|
|||||||
|
|
||||||
|
|
||||||
void us_gpio_init(void) {
|
void us_gpio_init(void) {
|
||||||
assert(us_gpio.chip == NULL);
|
assert(us_g_gpio.chip == NULL);
|
||||||
if (
|
if (
|
||||||
us_gpio.prog_running.pin >= 0
|
us_g_gpio.prog_running.pin >= 0
|
||||||
|| us_gpio.stream_online.pin >= 0
|
|| us_g_gpio.stream_online.pin >= 0
|
||||||
|| us_gpio.has_http_clients.pin >= 0
|
|| us_g_gpio.has_http_clients.pin >= 0
|
||||||
) {
|
) {
|
||||||
US_MUTEX_INIT(us_gpio.mutex);
|
US_MUTEX_INIT(us_g_gpio.mutex);
|
||||||
US_LOG_INFO("GPIO: Using chip device: %s", us_gpio.path);
|
US_LOG_INFO("GPIO: Using chip device: %s", us_g_gpio.path);
|
||||||
if ((us_gpio.chip = gpiod_chip_open(us_gpio.path)) != NULL) {
|
if ((us_g_gpio.chip = gpiod_chip_open(us_g_gpio.path)) != NULL) {
|
||||||
_gpio_output_init(&us_gpio.prog_running);
|
_gpio_output_init(&us_g_gpio.prog_running);
|
||||||
_gpio_output_init(&us_gpio.stream_online);
|
_gpio_output_init(&us_g_gpio.stream_online);
|
||||||
_gpio_output_init(&us_gpio.has_http_clients);
|
_gpio_output_init(&us_g_gpio.has_http_clients);
|
||||||
} else {
|
} else {
|
||||||
US_LOG_PERROR("GPIO: Can't initialize chip device %s", us_gpio.path);
|
US_LOG_PERROR("GPIO: Can't initialize chip device %s", us_g_gpio.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void us_gpio_destroy(void) {
|
void us_gpio_destroy(void) {
|
||||||
_gpio_output_destroy(&us_gpio.prog_running);
|
_gpio_output_destroy(&us_g_gpio.prog_running);
|
||||||
_gpio_output_destroy(&us_gpio.stream_online);
|
_gpio_output_destroy(&us_g_gpio.stream_online);
|
||||||
_gpio_output_destroy(&us_gpio.has_http_clients);
|
_gpio_output_destroy(&us_g_gpio.has_http_clients);
|
||||||
if (us_gpio.chip != NULL) {
|
if (us_g_gpio.chip != NULL) {
|
||||||
gpiod_chip_close(us_gpio.chip);
|
gpiod_chip_close(us_g_gpio.chip);
|
||||||
us_gpio.chip = NULL;
|
us_g_gpio.chip = NULL;
|
||||||
US_MUTEX_DESTROY(us_gpio.mutex);
|
US_MUTEX_DESTROY(us_g_gpio.mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int us_gpio_inner_set(us_gpio_output_s *output, bool state) {
|
int us_gpio_inner_set(us_gpio_output_s *output, bool state) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
assert(us_gpio.chip != NULL);
|
assert(us_g_gpio.chip != NULL);
|
||||||
assert(output->line != NULL);
|
assert(output->line != NULL);
|
||||||
assert(output->state != state); // Must be checked in macro for the performance
|
assert(output->state != state); // Must be checked in macro for the performance
|
||||||
US_MUTEX_LOCK(us_gpio.mutex);
|
US_MUTEX_LOCK(us_g_gpio.mutex);
|
||||||
|
|
||||||
if (gpiod_line_set_value(output->line, (int)state) < 0) { \
|
if (gpiod_line_set_value(output->line, (int)state) < 0) { \
|
||||||
US_LOG_PERROR("GPIO: Can't write value %d to line %s (will be disabled)", state, output->consumer); \
|
US_LOG_PERROR("GPIO: Can't write value %d to line %s (will be disabled)", state, output->consumer); \
|
||||||
@@ -94,18 +94,18 @@ int us_gpio_inner_set(us_gpio_output_s *output, bool state) {
|
|||||||
retval = -1;
|
retval = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
US_MUTEX_UNLOCK(us_gpio.mutex);
|
US_MUTEX_UNLOCK(us_g_gpio.mutex);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _gpio_output_init(us_gpio_output_s *output) {
|
static void _gpio_output_init(us_gpio_output_s *output) {
|
||||||
assert(us_gpio.chip != NULL);
|
assert(us_g_gpio.chip != NULL);
|
||||||
assert(output->line == NULL);
|
assert(output->line == NULL);
|
||||||
|
|
||||||
US_ASPRINTF(output->consumer, "%s::%s", us_gpio.consumer_prefix, output->role);
|
US_ASPRINTF(output->consumer, "%s::%s", us_g_gpio.consumer_prefix, output->role);
|
||||||
|
|
||||||
if (output->pin >= 0) {
|
if (output->pin >= 0) {
|
||||||
if ((output->line = gpiod_chip_get_line(us_gpio.chip, output->pin)) != NULL) {
|
if ((output->line = gpiod_chip_get_line(us_g_gpio.chip, output->pin)) != NULL) {
|
||||||
if (gpiod_line_request_output(output->line, output->consumer, 0) < 0) {
|
if (gpiod_line_request_output(output->line, output->consumer, 0) < 0) {
|
||||||
US_LOG_PERROR("GPIO: Can't request pin=%d as %s", output->pin, output->consumer);
|
US_LOG_PERROR("GPIO: Can't request pin=%d as %s", output->pin, output->consumer);
|
||||||
_gpio_output_destroy(output);
|
_gpio_output_destroy(output);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ typedef struct {
|
|||||||
} us_gpio_s;
|
} us_gpio_s;
|
||||||
|
|
||||||
|
|
||||||
extern us_gpio_s us_gpio;
|
extern us_gpio_s us_g_gpio;
|
||||||
|
|
||||||
|
|
||||||
void us_gpio_init(void);
|
void us_gpio_init(void);
|
||||||
@@ -73,15 +73,15 @@ int us_gpio_inner_set(us_gpio_output_s *output, bool state);
|
|||||||
}
|
}
|
||||||
|
|
||||||
INLINE void us_gpio_set_prog_running(bool state) {
|
INLINE void us_gpio_set_prog_running(bool state) {
|
||||||
SET_STATE(us_gpio.prog_running, state);
|
SET_STATE(us_g_gpio.prog_running, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void us_gpio_set_stream_online(bool state) {
|
INLINE void us_gpio_set_stream_online(bool state) {
|
||||||
SET_STATE(us_gpio.stream_online, state);
|
SET_STATE(us_g_gpio.stream_online, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void us_gpio_set_has_http_clients(bool state) {
|
INLINE void us_gpio_set_has_http_clients(bool state) {
|
||||||
SET_STATE(us_gpio.has_http_clients, state);
|
SET_STATE(us_g_gpio.has_http_clients, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef SET_STATE
|
#undef SET_STATE
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ char *us_bufferevent_format_reason(short what) {
|
|||||||
US_CALLOC(reason, 2048);
|
US_CALLOC(reason, 2048);
|
||||||
|
|
||||||
// evutil_socket_error_to_string() is not thread-safe
|
// evutil_socket_error_to_string() is not thread-safe
|
||||||
char perror_buf[1024] = {0};
|
char *const perror_str = us_errno_to_string(EVUTIL_SOCKET_ERROR());
|
||||||
const char *perror_ptr = us_errno_to_string(EVUTIL_SOCKET_ERROR(), perror_buf, 1024);
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
strcat(reason, perror_ptr);
|
strcat(reason, perror_str);
|
||||||
|
free(perror_str);
|
||||||
strcat(reason, " (");
|
strcat(reason, " (");
|
||||||
|
|
||||||
# define FILL_REASON(x_bev, x_name) { \
|
# define FILL_REASON(x_bev, x_name) { \
|
||||||
|
|||||||
@@ -40,12 +40,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
static us_stream_s *_g_stream = NULL;
|
||||||
us_stream_s *stream;
|
static us_server_s *_g_server = NULL;
|
||||||
us_server_s *server;
|
|
||||||
} _main_context_s;
|
|
||||||
|
|
||||||
static _main_context_s *_ctx;
|
|
||||||
|
|
||||||
static void _block_thread_signals(void) {
|
static void _block_thread_signals(void) {
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
@@ -58,25 +55,23 @@ static void _block_thread_signals(void) {
|
|||||||
static void *_stream_loop_thread(UNUSED void *arg) {
|
static void *_stream_loop_thread(UNUSED void *arg) {
|
||||||
US_THREAD_RENAME("stream");
|
US_THREAD_RENAME("stream");
|
||||||
_block_thread_signals();
|
_block_thread_signals();
|
||||||
us_stream_loop(_ctx->stream);
|
us_stream_loop(_g_stream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *_server_loop_thread(UNUSED void *arg) {
|
static void *_server_loop_thread(UNUSED void *arg) {
|
||||||
US_THREAD_RENAME("http");
|
US_THREAD_RENAME("http");
|
||||||
_block_thread_signals();
|
_block_thread_signals();
|
||||||
us_server_loop(_ctx->server);
|
us_server_loop(_g_server);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _signal_handler(int signum) {
|
static void _signal_handler(int signum) {
|
||||||
switch (signum) {
|
char *const name = us_signum_to_string(signum);
|
||||||
case SIGTERM: US_LOG_INFO_NOLOCK("===== Stopping by SIGTERM ====="); break;
|
US_LOG_INFO_NOLOCK("===== Stopping by %s =====", name);
|
||||||
case SIGINT: US_LOG_INFO_NOLOCK("===== Stopping by SIGINT ====="); break;
|
free(name);
|
||||||
default: US_LOG_INFO_NOLOCK("===== Stopping by %d =====", signum); break;
|
us_stream_loop_break(_g_stream);
|
||||||
}
|
us_server_loop_break(_g_server);
|
||||||
us_stream_loop_break(_ctx->stream);
|
|
||||||
us_server_loop_break(_ctx->server);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _install_signal_handlers(void) {
|
static void _install_signal_handlers(void) {
|
||||||
@@ -107,22 +102,17 @@ int main(int argc, char *argv[]) {
|
|||||||
us_options_s *options = us_options_init(argc, argv);
|
us_options_s *options = us_options_init(argc, argv);
|
||||||
us_device_s *dev = us_device_init();
|
us_device_s *dev = us_device_init();
|
||||||
us_encoder_s *enc = us_encoder_init();
|
us_encoder_s *enc = us_encoder_init();
|
||||||
us_stream_s *stream = us_stream_init(dev, enc);
|
_g_stream = us_stream_init(dev, enc);
|
||||||
us_server_s *server = us_server_init(stream);
|
_g_server = us_server_init(_g_stream);
|
||||||
|
|
||||||
if ((exit_code = options_parse(options, dev, enc, stream, server)) == 0) {
|
if ((exit_code = options_parse(options, dev, enc, _g_stream, _g_server)) == 0) {
|
||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
us_gpio_init();
|
us_gpio_init();
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
_install_signal_handlers();
|
_install_signal_handlers();
|
||||||
|
|
||||||
_main_context_s ctx;
|
if ((exit_code = us_server_listen(_g_server)) == 0) {
|
||||||
ctx.stream = stream;
|
|
||||||
ctx.server = server;
|
|
||||||
_ctx = &ctx;
|
|
||||||
|
|
||||||
if ((exit_code = us_server_listen(server)) == 0) {
|
|
||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
us_gpio_set_prog_running(true);
|
us_gpio_set_prog_running(true);
|
||||||
# endif
|
# endif
|
||||||
@@ -141,8 +131,8 @@ int main(int argc, char *argv[]) {
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
us_server_destroy(server);
|
us_server_destroy(_g_server);
|
||||||
us_stream_destroy(stream);
|
us_stream_destroy(_g_stream);
|
||||||
us_encoder_destroy(enc);
|
us_encoder_destroy(enc);
|
||||||
us_device_destroy(dev);
|
us_device_destroy(dev);
|
||||||
us_options_destroy(options);
|
us_options_destroy(options);
|
||||||
|
|||||||
@@ -437,11 +437,11 @@ int options_parse(us_options_s *options, us_device_s *dev, us_encoder_s *enc, us
|
|||||||
# undef ADD_SINK
|
# undef ADD_SINK
|
||||||
|
|
||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
case _O_GPIO_DEVICE: OPT_SET(us_gpio.path, optarg);
|
case _O_GPIO_DEVICE: OPT_SET(us_g_gpio.path, optarg);
|
||||||
case _O_GPIO_CONSUMER_PREFIX: OPT_SET(us_gpio.consumer_prefix, optarg);
|
case _O_GPIO_CONSUMER_PREFIX: OPT_SET(us_g_gpio.consumer_prefix, optarg);
|
||||||
case _O_GPIO_PROG_RUNNING: OPT_NUMBER("--gpio-prog-running", us_gpio.prog_running.pin, 0, 256, 0);
|
case _O_GPIO_PROG_RUNNING: OPT_NUMBER("--gpio-prog-running", us_g_gpio.prog_running.pin, 0, 256, 0);
|
||||||
case _O_GPIO_STREAM_ONLINE: OPT_NUMBER("--gpio-stream-online", us_gpio.stream_online.pin, 0, 256, 0);
|
case _O_GPIO_STREAM_ONLINE: OPT_NUMBER("--gpio-stream-online", us_g_gpio.stream_online.pin, 0, 256, 0);
|
||||||
case _O_GPIO_HAS_HTTP_CLIENTS: OPT_NUMBER("--gpio-has-http-clients", us_gpio.has_http_clients.pin, 0, 256, 0);
|
case _O_GPIO_HAS_HTTP_CLIENTS: OPT_NUMBER("--gpio-has-http-clients", us_g_gpio.has_http_clients.pin, 0, 256, 0);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef HAS_PDEATHSIG
|
# ifdef HAS_PDEATHSIG
|
||||||
@@ -457,12 +457,12 @@ int options_parse(us_options_s *options, us_device_s *dev, us_encoder_s *enc, us
|
|||||||
# endif
|
# endif
|
||||||
case _O_NOTIFY_PARENT: OPT_SET(server->notify_parent, true);
|
case _O_NOTIFY_PARENT: OPT_SET(server->notify_parent, true);
|
||||||
|
|
||||||
case _O_LOG_LEVEL: OPT_NUMBER("--log-level", us_log_level, US_LOG_LEVEL_INFO, US_LOG_LEVEL_DEBUG, 0);
|
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_log_level, US_LOG_LEVEL_PERF);
|
case _O_PERF: OPT_SET(us_g_log_level, US_LOG_LEVEL_PERF);
|
||||||
case _O_VERBOSE: OPT_SET(us_log_level, US_LOG_LEVEL_VERBOSE);
|
case _O_VERBOSE: OPT_SET(us_g_log_level, US_LOG_LEVEL_VERBOSE);
|
||||||
case _O_DEBUG: OPT_SET(us_log_level, US_LOG_LEVEL_DEBUG);
|
case _O_DEBUG: OPT_SET(us_g_log_level, US_LOG_LEVEL_DEBUG);
|
||||||
case _O_FORCE_LOG_COLORS: OPT_SET(us_log_colored, true);
|
case _O_FORCE_LOG_COLORS: OPT_SET(us_g_log_colored, true);
|
||||||
case _O_NO_LOG_COLORS: OPT_SET(us_log_colored, false);
|
case _O_NO_LOG_COLORS: OPT_SET(us_g_log_colored, false);
|
||||||
|
|
||||||
case _O_HELP: _help(stdout, dev, enc, stream, server); return 1;
|
case _O_HELP: _help(stdout, dev, enc, stream, server); return 1;
|
||||||
case _O_VERSION: puts(US_VERSION); return 1;
|
case _O_VERSION: puts(US_VERSION); return 1;
|
||||||
@@ -676,8 +676,8 @@ static void _help(FILE *fp, us_device_s *dev, us_encoder_s *enc, us_stream_s *st
|
|||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
SAY("GPIO options:");
|
SAY("GPIO options:");
|
||||||
SAY("═════════════");
|
SAY("═════════════");
|
||||||
SAY(" --gpio-device </dev/path> ───── Path to GPIO character device. Default: %s.\n", us_gpio.path);
|
SAY(" --gpio-device </dev/path> ───── Path to GPIO character device. Default: %s.\n", us_g_gpio.path);
|
||||||
SAY(" --gpio-consumer-prefix <str> ── Consumer prefix for GPIO outputs. Default: %s.\n", us_gpio.consumer_prefix);
|
SAY(" --gpio-consumer-prefix <str> ── Consumer prefix for GPIO outputs. Default: %s.\n", us_g_gpio.consumer_prefix);
|
||||||
SAY(" --gpio-prog-running <pin> ───── Set 1 on GPIO pin while uStreamer is running. Default: disabled.\n");
|
SAY(" --gpio-prog-running <pin> ───── Set 1 on GPIO pin while uStreamer is running. Default: disabled.\n");
|
||||||
SAY(" --gpio-stream-online <pin> ──── Set 1 while streaming. Default: disabled.\n");
|
SAY(" --gpio-stream-online <pin> ──── Set 1 while streaming. Default: disabled.\n");
|
||||||
SAY(" --gpio-has-http-clients <pin> ─ Set 1 while stream has at least one client. Default: disabled.\n");
|
SAY(" --gpio-has-http-clients <pin> ─ Set 1 while stream has at least one client. Default: disabled.\n");
|
||||||
@@ -702,7 +702,7 @@ static void _help(FILE *fp, us_device_s *dev, us_encoder_s *enc, us_stream_s *st
|
|||||||
SAY(" --log-level <N> ──── Verbosity level of messages from 0 (info) to 3 (debug).");
|
SAY(" --log-level <N> ──── Verbosity level of messages from 0 (info) to 3 (debug).");
|
||||||
SAY(" Enabling debugging messages can slow down the program.");
|
SAY(" Enabling debugging messages can slow down the program.");
|
||||||
SAY(" Available levels: 0 (info), 1 (performance), 2 (verbose), 3 (debug).");
|
SAY(" Available levels: 0 (info), 1 (performance), 2 (verbose), 3 (debug).");
|
||||||
SAY(" Default: %d.\n", us_log_level);
|
SAY(" Default: %d.\n", us_g_log_level);
|
||||||
SAY(" --perf ───────────── Enable performance messages (same as --log-level=1). Default: disabled.\n");
|
SAY(" --perf ───────────── Enable performance messages (same as --log-level=1). Default: disabled.\n");
|
||||||
SAY(" --verbose ────────── Enable verbose messages and lower (same as --log-level=2). Default: disabled.\n");
|
SAY(" --verbose ────────── Enable verbose messages and lower (same as --log-level=2). Default: disabled.\n");
|
||||||
SAY(" --debug ──────────── Enable debug messages and lower (same as --log-level=3). Default: disabled.\n");
|
SAY(" --debug ──────────── Enable debug messages and lower (same as --log-level=3). Default: disabled.\n");
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ us_worker_s *us_workers_pool_wait(us_workers_pool_s *pool) {
|
|||||||
us_worker_s *ready_wr = NULL;
|
us_worker_s *ready_wr = NULL;
|
||||||
|
|
||||||
US_MUTEX_LOCK(pool->free_workers_mutex);
|
US_MUTEX_LOCK(pool->free_workers_mutex);
|
||||||
US_COND_WAIT_TRUE(pool->free_workers, pool->free_workers_cond, pool->free_workers_mutex);
|
US_COND_WAIT_FOR(pool->free_workers, pool->free_workers_cond, pool->free_workers_mutex);
|
||||||
US_MUTEX_UNLOCK(pool->free_workers_mutex);
|
US_MUTEX_UNLOCK(pool->free_workers_mutex);
|
||||||
|
|
||||||
if (pool->oldest_wr && !atomic_load(&pool->oldest_wr->has_job)) {
|
if (pool->oldest_wr && !atomic_load(&pool->oldest_wr->has_job)) {
|
||||||
@@ -185,7 +185,7 @@ static void *_worker_thread(void *v_worker) {
|
|||||||
US_LOG_DEBUG("Worker %s waiting for a new job ...", wr->name);
|
US_LOG_DEBUG("Worker %s waiting for a new job ...", wr->name);
|
||||||
|
|
||||||
US_MUTEX_LOCK(wr->has_job_mutex);
|
US_MUTEX_LOCK(wr->has_job_mutex);
|
||||||
US_COND_WAIT_TRUE(atomic_load(&wr->has_job), wr->has_job_cond, wr->has_job_mutex);
|
US_COND_WAIT_FOR(atomic_load(&wr->has_job), wr->has_job_cond, wr->has_job_mutex);
|
||||||
US_MUTEX_UNLOCK(wr->has_job_mutex);
|
US_MUTEX_UNLOCK(wr->has_job_mutex);
|
||||||
|
|
||||||
if (!atomic_load(&wr->pool->stop)) {
|
if (!atomic_load(&wr->pool->stop)) {
|
||||||
|
|||||||
@@ -26,13 +26,11 @@ import os
|
|||||||
import io
|
import io
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import common
|
import common
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
def _get_jpeg_size(data: bytes) -> Tuple[int, int]:
|
def _get_jpeg_size(data: bytes) -> tuple[int, int]:
|
||||||
# https://sheep.horse/2013/9/finding_the_dimensions_of_a_jpeg_file_in_python.html
|
# https://sheep.horse/2013/9/finding_the_dimensions_of_a_jpeg_file_in_python.html
|
||||||
|
|
||||||
stream = io.BytesIO(data)
|
stream = io.BytesIO(data)
|
||||||
|
|||||||
Reference in New Issue
Block a user