dingenskirchen.org

Using My Pinebook Pro As A Webcam

Because of *gestures wildly* current events, i’ve found it necessary to participate in a few video conferences. These can be somewhat more awkward than usual if you’re the only person that doesn’t have a webcam and so remain a perfectly motionless avatar while everyone else at least seems to breathe once in a while.

I’ve previously circumvented this aesthetic issue by means of v4l2loopback, a kernel module that allows you to feed any video stream1 into a virtual “loopback” webcam, like this:

ffmpeg -re -i ~/Downloads/07_27_1978-NAh9oLs67Cw.mp4 \ 
-s 1280x720 -vcodec rawvideo -pix_fmt yuv420p -f v4l2 /dev/video0

As always, a degree in Command Line Shitfuckery is needed to change anything other than the filename without risking breakage and probably a fire. Ffmpeg works in mysterious ways.

Armed with this knowledge and the prospect of another conference where having no video would pose a rather serious problem, i decided that it was time to actually try and get myself2 onto the feed. I did after all have a Pinebook Pro, which has an (admittedly, hardly first-rate) webcam installed. Sadly, it’s also an ARM laptop which i insist on using with NixOS, whose ARM support is rather lacking currently. Particularly, the only browser i can get to work reliably is GNOME’s epiphany, which is a perfectly fine browser but doesn’t play well with the videoconferencing software i need to use. The project then became getting the video feed from the PBP onto my desktop, which doesn’t have these limitations.

After about an evening mucking around with various completely ineffective and increasingly cryptic command lines grabbed from Stack Overflow, i took a turn to look what VLC, the multimedia swiss army knife, has to offer in this department.

I did some experimenting based on their Streaming HowTo and found a way to stream the output of the PBP’s built in webcam at /dev/video1 to some port over HTTP. I did most of the finetuning in the GUI and copied over the argument strings it spat out so i could automate it more easily.

cvlc --sout "#transcode{vcodec=WMV2,vb=800,acodec=wma2,ab=128,channels=2,samplerate=44100,scodec=none}:http{dst=:8080/go.wmv}" \
--sout-all --sout-keep --live-caching 0 \
v4l2:///dev/video1 --v4l2-width 1280 --v4l2-height 720

Impressive, isn’t it? I’d bet that even a core VLC developer has no clue what exactly this eldritch invocation does. The analysis of the effects above is based on purely empirical observations, not understanding. Not in the slightest.

On my computer, i then use a modified version of the above ffmpeg charm to bring the video stream into the loopback camera:

ffmpeg -hide_banner -fflags nobuffer -flags low_delay \
-i http://thingy:8080/go.wmv \
-s 1280x720 -vcodec rawvideo -pix_fmt yuv420p -f v4l2 /dev/video0

The extra options3 are there to reduce latency, which on my somewhat subpar wi-fi works out to about half a second: noticeable, but not enough so to make it unusable for video conferencing.

I actually combined all of these into a script that SSHs into my laptop to bring up the camera stream and then give me a preview of how it looks before starting up the fake camera:

#!/usr/bin/env bash
set -xe

# pick a random port that's hopefully unused
port=$(($RANDOM+1025))

# start the loopback driver if it isn't on yet
sudo modprobe v4l2loopback devices=1 exclusive_caps=1

# ssh into the notebook to bring up the stream
ssh dingens@thingy \
"cvlc --sout \"#transcode{vcodec=WMV2,vb=800,acodec=wma2,ab=128,channels=2,samplerate=44100,scodec=none}:http{dst=:$port/go.wmv}\" \
--sout-all --sout-keep --live-caching 0 v4l2:///dev/video1 \
--v4l2-width 1280 --v4l2-height 720"&

# there is some delay involved before the stream's actually usable
sleep 10

# display a preview of the stream, continue by closing the window
ffplay -hide_banner -fflags nobuffer -flags low_delay -framedrop http://thingy:$port/go.wmv
# feed the stream into the loopback camera until you hit [q] in the console
ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://thingy:$port/go.wmv -s 1280x720 -vcodec rawvideo -pix_fmt yuv420p -f v4l2 /dev/video0

# ssh into the notebook to kill the stream
ssh dingens@thingy "killall .vlc-wrapped"

I hope that if you’re in a similar situation as i was, this will prove moderately useful to you.

If you want to comment on this, please send an email to any address at 15318.de and include the title of this post in your subject line. Thanks!


  1. For me, usually one looking not even vaguely like myself (or indeed any person livestreaming their face), to my fellow users’ distraction.↩︎

  2. Instead of, say, John Blyth Barrymore Jr.↩︎

  3. Courtesy, some random person on StackOverflow. Dear Teocci, please find attached my proposal↩︎