Before beginning, you will need:
- v4l2loopback, a Linux kernel module that, like
aloop
, creates a loopback device that can be seen as a camera; - gstreamer, which can integrate with pipewire but doesn't seem to use
v4l2loopback
devices well; - ffmpeg, which does perfectly well with
v4l2loopback
but (for now) lacks pipewire support.
I'm presuming you're using pipewire and any of the xdg-desktop-portal implementations appropriate to your compositor, and that it is configured to be running as part of your session (and reachable via the DBus session bus).
The scripts copied below are fairly straightforward, but there are a few gotchas:
exclusive_caps=1
ensures that the V4L2 "Loopback" camera looks like "a regular camera" after an application (hereffmpeg
) starts using it as a destination. This is not strictly necessary for all applications, including Electron applications, but--if not done--may cause some other applications to dismiss the device as "not a camera".- The node ID (it must be a pipewire
Node
) is extracted from thepipewire
command line tools. This is technically a workaround to a bug inxdg-desktop-portal-wlr
where, although the portal opened the pipewire node, it returnedUINT32_MAX - 1
as the node ID--which also prevented screen capture from working in, among other things, Firefox. - The color space is converted to
yuyv422
. The desktop portal usually streams in your native framebuffer colorspace, oftenrgba
, but Electron/Chromium does not recognize devices without a "more typical" camera colorspace as being a camera.
xdp-screen-cast.py
is copied, with light modifications, from this GNOME snippet or a previous version (which is how I know the Node ID was wrong).
Run ./stream_screen.sh
. It should print out helpful error messages, including the command line recommended for loading v4l2loopback
:
sudo modprobe v4l2loopback exclusive_caps=1 card_label=Loopback
... as well as when it can't find an application already having created a streaming node (in which case it recommends you run the included xdp-screen-cast.py
).
If all goes well, you'll see ffmpeg
count the frames being sent to the loopback device. At that point, it should exist as a camera, for all intents and purposes.