iterframes
Video frames as NumPy arrays, decoded while your code is busy with the last one.
import iterframes
for frame in iterframes.read("video.mp4", height=224, width=224):
model(frame) # (224, 224, 3) uint8 RGB, resized by FFmpeg, no copy
model runs on one frame while a Rust thread decodes the next ones. That
thread never takes the GIL, so decoding overlaps with your work instead of
adding to it, even when your code is pure Python. pip install iterframes
brings FFmpeg with it: nothing else to install, no system packages, no
ffmpeg binary to call.
The landing page at alesanfra.github.io/iterframes shows what the decoder does while your loop runs. The documentation is at iterframes.readthedocs.io: the guides explain the features, the API documents every argument and error, and the development guide covers building from source.
Numbers
One video, 901 frames of 480x270 H.264, decoded and converted to RGB,
best of seven runs on an Apple silicon Mac with the bundled FFmpeg 9.0.2.
The benchmarks are in
tests/test_benchmark.py;
run them on your own videos before believing them.
| Time | |
|---|---|
| Every frame, iterframes | 0.046 s |
| Every frame, PyAV, same decode and conversion | 0.208 s |
| 32 frames at random positions | 0.036 s |
First 10 frames (stop=10) |
0.003 s |
Second half (start=450) |
0.028 s |
In the overlap benchmark, which upscales the same video to 1080p, adding per-frame work as expensive as decoding took 16% longer in total, not twice as long: the decoding had already happened.
What you get
- Frames without copies. RGB
uint8arrays of shape(height, width, 3), straight out of FFmpeg's buffers. - Batches as one array.
read_batchesdecodes into a single(batch, height, width, 3)block, ready for a model. - Resizing while decoding, not a
cv2.resizeafterwards, from nearest to Lanczos. - Random access. Read frames by number, without decoding the rest.
- Hardware decoding on NVIDIA GPUs (NVDEC) and Apple silicon (VideoToolbox), in the wheels. On NVIDIA the frames can stay on the GPU for PyTorch.
- Wheels for Linux (x86_64, aarch64), macOS (Apple silicon), and Windows, for every CPython from 3.11 on.
# Batches of 12 frames, decoded into one (12, 224, 224, 3) array
for batch in iterframes.read_batches("video.mp4", 12, height=224, width=224):
...
# Stop whenever you like; the decoder stops with the loop
for index, frame in enumerate(iterframes.read("video.mp4")):
if index == 100:
break
Random access
Sample clips for training, or grab a thumbnail, without reading the whole file:
clip = list(iterframes.read("video.mp4", frames=[0, 30, 60]))
every_fifth = iterframes.read("video.mp4", start=100, stop=200, step=5)
last = next(iterframes.read("video.mp4", frames=[-1]))
Both work with read_batches. Negative numbers count from the end, and
frame n is the one read yields n-th. iterframes indexes the file
once, without decoding it, then decodes each frame from the key frame
before it; frames asked for in order cost no more than reading the video
straight through. See
Reading frames by number.
When a frame nearby will do, approximate reads the key frame closest to
each of frames, which costs one decoded frame instead of the frames from
the key frame on:
# The nearest key frame within 5 frames, else the frame itself.
frames = list(iterframes.read("video.mp4", frames=[100, 200, 300], approximate=5))
See Approximate frames.
Hardware decoding
Pass device to decode on a GPU instead of the CPU, which then stays free
for your model. The names are PyTorch's:
# NVIDIA GPU on Linux and Windows; with height and width, the GPU resizes too
for frame in iterframes.read("video.mp4", height=224, width=224, device="cuda"):
...
# Apple silicon (VideoToolbox)
for frame in iterframes.read("video.mp4", device="mps"):
...
# Whatever the machine has, else the CPU
for frame in iterframes.read("video.mp4", device="auto"):
...
print(iterframes.DEVICES) # ('cpu', 'mps') on a Mac
The frames still arrive as NumPy arrays in memory. A GPU saves CPU time but is not always faster than the CPU decoder, so measure both; see Hardware decoding.
With an NVIDIA GPU, on_device=True keeps the frames on it, in NV12, for
PyTorch and other libraries to take without a copy:
import torch
for frame in iterframes.read("video.mp4", device="cuda", on_device=True):
y = torch.from_dlpack(frame.y) # (height, width) uint8, on the GPU
uv = torch.from_dlpack(frame.uv) # (height / 2, width / 2, 2)
Frames on the GPU shows how to convert them to RGB there.
Compared with OpenCV, decord, and PyAV
| iterframes | OpenCV VideoCapture |
decord | PyAV | |
|---|---|---|---|---|
| Decoding runs | Ahead of your code, on a background thread | When you call read() |
When you index the reader | When you ask for the next frame |
| Pixels | RGB | BGR | RGB | Any format FFmpeg supports |
| Resize while decoding | Yes | No, with cv2.resize after |
Yes | Yes, with reformat |
| Batches as one array | Yes, read_batches |
No | Yes, get_batch |
No |
| Seeking and random access | Yes, frames=[...] or start, stop, step |
Yes | Yes, fast | Yes |
| Audio, encoding, muxing | No | Encoding with VideoWriter |
Audio reading | Yes |
| Hardware decoding | NVIDIA, Apple silicon, in the wheels | Depends on the build and backend | NVIDIA, when built from source | Depends on the build |
| Latest wheels | Linux, macOS, Windows, CPython 3.11+ | Linux, macOS, Windows | x86_64 only, last release in 2021 | Linux, macOS, Windows |
Pick iterframes to read videos into a model, in order or by frame number, and keep decoding out of your loop's way. Pick PyAV when you need the rest of FFmpeg: audio, encoding, streams, or precise control over the decoder. OpenCV is the natural choice when the rest of the pipeline already uses it.
Installation
pip install iterframes
The wheels bundle FFmpeg and work on any CPython from 3.11 on, on Linux (x86_64, aarch64), macOS (Apple silicon), and Windows (x86_64). Other platforms build from source, FFmpeg included.
Contributing
Contributions are welcome. The development guide lists features that are waiting for someone to build them.
License
iterframes is released under the Apache License 2.0.
The wheels include FFmpeg, built under the LGPL, and
dav1d, under the BSD 2-clause
license. They are listed in
NOTICE, with
their license texts in
licenses/.
Metadata
Release files for iterframes 0.7.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 | |
|---|---|---|---|
| iterframes-0.7.0.tar.gz | 1.5 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| iterframes-0.7.0-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| iterframes-0.7.0-cp311-abi3-manylinux_2_28_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ x86-64 | Details |
| iterframes-0.7.0-cp311-abi3-manylinux_2_28_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ ARM64 | Details |
| iterframes-0.7.0-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 36.4 MB
Release files / iterframes-0.7.0.tar.gz
| Download URL | iterframes-0.7.0.tar.gz |
|---|---|
| Size | 1.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dc613230d16cc47b2efe4358143f7efe64559cacf2f436c68460b824ded8dde1
|
|
BLAKE2b-256 checksum How to use checksums |
d06ba04e23cf26077e60528deabba879e086a6c5a2a0a7b25b849f4dfbd68036
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / iterframes-0.7.0-cp311-abi3-win_amd64.whl
| Download URL | iterframes-0.7.0-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 7.5 MB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
974a03cf2470265aec9aa758e849f9413999c23c337636f7612d6a3320233ad1
|
|
BLAKE2b-256 checksum How to use checksums |
95bfc778893da5b95c9d25d8d8db3a993e1b45d54eeb7f4385546f9e69b5aba6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / iterframes-0.7.0-cp311-abi3-manylinux_2_28_x86_64.whl
| Download URL | iterframes-0.7.0-cp311-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 10.1 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
1d62a050f27b7add970e4dd34a7e52ffd84dfd198de8b191108f5907db3d2bea
|
|
BLAKE2b-256 checksum How to use checksums |
3fa920b798fbe471f6b538bcf0b3e9c18caff7b1f606b45a0a12079f15ae8f92
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / iterframes-0.7.0-cp311-abi3-manylinux_2_28_aarch64.whl
| Download URL | iterframes-0.7.0-cp311-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 9.5 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
53a506e744b0858d859746931c877f3c255ebbf193c749cc4fe991245a0abb35
|
|
BLAKE2b-256 checksum How to use checksums |
2c4554c2f5b83a3a244ed12bca229913abf98713a628f58ab544efe27679f862
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / iterframes-0.7.0-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | iterframes-0.7.0-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 7.7 MB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
7aa02c959eb452fee87e8ae985db99b10459a3cf1df6a5d24788a35aa9afbe11
|
|
BLAKE2b-256 checksum How to use checksums |
ec25e2f5ffd8550e0905109bc31aa7dbb9a9b8a3bbc9ce68a497e3ba34afd3f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|