Nodes/H3 Relay/H3 · Prepare Source
ComfyUI Node

H3 · Prepare Source

The CPU-only node that decides whether the rest of your graph works

By akatz-ai·Created 2 months ago·Updated a day ago· 30
H3 · Prepare Source
  • video
  • reference_frames
  • source_audio
  • width
  • height
  • h3_length
  • source_frames
  • fps
  • summary
  • prepared_video
◄resolution480►
◄duration_seconds0.0►
◄missing_audiosilence►

MiniMax H3 will not accept the video you have. It wants 24 fps, dimensions on a 32-pixel grid, and a frame count from the 17n+5 family - and it will happily generate you a mangled, time-stretched mess if you feed it something close-but-not-quite. H3 · Prepare Source is the node that fixes all three, on the CPU, before any model is loaded.

It's the front door of the H3 Relay toolkit, and the one to understand first: half the other nodes' inputs are numbers it prints.

What it's actually for

H3 is a 33B omni-modal model that generates picture and stereo audio in one pass at 24 fps (the model panel has the full story). That single-pass AV design is why the timing surface is so rigid: audio and video are packed into the same latent timeline, so "just stretch it to fit" isn't available to you.

What makes this node different from a generic video-prep chain is that it is source-exact. It returns the padded model length and the real source length as two separate outputs. The padding exists so H3 gets a legal window; it is never delivered in your final clip. Every downstream node in the pack is built around that distinction, and if you ignore it you'll spend an evening wondering why your 8-second shot renders 9 frames too long.

How it works

It shells out to ffprobe for the real display dimensions - including sample aspect ratio and rotation metadata, which is where phone footage usually gets silently squashed - then picks a canvas that fits a pixel budget (500,000 for 480, 1,000,000 for 768) by searching the 32-px grid near the ideal area-scaled size. Naively rounding both axes up is how you blow past that budget and OOM on a 24 GB card.

Then it resamples to 24 fps with an aspect-preserving center crop onto that grid, computes the legal H3 length (5 + 17n frames, capped at 3592 frames ≈ 149.7 s), and decodes the audio to a waveform at the same clock.

Inputs and outputs that matter

The one input you must wire is video - ComfyUI's native VIDEO type, so a Load Video node drops straight in. resolution is the only real decision: 480 (500k pixels) is the sane default for iterating, 768 when you've accepted the shot. duration_seconds at 0 keeps the whole clip; a positive value snaps to the nearest legal H3 length and never extends your source. missing_audio defaults to silence, which synthesizes a silent 48 kHz stereo track so the audio VAE still gets a reference.

From the outputs, three go somewhere useful:

  • source_frames - the unpadded count. Wire this into H3 · Plan Windows and into every mask tool's source_frames. This is the number the whole timeline is built from.
  • reference_frames - the prepared IMAGE batch, tail-padded for H3. Feeds SAM detection/tracking and the Window Inputs node.
  • source_audio - the decoded original audio, used as the history audio and as the final mux, so your finished clip keeps its real sound instead of H3's hallucinated room tone.

Plus width, height, h3_length, fps and a readable summary, and prepared_video - a VIDEO you can wire to a native Save Video node to eyeball the prep before spending GPU time.

Install

In ComfyUI Manager, search H3 Relay, install, restart. Manual:

cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/akatz-ai/h3-relay.git

Then restart again. The pack's pyproject.toml declares no pip dependencies (dependencies = []), but this node does need ffmpeg and ffprobe on PATH, because it invokes them directly. It also needs ComfyUI 0.37.0 or newer - the README's Requirements section says 0.32.0 in one place, which is stale; the version pin in pyproject.toml and the graph notes both say 0.37.0.

You'll also want the H3 weights before anything downstream of this can render:

hf auth login
cd /path/to/ComfyUI
hf download Comfy-Org/MiniMax-H3 \
  diffusion_models/minimax_h3_fl2va_int8_convrot.safetensors \
  diffusion_models/minimax_h3_ref2va_int8_convrot.safetensors \
  text_encoders/qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors \
  vae/minimax_h3_video_vae_fp16.safetensors \
  vae/minimax_h3_audio_vae_fp32.safetensors \
  --local-dir models

One non-technical thing: the MiniMax H3 Community Licence excludes the US, EU, UK and South Korea from its applicable territory, outputs included. The code is GPL-3.0 and free; the weights are not, in those regions.

Where people get burned

The node runs on CPU and never loads a model, so when it fails it fails fast and up front - which is a gift. A missing ffprobe produces a straight error here, not a mysterious failure twenty nodes later in the sampler.

The real trap is picking the wrong output number. source_frames is the count of frames that actually exist. h3_length is what the model will legally accept, which is larger. Wire h3_length into the planner and it will plan windows over frames that don't exist, and the whole run dies on a coverage check.

CategoryH3 Relay/timeline

Inputs (4)

NameTypeDefaultDescription
videoVIDEO—
resolutionCOMBO480Preserve aligned sources within the pixel budget; otherwise fit the H3 canvas.
duration_secondsoptFLOAT0.00–149.66Keep the requested source duration. Model padding is excluded from the final output. Zero keeps the full source.
missing_audiooptCOMBOsilence2 options: silence, none

Outputs (9)

NameTypeDescription
reference_framesIMAGE—
source_audioAUDIO—
widthINT—
heightINT—
h3_lengthINT—
source_framesINT—
fpsFLOAT—
summarySTRING—
prepared_videoVIDEO—