Skip to main content

habemus-papadum-vtenc (import pdum.vtenc)

macOS host NV12 → H.264 Annex B via Apple's VideoToolbox (VTCompressionSession), with no PyAV and no ffmpeg. The companion encoder for pdum.rfb (PyPI: habemus-papadum-rfb) on Apple Silicon — the counterpart of habemus-papadum-nvenc on NVIDIA. A uv workspace member of this repo. Design notes: docs/mlx_metal_videotoolbox_encoder_design.md.

Why it exists:

  1. Hardware H.264 on macOS without PyAV. VideoToolbox is the Apple-Silicon hardware encoder; this binds it directly, so the GPU path needs no ffmpeg layer.
  2. MLX-friendly. Its encode() takes any Python buffer-protocol object, so an evaluated MLX mx.array (Apple-Silicon unified memory) feeds it directly.

What's ours

Everything is ours — there is no vendored SDK (VideoToolbox/CoreVideo/CoreMedia are macOS system frameworks):

src/cpp/vtenc_ext.mm        OURS — the only native code; a thin pybind11 binding over
                            VTCompressionSession (Objective-C++).
src/pdum/vtenc/__init__.py  OURS — Python surface + single-extension loader.
CMakeLists.txt              OURS — pybind11 3.0.4; -framework links; one _vtenc module.
build-wheel.sh              OURS — self-contained wheel build (delocate).

Behaviour (matches the pdum.rfb invariants)

  • NV12 in → H.264 Annex B out (start codes, in-band SPS/PPS on every IDR — what the browser's WebCodecs VideoDecoder wants).
  • Low-latency, no frame reordering (no B-frames ⇒ output order == input order) and synchronous 1-in-1-out: each encode() returns its own frame's access unit (CompleteFrames after each submit) — required for correct seq attribution.
  • BT.601 limited range VUI (matches pdum.rfb's gpu.rgb_to_nv12 kernel), so a browser decodes the color correctly.
  • Fixed-resolution, even dimensions; one VTCompressionSession per instance.

Usage

import numpy as np
from pdum.vtenc import VtEncoder

enc = VtEncoder(1920, 1080, fps=30, bitrate=12_000_000)
nv12 = np.zeros((1080 * 3 // 2, 1920), dtype=np.uint8)   # contiguous NV12 (Y then UV)
# ... fill nv12 (e.g. from an evaluated MLX array) ...
annexb = enc.encode(nv12, force_idr=True)                # bytes; H.264 Annex B
annexb += enc.flush()
print(enc.codec_string)                                  # e.g. "avc1.420028" (from the SPS)
enc.close()

encode() accepts any contiguous (H*3//2, W) uint8 buffer-protocol object — numpy or an evaluated MLX mx.array (call mx.eval(frame) first; MLX is lazy).

VtEncoder.codec_string is the avc1.PPCCLL string derived from the actual emitted SPS (VideoToolbox picks the level from the resolution, so it is not a constant — 1080p Baseline is avc1.420028, not avc1.42E01F). Empty until the first keyframe.

Build & test (local, CMake)

cmake -S . -B build -G Ninja
cmake --build build -j

Build wheels (maintainer)

./build-wheel.sh                                 # cp314 -> dist/habemus_papadum_vtenc-*.whl
PYTHON_VERSIONS="3.12 3.13 3.14" ./build-wheel.sh

Requires only Xcode Command Line Tools (clang + the macOS SDK frameworks); the full Metal toolchain is not needed for v1. The wheel bundles nothing beyond the extension — the frameworks come from macOS, as they must. Publishing to PyPI is done by scripts/publish.sh, not from CI.

Scope / caveats

  • Fixed-resolution NV12 in, Annex B out, one encoder per instance. H.264 only (HEVC is a follow-up). No EncoderBackend/serve() wiring yet — that's the pdum.rfb integration.
  • Input is a host-visible (CPU / unified-memory) NV12 buffer, memcpy'd into an encoder-owned CVPixelBuffer. Wrapping an MLX unified-memory buffer as the CVPixelBuffer backing directly (true zero-copy) is a follow-up.

Metadata

Release files for habemus-papadum-vtenc 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for habemus-papadum-vtenc 0.3.0
File Interpreter ABI Platform
habemus_papadum_vtenc-0.3.0-cp314-cp314-macosx_12_0_arm64.whl CPython 3.14 CPython 3.14 macOS 12.0+ ARM64 Details
habemus_papadum_vtenc-0.3.0-cp313-cp313-macosx_12_0_arm64.whl CPython 3.13 CPython 3.13 macOS 12.0+ ARM64 Details
habemus_papadum_vtenc-0.3.0-cp312-cp312-macosx_12_0_arm64.whl CPython 3.12 CPython 3.12 macOS 12.0+ ARM64 Details

Total release size: 277.7 kB

Release files / habemus_papadum_vtenc-0.3.0-cp314-cp314-macosx_12_0_arm64.whl

Download URL habemus_papadum_vtenc-0.3.0-cp314-cp314-macosx_12_0_arm64.whl
Size 92.6 kB
Tags CPython 3.14 macOS 12.0+ ARM64
SHA-256 checksum
How to use checksums
c85ffa478a6e803882feffdee3904f94fd6bd034dba7aa9005d47ac4008a0907
BLAKE2b-256 checksum
How to use checksums
61c9c21f2c4e56351f86534718526ee6cb5d91ce4c8c19ab998368c801a59cf5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / habemus_papadum_vtenc-0.3.0-cp313-cp313-macosx_12_0_arm64.whl

Download URL habemus_papadum_vtenc-0.3.0-cp313-cp313-macosx_12_0_arm64.whl
Size 92.6 kB
Tags CPython 3.13 macOS 12.0+ ARM64
SHA-256 checksum
How to use checksums
aada6be76c8aed64f1d319ea0d2ae7b2eb2143707049aed270f7ba2f224054fb
BLAKE2b-256 checksum
How to use checksums
922071422d427a1b409e4fde57689b00bcf9fc407b57928c43abc36f0d5a5d6d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / habemus_papadum_vtenc-0.3.0-cp312-cp312-macosx_12_0_arm64.whl

Download URL habemus_papadum_vtenc-0.3.0-cp312-cp312-macosx_12_0_arm64.whl
Size 92.5 kB
Tags CPython 3.12 macOS 12.0+ ARM64
SHA-256 checksum
How to use checksums
59f474b4f43866fcea3d16c3b0a3c85da16ed9fa9fc055b3beb4331d381aedb2
BLAKE2b-256 checksum
How to use checksums
829e8f524459497659498b8646c37e87cb16a7bd8a2973d7fd9923c760bb5d07
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

0.3.0 This release

3 release files

0.2.1

3 release files

0.2.0

3 release files

0.1.0

3 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page