mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-28 04:36:33 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90f09b197e | ||
|
|
687e97d523 | ||
|
|
c1675001fa | ||
|
|
69cc45a2a0 | ||
|
|
ece96b5834 | ||
|
|
383ed7530b | ||
|
|
7f620c758f | ||
|
|
fb50eea526 | ||
|
|
63f757a9da | ||
|
|
4ec02d46b9 | ||
|
|
527afb66df | ||
|
|
5502758a7e | ||
|
|
faa1776407 | ||
|
|
3d7fb8c8dd |
@@ -1,7 +1,7 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
current_version = 5.18
|
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); \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.18" "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.18" "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.18
|
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.18
|
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.18",
|
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",
|
||||||
|
|||||||
@@ -195,7 +195,9 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
|
|
||||||
static void _signal_handler(int signum) {
|
static void _signal_handler(int signum) {
|
||||||
US_LOG_INFO_NOLOCK("===== Stopping by SIG%s =====", us_signum_to_string(signum));
|
char *const name = us_signum_to_string(signum);
|
||||||
|
US_LOG_INFO_NOLOCK("===== Stopping by %s =====", name);
|
||||||
|
free(name);
|
||||||
_g_stop = true;
|
_g_stop = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define US_VERSION_MAJOR 5
|
#define US_VERSION_MAJOR 5
|
||||||
#define US_VERSION_MINOR 18
|
#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)
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ extern pthread_mutex_t us_g_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, ...) { \
|
||||||
@@ -149,9 +149,9 @@ extern pthread_mutex_t us_g_log_mutex;
|
|||||||
|
|
||||||
#define US_LOG_VERBOSE_PERROR(x_msg, ...) { \
|
#define US_LOG_VERBOSE_PERROR(x_msg, ...) { \
|
||||||
if (us_g_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); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,20 +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;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE const char *us_signum_to_string(int signum) {
|
INLINE char *us_signum_to_string(int signum) {
|
||||||
const char *const str = sigabbrev_np(signum);
|
# ifdef HAS_SIGABBREV_NP
|
||||||
return (str == NULL ? "???" : str);
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) { \
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ static void *_server_loop_thread(UNUSED void *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _signal_handler(int signum) {
|
static void _signal_handler(int signum) {
|
||||||
US_LOG_INFO_NOLOCK("===== Stopping by SIG%s =====", us_signum_to_string(signum));
|
char *const name = us_signum_to_string(signum);
|
||||||
|
US_LOG_INFO_NOLOCK("===== Stopping by %s =====", name);
|
||||||
|
free(name);
|
||||||
us_stream_loop_break(_g_stream);
|
us_stream_loop_break(_g_stream);
|
||||||
us_server_loop_break(_g_server);
|
us_server_loop_break(_g_server);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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