mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-19 16:26:30 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16d5c81c22 | ||
|
|
58e3a77a79 | ||
|
|
16105db7a0 | ||
|
|
6e307b1ef4 | ||
|
|
554491ff19 | ||
|
|
fcd70c3166 | ||
|
|
aaed14e9de |
@@ -1,7 +1,7 @@
|
||||
[bumpversion]
|
||||
commit = True
|
||||
tag = True
|
||||
current_version = 0.80
|
||||
current_version = 1.1
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)?
|
||||
serialize =
|
||||
{major}.{minor}
|
||||
|
||||
10
Makefile
10
Makefile
@@ -24,15 +24,15 @@ endef
|
||||
|
||||
|
||||
ifneq ($(call optbool,$(WITH_OMX)),)
|
||||
LIBS += -lbcm_host -lvcos -lopenmaxil -L$(RPI_VC_LIBS)
|
||||
override CFLAGS += -DWITH_OMX -DOMX_SKIP64BIT -I$(RPI_VC_HEADERS)
|
||||
SOURCES += $(shell ls src/encoders/omx/*.c)
|
||||
LIBS += -lbcm_host -lvcos -lopenmaxil -L$(RPI_VC_LIBS)
|
||||
override CFLAGS += -DWITH_OMX -DOMX_SKIP64BIT -I$(RPI_VC_HEADERS)
|
||||
SOURCES += $(shell ls src/encoders/omx/*.c)
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(call optbool,$(WITH_GPIO)),)
|
||||
LIBS += -lwiringPi
|
||||
override CFLAGS += -DWITH_GPIO
|
||||
LIBS += -lwiringPi
|
||||
override CFLAGS += -DWITH_GPIO
|
||||
endif
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[[Русская версия]](README.ru.md)
|
||||
|
||||
µStreamer is a lightweight and very quick server to broadcast [MJPG](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/pi-kvm) 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 [Pi-KVM](https://github.com/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:
|
||||
|
||||
@@ -35,7 +35,7 @@ You'll need ```make```, ```gcc```, ```libevent``` with ```pthreads``` support,
|
||||
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```.
|
||||
|
||||
```
|
||||
$ git clone --depth=1 https://github.com/pi-kvm/ustreamer
|
||||
$ git clone --depth=1 https://github.com/pikvm/ustreamer
|
||||
$ cd ustreamer
|
||||
$ make
|
||||
$ ./ustreamer --help
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[[English version]](README.md)
|
||||
|
||||
|
||||
µStreamer - это маленький и очень быстрый сервер, который позволяет организовать трансляцию видео в формате [MJPG](https://en.wikipedia.org/wiki/Motion_JPEG) с любого устройства V4L2 в сеть. Этот формат нативно поддерживается всеми современными браузерами и большинством приложений для просмотра видео (mplayer, VLC и так далее). µStreamer был разработан в рамках проекта [Pi-KVM](https://github.com/pi-kvm) специально для стриминга с устройств видеозахвата [VGA](https://www.amazon.com/dp/B0126O0RDC) и [HDMI](https://auvidea.com/b101-hdmi-to-csi-2-bridge-15-pin-fpc/) с максимально возможным разрешением и FPS, которые только позволяет железо.
|
||||
µStreamer - это маленький и очень быстрый сервер, который позволяет организовать трансляцию видео в формате [MJPG](https://en.wikipedia.org/wiki/Motion_JPEG) с любого устройства V4L2 в сеть. Этот формат нативно поддерживается всеми современными браузерами и большинством приложений для просмотра видео (mplayer, VLC и так далее). µStreamer был разработан в рамках проекта [Pi-KVM](https://github.com/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```, однако имеет ряд серьезных отличий. Основные приведены в этой таблице:
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
На Raspberry Pi программу можно собрать с поддержкой OpenMAX IL. Для этого передайте ```make``` параметр ```WITH_OMX=1```. Для включения сборки с поддержкой GPIO установите [wiringPi](http://wiringpi.com) и добавьте параметр ```WITH_GPIO=1```.
|
||||
|
||||
```
|
||||
$ git clone --depth=1 https://github.com/pi-kvm/ustreamer
|
||||
$ git clone --depth=1 https://github.com/pikvm/ustreamer
|
||||
$ cd ustreamer
|
||||
$ make
|
||||
$ ./ustreamer --help
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
|
||||
|
||||
pkgname=ustreamer
|
||||
pkgver=0.80
|
||||
pkgver=1.1
|
||||
pkgrel=1
|
||||
pkgdesc="Lightweight and fast MJPG-HTTP streamer"
|
||||
url="https://github.com/pi-kvm/ustreamer"
|
||||
url="https://github.com/pikvm/ustreamer"
|
||||
license=(GPL)
|
||||
arch=(i686 x86_64 armv6h armv7h)
|
||||
depends=(libjpeg libevent libutil-linux)
|
||||
# optional: raspberrypi-firmware for OMX JPEG encoder
|
||||
# optional: raspberrypi-firmware for OMX encoder
|
||||
# optional: wiringpi for GPIO support
|
||||
makedepends=(gcc make)
|
||||
source=(${pkgname}::"git+https://github.com/pi-kvm/ustreamer#commit=v${pkgver}")
|
||||
source=(${pkgname}::"git+https://github.com/pikvm/ustreamer#commit=v${pkgver}")
|
||||
md5sums=(SKIP)
|
||||
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ EAPI=7
|
||||
inherit git-r3
|
||||
|
||||
DESCRIPTION="uStreamer - Lightweight and fast MJPG-HTTP streamer"
|
||||
HOMEPAGE="https://github.com/pi-kvm/ustreamer"
|
||||
EGIT_REPO_URI="https://github.com/pi-kvm/ustreamer.git"
|
||||
HOMEPAGE="https://github.com/pikvm/ustreamer"
|
||||
EGIT_REPO_URI="https://github.com/pikvm/ustreamer.git"
|
||||
|
||||
LICENSE="GPL-3"
|
||||
SLOT="0"
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ustreamer
|
||||
PKG_VERSION:=0.80
|
||||
PKG_VERSION:=1.1
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/pi-kvm/ustreamer.git
|
||||
PKG_SOURCE_URL:=https://github.com/pikvm/ustreamer.git
|
||||
PKG_SOURCE_VERSION:=v$(PKG_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
@@ -26,7 +26,7 @@ define Package/ustreamer
|
||||
CATEGORY:=Multimedia
|
||||
TITLE:=uStreamer
|
||||
DEPENDS:=+libpthread +libjpeg +libv4l +libuuid +libevent2 +libevent2-core +libevent2-extra +libevent2-pthreads
|
||||
URL:=https://github.com/pi-kvm/ustreamer
|
||||
URL:=https://github.com/pikvm/ustreamer
|
||||
endef
|
||||
|
||||
define Package/ustreamer/description
|
||||
|
||||
@@ -23,5 +23,5 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef VERSION
|
||||
# define VERSION "0.80"
|
||||
# define VERSION "1.1"
|
||||
#endif
|
||||
|
||||
10
src/device.h
10
src/device.h
@@ -28,11 +28,13 @@
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
|
||||
#define VIDEO_MIN_WIDTH 320
|
||||
#define VIDEO_MAX_WIDTH 1920
|
||||
#define VIDEO_MIN_WIDTH 160
|
||||
#define VIDEO_MAX_WIDTH 10240
|
||||
|
||||
#define VIDEO_MIN_HEIGHT 180
|
||||
#define VIDEO_MAX_HEIGHT 1200
|
||||
#define VIDEO_MIN_HEIGHT 120
|
||||
#define VIDEO_MAX_HEIGHT 4320
|
||||
|
||||
#define VIDEO_MAX_FPS 120
|
||||
|
||||
#define STANDARD_UNKNOWN V4L2_STD_UNKNOWN
|
||||
#define STANDARDS_STR "PAL, NTSC, SECAM"
|
||||
|
||||
@@ -108,13 +108,13 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) {
|
||||
bool cpu_forced = false;
|
||||
|
||||
if ((dev->run->format == V4L2_PIX_FMT_MJPEG || dev->run->format == V4L2_PIX_FMT_JPEG) && type != ENCODER_TYPE_HW) {
|
||||
LOG_INFO("Switching to HW JPEG encoder because the input format is (M)JPEG");
|
||||
LOG_INFO("Switching to HW encoder because the input format is (M)JPEG");
|
||||
type = ENCODER_TYPE_HW;
|
||||
}
|
||||
|
||||
if (type == ENCODER_TYPE_HW) {
|
||||
if (dev->run->format != V4L2_PIX_FMT_MJPEG && dev->run->format != V4L2_PIX_FMT_JPEG) {
|
||||
LOG_INFO("Switching to CPU JPEG encoder because the input format is not (M)JPEG");
|
||||
LOG_INFO("Switching to CPU encoder because the input format is not (M)JPEG");
|
||||
goto use_cpu;
|
||||
}
|
||||
|
||||
@@ -131,16 +131,16 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) {
|
||||
encoder->glitched_resolutions[index][0] == dev->run->width
|
||||
&& encoder->glitched_resolutions[index][1] == dev->run->height
|
||||
) {
|
||||
LOG_INFO("Switching to CPU JPEG encoder the resolution %ux%u marked as glitchy for OMX",
|
||||
LOG_INFO("Switching to CPU encoder the resolution %ux%u marked as glitchy for OMX",
|
||||
dev->run->width, dev->run->height);
|
||||
goto use_cpu;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("Preparing OMX JPEG encoder ...");
|
||||
LOG_DEBUG("Preparing OMX encoder ...");
|
||||
|
||||
if (dev->run->n_workers > OMX_MAX_ENCODERS) {
|
||||
LOG_INFO("OMX JPEG encoder sets limit for worker threads: %u", OMX_MAX_ENCODERS);
|
||||
LOG_INFO("OMX encoder sets limit for worker threads: %u", OMX_MAX_ENCODERS);
|
||||
dev->run->n_workers = OMX_MAX_ENCODERS;
|
||||
}
|
||||
|
||||
@@ -151,14 +151,14 @@ void encoder_prepare(struct encoder_t *encoder, struct device_t *dev) {
|
||||
// Начинаем с нуля и доинициализируем на следующих заходах при необходимости
|
||||
for (; encoder->run->n_omxs < dev->run->n_workers; ++encoder->run->n_omxs) {
|
||||
if ((encoder->run->omxs[encoder->run->n_omxs] = omx_encoder_init()) == NULL) {
|
||||
LOG_ERROR("Can't initialize OMX JPEG encoder, falling back to CPU");
|
||||
LOG_ERROR("Can't initialize OMX encoder, falling back to CPU");
|
||||
goto force_cpu;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned index = 0; index < encoder->run->n_omxs; ++index) {
|
||||
if (omx_encoder_prepare(encoder->run->omxs[index], dev, quality) < 0) {
|
||||
LOG_ERROR("Can't prepare OMX JPEG encoder, falling back to CPU");
|
||||
LOG_ERROR("Can't prepare OMX encoder, falling back to CPU");
|
||||
goto force_cpu;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ void cpu_encoder_compress_buffer(struct device_t *dev, unsigned index, unsigned
|
||||
WRITE_SCANLINES(V4L2_PIX_FMT_UYVY, _jpeg_write_scanlines_uyvy);
|
||||
WRITE_SCANLINES(V4L2_PIX_FMT_RGB565, _jpeg_write_scanlines_rgb565);
|
||||
WRITE_SCANLINES(V4L2_PIX_FMT_RGB24, _jpeg_write_scanlines_rgb24);
|
||||
default: assert(0 && "Unsupported input format for CPU JPEG encoder");
|
||||
default: assert(0 && "Unsupported input format for CPU encoder");
|
||||
}
|
||||
|
||||
# undef WRITE_SCANLINES
|
||||
|
||||
@@ -51,12 +51,12 @@ int hw_encoder_prepare(struct device_t *dev, unsigned quality) {
|
||||
MEMSET_ZERO(comp);
|
||||
|
||||
if (xioctl(dev->run->fd, VIDIOC_G_JPEGCOMP, &comp) < 0) {
|
||||
LOG_ERROR("Can't query HW JPEG encoder params and set quality (unsupported)");
|
||||
LOG_ERROR("Can't query HW encoder params and set quality (unsupported)");
|
||||
return -1;
|
||||
}
|
||||
comp.quality = quality;
|
||||
if (xioctl(dev->run->fd, VIDIOC_S_JPEGCOMP, &comp) < 0) {
|
||||
LOG_ERROR("Can't set HW JPEG encoder quality (unsopported)");
|
||||
LOG_ERROR("Can't set HW encoder quality (unsupported)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -64,7 +64,7 @@ int hw_encoder_prepare(struct device_t *dev, unsigned quality) {
|
||||
|
||||
void hw_encoder_compress_buffer(struct device_t *dev, unsigned index) {
|
||||
if (dev->run->format != V4L2_PIX_FMT_MJPEG && dev->run->format != V4L2_PIX_FMT_JPEG) {
|
||||
assert(0 && "Unsupported input format for HW JPEG encoder");
|
||||
assert(0 && "Unsupported input format for HW encoder");
|
||||
}
|
||||
|
||||
# define PICTURE(_next) dev->run->pictures[index]._next
|
||||
|
||||
@@ -99,7 +99,7 @@ struct omx_encoder_t *omx_encoder_init(void) {
|
||||
}
|
||||
_i_omx += 1;
|
||||
|
||||
LOG_INFO("Initializing OMX JPEG encoder ...");
|
||||
LOG_INFO("Initializing OMX encoder ...");
|
||||
|
||||
if (vcos_semaphore_create(&omx->handler_lock, "handler_lock", 0) != VCOS_SUCCESS) {
|
||||
LOG_ERROR("Can't create VCOS semaphore");
|
||||
@@ -125,7 +125,7 @@ struct omx_encoder_t *omx_encoder_init(void) {
|
||||
void omx_encoder_destroy(struct omx_encoder_t *omx) {
|
||||
OMX_ERRORTYPE error;
|
||||
|
||||
LOG_INFO("Destroying OMX JPEG encoder ...");
|
||||
LOG_INFO("Destroying OMX encoder ...");
|
||||
|
||||
component_set_state(&omx->encoder, OMX_StateIdle);
|
||||
_omx_encoder_clear_ports(omx);
|
||||
@@ -329,7 +329,7 @@ static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev) {
|
||||
// FIXME: RGB24 не работает нормально, нижняя половина экрана зеленая.
|
||||
// FIXME: Китайский EasyCap тоже не работает, мусор на экране.
|
||||
// Вероятно обе проблемы вызваны некорректной реализацией OMX на пае.
|
||||
default: assert(0 && "Unsupported input format for OMX JPEG encoder");
|
||||
default: assert(0 && "Unsupported input format for OMX encoder");
|
||||
}
|
||||
|
||||
# undef MAP_FORMAT
|
||||
|
||||
@@ -54,6 +54,6 @@
|
||||
</ul>
|
||||
<br>
|
||||
<hr>
|
||||
<a href="https://github.com/pi-kvm/ustreamer">Sources & docs</a>
|
||||
<a href="https://github.com/pikvm/ustreamer">Sources & docs</a>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -82,7 +82,7 @@ const char HTML_INDEX_PAGE[] = " \
|
||||
</ul> \
|
||||
<br> \
|
||||
<hr> \
|
||||
<a href=\"https://github.com/pi-kvm/ustreamer\">Sources & docs</a> \
|
||||
<a href=\"https://github.com/pikvm/ustreamer\">Sources & docs</a> \
|
||||
</body> \
|
||||
</html> \
|
||||
";
|
||||
|
||||
@@ -381,7 +381,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
case 'm': OPT_PARSE("pixel format", dev->format, device_parse_format, FORMAT_UNKNOWN);
|
||||
# pragma GCC diagnostic pop
|
||||
case 'a': OPT_PARSE("TV standard", dev->standard, device_parse_standard, STANDARD_UNKNOWN);
|
||||
case 'f': OPT_NUMBER("--desired-fps", dev->desired_fps, 0, 30, 0);
|
||||
case 'f': OPT_NUMBER("--desired-fps", dev->desired_fps, 0, VIDEO_MAX_FPS, 0);
|
||||
case 'z': OPT_NUMBER("--min-frame-size", dev->min_frame_size, 0, 8192, 0);
|
||||
case 'n': OPT_SET(dev->persistent, true);
|
||||
case 't': OPT_SET(dev->dv_timings, true);
|
||||
@@ -418,7 +418,7 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
case 3001: OPT_SET(server->passwd, optarg);
|
||||
case 3002: OPT_SET(server->static_path, optarg);
|
||||
case 'k': OPT_SET(server->blank_path, optarg);
|
||||
case 'e': OPT_NUMBER("--drop-same-frames", server->drop_same_frames, 0, 30, 0);
|
||||
case 'e': OPT_NUMBER("--drop-same-frames", server->drop_same_frames, 0, VIDEO_MAX_FPS, 0);
|
||||
case 'l': OPT_SET(server->slowdown, true);
|
||||
case 'R': OPT_RESOLUTION("--fake-resolution", server->fake_width, server->fake_height, false);
|
||||
case 3003: OPT_RESOLUTION_OBSOLETE("--fake-width", "--fake-resolution", server->fake_width, 0, UINT_MAX);
|
||||
|
||||
Reference in New Issue
Block a user