Can't get second webcam working (SOLVED)

Camera model
1st camera - picam, working fine
2nd camera - logitech c920

What is the problem?
I followed the Setting up multiple webcams in OctoPi the right way guide. first camera, the raspi cam, works fine. But I can't get the second camera to stream at all.

Raspi cam streams perfect at http://192.168.1.189:8080/?action=stream
In theory, logi cam should be streaming at http://192.168.1.189:8081/?action=stream but getting the generic "site cannot be reached" error

What did you already try to solve it?
Ensured the camera shows up under both lsusb and ls /dev/v4l/by-id, it does:
usb-046d_HD_Pro_Webcam_C920_B596D2EF-video-index0
usb-046d_HD_Pro_Webcam_C920_B596D2EF-video-index1

Tweaked the octopi.txt and octopi.conf.d/webcam2.txt files according to a few other forum posts (change www-octopi to www, etc)

Made sure TSD was fully uninstalled using this guide: I installed a broken plugin, how do I uninstall it again?. No change

Logs

webcamd.log attached
webcamd.log (73.3 KB)

Additional information about your setup (OctoPrint version, OctoPi version, ...)
OctoPrint version : 1.6.1
OctoPi version : 0.18.0

octopi.txt and octopi.conf.d/webcam2.txt files

octopi.txt:

### Configure which camera to use
#
camera="usb"

### Additional options to supply to MJPG Streamer for the USB camera
#
#camera_usb_options="-r 1920x1080 -f 24"
camera_usb_options="-d /dev/video0 -r 1920x1080 -f 24"

### Configuration of camera HTTP output
#
camera_http_webroot="./www"
camera_http_options="-n"

octopi.conf.d/webcam2.txt:

### 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="usb"

### Additional options to supply to MJPG Streamer for the USB camera
#
#camera_usb_options="-r 1280x720 -f 10"
camera_usb_options="-r 640x480 -f 10 -d /dev/v4l/by-id/usb-046d_HD_Pro_Webcam_C920_B596D2EF-video-index0 -y"
#camera_usb_options="-r 640x480 -f 10 -d /dev/video0"


### Configuration of camera HTTP output
#
camera_http_webroot="./www"
camera_http_options="-p 8081"

Hi,

Reading your webcamd.log, there seems to be an error with the MJPGStreamer command line that's being invoked...

Could you paste the output of sudo cat /root/bin/webcamd since the error would lie within ?

I'm also seeing this in the log file:

--- Configuration: ----------------------------
cfg_file:      /boot/octopi.txt
camera:        usb
usb options:   -d /dev/video0 -r 1920x1080 -f 24
raspi options: -fps 10
http options:  -w ./www -n

Explicitly USB device: /dev/video0
-----------------------------------------------

cfg_file:      /boot/octopi.conf.d/webcam2.txt
camera:        usb
usb options:   -r 640x480 -f 10 -d /dev/video0
raspi options: -fps 10
http options:  -w ./www -p 8081

Explicitly USB device: /dev/video0
-----------------------------------------------

They can't both access the same camera - you have an error about video device already in use somewhere there as well. The guide suggests using the /dev/v4l/by-id addresses for both cameras, not just one otherwise you may randomly find that /dev/video0 switches device.

So when I change octopi.txt to "raspi" (it's a pi camera), it somehow switches that camera stream from http://192.168.1.189:8080/?action=stream to http://192.168.1.189:8081/?action=stream

The second USB camera still doesn't work after this change. Same symptoms even when defining the second camera with camera_usb_options="-r 640x480 -f 10 -d /dev/v4l/by-id/usb-046d_HD_Pro_Webcam_C920_B596D2EF-video-index0 -y"

See below! Please note this is after trying a change suggested above and explicitly pointing the second config file at the USB webcam- /dev/v4l/by-id/usb-046d_HD_Pro_Webcam_C920_B596D2EF-video-index0 and removing the reference to video0 in the first config


pi@octopi:/boot $ sudo cat /root/bin/webcamd
#!/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="-r 640x480 -f 10"
  camera_raspi_options="-fps 10"
  camera_http_webroot="./www-octopi"
  camera_http_options="-n --listen 127.0.0.1"
  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"

    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

There's something wrong here, the last line shouldn't have a # in front of the options.

So you need to do a sudo nano /root/bin/webcamd and delete that # in front of the options="$options -d /dev/$device" then save and exit, and systemctl restart webcamd.service. Then both of the cameras should be streamed.

1 Like

Definitely progress, thanks for your help!
The USB webcam is now working for the first time at 8081, but now the pi camera at 8080 is giving me the "This site can’t be reached" error and doesn't seem to be working anymore. Any thoughts?

Without seeing the logs, not really...

Fair enough, see attached for webcamd.log from just now.
webcamd(2).log (79.4 KB)

Thanks again for all your help, hopefully I can quit bugging you soon :stuck_out_tongue:

EDIT: weirdly enough, rebooted the Pi and both are working fine now. Looks good to go! Thank you so much

Glad we could make it work, could you then marked the issue as solved, as described here ?

Thanks

1 Like