Compare commits

..

14 Commits
v0.64 ... v0.68

Author SHA1 Message Date
Devaev Maxim
2077d94edc Bump version: 0.67 → 0.68 2019-04-10 16:47:18 +03:00
Devaev Maxim
defe5eb6fe openwrt package 2019-04-10 16:46:01 +03:00
Devaev Maxim
dee5e18134 better makefile 2019-04-10 02:38:08 +03:00
Devaev Maxim
6ef5a7e440 Bump version: 0.66 → 0.67 2019-03-28 05:52:44 +03:00
Devaev Maxim
462735147d another place for SEP_INFO 2019-03-28 05:52:21 +03:00
Devaev Maxim
51ca0e4474 Bump version: 0.65 → 0.66 2019-03-26 21:45:14 +03:00
Devaev Maxim
4ee3b18533 better tools 2019-03-25 02:36:12 +03:00
Maxim Devaev
cdc9ed54c9 Update README.ru.md 2019-03-23 20:54:52 +03:00
Maxim Devaev
d9e7c07851 Update README.ru.md 2019-03-23 20:52:43 +03:00
Maxim Devaev
f2debc5d16 Update README.ru.md 2019-03-23 20:19:49 +03:00
Maxim Devaev
b3dbaf40cf Update README.md 2019-03-23 20:19:22 +03:00
Devaev Maxim
abfc7b917b Bump version: 0.64 → 0.65 2019-03-23 06:44:36 +03:00
Devaev Maxim
a0e488b0a5 help fix 2019-03-23 06:44:11 +03:00
Devaev Maxim
6b99df2792 minor fix for b101 2019-03-23 06:36:17 +03:00
16 changed files with 209 additions and 51 deletions

View File

@@ -1,7 +1,7 @@
[bumpversion]
commit = True
tag = True
current_version = 0.64
current_version = 0.68
parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)?
serialize =
{major}.{minor}
@@ -14,3 +14,7 @@ replace = VERSION "{new_version}"
search = pkgver={current_version}
replace = pkgver={new_version}
[bumpversion:file:pkg/openwrt/Makefile]
search = PKG_VERSION:={current_version}
replace = PKG_VERSION:={new_version}

View File

@@ -50,7 +50,7 @@ release:
bump:
bumpversion minor
bumpversion $(if $(V), $(V), minor)
push:

View File

@@ -11,7 +11,7 @@
| Multithreaded JPEG encoding | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No |
| [OpenMAX IL](https://www.khronos.org/openmaxil) hardware acceleration<br>on Raspberry Pi | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No |
| Behavior when the device<br>is disconnected while streaming | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Shows a black screen<br>with ```NO SIGNAL``` on it<br>until reconnected | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Stops the broadcast <sup>1</sup> |
| [DV-timings](https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/dv-timings.html) support -<br>the ability to change resolution<br>on the fly by source signal | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#ffaa00](https://placehold.it/15/ffaa00/000000?text=+) Partially yes <sup>2</sup> |
| [DV-timings](https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/dv-timings.html) support -<br>the ability to change resolution<br>on the fly by source signal | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#ffaa00](https://placehold.it/15/ffaa00/000000?text=+) Partially yes <sup>1</sup> |
| Option to skip frames when streaming<br>static images by HTTP to save traffic | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes <sup>2</sup> | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No |
| Streaming via UNIX domain socket | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No |
| Debug logs without recompiling,<br>performance statistics log,<br>access to HTTP broadcast parameters | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No |

View File

@@ -10,8 +10,8 @@
|----------|---------------|-------------------|
| Многопоточное кодирование JPEG | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет |
| Аппаратное кодирование с помощью [OpenMAX IL](https://www.khronos.org/openmaxil) на Raspberry Pi | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет |
| Поведение при физическом отключении устройства<br>от сервера во время работы | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Транслирует черный экран<br>с надписью ```NO SIGNAL```,<br>пока устройство не будет подключено снова | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Прерывает трансляцию <sup>1</sup> |
| Поддержка [DV-таймингов](https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/dv-timings.html) - возможности изменения <br>параметров разрешения трансляции на лету<br>по сигналу источника (устройства видеозахвата) | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#ffaa00](https://placehold.it/15/ffaa00/000000?text=+) Условно есть <sup>2</sup> |
| Поведение при физическом отключении<br>устройства от сервера во время работы | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Транслирует черный экран<br>с надписью ```NO SIGNAL```,<br>пока устройство не будет подключено снова | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Прерывает трансляцию <sup>1</sup> |
| Поддержка [DV-таймингов](https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/dv-timings.html) - возможности<br>изменения параметров разрешения<br>трансляции на лету по сигналу<br>источника (устройства видеозахвата) | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#ffaa00](https://placehold.it/15/ffaa00/000000?text=+) Условно есть <sup>1</sup> |
| Возможность пропуска фреймов при передаче<br>статического изображения по HTTP<br>для экономии трафика | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть <sup>2</sup> | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет |
| Стрим через UNIX domain socket | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет |
| Дебаг-логи без перекомпиляции,<br>логгирование статистики производительности,<br>возможность получения параметров<br>трансляции по HTTP | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет |

View File

@@ -3,7 +3,7 @@
pkgname=ustreamer
pkgver=0.64
pkgver=0.68
pkgrel=1
pkgdesc="Lightweight and fast MJPG-HTTP streamer"
url="https://github.com/pi-kvm/ustreamer"

45
pkg/openwrt/Makefile Normal file
View File

@@ -0,0 +1,45 @@
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=ustreamer
PKG_VERSION:=0.68
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_VERSION:=v$(PKG_VERSION)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_LICENSE:=GPL-3.0
PKG_LICENSE_FILES:=LICENSE
include $(INCLUDE_DIR)/package.mk
define Package/ustreamer
SECTION:=multimedia
CATEGORY:=Multimedia
TITLE:=uStreamer
DEPENDS:=+libpthread +libjpeg +libv4l +libuuid +libevent2 +libevent2-core +libevent2-extra +libevent2-pthreads
URL:=https://github.com/pi-kvm/ustreamer
endef
define Package/ustreamer/description
µStreamer - Lightweight and fast MJPG-HTTP streamer
endef
define Package/ustreamer/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ustreamer $(1)/usr/bin/
$(INSTALL_DIR) $(1)/etc/config
$(CP) ./files/ustreamer.config $(1)/etc/config/ustreamer
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/ustreamer.init $(1)/etc/init.d/ustreamer
endef
$(eval $(call BuildPackage,ustreamer))

View File

@@ -0,0 +1,20 @@
config ustreamer
option enabled '0'
option device '/dev/video0'
option device_timeout '5'
option input '0'
option width '640'
option height '480'
option format 'YUYV'
option quality '80'
option desired_fps '0'
option encoder 'CPU'
option host '::'
option port '8080'
option static ''
option user ''
option password ''

View File

@@ -0,0 +1,55 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2009-2019 OpenWrt.org
START=90
STOP=10
USE_PROCD=1
PROG=/usr/bin/ustreamer
getcfg() {
config_get value ustreamer $1 $2
return "$value"
}
start_instance() {
config_get_bool enabled ustreamer enabled 0
[ "$enabled" -eq 0 ] && return
local options=""
options="$options --device='`getcfg device /dev/video0`'"
options="$options --device-timeout='`getcfg device_timeout 5`'"
options="$options --input='`getcfg input 0`'"
options="$options --width='`getcfg width 640`'"
options="$options --height='`getcfg height 480`'"
options="$options --format='`getcfg format YUYV`'"
options="$options --quality='`getcfg quality 80`'"
options="$options --desired-fps='`getcfg desired_fps 0`'"
options="$options --encoder='`getcfg encoder CPU`'"
options="$options --host='`getcfg host '::'`'"
local port=`getcfg port 8080`
options="$options --port='$port'"
options="$options --static='`getcfg static ''`'"
options="$options --user='`getcfg user ''`'"
options="$options --passwd='`getcfg password ''`'"
config-get-bool opt_slowdown ustreamer slowdown 1
[ "$slowdown" -eq 1 ] && options="$options --slowdown"
procd_open_instance
procd_set_param command "$PROG" $options
procd_add_mdns http tcp "$port" daemon=ustreamer
procd_close_instance
}
start_service() {
config_load ustreamer
config_foreach start_instance ustreamer
}
service_triggers() {
procd_add_reload_trigger ustreamer
}

View File

@@ -22,4 +22,4 @@
#pragma once
#define VERSION "0.64"
#define VERSION "0.68"

View File

@@ -27,6 +27,7 @@
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/mman.h>
@@ -432,7 +433,11 @@ static void _device_open_hw_fps(struct device_t *dev) {
LOG_DEBUG("Calling ioctl(VIDIOC_G_PARM) ...");
if (xioctl(dev->run->fd, VIDIOC_G_PARM, &setfps) < 0) {
LOG_PERROR("Unable to query HW FPS changing");
if (errno == ENOTTY) { // Quiet message for Auvidea B101
LOG_INFO("Quierying HW FPS changing is not supported");
} else {
LOG_PERROR("Unable to query HW FPS changing");
}
return;
}
@@ -454,7 +459,7 @@ static void _device_open_hw_fps(struct device_t *dev) {
}
if (dev->desired_fps != SETFPS_TPF(denominator)) {
LOG_INFO("Using HW FPS (coerced): %u -> %u", dev->desired_fps, SETFPS_TPF(denominator));
LOG_INFO("Using HW FPS: %u -> %u (coerced)", dev->desired_fps, SETFPS_TPF(denominator));
} else {
LOG_INFO("Using HW FPS: %u", dev->desired_fps);
}

View File

@@ -171,7 +171,7 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
printf(" the CPU loading. Don't use this option with analog signal sources\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 connected.\n");
printf(" Useful to reduce CPU cosumption. Default: disabled.\n\n");
printf(" Useful to reduce CPU consumption. Default: disabled.\n\n");
printf(" --fake-width <N> ─────────── Override image width for /state. Default: disabled.\n\n");
printf(" --fake-height <N> ────────── Override image height for /state. Default: disabled.\n\n");
printf(" --server-timeout <seconds> ─ Timeout for client connections. Default: %u.\n\n", server->timeout);

View File

@@ -376,12 +376,12 @@ static int _stream_init_loop(struct stream_t *stream, struct workers_pool_t *poo
}
static int _stream_init(struct stream_t *stream, struct workers_pool_t *pool) {
SEP_INFO('=');
_stream_destroy_workers(stream, pool);
device_switch_capturing(stream->dev, false);
device_close(stream->dev);
SEP_INFO('=');
if (device_open(stream->dev) < 0) {
goto error;
}

53
tools/common.py Normal file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python3
#============================================================================#
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
#============================================================================#
import textwrap
# =====
def get_prepend() -> str:
return textwrap.dedent("""
/*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#pragma once
""").strip() + "\n"

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env -S python3 -B
#============================================================================#
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
@@ -22,12 +22,13 @@
import sys
import os
import textwrap
import common
# =====
def main():
def main() -> None:
assert len(sys.argv) == 4, "%s <file.html> <file.h> <name>" % (sys.argv[0])
html_path = sys.argv[1]
header_path = sys.argv[2]
@@ -36,9 +37,6 @@ def main():
with open(html_path, "r") as html_file:
text = html_file.read()
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "prepend.h")) as prepend_file:
prepend = prepend_file.read()
text = text.strip()
text = text.replace("\"", "\\\"")
text = text.replace("%VERSION%", "\" VERSION \"")
@@ -48,7 +46,7 @@ def main():
for line in text.split("\n")
)
text = "const char HTML_%s_PAGE[] = \" \\\n%s\n\";\n" % (name, text)
text = prepend + "\n#include \"../../config.h\"\n\n\n" + text
text = common.get_prepend() + "\n#include \"../../config.h\"\n\n\n" + text
with open(header_path, "w") as header_file:
header_file.write(text)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env -S python3 -B
#============================================================================#
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
@@ -22,13 +22,17 @@
import sys
import os
import io
import struct
from typing import Tuple
from typing import List
import common
# =====
def _get_jpeg_size(data):
def _get_jpeg_size(data: bytes) -> Tuple[int, int]:
# https://sheep.horse/2013/9/finding_the_dimensions_of_a_jpeg_file_in_python.html
stream = io.BytesIO(data)
@@ -55,7 +59,7 @@ def _get_jpeg_size(data):
# =====
def main():
def main() -> None:
assert len(sys.argv) == 4, "%s <file.jpeg> <file.h> <name>" % (sys.argv[0])
jpeg_path = sys.argv[1]
header_path = sys.argv[2]
@@ -66,10 +70,7 @@ def main():
(width, height) = _get_jpeg_size(jpeg_data)
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "prepend.h")) as prepend_file:
prepend = prepend_file.read()
rows = [[]]
rows: List[List[str]] = [[]]
for ch in jpeg_data:
if len(rows[-1]) > 20:
rows.append([])
@@ -79,7 +80,7 @@ def main():
text = "const unsigned char %s_JPEG_DATA[] = {\n\t%s\n};\n" % (name, text)
text = "const unsigned %s_JPEG_HEIGHT = %d;\n\n" % (name, height) + text
text = "const unsigned %s_JPEG_WIDTH = %d;\n" % (name, width) + text
text = prepend + "\n\n" + text
text = common.get_prepend() + "\n\n" + text
with open(header_path, "w") as header_file:
header_file.write(text)

View File

@@ -1,23 +0,0 @@
/*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#pragma once