diff --git a/multimedia/ustreamer/Makefile b/multimedia/ustreamer/Makefile new file mode 100644 index 0000000000..7ce259b2c7 --- /dev/null +++ b/multimedia/ustreamer/Makefile @@ -0,0 +1,53 @@ +# +# 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:=6.51 +PKG_RELEASE:=1 +PKG_MAINTAINER:=Georgi Valkov + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/pikvm/ustreamer/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=384e90b0b8e9669cf903fad10e361401bfb1b2f808be44498e3855a65d7c0145 + +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILES:=LICENSE + +include $(INCLUDE_DIR)/package.mk + +MAKE_FLAGS += WITH_SETPROCTITLE=0 + +define Package/ustreamer + SECTION:=multimedia + CATEGORY:=Multimedia + TITLE:=Lightweight and fast MJPEG-HTTP streamer + DEPENDS:=+libatomic +libjpeg +libevent2 +libevent2-pthreads + URL:=https://github.com/pikvm/ustreamer +endef + +define Package/ustreamer/description +uStreamer is a lightweight and very quick server to stream MJPEG 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. uStreamer is a part of the PiKVM project designed to stream +VGA and HDMI screencast hardware data with the highest resolution and +FPS possible. +endef + +define Package/ustreamer/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ustreamer $(1)/usr/bin/ustreamer + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ustreamer-dump $(1)/usr/bin/ustreamer-dump + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/ustreamer.config $(1)/etc/config/ustreamer + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/ustreamer.init $(1)/etc/init.d/ustreamer + $(INSTALL_DIR) $(1)/etc/hotplug.d/usb + $(INSTALL_DATA) ./files/ustreamer.hotplug $(1)/etc/hotplug.d/usb/20-ustreamer +endef + +$(eval $(call BuildPackage,ustreamer)) diff --git a/multimedia/ustreamer/files/ustreamer.config b/multimedia/ustreamer/files/ustreamer.config new file mode 100644 index 0000000000..1861499774 --- /dev/null +++ b/multimedia/ustreamer/files/ustreamer.config @@ -0,0 +1,99 @@ + +config ustreamer 'video0' + option enabled '1' + + option device '/dev/video0' + option device_timeout '5' + option input '0' + +# option resolution '1920x1080' +# option resolution '1280x720' +# option resolution '800x600' +# option resolution '864x480' + option resolution '640x480' + option desired_fps '0' + option slowdown '1' + option format 'MJPEG' +# option format 'YUYV' +# option encoder 'CPU' + option encoder 'HW' + option quality '80' + + option host '::' + option port '8080' + option user '' + option pass '' + + # capturing +# option allow_truncated_frames '0' +# option format_swap_rgb '0' +# option persistent '0' +# option dv_timings '0' +# option tv_standard 'PAL' +# option tv_standard 'NTSC' +# option tv_standard 'SECAM' +# option io_method 'MMAP' +# option io_method 'USERPTR' +# option buffers '3' +# option workers '2' +# option m2m_device '/dev/path' +# option min_frame_size '128' +# option device_error_delay '1' + + # HTTP server +# option tcp_nodelay '1' +# option unix_rm '0' +# option static '/www/webcam' +# option unix '/path/to/socket' +# option unix_mode '660' +# option drop_same_frames '0' +# option fake_resolution '640x480' +# option allow_origin '' +# option instance_id '' +# option server_timeout '10' + + # JPEG sink +# option jpeg_sink 'name.jpeg' +# option jpeg_sink_mode '660' +# option jpeg_sink_client_ttl '10' +# option jpeg_sink_timeout '1' +# option jpeg_sink_rm '0' + + # RAW sink +# option raw_sink 'name.raw' +# option raw_sink_mode '660' +# option raw_sink_client_ttl '10' +# option raw_sink_timeout '1' +# option raw_sink_rm '0' + + # H264 sink +# option h264_sink 'name.h264' +# option h264_sink_mode '660' +# option h264_sink_client_ttl '10' +# option h264_sink_timeout '1' +# option h264_sink_rm '0' +# option h264_boost '0' +# option h264_bitrate '5000' +# option h264_gop '30' +# option h264_m2m_device '/dev/path' +# option exit_on_no_clients '0' + + # logging +# option log_level '0' + + # image control +# option image_default '0' +# option brightness '128' +# option contrast '128' +# option saturation '128' +# option gamma '' +# option gain 'auto' +# option hue '' +# option sharpness '128' +# option color_effect '' +# option white_balance 'auto' +# option white_balance '2000-6500' +# option backlight_compensation '0' +# option flip_horizontal '0' +# option flip_vertical '0' +# option rotate '' diff --git a/multimedia/ustreamer/files/ustreamer.hotplug b/multimedia/ustreamer/files/ustreamer.hotplug new file mode 100644 index 0000000000..6091761c12 --- /dev/null +++ b/multimedia/ustreamer/files/ustreamer.hotplug @@ -0,0 +1,10 @@ +case "$ACTION" in + add) + # start process + ls /dev/video* > /dev/null && /etc/init.d/ustreamer start + ;; + remove) + # stop process + ls /dev/video* > /dev/null || /etc/init.d/ustreamer stop + ;; +esac diff --git a/multimedia/ustreamer/files/ustreamer.init b/multimedia/ustreamer/files/ustreamer.init new file mode 100644 index 0000000000..2be2dac1ce --- /dev/null +++ b/multimedia/ustreamer/files/ustreamer.init @@ -0,0 +1,289 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2009-2026 OpenWrt.org + +START=90 +STOP=10 + +USE_PROCD=1 +PROG=/usr/bin/ustreamer + +start_instance() { + local enabled=0 + local device="/dev/video0" + + config_get_bool enabled "$1" 'enabled' "$enabled" + [ "$enabled" -eq 0 ] && return + + config_get device "$1" 'device' "$device" + [ -n "$device" -a -c "$device" ] || return + + # primary + local input="" + local format="YUYV" + local encoder="CPU" + local quality=80 + local resolution="640x480" + local desired_fps=0 + local slowdown=1 + local device_timeout=5 + local host="::" + local port=8080 + local user="" + local pass="" + + # capturing + local allow_truncated_frames=0 + local format_swap_rgb=0 + local persistent=0 + local dv_timings=0 + local tv_standard="" + local io_method="" + local buffers="" + local workers="" + local m2m_device="" + local min_frame_size="" + local device_error_delay="" + + # HTTP server + local tcp_nodelay=0 + local unix_rm=0 + local static="" + local unix="" + local unix_mode="" + local drop_same_frames="" + local fake_resolution="" + local allow_origin="" + local instance_id="" + local server_timeout="" + + # JPEG sink + local jpeg_sink="" + local jpeg_sink_mode="" + local jpeg_sink_client_ttl="" + local jpeg_sink_timeout="" + local jpeg_sink_rm=0 + + # RAW sink + local raw_sink="" + local raw_sink_mode="" + local raw_sink_client_ttl="" + local raw_sink_timeout="" + local raw_sink_rm=0 + + # H264 sink + local h264_sink="" + local h264_sink_mode="" + local h264_sink_client_ttl="" + local h264_sink_timeout="" + local h264_sink_rm=0 + local h264_boost=0 + local h264_bitrate="" + local h264_gop="" + local h264_m2m_device="" + local exit_on_no_clients="" + + # logging + local log_level="" + + # image control + local image_default=0 + local brightness="" + local contrast="" + local saturation="" + local gamma="" + local gain="" + local hue="" + local sharpness="" + local color_effect="" + local white_balance="" + local backlight_compensation="" + local flip_horizontal="" + local flip_vertical="" + local rotate="" + + # primary + config_get input "$1" 'input' "$input" + config_get format "$1" 'format' "$format" + config_get encoder "$1" 'encoder' "$encoder" + config_get quality "$1" 'quality' "$quality" + config_get resolution "$1" 'resolution' "$resolution" + config_get desired_fps "$1" 'desired_fps' "$desired_fps" + config_get_bool slowdown "$1" 'slowdown' "$slowdown" + config_get device_timeout "$1" 'device_timeout' "$device_timeout" + config_get host "$1" 'host' "$host" + config_get port "$1" 'port' "$port" + config_get user "$1" 'user' "$user" + config_get pass "$1" 'pass' "$pass" + + # capturing + config_get_bool allow_truncated_frames "$1" 'allow_truncated_frames' "$allow_truncated_frames" + config_get_bool format_swap_rgb "$1" 'format_swap_rgb' "$format_swap_rgb" + config_get_bool persistent "$1" 'persistent' "$persistent" + config_get_bool dv_timings "$1" 'dv_timings' "$dv_timings" + config_get tv_standard "$1" 'tv_standard' "$tv_standard" + config_get io_method "$1" 'io_method' "$io_method" + config_get buffers "$1" 'buffers' "$buffers" + config_get workers "$1" 'workers' "$workers" + config_get m2m_device "$1" 'm2m_device' "$m2m_device" + config_get min_frame_size "$1" 'min_frame_size' "$min_frame_size" + config_get device_error_delay "$1" 'device_error_delay' "$device_error_delay" + + # HTTP server + config_get_bool tcp_nodelay "$1" 'tcp_nodelay' "$tcp_nodelay" + config_get_bool unix_rm "$1" 'unix_rm' "$unix_rm" + config_get static "$1" 'static' "$static" + config_get unix "$1" 'unix' "$unix" + config_get unix_mode "$1" 'unix_mode' "$unix_mode" + config_get drop_same_frames "$1" 'drop_same_frames' "$drop_same_frames" + config_get fake_resolution "$1" 'fake_resolution' "$fake_resolution" + config_get allow_origin "$1" 'allow_origin' "$allow_origin" + config_get instance_id "$1" 'instance_id' "$instance_id" + config_get server_timeout "$1" 'server_timeout' "$server_timeout" + + # JPEG sink + config_get jpeg_sink "$1" 'jpeg_sink' "$jpeg_sink" + config_get jpeg_sink_mode "$1" 'jpeg_sink_mode' "$jpeg_sink_mode" + config_get jpeg_sink_client_ttl "$1" 'jpeg_sink_client_ttl' "$jpeg_sink_client_ttl" + config_get jpeg_sink_timeout "$1" 'jpeg_sink_timeout' "$jpeg_sink_timeout" + config_get_bool jpeg_sink_rm "$1" 'jpeg_sink_rm' "$jpeg_sink_rm" + + # RAW sink + config_get raw_sink "$1" 'raw_sink' "$raw_sink" + config_get raw_sink_mode "$1" 'raw_sink_mode' "$raw_sink_mode" + config_get raw_sink_client_ttl "$1" 'raw_sink_client_ttl' "$raw_sink_client_ttl" + config_get raw_sink_timeout "$1" 'raw_sink_timeout' "$raw_sink_timeout" + config_get_bool raw_sink_rm "$1" 'raw_sink_rm' "$raw_sink_rm" + + # H264 sink + config_get h264_sink "$1" 'h264_sink' "$h264_sink" + config_get h264_sink_mode "$1" 'h264_sink_mode' "$h264_sink_mode" + config_get h264_sink_client_ttl "$1" 'h264_sink_client_ttl' "$h264_sink_client_ttl" + config_get h264_sink_timeout "$1" 'h264_sink_timeout' "$h264_sink_timeout" + config_get_bool h264_sink_rm "$1" 'h264_sink_rm' "$h264_sink_rm" + config_get_bool h264_boost "$1" 'h264_boost' "$h264_boost" + config_get h264_bitrate "$1" 'h264_bitrate' "$h264_bitrate" + config_get h264_gop "$1" 'h264_gop' "$h264_gop" + config_get h264_m2m_device "$1" 'h264_m2m_device' "$h264_m2m_device" + config_get exit_on_no_clients "$1" 'exit_on_no_clients' "$exit_on_no_clients" + + # logging + config_get log_level "$1" 'log_level' "$log_level" + + # image control + config_get_bool image_default "$1" 'image_default' "$image_default" + config_get brightness "$1" 'brightness' "$brightness" + config_get contrast "$1" 'contrast' "$contrast" + config_get saturation "$1" 'saturation' "$saturation" + config_get gamma "$1" 'gamma' "$gamma" + config_get gain "$1" 'gain' "$gain" + config_get hue "$1" 'hue' "$hue" + config_get sharpness "$1" 'sharpness' "$sharpness" + config_get color_effect "$1" 'color_effect' "$color_effect" + config_get white_balance "$1" 'white_balance' "$white_balance" + config_get backlight_compensation "$1" 'backlight_compensation' "$backlight_compensation" + config_get flip_horizontal "$1" 'flip_horizontal' "$flip_horizontal" + config_get flip_vertical "$1" 'flip_vertical' "$flip_vertical" + config_get rotate "$1" 'rotate' "$rotate" + + # configure service + procd_open_instance + procd_set_param command "$PROG" + + # primary + [ -n "$device" ] && procd_append_param command --device "$device" + [ -n "$input" ] && procd_append_param command --input "$input" + [ -n "$format" ] && procd_append_param command --format "$format" + [ -n "$encoder" ] && procd_append_param command --encoder "$encoder" + [ -n "$quality" ] && procd_append_param command --quality "$quality" + [ -n "$resolution" ] && procd_append_param command --resolution "$resolution" + [ -n "$desired_fps" ] && procd_append_param command --desired-fps "$desired_fps" + [ "$slowdown" -ne "0" ] && procd_append_param command --slowdown + [ -n "$device_timeout" ] && procd_append_param command --device-timeout "$device_timeout" + [ -n "$host" ] && procd_append_param command --host "$host" + [ -n "$port" ] && procd_append_param command --port "$port" + [ -n "$user" ] && procd_append_param command --user "$user" + [ -n "$pass" ] && procd_append_param command --passwd "$pass" + + # capturing + [ "$allow_truncated_frames" -ne "0" ] && procd_append_param command --allow-truncated-frames + [ "$format_swap_rgb" -ne "0" ] && procd_append_param command --format-swap-rgb + [ "$persistent" -ne "0" ] && procd_append_param command --persistent + [ "$dv_timings" -ne "0" ] && procd_append_param command --dv-timings + [ -n "$tv_standard" ] && procd_append_param command --tv-standard "$tv_standard" + [ -n "$io_method" ] && procd_append_param command --io-method "$io_method" + [ -n "$buffers" ] && procd_append_param command --buffers "$buffers" + [ -n "$workers" ] && procd_append_param command --workers "$workers" + [ -n "$m2m_device" ] && procd_append_param command --m2m-device "$m2m_device" + [ -n "$min_frame_size" ] && procd_append_param command --min-frame-size "$min_frame_size" + [ -n "$device_error_delay" ] && procd_append_param command --device-error-delay "$device_error_delay" + + # HTTP server + [ "$tcp_nodelay" -ne "0" ] && procd_append_param command --tcp-nodelay + [ "$unix_rm" -ne "0" ] && procd_append_param command --unix-rm + [ -n "$static" ] && procd_append_param command --static "$static" + [ -n "$unix" ] && procd_append_param command --unix "$unix" + [ -n "$unix_mode" ] && procd_append_param command --unix-mode "$unix_mode" + [ -n "$drop_same_frames" ] && procd_append_param command --drop-same-frames "$drop_same_frames" + [ -n "$fake_resolution" ] && procd_append_param command --fake-resolution "$fake_resolution" + [ -n "$allow_origin" ] && procd_append_param command --allow-origin "$allow_origin" + [ -n "$instance_id" ] && procd_append_param command --instance-id "$instance_id" + [ -n "$server_timeout" ] && procd_append_param command --server-timeout "$server_timeout" + + # JPEG sink + [ -n "$jpeg_sink" ] && procd_append_param command --jpeg-sink "$jpeg_sink" + [ -n "$jpeg_sink_mode" ] && procd_append_param command --jpeg-sink-mode "$jpeg_sink_mode" + [ -n "$jpeg_sink_client_ttl" ] && procd_append_param command --jpeg-sink-client-ttl "$jpeg_sink_client_ttl" + [ -n "$jpeg_sink_timeout" ] && procd_append_param command --jpeg-sink-timeout "$jpeg_sink_timeout" + [ "$jpeg_sink_rm" -ne "0" ] && procd_append_param command --jpeg-sink-rm + + # RAW sink + [ -n "$raw_sink" ] && procd_append_param command --raw-sink "$raw_sink" + [ -n "$raw_sink_mode" ] && procd_append_param command --raw-sink-mode "$raw_sink_mode" + [ -n "$raw_sink_client_ttl" ] && procd_append_param command --raw-sink-client-ttl "$raw_sink_client_ttl" + [ -n "$raw_sink_timeout" ] && procd_append_param command --raw-sink-timeout "$raw_sink_timeout" + [ "$raw_sink_rm" -ne "0" ] && procd_append_param command --raw-sink-rm + + # H264 sink + [ -n "$h264_sink" ] && procd_append_param command --h264-sink "$h264_sink" + [ -n "$h264_sink_mode" ] && procd_append_param command --h264-sink-mode "$h264_sink_mode" + [ -n "$h264_sink_client_ttl" ] && procd_append_param command --h264-sink-client-ttl "$h264_sink_client_ttl" + [ -n "$h264_sink_timeout" ] && procd_append_param command --h264-sink-timeout "$h264_sink_timeout" + [ "$h264_sink_rm" -ne "0" ] && procd_append_param command --h264-sink-rm + [ "$h264_boost" -ne "0" ] && procd_append_param command --h264-boost + [ -n "$h264_bitrate" ] && procd_append_param command --h264-bitrate "$h264_bitrate" + [ -n "$h264_gop" ] && procd_append_param command --h264-gop "$h264_gop" + [ -n "$h264_m2m_device" ] && procd_append_param command --h264-m2m-device "$h264_m2m_device" + [ -n "$exit_on_no_clients" ] && procd_append_param command --exit-on-no-clients "$exit_on_no_clients" + + # logging + [ -n "$log_level" ] && procd_append_param command --log-level "$log_level" + + # image control + [ "$image_default" -ne "0" ] && procd_append_param command --image-default + [ -n "$brightness" ] && procd_append_param command --brightness "$brightness" + [ -n "$contrast" ] && procd_append_param command --contrast "$contrast" + [ -n "$saturation" ] && procd_append_param command --saturation "$saturation" + [ -n "$gamma" ] && procd_append_param command --gamma "$gamma" + [ -n "$gain" ] && procd_append_param command --gain "$gain" + [ -n "$hue" ] && procd_append_param command --hue "$hue" + [ -n "$sharpness" ] && procd_append_param command --sharpness "$sharpness" + [ -n "$color_effect" ] && procd_append_param command --color-effect "$color_effect" + [ -n "$white_balance" ] && procd_append_param command --white-balance "$white_balance" + [ -n "$backlight_compensation" ] && procd_append_param command --backlight-compensation "$backlight_compensation" + [ -n "$flip_horizontal" ] && procd_append_param command --flip-horizontal "$flip_horizontal" + [ -n "$flip_vertical" ] && procd_append_param command --flip-vertical "$flip_vertical" + [ -n "$rotate" ] && procd_append_param command --rotate "$rotate" + + procd_add_mdns http tcp "$port" "daemon=ustreamer" + procd_set_param respawn 3600 5 5 + procd_close_instance +} + +start_service() { + config_load 'ustreamer' + config_foreach start_instance 'ustreamer' +} + +service_triggers() { + procd_add_reload_trigger 'ustreamer' +}