Created
December 24, 2021 21:31
-
-
Save CODeRUS/d0f2409def55343f3bb785ca25f39e87 to your computer and use it in GitHub Desktop.
webcamd mod
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# modified webcamd sctipt | |
# | |
# changes: | |
# 1. argument for named configs. | |
# load config from camera-$1.conf files | |
# named systemd unit@ should be used and %i passed to webcamd arg | |
# 2. v4l-name option | |
# allow to assign video4linux camera device by it's name. | |
# useful if multiple cameras are used | |
######################################################################## | |
### 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/camera-*.conf 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/user/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/user/klipper_config | |
echo "Starting up webcamDaemon..." | |
echo "" | |
cfg_files=() | |
#cfg_files+=/boot/mainsail.txt | |
if [[ -d ${config_dir} ]]; then | |
cfg_files+=( `ls ${config_dir}/camera-$1*.conf` ) | |
fi | |
v4l_devices+=( `ls /sys/class/video4linux` ) | |
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 | |
if [[ "$camera" == "v4l-name" ]] | |
then | |
for d in ${v4l_devices[@]}; do | |
d_name=$(cat "/sys/class/video4linux/$d/name") | |
if [[ "$v4l_name" == "$d_name" ]] | |
then | |
camera="usb" | |
extracted_device="/dev/$d" | |
fi | |
done | |
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" "v4l-name"; 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment