From 6df388f42bd960deefb4c6a557b1cb9b11972413 Mon Sep 17 00:00:00 2001 From: th33xitus Date: Fri, 29 Jul 2022 19:46:39 +0200 Subject: [PATCH] refactor: install webcamd from self provided resources with the upcoming release of a new MainsailOS image, mjpg-streamer is replaced by crowsnest. it is therefore not possible anymore to pull the files from the mainsailOS repository. hence adding them to the KIAUH repository. Signed-off-by: Dominik Willner --- resources/mjpg-streamer/webcam.txt | 79 +++++ resources/mjpg-streamer/webcamd | 303 ++++++++++++++++++ resources/{ => mjpg-streamer}/webcamd.service | 0 scripts/mjpg-streamer.sh | 10 +- 4 files changed, 387 insertions(+), 5 deletions(-) create mode 100644 resources/mjpg-streamer/webcam.txt create mode 100644 resources/mjpg-streamer/webcamd rename resources/{ => mjpg-streamer}/webcamd.service (100%) diff --git a/resources/mjpg-streamer/webcam.txt b/resources/mjpg-streamer/webcam.txt new file mode 100644 index 0000000..e8bd44c --- /dev/null +++ b/resources/mjpg-streamer/webcam.txt @@ -0,0 +1,79 @@ +### Windows users: To edit this file use Notepad++, VSCode, Atom or SublimeText. +### Do not use Notepad or WordPad. + +### MacOSX users: If you use Textedit to edit this file make sure to use +### "plain text format" and "disable smart quotes" in "Textedit > Preferences" + +### Configure which camera to use +# +# Available options are: +# - auto: tries first usb webcam, if that's not available tries raspi cam +# - usb: only tries usb webcam +# - raspi: only tries raspi cam +# +# Defaults to auto +# +#camera="auto" + +### Additional options to supply to MJPG Streamer for the USB camera +# +# See https://faq.octoprint.org/mjpg-streamer-config for available options +# +# Defaults to a resolution of 640x480 px and a framerate of 10 fps +# +#camera_usb_options="-r 640x480 -f 10" + +### Additional webcam devices known to cause problems with -f +# +# Apparently there a some devices out there that with the current +# mjpg_streamer release do not support the -f parameter (for specifying +# the capturing framerate) and will just refuse to output an image if it +# is supplied. +# +# The webcam daemon will detect those devices by their USB Vendor and Product +# ID and remove the -f parameter from the options provided to mjpg_streamer. +# +# By default, this is done for the following devices: +# Logitech C170 (046d:082b) +# GEMBIRD (1908:2310) +# Genius F100 (0458:708c) +# Cubeternet GL-UPC822 UVC WebCam (1e4e:0102) +# +# Using the following option it is possible to add additional devices. If +# your webcam happens to show above symptoms, try determining your cam's +# vendor and product id via lsusb, activating the line below by removing # and +# adding it, e.g. for two broken cameras "aabb:ccdd" and "aabb:eeff" +# +# additional_brokenfps_usb_devices=("aabb:ccdd" "aabb:eeff") +# +# +#additional_brokenfps_usb_devices=() + +### Additional options to supply to MJPG Streamer for the RasPi Cam +# +# See https://faq.octoprint.org/mjpg-streamer-config for available options +# +# Defaults to 10fps +# +#camera_raspi_options="-fps 10" + +### Configuration of camera HTTP output +# +# Usually you should NOT need to change this at all! Only touch if you +# know what you are doing and what the parameters mean. +# +# Below settings are used in the mjpg-streamer call like this: +# +# -o "output_http.so -w $camera_http_webroot $camera_http_options" +# +# Current working directory is the mjpg-streamer base directory. +# +#camera_http_webroot="./www-mainsail" +#camera_http_options="-n" + +### EXPERIMENTAL +# Support for different streamer types. +# +# Available options: +# mjpeg [default] - stable MJPG-streamer +#camera_streamer=mjpeg diff --git a/resources/mjpg-streamer/webcamd b/resources/mjpg-streamer/webcamd new file mode 100644 index 0000000..7d3dbed --- /dev/null +++ b/resources/mjpg-streamer/webcamd @@ -0,0 +1,303 @@ +#!/bin/bash + +######################################################################## +### DO NOT EDIT THIS FILE TO CHANGE THE CONFIG!!! ### +### ---------------------------------------------------------------- ### +### There is no need to edit this file for changing resolution, ### +### frame rates or any other mjpg-streamer parameters. Please edit ### +### /home/pi/klipper_config/webcam.txt instead - that's what it's ### +### there for! You can even do this with your Pi powered down by ### +### directly accessing the file when using the SD card as thumb ### +### drive in your regular computer. ### +######################################################################## + +MJPGSTREAMER_HOME=/home/pi/mjpg-streamer +MJPGSTREAMER_INPUT_USB="input_uvc.so" +MJPGSTREAMER_INPUT_RASPICAM="input_raspicam.so" + +brokenfps_usb_devices=("046d:082b" "1908:2310" "0458:708c" "1e4e:0102" "0471:0311" "038f:6001" "046d:0804" "046d:0825" "046d:0994" "0ac8:3450") + +config_dir="/home/pi/klipper_config" + +echo "Starting up webcamDaemon..." +echo "" + +cfg_files=() +#cfg_files+=/boot/mainsail.txt +if [[ -d ${config_dir} ]]; then + cfg_files+=( `ls ${config_dir}/webcam*.txt` ) +fi + +array_camera_config=() +array_camera=() +array_camera_usb_options=() +array_camera_usb_device=() +array_camera_raspi_options=() +array_camera_http_webroot=() +array_camera_http_options=() +array_additional_brokenfps_usb_devices=() +array_camera_device=() +array_assigned_device=() + +echo "--- Configuration: ----------------------------" +for cfg_file in ${cfg_files[@]}; do + # init configuration - DO NOT EDIT, USE /home/pi/klipper_config/webcam*.txt INSTEAD! + camera="auto" + camera_usb_options="-r 640x480 -f 10" + camera_raspi_options="-fps 10" + camera_http_webroot="./www-mjpgstreamer" + camera_http_options="-n" + additional_brokenfps_usb_devices=() + + if [[ -e ${cfg_file} ]]; then + source "$cfg_file" + fi + usb_options="$camera_usb_options" + + # if webcam device is explicitly given in /home/pi/klipper_config/webcam*.txt, save the path of the device + # to a variable and remove its parameter from usb_options + extracted_device=`echo $usb_options | sed 's@.*-d \(/dev/\(video[0-9]\+\|v4l/[^ ]*\)\).*@\1@'` + if [ "$extracted_device" != "$usb_options" ] + then + # the camera options refer to a device, save it in a variable + # replace video device parameter with empty string and strip extra whitespace + usb_options=`echo $usb_options | sed 's/\-d \/dev\/\(video[0-9]\+\|v4l\/[^ ]*\)//g' | awk '$1=$1'` + else + extracted_device="" + fi + + # echo configuration + echo "cfg_file: $cfg_file" + echo "camera: $camera" + echo "usb options: $camera_usb_options" + echo "raspi options: $camera_raspi_options" + echo "http options: -w $camera_http_webroot $camera_http_options" + echo "" + echo "Explicitly USB device: $extracted_device" + echo "-----------------------------------------------" + echo "" + + array_camera_config+=( $cfg_file ) + array_camera+=( $camera ) + array_camera_usb_options+=("$usb_options") + array_camera_usb_device+=("$extracted_device") + array_camera_raspi_options+=("$camera_raspi_options") + array_camera_http_webroot+=("$camera_http_webroot") + array_camera_http_options+=("$camera_http_options") + array_camera_brokenfps_usb_devices+=("${brokenfps_usb_devices[*]} ${additional_brokenfps_usb_devices[*]}") + array_camera_device+=("") +done + +# check if array contains a string +function containsString() { + local e match="$1" + shift + for e; do [[ "$e" == "$match" ]] && return 0; done + return 1 +} + +# cleans up when the script receives a SIGINT or SIGTERM +function cleanup() { + # make sure that all child processed die when we die + local pids=$(jobs -pr) + [ -n "$pids" ] && kill $pids + exit 0 +} + +# says goodbye when the script shuts down +function goodbye() { + # say goodbye + echo "" + echo "Goodbye..." + echo "" +} + +# runs MJPG Streamer, using the provided input plugin + configuration +function runMjpgStreamer { + input=$1 + + # There are problems with 0x000137ab firmware on VL805 (Raspberry Pi 4}). + # Try to autodetect offending firmware and temporarily fix the issue + # by changing power management mode + echo "Checking for VL805 (Raspberry Pi 4)..." + if [[ -f /usr/bin/vl805 ]]; then + VL805_VERSION=$(/usr/bin/vl805) + VL805_VERSION=${VL805_VERSION#*: } + echo " - version 0x${VL805_VERSION} detected" + case "$VL805_VERSION" in + 00013701) + echo " - nothing to be done. It shouldn't cause USB problems." + ;; + 000137ab) + echo -e " - \e[31mThis version is known to cause problems with USB cameras.\e[39m" + echo -e " You may want to downgrade to 0x0013701." + echo -e " - [FIXING] Trying the setpci -s 01:00.0 0xD4.B=0x41 hack to mitigate the" + echo -e " issue. It disables ASPM L1 on the VL805. Your board may (or may not) get" + echo -e " slightly hotter. For details see:" + echo -e " https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=244421" + setpci -s 01:00.0 0xD4.B=0x41 + ;; + *) + echo " - unknown firmware version. Doing nothing." + ;; + esac + else + echo " - It seems that you don't have VL805 (Raspberry Pi 4)." + echo " There should be no problems with USB (a.k.a. select() timeout)" + fi + + pushd $MJPGSTREAMER_HOME > /dev/null 2>&1 + echo Running ./mjpg_streamer -o "output_http.so -w $camera_http_webroot $camera_http_options" -i "$input" + LD_LIBRARY_PATH=. ./mjpg_streamer -o "output_http.so -w $camera_http_webroot $camera_http_options" -i "$input" & + sleep 1 & + sleep_pid=$! + wait ${sleep_pid} + popd > /dev/null 2>&1 +} + +# starts up the RasPiCam +function startRaspi { + logger -s "Starting Raspberry Pi camera" + runMjpgStreamer "$MJPGSTREAMER_INPUT_RASPICAM $camera_raspi_options" +} + +# starts up the USB webcam +function startUsb { + options="$usb_options" + device="video0" + + # check for parameter and set the device if it is given as a parameter + input=$1 + if [[ -n $input ]]; then + device=`basename "$input"` + fi + + # add video device into options + options="$options -d /dev/$device" + + uevent_file="/sys/class/video4linux/$device/device/uevent" + if [ -e $uevent_file ]; then + # let's see what kind of webcam we have here, fetch vid and pid... + product=`cat $uevent_file | grep PRODUCT | cut -d"=" -f2` + vid=`echo $product | cut -d"/" -f1` + pid=`echo $product | cut -d"/" -f2` + vidpid=`printf "%04x:%04x" "0x$vid" "0x$pid"` + + # ... then look if it is in our list of known broken-fps-devices and if so remove + # the -f parameter from the options (if it's in there, else that's just a no-op) + for identifier in ${brokenfps_usb_devices[@]}; + do + if [ "$vidpid" = "$identifier" ]; then + echo + echo "Camera model $vidpid is known to not work with -f parameter, stripping it out" + echo + options=`echo $options | sed -e "s/\(\s\+\|^\)-f\s\+[0-9]\+//g"` + fi + done + fi + + logger -s "Starting USB webcam" + runMjpgStreamer "$MJPGSTREAMER_INPUT_USB $options" +} + +# make sure our cleanup function gets called when we receive SIGINT, SIGTERM +trap "cleanup" SIGINT SIGTERM +# say goodbye when we EXIT +trap "goodbye" EXIT + +# we need this to prevent the later calls to vcgencmd from blocking +# I have no idea why, but that's how it is... +vcgencmd version > /dev/null 2>&1 + +# keep mjpg streamer running if some camera is attached +while true; do + + # get list of usb video devices into an array + video_devices=($(find /dev -regextype sed -regex '\/dev/video[0-9]\+' | sort -nk1.11 2> /dev/null)) + + # add list of raspi camera into an array + if [ "`vcgencmd get_camera`" = "supported=1 detected=1" ]; then + video_devices+=( "raspi" ) + fi + + echo "Found video devices:" + printf '%s\n' "${video_devices[@]}" + + for scan_mode in "usb" "usb-auto" "raspi" "auto"; do + camera=$scan_mode + if [[ "usb-auto" == "$scan_mode" ]]; then + camera="usb" + fi + for ((i=0;i<${#array_camera[@]};i++)); do + if [[ -z ${array_camera_device[${i}]} ]] && [[ $camera == ${array_camera[${i}]} ]]; then + camera_config="${array_camera_config[${i}]}" + usb_options="${array_camera_usb_options[${i}]}" + camera_usb_device="${array_camera_usb_device[${i}]}" + camera_raspi_options="${array_camera_raspi_options[${i}]}" + camera_http_webroot="${array_camera_http_webroot[${i}]}" + camera_http_options="${array_camera_http_options[${i}]}" + brokenfps_usb_devices="${array_camera_brokenfps_usb_devices[${i}]}" + if [[ ${camera_usb_device} ]] && { [[ "usb" == ${scan_mode} ]] || [[ "auto" == ${scan_mode} ]]; }; then + # usb device is explicitly set in options + usb_device_path=`readlink -f ${camera_usb_device}` + if containsString "$usb_device_path" "${array_camera_device[@]}"; then + if [[ "auto" != ${scan_mode} ]]; then + array_camera_device[${i}]="alredy_in_use" + echo "config file='$camera_config':Video device already in use." + continue + fi + elif containsString "$usb_device_path" "${video_devices[@]}"; then + array_camera_device[${i}]="$usb_device_path" + # explicitly set usb device was found in video_devices array, start usb with the found device + echo "config file='$camera_config':USB device was set in options and found in devices, start MJPG-streamer with the configured USB video device: $usb_device_path" + startUsb "$usb_device_path" + continue + fi + elif [[ -z ${camera_usb_device} ]] && { [[ "usb-auto" == ${scan_mode} ]] || [[ "auto" == ${scan_mode} ]]; }; then + for video_device in "${video_devices[@]}"; do + if [[ "raspi" != "$video_device" ]]; then + if containsString "$video_device" "${array_camera_device[@]}"; then + : #already in use + else + array_camera_device[${i}]="$video_device" + # device is not set explicitly in options, start usb with first found usb camera as the device + echo "config file='$camera_config':USB device was not set in options, start MJPG-streamer with the first found video device: ${video_device}" + startUsb "${video_device}" + break + fi + fi + done + if [[ -n ${array_camera_device[${i}]} ]]; then + continue + fi + fi + if [[ "raspi" == ${scan_mode} ]] || [[ "auto" == ${scan_mode} ]]; then + video_device="raspi" + if containsString "$video_device" "${array_camera_device[@]}"; then + if [[ "auto" != ${scan_mode} ]]; then + array_camera_device[${i}]="alredy_in_use" + echo "config file='$camera_config':RasPiCam device already in use." + fi + elif containsString "$video_device" "${video_devices[@]}"; then + array_camera_device[${i}]="$video_device" + echo "config file='$camera_config':Start MJPG-streamer with video device: ${video_device}" + startRaspi + sleep 30 & + sleep_pid=$! + wait ${sleep_pid} + fi + fi + fi + done + done + array_assigned_device=( ${array_camera_device[*]} ) + if [[ ${#array_camera[@]} -eq ${#array_assigned_device[@]} ]]; then + echo "Done bring up all configured video device" + exit 0 + else + echo "Scan again in two minutes" + sleep 120 & + sleep_pid=$! + wait ${sleep_pid} + fi +done diff --git a/resources/webcamd.service b/resources/mjpg-streamer/webcamd.service similarity index 100% rename from resources/webcamd.service rename to resources/mjpg-streamer/webcamd.service diff --git a/scripts/mjpg-streamer.sh b/scripts/mjpg-streamer.sh index ec84fbc..5317d0b 100644 --- a/scripts/mjpg-streamer.sh +++ b/scripts/mjpg-streamer.sh @@ -16,10 +16,10 @@ set -e #=================================================# function install_mjpg-streamer() { - local webcamd="https://raw.githubusercontent.com/mainsail-crew/MainsailOS/master/src/modules/mjpgstreamer/filesystem/root/usr/local/bin/webcamd" - local webcam_txt="https://raw.githubusercontent.com/mainsail-crew/MainsailOS/master/src/modules/mjpgstreamer/filesystem/home/pi/klipper_config/webcam.txt" + local webcamd="${KIAUH_SRCDIR}/resources/mjpg-streamer/webcamd" + local webcam_txt="${KIAUH_SRCDIR}/resources/mjpg-streamer/webcam.txt" + local service="${KIAUH_SRCDIR}/resources/mjpg-streamer/webcamd.service" local repo="https://github.com/jacksonliam/mjpg-streamer.git" - local service="${KIAUH_SRCDIR}/resources/webcamd.service" ### return early if webcamd.service already exists if [[ -f "${SYSTEMD}/webcamd.service" ]]; then @@ -77,7 +77,7 @@ function install_mjpg-streamer() { EOT - sudo wget "${webcamd}" -O "/usr/local/bin/webcamd" + sudo cp "${webcamd}" "/usr/local/bin/webcamd" sudo sed -i "/^config_dir=/ s|=.*|=${KLIPPER_CONFIG}|" /usr/local/bin/webcamd sudo sed -i "/MJPGSTREAMER_HOME/ s/pi/${USER}/" /usr/local/bin/webcamd sudo chmod +x /usr/local/bin/webcamd @@ -86,7 +86,7 @@ EOT [[ ! -d ${KLIPPER_CONFIG} ]] && mkdir -p "${KLIPPER_CONFIG}" if [[ ! -f "${KLIPPER_CONFIG}/webcam.txt" ]]; then status_msg "Creating webcam.txt config file ..." - wget "${webcam_txt}" -O "${KLIPPER_CONFIG}/webcam.txt" + cp "${webcam_txt}" "${KLIPPER_CONFIG}/webcam.txt" ok_msg "Done!" fi