TensorCodec
TorchCodec-style video and audio decoding, without PyTorch.
- Use the CPU decoder API and playback rules of TorchCodec 0.17.0.
- Get NumPy arrays instead of
torch.Tensor. - Install NumPy + TensorCodec. No Torch, PyAV, or FFmpeg CLI at runtime.
The goal is predictable frame selection, timestamps and audio ranges with a small runtime dependency set. This is a CPU decoding subset, not the entire TorchCodec package. It does not promise a speedup over PyAV or TorchCodec.
Scope compared with TorchCodec
TorchCodec includes decoders, encoders, sampling and transforms.
Legend for both tables: ✓ supported · △ limited support · — unavailable.
| Module family | Component | TorchCodec 0.17.0 | TensorCodec 0.1.1 |
|---|---|---|---|
| Decoders | Video · VideoDecoder |
✓ | △ CPU, SDR |
Audio · AudioDecoder |
✓ | △ CPU | |
| Images | ✓ | — | |
| Encoders | Video / audio / JPEG / PNG | ✓ | — |
| Samplers | Clip sampling | ✓ | — |
| Transforms | Decoder transforms | ✓ | — |
FPS-based decoder queries are available; clip samplers are not implemented.
Decoder compatibility
| Area | Capability | TorchCodec 0.17.0 | TensorCodec 0.1.1 |
|---|---|---|---|
| Video · selection | Index / slice / batch | ✓ | ✓ |
| Playback time / range | ✓ | ✓ | |
| Order / duplicates preserved | ✓ | ✓ | |
| Exact / approximate seek | ✓ | ✓ Default: exact | |
| FPS queries / custom frame mappings | ✓ | ✓ | |
| Video · formats | CFR / VFR / offset PTS / B-frames | ✓ | ✓ Tested |
| NCHW / NHWC RGB | ✓ | ✓ | |
| uint8 / float32 | ✓ | △ SDR | |
| HDR transfer / display rotation | ✓ | — Explicit rejection | |
| Audio | Ranges / resampling / channel mixing | ✓ | ✓ float32 |
| Input / output | Paths / URLs / bytes / seekable files | ✓ | ✓ |
| Encoded array input | torch.Tensor |
1-D uint8 NumPy arrays | |
| Decoded arrays | torch.Tensor |
numpy.ndarray + array interface / DLPack |
|
| Execution | CPU | ✓ | ✓ |
| CUDA | ✓ | — | |
| Python runtime dependency | PyTorch | NumPy |
Compatibility means
- Match the supported CPU API's frame selection, ordering, timing and metadata.
- Check behavior independently and against pinned TorchCodec 0.17.0.
- Allow color-conversion rounding: at most 1 uint8 unit or 1/65535 for float32 in the tested cases. Do not claim identical pixels across every FFmpeg build.
- Accept empty index lists, including the case affected by the reference's empty-list dtype inference bug.
Details and the tested scope: compatibility contract.
Current limits
- Binary wheels: Linux x86_64 / ARM64 (aarch64), glibc 2.17+, CPython 3.10+.
- A compatible NumPy wheel is also required. On older glibc, the installer may select an older NumPy; newer Python versions may require a newer glibc.
- No macOS, Windows or musl/Alpine wheels yet; free-threaded Python is not a release target.
- Exact video seeking scans packet timestamps when opening the decoder.
- Seeking trusts container keyframe flags; incorrect flags can corrupt decoded frames. Corrected frame mappings or a repaired input are needed in that case.
- Audio range queries currently decode from the beginning; late ranges can be expensive.
- NumPy return types require caller changes where code expects Torch tensors.
- Historical avdec benchmarks are not TensorCodec performance results.
Install
uv pip install tensorcodec
Use an existing virtual environment, or create one with uv venv first.
Linux wheels bundle shared FFmpeg libraries. Source builds need Rust, libclang
and FFmpeg 7 development headers/libraries.
Use
from tensorcodec.decoders import VideoDecoder, AudioDecoder
with VideoDecoder("video.mp4") as video:
frame = video.get_frame_played_at(1.25) # frame playing at this time
print(frame.data.shape) # CHW NumPy array
batch = video.get_frames_at([4, 0, 4]) # order and duplicates preserved
clip = video.get_frames_played_in_range(0, 1, fps=8)
with AudioDecoder("audio.wav", sample_rate=16000, num_channels=1) as audio:
samples = audio.get_samples_played_in_range(0, 1)
print(samples.data.shape) # channels × samples, float32
Decoded arrays keep their storage after the decoder closes. Input file objects remain caller-owned.
Implementation
| Layer | Responsibility |
|---|---|
| Python | Public API, frame/time selection, validation, result objects |
| Rust + PyO3 | FFmpeg handles, seeking/decoding, color conversion, resampling |
| FFmpeg | Codec and container implementations |
A batch crosses the Python/Rust boundary once. Native decoding releases the GIL.
Development and verification
# Requires uv, Rust, Clang/libclang, pkg-config and FFmpeg 7 development libraries.
# Build the editable package and install development + pinned CPU oracle groups.
uv sync --group dev --group oracle
uv run --group oracle pytest tests/test_video_contract.py tests/test_audio_contract.py --backend torchcodec
uv run --group oracle pytest --compare
# Rebuild after changing Rust code.
uv run --group oracle maturin develop --locked --uv
Tests generate fixtures with FFmpeg/ffprobe and Python's wave module.
--compare requires the exact oracle version; otherwise differential tests skip.
The old avdec decoder and tests are never executed.
- Playback rules
- Release builds and PyPI publishing
- Native dependency licenses and source/build notices
TensorCodec's own code is MIT licensed.
Metadata
Release files for tensorcodec 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tensorcodec-0.1.1.tar.gz | 55.8 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tensorcodec-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| tensorcodec-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
Total release size: 21.7 MB
Release files / tensorcodec-0.1.1.tar.gz
| Download URL | tensorcodec-0.1.1.tar.gz |
|---|---|
| Size | 55.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d3398ee313245f9c299758cdbc3816153560cbbf906ba121adc6d2e1d021b9c8
|
|
BLAKE2b-256 checksum How to use checksums |
0e7789b052f349f664832c757438439778353c4edbdcdb816e6422d011af5bfa
|
| 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 Oct 1, 2026.
Transparency logRelease files / tensorcodec-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | tensorcodec-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 10.7 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
15350c7a75afa64ac01b11d81b21183d245aac789e7e8002e1ffa02f1911235e
|
|
BLAKE2b-256 checksum How to use checksums |
9bb11d6a3cfda745cf651d7c88968a9470be98fb3834100b1be826aee8011725
|
| 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 Oct 1, 2026.
Transparency logRelease files / tensorcodec-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | tensorcodec-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 10.9 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
43ad879c5fed414a20673ea59496b63148d3dfea3b3acb18e25141d40af3669d
|
|
BLAKE2b-256 checksum How to use checksums |
8e1d309a74319d7eeeb50771e06b2f691630dd7faf34b743fd8134d01a3d0940
|
| 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 Oct 1, 2026.
Transparency log