Notes to Self

Alex Sokolsky's Notes on Computers and Programming

mjpg-streamer in an LXC Container on Proxmox

Streaming video from a USB webcam connected to a Proxmox node via mjpg-streamer deployed in an LXC container.

Create an LXC

I created a debian-based LSC. Because there is a need to compile sources, I allocated 2 cores and 2GB of RAM.

Build mjpg-streamer

apt-get update
apt-get install git cmake gcc g++

Package libjpeg8-dev was not found. Instead I did:

apt-get install libjpeg-dev

will also need:

apt-get install ffmpeg v4l-utils psmisc

Then:

git clone https://github.com/jacksonliam/mjpg-streamer.git
root@mjpg-streamer:~/mjpg-streamer/mjpg-streamer-experimental# make
root@mjpg-streamer:~/mjpg-streamer/mjpg-streamer-experimental# make install

mjpg-streamer service installation

as root:

git clone https://github.com/john-clark/mjpg-streamer-setup.git
cd mjpg-streamer-setup
./installWebcams instal

Passthrough USB webcam port(s) to the LXC Container

root@suprox:~# lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 011: ID 0c45:636b Microdia USB  Live camera
Bus 001 Device 010: ID 2c99:0002 Prusa Original Prusa i3 MK3
Bus 001 Device 004: ID 0557:2419 ATEN International Co., Ltd
Bus 001 Device 003: ID 0557:7000 ATEN International Co., Ltd Hub
Bus 001 Device 002: ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

root@suprox:~# ls -la /dev/bus/usb/001/011
crw-rw-r-- 1 root root 189, 10 Feb  4 16:16 /dev/bus/usb/001/011

Set the owner of /dev/bus/usb/001/011 on pve node to the unprivileged uid of your container (100000 by default):

chown 100000:100000 /dev/bus/usb/001/011

Set the owner of /dev/video0 on pve node to the unprivileged uid of your container (100000 by default) and group video:

root@suprox:~# ls -la /dev/video0
crw-rw---- 1 root video 81, 0 Feb  4 16:16 /dev/video0
root@suprox:~# grep video /etc/group
video:x:44:
root@suprox:~# chown 100000:100044 /dev/video0

Now we know that:

My mjpg-streamer lxc ID is 108. Edit /etc/pve/lxc/108.conf, and add the following lines:

lxc.cgroup2.devices.allow: c 189:* rwm
lxc.mount.entry: /dev/bus/usb/001/011 dev/bus/usb/001/011 none bind,optional,create=file
lxc.mount.entry: /dev/video0 dev/video0 none bind,optional,create=file

Now in the container:

root@mjpg-streamer:~# ls -la /dev/bus/usb/001/011
crw-rw-r-- 1 root root 189, 10 Feb  5 00:16 /dev/bus/usb/001/011
root@mjpg-streamer:~# ls -la /dev/video0
crw-rw---- 1 root video 81, 0 Feb  5 00:16 /dev/video0

Show formats supported by the webcam:

# ffmpeg -f v4l2 -list_formats all -i /dev/video0
...
[video4linux2,v4l2 @ 0x561a198da280] Compressed:       mjpeg :          Motion-JPEG : 640x480 1600x896 1280x720 1024x768 1024x576 960x544 864x480 848x480 800x448 640x360 352x288 320x240 1920x1080
[video4linux2,v4l2 @ 0x561a198da280] Raw       :     yuyv422 :           YUYV 4:2:2 : 640x480 1600x896 1280x720 1024x768 1024x576 960x544 864x480 848x480 800x448 640x360 352x288 320x240 1920x1080
/dev/video0: Immediate exit requested

Alternatively:

# v4l2-ctl --list-formats
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

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

or even

# v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'MJPG' (Motion-JPEG, compressed)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 1600x896
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 1024x768
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 1024x576
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 960x544
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 864x480
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 848x480
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 800x448
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 640x360
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 352x288
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.033s (30.000 fps)
        [1]: 'YUYV' (YUYV 4:2:2)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 1600x896
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.100s (10.000 fps)
                Size: Discrete 1024x768
                        Interval: Discrete 0.100s (10.000 fps)
                Size: Discrete 1024x576
                        Interval: Discrete 0.100s (10.000 fps)
                Size: Discrete 960x544
                        Interval: Discrete 0.100s (10.000 fps)
                Size: Discrete 864x480
                        Interval: Discrete 0.100s (10.000 fps)
                Size: Discrete 848x480
                        Interval: Discrete 0.100s (10.000 fps)
                Size: Discrete 800x448
                        Interval: Discrete 0.100s (10.000 fps)
                Size: Discrete 640x360
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 352x288
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.200s (5.000 fps)

Service Configuration

Created from template in /root/mjpg-streamer-setup/templates:

root@mjpg-streamer:~# cat /etc/systemd/system/mjpg-streamer.service
[Unit]
Description=mjpg_streamer for picam
After=network.target

[Service]
Type=simple
User=root
RemainAfterExit=yes
ExecStart=/root/mjpg-streamer-setup/bin/startAllCams

[Install]
WantedBy=multi-user.target
root@mjpg-streamer:~#
root@mjpg-streamer:~# systemctl enable mjpg-streamer
Created symlink /etc/systemd/system/multi-user.target.wants/mjpg-streamer.service -> /etc/systemd/system/mjpg-streamer.service.
root@mjpg-streamer:~# systemctl status mjpg-streamer
* mjpg-streamer.service - mjpg_streamer for picam
     Loaded: loaded (/etc/systemd/system/mjpg-streamer.service; enabled; vendor preset: enabled)
     Active: inactive (dead)

root@mjpg-streamer:~# systemctl start mjpg-streamer

root@mjpg-streamer:~# systemctl status mjpg-streamer
* mjpg-streamer.service - mjpg_streamer for picam
     Loaded: loaded (/etc/systemd/system/mjpg-streamer.service; enabled; vendor preset: enabled)
     Active: active (exited) since Sun 2023-02-05 23:17:03 UTC; 6s ago
    Process: 1150 ExecStart=/root/mjpg-streamer-setup/bin/startAllCams (code=exited, status=0/SUCCESS)
   Main PID: 1150 (code=exited, status=0/SUCCESS)
      Tasks: 0 (limit: 38329)
     Memory: 12.0K
        CPU: 13ms
     CGroup: /system.slice/mjpg-streamer.service

Feb 05 23:17:03 mjpg-streamer startAllCams[1154]: /root/mjpg-streamer-setup/bin/startAllCams: line 8: vcgencmd: command not found
Feb 05 23:17:04 mjpg-streamer startAllCams[1156]: Webcam does not support MJPG - using slower YUYV instead!
Feb 05 23:17:04 mjpg-streamer startAllCams[1156]: Best resolution: 0 x 0 at 0
Feb 05 23:17:04 mjpg-streamer startAllCams[1156]: /usr/local/bin/mjpg_streamer -i "/usr/local/lib/mjpg-streamer/input_uvc.so -d /dev/video0 --fps 0 -r 0x0 -y " ->
Feb 05 23:17:04 mjpg-streamer mjpg_streamer[1163]: MJPG-streamer [1163]: starting application
Feb 05 23:17:04 mjpg-streamer mjpg_streamer[1163]: MJPG-streamer [1163]: enabling daemon mode
Feb 05 23:17:04 mjpg-streamer startAllCams[1163]: enabling daemon mode
Feb 05 23:17:04 mjpg-streamer startAllCams[1164]: forked to background (1165)
Feb 05 23:17:04 mjpg-streamer mjpg_streamer[1165]: MJPG-streamer [1165]: MJPG Streamer Version: git rev: 310b29f4a94c46652b20c4b7b6e5cf24e532af39
Feb 05 23:17:04 mjpg-streamer mjpg_streamer[1165]: MJPG-streamer [1165]: input_init() return value signals to exit

Fixing mjpg-streamer

Fix startAllCams

Remove reference to vcgencmd

Fix mjpgStart

Test for MJPG support is broken:

MJPG_TEST=$(echo "$VIDEO_TEST" | /bin/grep "'MJPG'")

Calculation for best resolution and framerate is broken:

BEST_WIDTH=$WEBCAM_WIDTH
BEST_HEIGHT=$WEBCAM_HEIGHT
BEST_FRAMERATE=$WEBCAM_FRAMERATE

Final test:

root@mjpg-streamer:~/mjpg-streamer-setup/bin# ./startAllCams
Best resolution: 640 x 480 at 30
/usr/local/bin/mjpg_streamer -i "/usr/local/lib/mjpg-streamer/input_uvc.so -d /dev/video0 --fps 30 -r 640x480 " -o "/usr/local/lib/mjpg-streamer/output_http.so -p 5050 -w /usr/local/share/mjpg-streamer/www" -b
enabling daemon modeforked to background (1329)