Running two webcams with Octoprint for HD timelapses

Referencing my previous post on setting up a proxy for your Octoprint webcam, I found that I wasn’t happy with the quality of the timelapse videos. Especially when my webcam is 1080p!

I happen to have a second webcam lying around, so I decided to hook it up to Octoprint and use one webcam for streaming, and one for capturing high-res stills for the timelapse.

62271960

NOTE: To run two webcams and wifi, you’ll probably need a powered USB hub, or a 2.5A+ power supply for the raspberry pi. I had all sorts of problems with my RasPi not booting properly until I set up a powered USB hub.

The plan, stan!

  • Change the webcamd script settings so we specify which camera we want to use for the low-res stream. This will be broadcast by mjpg-streamer on port 8080 as normal.
  • Set up a new script called webcamd2 with settings for the 2nd high-res webcam. Broadcast this with mjpg-streamer on port 8081. Because the bandwidth doesn’t matter, we don’t have to use the ‘-y’ command, so the CPU usage is about 5% even at 1080p!

Configuring a new webcamd script for high-res

  • In /root/bin/, make a copy of your old webcamd script as a backup.
  • Copy webcamd and name it webcamd2
  • Edit webcamd2 and modify the below options
  • Set the camera USB options to high res. Note that we’ve removed ‘-y’ to reduce CPU load.
camera2_usb_options="-d /dev/video1 -r 1920x1080 -f 5"
  • Comment out the octopi.txt section so it doesn’t pull the same settings as your low-res camera:
#if [ -e "/boot/octopi.txt" ]; then
#    source "/boot/octopi.txt"
#fi
  • Set the port for mjpg-streamer to output on
        echo Running ./mjpg_streamer -o "output_http.so -w ./www -p 8081" -i "$input"
        LD_LIBRARY_PATH=. ./mjpg_streamer -o "output_http.so -w ./www -p 8081" -i "$input" &
  • Set the USB device to pull video from
# starts up the USB webcam
function startUsb {
    options="$camera1_usb_options"
    device="video1"
  • Set the keep-alive to check video1 instead of video0
# keep mjpg streamer running if some camera1 is attached
while true; do
    if [ -e "/dev/video1" ] && { [ "$camera1" = "auto" ] || [ "$camera1" = "usb" ] ; }; then
  • Run the script to see if it works. Any errors should be displayed in the log. If it starts up OK, you should be able to browse to http://server-ip:8081 and see the webcam. If the settings it spits out don’t match what you’ve entered, check that you commented out the octopi.txt.
pi@octopi /root/bin $ ./webcamd
Starting up webcamDaemon...

--- Configuration: ----------------------------
camera1:        auto
usb options:   -d /dev/video0 -r 1920x1080 -f 5
raspi options: -fps 10
-----------------------------------------------

pi: Starting USB webcam
Running ./mjpg_streamer -o output_http.so -w ./www -p 8081 -i input_uvc.so -d /dev/video0 -r 1920x1080 -f 5
MJPG Streamer Version: svn rev: Unversioned directory
 i: Using V4L2 device.: /dev/video0
 i: Desired Resolution: 1920 x 1080
 i: Frames Per Second.: 5
 i: Format............: JPEG
 i: TV-Norm...........: DEFAULT
 o: www-folder-path...: ./www/
 o: HTTP TCP port.....: 8081
 o: username:password.: disabled
 o: commands..........: enabled

Autostart because I will forget how I set all this up oh god it’s already going what was I saying again oh look a muffin

Now we need to set up the script as a service, and register it so that it starts automatically on boot.

  • Navigate to /etc/init.d/ and copy webcamd and name it ‘webcamd2’. Change the following lines:
# Provides:          webcamd2
DESC="Webcam 2 Daemon"
NAME="webcamd2"
DAEMON=/root/bin/webcamd2
PKGNAME=webcamd2
LOG=/var/log/webcamd2.log
  • Navigate to /etc/default and copy webcamd to ‘webcamd2’. Change the following lines:
DAEMON=/root/bin/webcamd2
LOG=/var/log/webcamd2.log
  • Register the service so it runs automatically at boot-time
pi@octopi / $ sudo update-rc.d webcamd2 defaults
  • Lastly, in the Octoprint interface, change the webcam settings so that your Timelapse URL is as follows:
http://localhost:8081/?action=snapshot

It’s a grunty little thing

With my Raspberry Pi 2 Model B, I have had no problems running Octoprint, two webcams and a wifi adaptor. Note that you will likely need a powered USB hub, but the Pi seems to have plenty of grunt.

While printing and logged into the web interface watching the webcam, my raspberry pi’s load information is as follows:

top - 18:16:45 up 33 min,  1 user,  load average: 1.19, 1.05, 0.91
Tasks:  92 total,   1 running,  91 sleeping,   0 stopped,   0 zombie
%Cpu0  : 12.3 us,  0.0 sy,  0.0 ni, 78.9 id,  0.0 wa,  0.0 hi,  8.8 si,  0.0 st
%Cpu1  : 60.1 us,  0.0 sy,  0.0 ni, 39.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  2.0 us,  0.0 sy,  0.0 ni, 98.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  1.3 sy,  0.0 ni, 98.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:    884384 total,   174228 used,   710156 free,    15912 buffers
KiB Swap:   102396 total,        0 used,   102396 free,    67796 cached

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND
 2165 pi        20   0 53236 3004 2600 S  68.2  0.3  27:03.11 mjpg_streamer
 2029 pi        20   0  152m  29m 7256 S   7.6  3.5   1:58.43 octoprint
 3086 root      20   0     0    0    0 S   1.6  0.0   0:00.70 kworker/u8:2
 3094 pi        20   0  3592 2296 1872 R   1.0  0.3   0:00.75 top
    3 root      20   0     0    0    0 S   0.3  0.0   0:04.15 ksoftirqd/0
 2339 ntp       20   0  5604 3260 2872 S   0.3  0.4   0:00.52 ntpd
 2793 root      20   0     0    0    0 S   0.3  0.0   0:05.73 kworker/u8:0
 2948 pi        20   0 55496  18m  17m S   0.3  2.1   0:02.41 mjpg_streamer
    1 root      20   0  2148 1268 1164 S   0.0  0.1   0:01.87 init
    2 root      20   0     0    0    0 S   0.0  0.0   0:00.00 kthreadd
    5 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 kworker/0:0H
    7 root      20   0     0    0    0 S   0.0  0.0   0:00.59 rcu_preempt

The majority of the CPU goes to the low-res mjpg-streamer due to the ‘-y’ command to compress the video feed. As you can see, the 1080p mjpg-streamer is barely using any CPU at all.

Because the RasPi is a quad-core cpu, I’m comfortable with the load averages at this amount. Load averages are divided by core, EG a 4-core CPU will have a load average of 4.0 at full utilization. Looking at it that way, my RasPi is only using 25% cpu!

Enjoy your delicious 1080p timelapses!

22 comments

  1. I cant start my webcam server when octoprint boots up. I have to manualy type:

    cd mjpg-streamer/mjpg-streamer-experimental
    ./mjpg_streamer -i “./input_uvc.so -y” -o “./output_http.so”

    How can i start the webcam server automatically?

    Tkhs

  2. THANKS !!!!!!!!!!!

    but only works with

    camera1_usb_options=”-d /dev/video1 -r 1920×1080 -f 5″

    instead of

    camera2_usb_options=”-d /dev/video1 -r 1920×1080 -f 5″

  3. This is fantastic, thanks for posting this. Worked like a charm! Running it on a pi 3, only questions is how tobget both streams on one screen, either on octopi interface or simple webpge

    1. Great to hear it – you could probably make a simple page to embed both videos. Take a look at the HTML of the MJPEG default page on http://localhost:8080 and just snip the bit which embeds the video. Then just make an apache virtual site or you could probably edit octopi’s webcam page HTML to display both video feeds.

    1. Hi Brandon, are you able to browse to the webcams HTML page at http://server-ip:8081 ?

      If not then there is a configuration problem with the webcamd service.

      If so, then check your webcam settings in Octopi – maybe send a screenshot for me?

  4. I figured it out.. I had to look at the problem backwards.

    The USB Camera ends up comping up as default. The Pi Cam comes up second. So in Webcamd2, I commented out the USB stuff and changed the lines below.
    echo Running ./mjpg_streamer -o “output_http.so -w ./www -p 8081” -i “input_raspicam.so”
    LD_LIBRARY_PATH=. ./mjpg_streamer -o “output_http.so -w ./www -p 8081” -i “input_raspicam.so” &

    I have two cameras up, one USB on port 8080 and one Pi Cam on 8081.

    Great instructions. Thanks again.

    1. Can’t get it work like you did. Could you maybe send me the whole script? Also Octopi start my USB cam. On with the webcamd2 I want to get the Pi Cam running. 🙁

    1. Hi Dan
      No, the idea is to have one camera which runs full HD for your timelapse, and a second camera running at low quality to allow you to stream it online.
      Thanks

  5. Hey! When I try to run the script I get:

    Starting up webcamDaemon…

    — Configuration: —————————-
    camera: auto
    usb options: -d /dev/video1 -r 1920×1080 -f 5
    raspi options: -fps 10
    http options: -w ./www-octopi -n
    ———————————————–

    Explicitly set USB device was found in options: /dev/video1
    ./webcamd2: line 189: syntax error near unexpected token `done’
    ./webcamd2: line 189: `done’

    Goodbye…

    Any ideas? Any help would be awesome

  6. can any of you guys please help me do this i still new to all of this and none of it makes since. if any of you guys can help me please. or can someone please make a video of how to do it step by step. thanks if you are willing to help please feel free to help me. my email is kayeaustin2013@gmail.com

  7. Great write-up. Thanks, man!

    Used this to get my second camera working today.

    Also installed the multicam plugin for octoprint so I can click a button and switch between the cams.

  8. Could you please give a more detailed description where the keep alive check has to be inserted?

    I‘m a bit confused about that.

    Thx

    1. Hi Doc, the keepalive is part of the webcamd script. You first make a copy of this script – so there’s a unique script for each webcam you have connected. Then you edit the contents to get the ‘new’ script to access video1 instead of video0. The keep-alive check should already be present in the webcamd script which you copied from the original, you’re just altering the video/camera ID.
      Hope this helps!
      James

Leave a Reply to Sarel Botha Cancel reply

Your email address will not be published. Required fields are marked *