Installation¶
pdum.rfb works out of the box with a dependency-light image path and grows
into hardware H.264 via extras. This page lists every option, easiest + fastest
first, and the platform limits that apply to the GPU paths.
Not sure what your box supports? Ask — no install needed, via
uvx:
doctorprobes every encode path and tells you which one to prefer (see Performance for why). The[doctor]extra bundles the cross-platform encoders so a freshuvxrun reports both what runs on this platform and what is actually importable; platform-specific paths (CuPy / VideoToolbox / NVENC-SDK) are reported as "install X to enable".Want to try it interactively? One command, no clone, no Node:
See the interactive demo.
TL;DR — pick a path¶
| Want | Install | Works on | Speed |
|---|---|---|---|
| Just stream something | pip install habemus-papadum-rfb |
anywhere | image only |
| Software H.264 | pip install 'habemus-papadum-rfb[h264]' |
anywhere PyAV has wheels | good |
| GPU H.264 on NVIDIA (recommended) | pip install 'habemus-papadum-rfb[gpu-nvenc-sdk]' |
Linux · amd64 · NVIDIA | fastest |
| GPU H.264 on NVIDIA (PyAV route) | [gpu-cuda13] + PyAV 18 |
Linux · NVIDIA | fastest |
| GPU H.264 on a Mac | pip install 'habemus-papadum-rfb[mac-vt]' + mlx |
macOS · Apple Silicon | fastest on Mac |
| View in a notebook | pip install 'habemus-papadum-rfb[anywidget]' |
Jupyter · marimo | — |
The two GPU rows reach the same hardware NVENC speed; the SDK path is easier to
install — one pip install of a prebuilt wheel (habemus-papadum-nvenc) straight
from PyPI, no PyAV-18 build — and is what doctor recommends when present. Details below.
1. Core — the image path (no extras)¶
Pulls only numpy, pillow, websockets. Every frame is an independent
JPEG/PNG/WebP. Runs anywhere Python 3.12+ runs — no GPU, no compiler, no system
libraries. Good for stills, snapshots, and the lossless-final still.
2. CPU H.264 — [h264]¶
Adds PyAV (libx264). Software H.264 — far smaller than image-per-frame at the same quality, and it installs anywhere PyAV publishes wheels. No GPU required. This is the best portable video path.
2b. Mount in an ASGI app — [asgi]¶
Adds Starlette so you can host the framebuffer inside an existing
Starlette/FastAPI app (same origin, sharing its TLS and session cookie) instead of
the standalone serve() listener. Pure Python, installs anywhere; it's a front-end
choice, orthogonal to which encoder you pick. See the
ASGI / Starlette adapter guide.
2c. View in a Jupyter/marimo notebook — [anywidget]¶
Adds anywidget so display.widget() renders the framebuffer
straight into a notebook cell. The widget's JS ships prebuilt in the wheel (no Node
step); frames ride a plain WebSocket owned by the widget, not the kernel comm. Pure
Python, installs anywhere, orthogonal to the encoder — pair it with [gpu-nvenc-sdk]
for a hardware-encoded stream in the notebook. See the
notebook guide.
3. Host NVENC — [nvenc] + an NVIDIA GPU¶
Hardware H.264 through PyAV's bundled h264_nvenc. Needs a host NVIDIA driver +
an NVENC-capable card (pip can't install those). serve() auto-prefers it when
available. Frames originate on the CPU, so each one pays a CPU rgb→yuv reformat
+ a PCIe upload before the GPU encodes — see Performance; this is
why the GPU-resident paths below are much faster for GPU-rendered scenes.
4. GPU zero-copy — render on the GPU, encode with no host copy¶
If your frames are already on the GPU (CuPy / PyTorch / JAX), feed them straight to NVENC. Two routes reach the same speed; start with the SDK wheel.
4a. NVENC SDK wheel — [gpu-nvenc-sdk] (recommended GPU path)¶
NVIDIA's Video Codec SDK encoder, packaged as the self-contained
habemus-papadum-nvenc wheel (import pdum.nvenc) — a prebuilt manylinux wheel
on PyPI. No PyAV at all, no compiler, no LD_LIBRARY_PATH — just the host
driver. One ABI-agnostic wheel ships both NVENC 12.1 and 13.0 builds and loads the
one your driver supports.
pip install 'habemus-papadum-rfb[gpu-nvenc-sdk]' # the SDK encoder (habemus-papadum-nvenc); no CuPy needed
# for the zero-copy CUDA→NVENC frame path, add CuPy for your toolkit:
pip install 'habemus-papadum-rfb[gpu-nvenc-sdk,gpu-cuda13]' # gpu-cuda12 for a CUDA 12 toolkit
Verify: pdum-rfb doctor should show nvenc-gpu-pdum — NVENC SDK (pdum.nvenc): ✓ and recommend it.
This is the easiest GPU install and the fastest path measured on this hardware.
4b. PyAV 18 zero-copy — [gpu-cuda13] + PyAV ≥ 18¶
Feeds a CuPy/DLPack NV12 buffer to h264_nvenc via VideoFrame.from_dlpack. Same
hardware speed, but it needs PyAV ≥ 18 (the encode-side hw_frames_ctx wiring),
which isn't on PyPI yet — so it's a build or a prebuilt-av wheel:
pip install 'habemus-papadum-rfb[gpu-cuda13]' # CuPy (cupy-cuda12x for CUDA 12)
./scripts/install-gpu.sh # builds PyAV 18 (~1 min), or:
PYAV_WHEEL_URL=<release-url>/av-<...>.whl ./scripts/install-gpu.sh # prebuilt
Full details (the PyAV-18 requirement, the from-source recipe, the gotchas) live in Zero-copy CUDA→NVENC. Prefer 4a unless you specifically want the PyAV/ffmpeg stack.
5. Apple Silicon — VideoToolbox + MLX — [mac-vt] (macOS)¶
On a Mac, hardware H.264 comes from Apple VideoToolbox instead of NVENC. Render
with MLX and serve(gpu=True) selects the VideoToolbox encoder, converting
RGB→NV12 on the GPU — the macOS counterpart of the NVIDIA GPU paths above.
pip install 'habemus-papadum-rfb[mac-vt]' # habemus-papadum-vtenc / pdum.vtenc
pip install mlx # the GPU frame producer (repo group: mac-dev)
The [mac-vt] wheel bundles no Apple binaries — the VideoToolbox / CoreVideo /
CoreMedia frameworks are system-provided, so at runtime it needs only macOS itself.
MLX is optional: without it, serve(gpu=True) still works but converts RGB→NV12 on
the CPU (fine at ≤720p, a bottleneck at 1080p+).
Verify: pdum-rfb doctor should show vtenc — Apple VideoToolbox (H.264): ✓ and
mlx — Apple Metal (GPU RGB→NV12): ✓, and recommend the VideoToolbox path. Full
details are in the Apple Metal / VideoToolbox guide.
Platform limits (read this for the GPU paths)¶
The NVIDIA GPU wheels are not universal (the macOS [mac-vt] path is separate —
see the note below). Current NVENC support, with everything else needing a quick issue:
| Axis | Supported today | Notes |
|---|---|---|
| Python | 3.12+ | the package's requires-python; CPython only |
| OS | Linux (NVENC) · macOS/Apple Silicon (VideoToolbox, §5) | Windows GPU untested |
| Arch | amd64 (x86_64) for NVENC; arm64 for macOS | aarch64 NVENC wheels buildable but not yet published |
| manylinux | manylinux_2_34 (local build) / manylinux_2_28 (CI) |
2_28 installs on RHEL8 / Ubuntu 18.10+; 2_34 needs glibc ≥ 2.34 (Ubuntu 22.04+) |
| CUDA | 12.x or 13.x | match the CuPy extra: gpu-cuda12 vs gpu-cuda13 |
| GPU/driver | NVIDIA, NVENC-capable, recent driver | not installable by pip; libcuda/libnvidia-encode come from the driver |
The CPU paths (core, [h264]) have none of these limits — they install wherever
PyAV/Pillow wheels do. The macOS [mac-vt] path (§5) has none of the
NVIDIA-specific rows either (no CUDA, no manylinux, no driver): it needs macOS on
Apple Silicon and uses the system VideoToolbox frameworks.
Need broader support?¶
If your box is outside the matrix — aarch64 NVENC, an older glibc (need
manylinux_2_28/_2_17), a different Python, Windows GPU, or a CUDA 11
toolkit — please open an issue.
Both GPU wheels are built by on-demand CI workflows
(build-nvenc-sdk-wheel, build-pyav-cuda-wheel) that already accept a list of
Python versions and can target other manylinux tags, so adding a build is usually
cheap. In the issue, paste:
- the output of
pdum-rfb doctor, python -c "import platform,sys; print(sys.version, platform.machine())",- your NVIDIA driver / CUDA toolkit version (
nvidia-smi), and - the wheel tag that failed to install (pip prints it as "not a supported wheel on this platform").
What's on PyPI, what isn't¶
habemus-papadum-nvenc(SDK wheel) — on PyPI. Its NVIDIA SDK source is MIT, so the wheel is clean to publish; the[gpu-nvenc-sdk]extra pulls it as a normal dependency. Maintainers publish it (and the rfb package) withscripts/publish.sh; CI only builds it as a validation artifact, never publishes.- PyAV 18 (
[gpu-cuda13]route) — not on PyPI yet. PyAV 18 itself is unreleased, and the CUDA-enabled build bundles LGPL ffmpeg, so it stays on this repo's GitHub Releases. Until PyAV 18.0 ships, usescripts/install-gpu.shor a prebuilt av wheel from Releases; when it ships, the[gpu-cuda13]extra becomes a one-linepip install(just add"av>=18"to it).
PyPI forbids direct-reference (URL) dependencies in published packages, which is why the PyAV-18 wheel can't be a plain transitive dependency today — but the SDK wheel now can.