Webcamd2 start error [solved]

Hello all,

I recently redid my octoprint and am trying to get both my cameras working again.

Unfortunately I can't get the second webcamd to start for the life of me.

here is what I have done and configured.

  1. udev rules
/etc/udev/rules.d# cat 99-usb.rules
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="081b", ATTRS{serial}=="887D05A0", SYMLINK+="videobed" #bed
SUBSYSTEM=="video4linux", ATTRS{idVendor}=="1415", ATTRS{idProduct}=="2000", ATTRS{devpath}=="1.1", SYMLINK+="videotop"
  1. daemon
/etc/default# cat webcamd2
# Configuration for /etc/init.d/webcamd

# Daemon
DAEMON=/root/bin/webcamd2

# Log file to use
LOG=/var/log/webcamd2.log

# User to run under
USER=pi

# Should we run at startup?
ENABLED=1
  1. webcamd conf
/etc/default# cat webcamd2
# Configuration for /etc/init.d/webcamd

# Daemon
DAEMON=/root/bin/webcamd2

# Log file to use
LOG=/var/log/webcamd2.log

# User to run under
USER=pi

# Should we run at startup?
ENABLED=1
root@octoprint:/etc/default# cd /root/bin/
root@octoprint:~/bin# ls
gencert  git  streamer_select  user-fix  webcamd  webcamd2
root@octoprint:~/bin# cat webcamd2
#!/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" "0458:6006" "1e4e:0102" "0471:0311" "038f:6001" "046d:0804" "046d:0825" "046d:0994" "0ac8:3450")

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="-f 1 -q 75 -y -d /dev/videotop"
  camera_raspi_options="-fps 120"
  camera_http_webroot="./www-octopi"
  camera_http_options="-p 8081"
  #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

    # 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"
    options="$options"

    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

  1. service
/etc/systemd/system# cat webcamd2.service
[Unit]
Description=the OctoPi webcam daemon with the user specified config

[Service]
WorkingDirectory=/root/bin
ExecStart=/root/bin/webcamd2
Restart=always
Type=forking

[Install]
WantedBy=multi-user.target
  1. haproxy
/etc/haproxy# cat haproxy.cfg
global
        maxconn 4096
        user haproxy
        group haproxy
        log 127.0.0.1 local1 debug

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        option redispatch
        option http-server-close
        option forwardfor
        maxconn 2000
        timeout connect 5s
        timeout client  15min
        timeout server  15min

frontend public
        bind :::80 v4v6
        bind :::443 v4v6 ssl crt /etc/ssl/snakeoil.pem
        option forwardfor except 127.0.0.1
        use_backend webcam if { path_beg /webcam/ }
        use_backend webcam2 if { path_beg /webcam2/ }
        default_backend octoprint

backend octoprint
        acl needs_scheme req.hdr_cnt(X-Scheme) eq 0

        reqrep ^([^\ :]*)\ /(.*) \1\ /\2
        reqadd X-Scheme:\ https if needs_scheme { ssl_fc }
        reqadd X-Scheme:\ http if needs_scheme !{ ssl_fc }
        option forwardfor
        server octoprint1 127.0.0.1:5000
        errorfile 503 /etc/haproxy/errors/503-no-octoprint.http

backend webcam
        reqrep ^([^\ :]*)\ /webcam/(.*)     \1\ /\2
        server webcam1  127.0.0.1:8080
        errorfile 503 /etc/haproxy/errors/503-no-webcam.http

backend webcam2
        reqrep ^([^\ :]*)\ /webcam2/(.*)     \1\ /\2
        server webcam1  127.0.0.1:8081
        errorfile 503 /etc/haproxy/errors/503-no-webcam.http

Unfortunately, I always get the following message when starting the second service:

service webcamd2 start
Job for webcamd2.service failed because the control process exited with error code.
See "systemctl status webcamd2.service" and "journalctl -xe" for details.
root@octoprint:/etc/haproxy# systemctl status webcamd2.service
● 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: exit-code) since Wed 2022-04-27 11:18:43 BST; 4s ago
  Process: 4017 ExecStart=/root/bin/webcamd2 (code=exited, status=203/EXEC)

Apr 27 11:18:43 octoprint systemd[1]: webcamd2.service: Service RestartSec=100ms expired, scheduling restart.
Apr 27 11:18:43 octoprint systemd[1]: webcamd2.service: Scheduled restart job, restart counter is at 5.
Apr 27 11:18:43 octoprint systemd[1]: Stopped the OctoPi webcam daemon with the user specified config.
Apr 27 11:18:43 octoprint systemd[1]: webcamd2.service: Start request repeated too quickly.
Apr 27 11:18:43 octoprint systemd[1]: webcamd2.service: Failed with result 'exit-code'.
Apr 27 11:18:43 octoprint systemd[1]: Failed to start the OctoPi webcam daemon with the user specified config.

I hope someone has an idea where I can check something else.

In addition, the following information. if I specify the second camera /dev/videotop in the first webcamd, the device works. Only the second service just will not start.

Usually, for multiple webcams it is not supported to start editing and duplicating the webcamd files. If you start editing stuff like that we don't know what has gone wrong to help.

For most multiple webcam instances the built in support for it is more than enough:

Then you are not editing the scripts, and everything is working as it is designed.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.