The Why

...I'm cheap.

I already have an old and crusty laptop doing nothing but collecting dust...and I couldn't justify the $40 to $80 bucks it would have cost to get a 'real' IP camera.

The How

There are two parts to this task.  The first part is standing up an RTSP server that will accept the webcam stream and serve it.

The Second part is the capture of the integrated webcam and microphone using FFmpeg so it can be sent to the RTSP server.

The Tech

The laptop in question is an old Dell Latitude E6520.

The OS installed is Archlinux.

The software used is rtsp-server and FFmpeg.

The Initial Attempt

I started out just using VLC to accomplish this, but ran into an issue.  It seems that there is something amiss between how VLC serves the RTSP stream and how FFMPEG connects to it or vice versa.

I could get the server stood up with VLC:

cvlc v4l2:///dev/video0 --sout '#rtp{mux=ts,sdp=rtsp://IP:PORT/cam.sdp}'

I could also get a VLC client to connect to it:

vlc rtsp://IP:PORT/cam.sdp

I could not however get FFmpeg to connect to it:

Command:

ffmpeg -i "rtsp://IP:PORT/cam.sdp"

Output:

ffmpeg version n4.1.1 Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 8.2.1 (GCC) 20181127
  ...
[rtsp @ 0x5602a0212e00] method SETUP failed: 459 Client error
rtsp://IP:PORT/cam.sdp: Server returned 4XX Client Error, but not one of 40{0,1,3,4}

I attempted to troubleshoot that...but eventually gave up when I could not find any good info.  So I changed my approach.

RTSP Server

Getting this installed on Archlinux was mostly an easy task.  I found building the package from the Archlinux User Repository a little time consuming as not all the required Perl modules are called out in the PKGBUILD.  That or they are and the required perl modules to install the required perl modules were missing.  I realize that is a confusing statement.  It really boils down to a little bit of dependency hell (which I may go through again and document that at a later date).

Once installed, you just have to start up the server:

/usr/share/perl5/site_perl/RTSP/rtsp-server.pl

By default, it attempts to bind to port 554 to serve the stream and port 5545 to accept input.  See https://github.com/revmischa/rtsp-server#running for more info.

FFmpeg Webcam Capture

You have to do a little work to determine where you microphone and camera are and what your camera is capable of.  In my case, /dev/video0 is my integrated webcam.

Finding the Webcam

Command:

v4l2-ctl --list-devices

Output:

Laptop_Integrated_Webcam_FHD: I (usb-0000:00:1a.0-1.5):
        /dev/video0
        /dev/video1

Command:

v4l2-ctl -d /dev/video0 --list-formats

Output:

ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'YUYV' (YUYV 4:2:2)
        [1]: 'MJPG' (Motion-JPEG, compressed)

I really don't know what /dev/video1 does.  If I --list-formats against it, I just get Type: Video Capture.

Finding the Microphone

Command:

arecord -l

Output:

**** List of CAPTURE Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: 92HD90BXX Analog [92HD90BXX Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Putting it all Together

Armed with this info, I hand crafted the following command from only the finest DuckDuckGo searches, StackExchange posts, and general trial and error:

/usr/bin/ffmpeg -f alsa -i hw:0,0 -f v4l2 -input_format mjpeg -i /dev/video0 -c:v copy -f rtsp -muxdelay 0.1 rtsp://IP:5545/cam

Microphone Capture:

  • -f alsa -i hw:0,0
    • This is the part that sets the format -f for the input -i. In this case the input is the audio capture device device.

Webcam Capture:

  • -f v4l2 -input_format mjpeg -i /dev/video0
    • Pretty much the same as the audio caputer bit, but this time we point it at the webcam and set the input format to v4l2 and tell v4l2 to use the input_format of mjpeg.
  • -c:v copy
    • Don't rencode the video
  • -f rtsp -muxdelay 0.1 rtsp://IP:5545/cam
    • Set the output format to rtsp
    • Set -muxdely to 0.1
    • Send the stream to our rtsp-server rtsp://IP:5545/cam
      • cam was randomly chosen. Pretty sure you can put anything there.

Command:

/usr/bin/ffmpeg -f alsa -i hw:0,0 -f v4l2 -input_format mjpeg -i /dev/video0 -c:v copy -f rtsp -muxdelay 0.1 rtsp://IP:5545/cam

Output:

ffmpeg version n4.1.1 Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 8.2.1 (GCC) 20181127
  ...
Guessed Channel Layout for Input Stream #0.0 : stereo
Input #0, alsa, from 'hw:0,0':
  Duration: N/A, start: 1553354038.802212, bitrate: 1536 kb/s
    Stream #0:0: Audio: pcm_s16le, 48000 Hz, stereo, s16, 1536 kb/s
Input #1, video4linux2,v4l2, from '/dev/video0':
  Duration: N/A, start: 54826.273717, bitrate: N/A
    Stream #1:0: Video: mjpeg, yuvj422p(pc, bt470bg/unknown/unknown), 640x480, 30 fps, 30 tbr, 1000k tbn, 1000k tbc
Stream mapping:
  Stream #1:0 -> #0:0 (copy)
  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, rtsp, to 'rtsp://IP:PORT/cam':
  Metadata:
    encoder         : Lavf58.20.100
    Stream #0:0: Video: mjpeg, yuvj422p(pc, bt470bg/unknown/unknown), 640x480, q=2-31, 30 fps, 30 tbr, 90k tbn, 1000k tbc
    Stream #0:1: Audio: aac (LC), 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc58.35.100 aac
[alsa @ 0x55a5e1911080] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8)
frame=   46 fps=7.6 q=-1.0 size=N/A time=00:00:06.42 bitrate=N/A speed=1.06x

The Results

You can play the stream with anything that accepts the protocal rtsp://

VLC can:

vlc rtsp://IP/cam

FFmpeg can:

ffmpeg -i rtsp://IP/cam -c:v copy -t 15 output.mkv

You could even send it to your Home Assistant!

camera:
  - platform: ffmpeg
    input: '-i rtsp://IP/cam'
    extra_arguments: '-q:v 2 -r 15'
    name: thickcam

Finally - The Glorious LIVE WEBCAM STREAM!!!!!! not really