Video Frame Reader
Step Through a Video One Frame at a Time — Without Loading the Whole Thing Into RAM
- video
- frame
Video Frame Reader is the front door of the comfyui-frame-step pack, and it solves a genuinely annoying problem: getting a single frame out of a video without blowing up your memory. It takes a VIDEO input, steps it forward one frame at a time, and hands you a plain IMAGE you can feed into anything - img2img, a ControlNet preprocessor, a detailer, or just a Save Image node for frame export.
Why does that matter? A 640×480 clip with 1,800 frames is already around 6.6 GB sitting in ComfyUI's float32 pipeline if some node eagerly decodes the whole thing. This node deliberately does the opposite: it streams through PyAV's decoder and keeps only what it needs. If you've ever watched ComfyUI grind to a halt loading a "short" video for a video-to-video workflow, you'll feel the difference immediately.
How it works
The mechanism is a streaming decoder plus a smart cache. The node keeps its last-opened container and decoder around, so when you step to the next frame it just decodes one more - no re-opening, no seeking. If you jump somewhere random, it re-opens the file and decodes forward from the start to reach it. That's correct but slow, so think of forward stepping as the fast path and random access as "it works, just give it a second." There's no true seek here.
The frame_index input uses the exact same control_after_generate widget as a KSampler seed. Set it to increment and hitting Run repeatedly plays the video forward; set it back to 0 to rewind. No separate reset button, no IS_CHANGED hack - the frontend just bumps the widget for you. It's the nicest touch in the whole pack.
The inputs that matter
Only two, and they're both simple:
frame_index- which frame to grab. Default 0. Leave it on increment for playback.on_end- what happens when you run past the last frame.loop(default) wraps back to frame 0;stopraises a clear error instead. If you're running a loop, keep it onloop- a red node mid-playback is a jarring way to find the end of the file.
The video input takes the VIDEO type straight from core's LoadVideo node. The output, frame, is a plain IMAGE - so it drops into literally anything.
One detail worth knowing: the total frame count isn't known up front (PyAV's metadata is often wrong about it), so the node discovers the true length the first time playback actually runs off the end. From then on, wrapping is exact.
Installing it
It's part of comfyui-frame-step, so install the pack once and you get all four nodes. The easiest route is ComfyUI Manager - search "comfyui-frame-step" - or clone it manually:
cd ComfyUI/custom_nodes
git clone https://github.com/NobutakaKuroki/comfyui-frame-step
cd comfyui-frame-step
pip install -r requirements.txt
Then restart ComfyUI. The only dependencies are av (PyAV) and opencv-python-headless - and crucially, there are no model files to download at all. It's pure code, MIT-licensed, written by Dr. Nobutaka Kuroki at Kobe University as a teaching pack. The sample clip lives in the repo's examples folder; copy it into your input folder to follow along with the bundled workflows.
Where people get burned
If you jump to frame 500 and it feels slow - that's the no-seek thing, not a hang. Just wait. And if on_end is set to stop and you loop through a long queue, expect a red node the first time a run crosses the end; flip it to loop unless you specifically want the error as a signal.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| video | VIDEO | — | |
| frame_index | INT | 00–4294967295 | — |
| on_end | COMBO | loop | 2 options: loop, stop |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| frame | IMAGE | — |