Running (Almost) Anything in LXC: Applications Using Your Webcam
Posted on Sun 17 January 2021 in hints-and-kinks • 3 min read
One of the non-open-source applications I sometimes have to run for work purposes, and which out of principle I run in LXC containers, is Zoom. Now Zoom is of course an X application, so my previously shared considerations for those apply. It also needs to process input from my microphone, and feed sound into my headphones, so that’ll have to work, too.
But a thus-configured LXC container is still missing one other bit: it’ll have to process the video feed from my webcam. Here’s how to do that.
In the article on running X applications in LXC, I give the example of sharing a host directory, (the one that contains the X.org server sockets). For sharing a webcam, I need to do the same for a few files.
Now, video capture devices like webcams are represented in Linux by
character devices named
/dev/video1 and so
forth. Udev manages these and (on Ubuntu platforms) creates them as
owned by the user
root and the group
video — but it helpfully also
creates POSIX ACL entries for the user currently logged in on the X
All I thus need to do is mount these files into the container (yes, LXC lets you “mount” individual files), like so:
lxc.mount.entry = /dev/video0 dev/video0 none bind,optional,create=file lxc.mount.entry = /dev/video1 dev/video0 none bind,optional,create=file lxc.mount.entry = /dev/video2 dev/video2 none bind,optional,create=file lxc.mount.entry = /dev/video3 dev/video2 none bind,optional,create=file
optional bit of course means that the container will start
even in case a particular file does not exist in the host at the time
the container receives its
That, in principle, is all there is to it.
Things to consider
Be aware that since early
(in other words, in kernel 4.16 and later) the Linux kernel’s
uvcvideo subsystem will create two
/dev/video devices for your
webcam. One of them is the actual video capture device; the second one
is a metadata device node. You can easily tell which is which, with
v4l2-ctl: only a video capture device will have a non-empty list of
This is a video capture device:
$ v4l2-ctl --list-formats --device /dev/video0 ioctl: VIDIOC_ENUM_FMT Type: Video Capture : 'MJPG' (Motion-JPEG, compressed) : 'YUYV' (YUYV 4:2:2) : 'H264' (H.264, compressed)
And this is the metadata device; note that it lists no video codecs:
$ v4l2-ctl --list-formats --device /dev/video1 ioctl: VIDIOC_ENUM_FMT Type: Video Capture
Normally, device nodes
/dev/video1 will be
occupied by a built-in webcam, your USB webcam will use
/dev/video3, and if you have another video capture device then
that will be
Thus, perhaps you want your container to see only your USB webcam,
and you don’t care about the metadata device. In that case, instead
of the four
lxc.mount.entry lines I gave above, you might use just
lxc.mount.entry = /dev/video2 dev/video2 none bind,optional,create=file
Also, the bind mounts occur at the time you start the container. Thus, if you plug in a USB webcam while the container is already running, it won’t magically become available to the container. There are two ways to address this:
You start (or restart) your container whenever you need to use a web cam (or other video device) that you have just plugged in, or
you remove the
optionalkeyword from your
lxc.mount.entryline(s), so that the container will refuse to start unless the correct webcam is plugged in.
Note further that for the same reason, if you disconnect your USB webcam while your container is running, you can’t just plug it back in and expect it to work. In that case, udev in the host will have deleted the device node, so the bind mount in your container is now stale, and your containerized applications won’t be able to use your capture device anymore. Under those circumstances, you’ll simply have to restart your container.