Selkies
Developer Reference

webcam

Virtual webcam: the client's camera uplink, served to applications as a V4L2 device.

Both transports deliver encoded camera frames here — the WebSocket as 0x06 binary messages carrying WebCodecs output, WebRTC as the depacketized frames of the recvonly video m-line — and this module forwards them to the process-wide pixelflux.VirtualCamera. Decoding, fitting, and publishing to every device sink (the shared-memory ring behind the selkies_v4l2_interposer.so LD_PRELOAD library, and a v4l2loopback device where one is configured) happen on pixelflux's own thread; Python only gates the sender and hands the bytes over without copying them.

Lifetime is process-wide, like the gamepad interposer servers: applications open /dev/videoN once at their own startup and must survive transport-mode switches and browser reconnects, so one camera is shared by every client and is only stopped with the server. Its format follows the first uplink, so a browser sending JPEG gets an MJPEG device its frames pass through untouched and a WebCodecs/WebRTC browser an I420 device. A later uplink of the other kind would otherwise be converted for the life of the process, so an auto device is re-created for it — but only while no sink reports a consumer, since an application holding the device is exactly what the process-wide lifetime is for (VirtualWebcam.ensure).

The WebSocket carries one encoded frame per 0x06 message: opcode, codec id, flags, payload. Besides the keyframe bit the flags byte carries the frame's upright transform, which the client's encoder leaves out of the bitstream: bits 1-2 are the clockwise rotation in quarter turns, bit 3 a horizontal flip applied after the rotation. Servers that predate the bits ignore them.

attributelogger
= logging.getLogger('webcam')
attributeWEBCAM_SOCKET_NAME
= 'selkies_webcam0.sock'
attributeCODEC_MJPEG
= 0
attributeCODEC_H264
= 1
attributeCODEC_VP8
= 2
attributeCODEC_VP9
= 3
attributeCODEC_AV1
= 4
attributeCODEC_HEVC
= 5
attributeCODEC_BY_NAMEDict[str, int]
= {'mjpeg': CODEC_MJPEG, 'jpeg': CODEC_MJPEG, 'h264': CODEC_H264, 'vp8': CODEC_VP8, 'vp9': CODEC_VP9, 'av1': CODEC_AV1, 'hevc': CODEC_HEVC, 'h265': CODEC_HEVC}
attributeWS_OPCODE_WEBCAM
= 6
attributeWS_HEADER_LEN
= 3
attributeWS_FLAG_KEYFRAME
= 1
attributeWS_FLAG_ROTATION_SHIFT
= 1
attributeWS_FLAG_ROTATION_MASK
= 6
attributeWS_FLAG_HFLIP
= 8
attributeMSG_WEBCAM_DISABLED
= 'WEBCAM_DISABLED'
attributeMSG_WEBCAM_KEYFRAME
= 'WEBCAM_KEYFRAME'
attributeREFORMAT_RECHECK_SECONDS
= 5.0

On this page

No Headings
Edit on GitHub