pypixelpack
Pixel layouts and wire encodings for video I/O, device-free.
The bytes a video frame becomes on a wire — v210, r210, the ST 2110-20 pgroup — and the encoding between a frame's RGB and those bytes: colour matrix, range, chroma subsampling. Written once against a caller-supplied array namespace, so the same source packs on numpy for a host frame and on torch for a frame that never leaves a GPU.
Extracted from pydecklink's packing module and a GPU render pipeline's colorspace node, which held the same layout twice. This repository's SPEC.md and ROADMAP.md govern the package.
Installation
uv add pypixelpack
numpy is the only dependency. torch is a namespace the caller supplies,
never a dependency of this package (§spec:backend).
Usage
import numpy as np
from pypixelpack import decode, encode, pack, unpack
rgb = np.zeros((1080, 1920, 3), dtype=np.float32) # [R, G, B] in [0, 1]
codes = encode(rgb, subsampling="422") # (H, W, 3) uint16 [Y, Cb, Cr]
data = pack(codes, "v210", row_bytes=5120) # 1-D uint8, DMA-ready
back = unpack(data, "v210", width=1920, height=1080, row_bytes=5120)
rgb_again = decode(back, subsampling="422") # float32 [R, G, B] in [0, 1]
On a GPU host, pass the namespace and the arrays stay resident:
import torch
codes = encode(rgb_on_cuda, subsampling="422", xp=torch)
data = pack(codes, "v210", row_bytes=5120, xp=torch)
API
pack(pixels, layout, row_bytes, *, xp=numpy)—(H, W, channels)integer samples to a 1-Duint8buffer ofH × row_bytesinlayout, on the input's device (§spec:layouts). RGB layouts take[R, G, B];v210and2vuytake[Y, Cb, Cr]with chroma read from even columns;ay10takes[Y, Cb, Cr, A]with a per-pixel alpha.unpack(data, layout, width, height, row_bytes, *, xp=numpy)— the inverse;unpack(pack(x)) == xfor every layout. Returnsuint8for 8-bit layouts anduint16otherwise.row_bytes(layout, width)— the smallestrow_bytesthat holds a line.channels(layout)— 3, or 4 for a layout inALPHA_LAYOUTS.LAYOUTS— the layout table,name → (pixels per group, bytes per group, bit depth):argb,bgra,r210,r10b,r10l,v210,2vuy,r12b,r12l,ay10.
pack raises ValueError for an unknown layout, a row_bytes shorter
than the packed line, or a sample above the layout's bit depth; the
last check is skipped under torch.compile, where a compiled caller
trusts its own inputs (§spec:backend).
Encoding
encode(rgb, *, matrix="bt709", levels="narrow", layout=None, bits=None, subsampling=None, xp=numpy)—(H, W, 3)float RGB in[0, 1]to(H, W, 3)uint16[Y, Cb, Cr](§spec:encoding).matrixisbt709orbt2020;levelsisnarrow(luma 16–235, chroma 16–240 at 8 bits, shifted up bybits - 8) orfull.layout="v210"selects the depth and subsampling that wire format expects — 10-bit 4:2:2;2vuyis 8-bit 4:2:2 — and abitsorsubsamplingthat contradicts it is refused; without a layout they default to 10 and444.422averages chroma over each horizontal pair and writes it to both pixels, the shapepackreads. Rounding is half to even, arithmetic is float32 on every backend, and codes clamp to the level range's span.decode(ycbcr, *, matrix, levels, layout=None, bits=None, xp=numpy)— the inverse, per pixel, to within half a code per component; returnsfloat32RGB clamped to[0, 1].encoding_for(layout)— the(bits, subsampling)a layout carries;ENCODINGSis the table behind it.legal_codes(*, levels="narrow", bits=10)— the(luma, chroma)code spans asrangeobjects;len(legal_codes().luma)is 877, the levels 10-bit narrow range can represent.MATRICES—name → (KR, KB):bt709,bt2020.
encode and decode raise ValueError for an unknown matrix, levels or
subsampling, a bits outside 8–16, or a layout with no component
encoding.
Development
uv sync
uv run ruff format --check . && uv run ruff check . && uv run pyright && uv run pytest
uv sync installs torch (CPU) into the dev group so the parity suite
runs; without it those tests skip. To prove the wheel on numpy alone:
uv build
uv run --isolated --no-project --with dist/*.whl python tools/check_core_install.py
License
BSD-3-Clause. See LICENSE.
Release files for pypixelpack 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pypixelpack-0.3.0.tar.gz | 57.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pypixelpack-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 73.2 kB
Release files / pypixelpack-0.3.0.tar.gz
| Download URL | pypixelpack-0.3.0.tar.gz |
|---|---|
| Size | 57.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
252a1983a32d744bca3d4e48225f6c77ad7d5e13f814d8202fc7972e25a4ca50
|
|
BLAKE2b-256 checksum How to use checksums |
4de2f371a20adce1cd1111c99220b167217f1d64a5f36a1ab3e781dd1132e2e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / pypixelpack-0.3.0-py3-none-any.whl
| Download URL | pypixelpack-0.3.0-py3-none-any.whl |
|---|---|
| Size | 15.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
908d8110549959f33ffd6c41615a1493672f77527e381834aa77bb8580409712
|
|
BLAKE2b-256 checksum How to use checksums |
b1b4b1215ce38a5bd67a00c04304ff0ad36e3d5b63ac041a31e41ab679572c12
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log