If i plugin both webcams:
VideoEndoskop is running quite well, the Logitech not. service webcamd status
shows:
Jan 17 23:25:28 octopi mjpg_streamer[452]: MJPG-streamer [452]: www-folder-path......: ./www-octopi/
Jan 17 23:25:28 octopi mjpg_streamer[452]: MJPG-streamer [452]: HTTP TCP port........: 8080
Jan 17 23:25:28 octopi mjpg_streamer[452]: MJPG-streamer [452]: HTTP Listen Address..: (null)
Jan 17 23:25:28 octopi mjpg_streamer[452]: MJPG-streamer [452]: username:password....: disabled
Jan 17 23:25:28 octopi mjpg_streamer[452]: MJPG-streamer [452]: commands.............: disabled
Jan 17 23:25:28 octopi mjpg_streamer[452]: MJPG-streamer [452]: starting input plugin input_uvc.so
Jan 17 23:25:28 octopi mjpg_streamer[452]: MJPG-streamer [452]: starting output plugin: output_http.so (ID: 00)
Jan 17 23:25:29 octopi webcamd[361]: Done bring up all configured video device
Jan 17 23:25:29 octopi webcamd[361]: Goodbye...
Jan 17 23:25:29 octopi systemd[1]: Started the OctoPi webcam daemon with the user specified config.
service webcamd2 status
shows:
β webcamd2.service - the OctoPi webcam daemon with the user specified config
Loaded: loaded (/etc/systemd/system/webcamd2.service; enabled; vendor preset: enabled)
Active: failed (Result: start-limit-hit) since Fri 2020-01-17 23:25:35 CET; 12h ago
Process: 593 ExecStart=/root/bin/webcamd2 (code=exited, status=0/SUCCESS)
Jan 17 23:25:35 octopi systemd[1]: webcamd2.service: Service RestartSec=100ms expired, scheduling restart.
Jan 17 23:25:35 octopi systemd[1]: webcamd2.service: Scheduled restart job, restart counter is at 5.
Jan 17 23:25:35 octopi systemd[1]: Stopped the OctoPi webcam daemon with the user specified config.
Jan 17 23:25:35 octopi systemd[1]: webcamd2.service: Start request repeated too quickly.
Jan 17 23:25:35 octopi systemd[1]: webcamd2.service: Failed with result 'start-limit-hit'.
Jan 17 23:25:35 octopi systemd[1]: Failed to start the OctoPi webcam daemon with the user specified config.
If I unplug the VideoEndoskop (assigned in /root/bin/webcamd)
REBOOT
the VideoLogitech (assigned in /root/bin/webcamd2) is running quite well.
service webcamd status:
shows:
β webcamd.service - the OctoPi webcam daemon with the user specified config
Loaded: loaded (/etc/systemd/system/webcamd.service; enabled; vendor preset: enabled)
Active: failed (Result: start-limit-hit) since Sat 2020-01-18 12:23:31 CET; 13min ago
Process: 580 ExecStart=/root/bin/webcamd (code=exited, status=0/SUCCESS)
Jan 18 12:23:30 octopi webcamd[580]: Goodbye...
Jan 18 12:23:30 octopi systemd[1]: webcamd.service: Succeeded.
Jan 18 12:23:30 octopi systemd[1]: Started the OctoPi webcam daemon with the user specified config.
Jan 18 12:23:31 octopi systemd[1]: webcamd.service: Service RestartSec=100ms expired, scheduling restart.
Jan 18 12:23:31 octopi systemd[1]: webcamd.service: Scheduled restart job, restart counter is at 5.
Jan 18 12:23:31 octopi systemd[1]: Stopped the OctoPi webcam daemon with the user specified config.
Jan 18 12:23:31 octopi systemd[1]: webcamd.service: Start request repeated too quickly.
Jan 18 12:23:31 octopi systemd[1]: webcamd.service: Failed with result 'start-limit-hit'.
Jan 18 12:23:31 octopi systemd[1]: Failed to start the OctoPi webcam daemon with the user specified config.
service webcamd2 status:
shows:
β webcamd2.service - the OctoPi webcam daemon with the user specified config
Loaded: loaded (/etc/systemd/system/webcamd2.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2020-01-18 12:23:25 CET; 13min ago
Process: 374 ExecStart=/root/bin/webcamd2 (code=exited, status=0/SUCCESS)
Main PID: 463 (mjpg_streamer)
Tasks: 3 (limit: 2077)
Memory: 2.0M
CGroup: /system.slice/webcamd2.service
ββ463 ./mjpg_streamer -o output_http.so -w ./www-octopi -n -i input_uvc.so -d /dev/VideoLogitech -r 1280x720 -f 10
Jan 18 12:23:24 octopi webcamd2[374]: o: commands.............: disabled
Jan 18 12:23:24 octopi mjpg_streamer[463]: MJPG-streamer [463]: HTTP TCP port........: 8080
Jan 18 12:23:24 octopi mjpg_streamer[463]: MJPG-streamer [463]: HTTP Listen Address..: (null)
Jan 18 12:23:24 octopi mjpg_streamer[463]: MJPG-streamer [463]: username:password....: disabled
Jan 18 12:23:24 octopi mjpg_streamer[463]: MJPG-streamer [463]: commands.............: disabled
Jan 18 12:23:24 octopi mjpg_streamer[463]: MJPG-streamer [463]: starting input plugin input_uvc.so
Jan 18 12:23:24 octopi mjpg_streamer[463]: MJPG-streamer [463]: starting output plugin: output_http.so (ID: 00)
Jan 18 12:23:25 octopi systemd[1]: Started the OctoPi webcam daemon with the user specified config.
Jan 18 12:23:25 octopi webcamd2[374]: Done bring up all configured video device
Jan 18 12:23:25 octopi webcamd2[374]: Goodbye...
I think the problem in my case is the port 8080, which is assigned to webcamd OR webcamd2 and assigning the 8080 to webcamd and webcamd2 will be a problem.
I have entered port 8081 in /root/bin/webcamd2 and /etc/haproxy/haproxy.cfg in the backend of webcam2.
Does anybody have a idea, how to solve the problem? Otherwise I am lost in space.
direct after service webcamd2 restart
the status shows:
octoopi:~ $ service webcamd2 status
β webcamd2.service - the OctoPi webcam daemon with the user specified config
Loaded: loaded (/etc/systemd/system/webcamd2.service; enabled; vendor preset: enabled)
Active: activating (start) since Mon 2020-01-20 23:22:03 CET; 648ms ago
Cntrl PID: 1084 (webcamd2)
Tasks: 2 (limit: 2077)
Memory: 1.2M
CGroup: /system.slice/webcamd2.service
ββ1084 /bin/bash /root/bin/webcamd2
ββ1109 sleep 1
Jan 20 23:22:03 octopi webcamd2[1084]: bind: Address already in use
Jan 20 23:22:03 octopi webcamd2[1084]: o: server_thread(): bind(8080) failed
Jan 20 23:22:03 octopi mjpg_streamer[1108]: MJPG-streamer [1108]: www-folder-path......: ./www-octopi/
Jan 20 23:22:03 octopi mjpg_streamer[1108]: MJPG-streamer [1108]: HTTP TCP port........: 8080
Jan 20 23:22:03 octopi mjpg_streamer[1108]: MJPG-streamer [1108]: HTTP Listen Address..: (null)
Jan 20 23:22:03 octopi mjpg_streamer[1108]: MJPG-streamer [1108]: username:password....: disabled
Jan 20 23:22:03 octopi mjpg_streamer[1108]: MJPG-streamer [1108]: commands.............: disabled
Jan 20 23:22:03 octopi mjpg_streamer[1108]: MJPG-streamer [1108]: starting input plugin input_uvc.so
Jan 20 23:22:03 octopi mjpg_streamer[1108]: MJPG-streamer [1108]: starting output plugin: output_http.so (ID: 00)
Jan 20 23:22:03 octopi mjpg_streamer[1108]: MJPG-streamer [1108]: server_thread(): bind(8080) failed
and here you can see that port 8080 is not assignable. (because it is already assigned to webcamd service).
If nobody knows about webcamd ports, does anybody have a forum-address, where I can post this problem?
I'm looking on my OctoPi-imaged Raspberry Pi right now:
ls /etc/systemd/system/webcamd.service # Note the location
[Unit]
Description=the OctoPi webcam daemon with the user specified config
[Service]
WorkingDirectory=/root/bin
ExecStart=/root/bin/webcamd
Restart=always
Type=forking
[Install]
WantedBy=multi-user.target
In theory, you'd need to clone that in that folder as webcamd2.service and edit its ExecStart line so that it's unique from the original.
Here's my /root/bin/webcamd. As you can see, it's nothing like yours. It might be worth introducing a /boot/octopi2.txt file to configure a cloned version of all this.
#!/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 ###
### /boot/octopi.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")
config_dir="/boot/octopi.conf.d"
echo "Starting up webcamDaemon..."
echo ""
cfg_files=()
cfg_files+=/boot/octopi.txt
if [[ -d ${config_dir} ]]; then
cfg_files+=( `ls ${config_dir}/*.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 /boot/octopi.conf.d/*.txt INSTEAD!
camera="auto"
camera_usb_options="-r 640x480 -f 10"
camera_raspi_options="-fps 10"
camera_http_webroot="./www-octopi"
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 /boot/octopi.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
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 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
And then again, it's like... why bother? You're not the only person on here who's spending many hours trying to add multiple webcams to the same Pi computer. Each stream eats of lots of processing time and puts your print job's quality at risk.
Why not instead dedicate one Pi per extra webcam and call it a day? You just offload the work to another Pi Zero which can be moved to anywhere you need it to be.