Expand description
Virtual camera: the browser’s webcam, delivered to applications as a V4L2 capture device.
The client encodes its camera (H.264/VP8/… over the WebRTC media track or WebCodecs over the
WebSocket, MJPEG as the last-resort canvas path) and Selkies hands each encoded frame to
VirtualCamera::push, which returns at once. A worker thread decodes, fits the picture into the
device’s fixed raw format, and publishes it to every sink at once:
- the shared-memory ring served over a Unix socket to the Selkies V4L2 interposer
(
LD_PRELOAD, no privileges, no kernel module), seeringandserver; - a v4l2loopback output device where one is configured or found, see
v4l2out— the kernel path for hosts and privileged containers, as/dev/uinputis for gamepads; - a PipeWire
Video/Sourcenode where a daemon is reachable, seepipewire— for PipeWire-native consumers and thepipewire-v4l2wrapper.
Nothing on the hot path copies more than the encoded bytes into a pooled buffer, and no worker thread ever calls back into the consumer.
Modules§
- convert
- Normalization of decoded frames into the virtual device’s fixed format.
- decode
- Decoders for the client camera uplink, and for the checks that read a session’s own output back.
- pipewire
- PipeWire sink: the camera as a
Video/Sourcenode. - ring
- Shared-memory frame ring consumed by the Selkies V4L2 interposer.
- server
- Control socket for the Selkies V4L2 interposer.
- v4l2out
- Kernel-device sink: writes frames into a v4l2loopback output device.
Structs§
- Camera
Running - The running camera’s negotiated format and sinks (
CameraStats::running). - Camera
Stats - What
VirtualCamera::statsreports: the counters since the camera was created, what the client last sent, and the running camera’s geometry and sinks where one runs. - Job 🔒
- Mjpeg
Encoder 🔒 - JPEG writer for the MJPEG device: the fitted, full-range I420 picture compressed straight into the ring slot.
- Pool 🔒
- Recycled encoded-frame buffers so the steady state allocates nothing per frame.
- Queue 🔒
- Bounded hand-off to the decoder thread that drops the oldest frame when the decoder falls behind: a camera must stay live, never grow latency.
- Queue
State 🔒 - Running 🔒
- Stats 🔒
- Counters read by
VirtualCamera.stats(). - Virtual
Camera - A virtual camera fed with encoded frames by the consumer.
- Virtual
Camera Settings - Configuration for
VirtualCamera::start. - Worker
Config 🔒
Constants§
- MJPEG_
REENCODE_ 🔒QUALITY - Re-encode quality for frames that must be fitted into an MJPEG device (a camera of another size, an H.264/VP8 uplink); frames of the device’s own size pass through as received.
Functions§
- black_
frame 🔒 - A black frame in
dev’s format, at mostcapacitybytes;Nonefor an MJPEG device without its encoder. - fan_out 🔒
- After a publish: wake the socket clients and mirror the frame into the kernel device and the PipeWire node where those sinks are up, retiring a sink that failed.
- monotonic_
ns 🔒 - parse_
pixel_ 🔒format - socket_
dir - Where the camera socket lives unless a caller names one: the session’s private runtime
directory, where no other account can take the name first, else
/tmp. The v4l2 interposer looks in the same place. - worker 🔒
- Decoder thread body: decode, fit, publish, wake clients. A dropped or undecodable inter-coded frame parks the stream until the next keyframe and asks the client for one, so a consumer never sees the smear of predictions built on a missing reference.