Virtual camera
Present any video in a stream as a camera that Zoom, Google Meet, OBS or a browser can select. Linux only.
VirtualCameraSink turns a video output into a camera that every other application on the machine can pick, like a webcam you plugged in. Put an effect, an overlay or a model’s annotations on your video, and use the result in a video call or a streaming tool.
A camera with an effect
Section titled “A camera with an effect”from tatolab.stream import CameraSource, StreamBuilder, VirtualCameraSink, stream
from nodes.vignette import Vignette
@streamdef call_camera(stream_builder: StreamBuilder) -> None: """The camera with a vignette, as a camera other apps can use.""" camera = stream_builder.add(CameraSource) effect = stream_builder.add(Vignette, config={"amount": 0.7}) virtual_camera = stream_builder.add(VirtualCameraSink, config={"name": "Tatolab Camera"}) stream_builder.connect(camera.output("video"), effect.input("video")) stream_builder.connect(effect.output("vignetted_video"), virtual_camera.input("video"))Vignette is the node from GPU effects. Run the stream, then open your video app’s camera settings and choose Tatolab Camera. The camera exists while its node runs: it appears when the stream starts and disappears when it stops, like a USB camera being plugged in and pulled out.
Add as many VirtualCameraSink nodes as you like; each one is a separate camera. The camera-virtual-camera example presents the plain camera and an inverted copy side by side.
Choose a route: v4l2loopback or PipeWire
Section titled “Choose a route: v4l2loopback or PipeWire”Linux has two routes for presenting a camera, and the door setting picks one:
door |
How it works | Who can see it |
|---|---|---|
"auto" (default) |
Uses v4l2loopback if it’s set up, and PipeWire otherwise | Depends on which it picked |
"v4l2loopback" |
Creates a standard video device, /dev/videoN |
Every application that uses cameras |
"pipewire" |
Registers a camera with PipeWire. Needs no kernel module and no root. | Applications that use PipeWire’s camera support |
The v4l2loopback route works with everything, including Zoom, browsers and OBS, so it’s the one to set up if you can. The log says which route each camera took.
Set up v4l2loopback (once)
Section titled “Set up v4l2loopback (once)”v4l2loopback is a Linux kernel module. Install it, then give Tatolab permission to create cameras with it:
sudo apt install v4l2loopback-dkms # Debian and Ubuntutatolab enable-virtual-cameratatolab enable-virtual-camera makes one privileged change, behind your desktop’s password prompt (or sudo in a terminal without a desktop): it loads the module at boot, with no devices of its own, and lets the logged-in user create cameras through it. You only do this once per machine. To see exactly what it would change without changing anything, run tatolab enable-virtual-camera --print.
Until it’s set up, door="auto" takes the PipeWire route, and the log names tatolab enable-virtual-camera as the way to switch to v4l2loopback.
The name setting is what applications show in their camera list. Leave it out and the camera is called StreamLib Camera plus a short ID that’s unique to the node and stream, and stays the same across runs. Names longer than 31 bytes are cut short, so keep them brief.
Ask an agent to do it
Section titled “Ask an agent to do it”The runtime gives agents a recipe for this, show_channel_on_virtual_camera: it adds a VirtualCameraSink to a running stream and connects any video output to it. Ask your agent “put the detector’s output on a virtual camera” and it can do it without restarting the stream. See Agents and MCP.
Troubleshooting
Section titled “Troubleshooting”- The camera doesn’t appear in my app. Check the stream’s log for which route the camera took. If it’s PipeWire and your app only lists
/dev/video*devices, set up v4l2loopback as above. Some apps only check for cameras when they start, so restart the app. door="v4l2loopback"is refused. The permission isn’t set up yet. Runtatolab enable-virtual-camera, and installv4l2loopback-dkmsfirst if it asks for the module.- The picture is mirrored in my video call. That’s usually the app mirroring your self-view; other people see it the right way round.