Zura Load Video
The 24 fps clock at the front of a Wan 2.2 Animate run
- video
- frames
Every Wan 2.2 Animate workflow starts with the same awkward question: where does the driving clip come from, and how long is it? Zura Load Video answers both in one node. It's the first of four nodes in ComfyUI_zura_nodes, and it's the one you'll touch on every run.
It looks boring. Two of its widgets quietly decide everything downstream.
What it actually does
You feed it a local file, or a URL, or a YouTube result. It decodes a trimmed slice at 24 fps and hands back an ordinary VIDEO wire plus the raw frames as an IMAGE.
The number that matters is duration_seconds, and the tooltip spells out why: every second is 24 rendered frames. Ten seconds in, 240 frames out. In a stock Wan graph that would be a wall - native context is 81 frames, roughly five seconds, and pushing past it without engineering gives you warps and looping. It's the field's unsolved constraint, not a settings error. Here you can ask for longer, because the chunking happens later in the sampler node. Load Video's only job is to define truth: frames, timing, audio.
The video output carries the source audio too, which is why the render node can produce a finished clip with the original soundtrack and no separate muxing node.
The inputs you'll actually set
clip- a dropdown of videos in ComfyUI's input folder. There's a Choose local video button that uploads and selects in one move, which is friendlier than the usual drag-and-drop-into-the-input-folder ritual.video_url- optional. A direct MP4 link, or a YouTube URL. Leave it empty and the dropdown wins.start_seconds/duration_seconds- the trim.source_max_side- the decode bound, 1280 by default. Drop it to 720-ish for fast preview passes; the sampler has its ownmax_sidefor the render, so this is purely "how much source detail do I want to pay for".keep_source_audio- on by default.
Outputs: video (a real VIDEO, understood by any ComfyUI video node) and frames (an IMAGE). Wire video into Zura Mask. Wire frames into a preview if you want to check the trim before committing to a 40-minute render.
How it works under the hood
ComfyUI core has no videos model category, so the node lists video files in the input directory - where uploads land anyway - plus anything a custom node has registered as a videos folder. Decoding goes through ffmpeg/ffprobe into a tensor, and the output is assembled with ComfyUI's native VideoFromComponents: a standard VIDEO, not some private payload.
One genuinely good detail: the node's cache key includes the trim, audio flag and max side, not just the file path, so changing start_seconds from 0 to 12 actually re-decodes instead of silently serving the old frames. It also returns a "always dirty" value when you're using a URL, because there's nothing stable to fingerprint. That's the correct call - the always-rerun trick is a footgun when a loader does it carelessly (ComfyUI's cache comparison semantics are genuinely subtle), but a remote URL is by definition not cacheable by path.
Install
ComfyUI Manager → search Zura Nodes. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/ZURAVFX/ComfyUI_zura_nodes
# then install the extras into the SAME python env ComfyUI runs in
pip install -r ComfyUI_zura_nodes/requirements.txt
Restart ComfyUI. The requirements are requests, yt-dlp[default] and ultralytics - ultralytics is for the mask node's person detection, not this one, but it ships with the pack. You also need ffmpeg and ffprobe on your system PATH, which is what actually decodes your clip. Nothing else models-wise: this node needs no checkpoints, no ONNX files.
The YouTube path is the only one that wants Node.js on PATH, because modern yt-dlp uses it as a JS runtime to extract YouTube streams. Local clips don't care.
Where people get burned
- ffmpeg not on PATH. The clone succeeds, the pack loads, and the first run dies on decode. Symptom is a decode error mentioning the subprocess, not a Python traceback about a missing module.
- A file that isn't in the list. Clips have to be in
ComfyUI/input/(use the picker, and this sorts itself out). The node's validator rejects paths it can't find rather than failing halfway through a render. - Confusing the two resolutions.
source_max_sidebounds the drive clip; the sampler'smax_sidebounds the render. Lowering only the first makes the pose/face conditioning coarse while the output stays expensive. - Assuming the pack is popular. It isn't - the wider community barely mentions "Zura", and this is effectively the pre-Zura Trend Studio line under new display names. The class ID is still
TrendStudioV2DrivingClipfor exactly that reason: graphs saved before the rename keep loading. Judge it on the output, not on the hype, because there is no hype.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| clip | COMBO | Uploaded clips (and any videos already in the input folder). Use the Choose local video button below, or pick from this list. | |
| video_url | STRING | Optional direct video URL (YouTube, direct MP4...). Leave empty to use the uploaded clip. | |
| start_seconds | FLOAT | 0.00–86400 | — |
| duration_seconds | FLOAT | 10.01–120 | Length of the driving clip. Every second is 24 rendered frames. |
| keep_source_audio | BOOLEAN | true | — |
| source_max_side | INT | 1280256–1920 | Decode bound for the driving frames. Lower this for fast previews. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| video | VIDEO | — |
| frames | IMAGE | — |