IAMCCS H3 Disk Upscale · 2 Tiled Refine + Stream
A Sampled Upscale That Never Holds the Whole Clip at Once
- model
- conditioning
- noise
- sampler
- sigmas
- video_vae
- fun_control_param
- inpaint_param
- segment_path
- segment_manifest_path
- report
There are two honest ways to make an H3 clip bigger, and this node is the expensive, better-looking one. Instead of asking an upscaler model to interpolate detail, it runs actual diffusion over the upscaled latent - in tiles, over time chunks, with the source as the guide. That's the tile-ControlNet lineage the knowledge base describes as the print-size answer on limited VRAM: arbitrary output dimensions on a card that can't hold the whole latent.
The reason you'd reach for it over Learned 3D is detail that isn't there. A learned 3D latent lift is fast and grid-free, but it's still an upscaler - it sharpens what exists. This one can put texture back into skin, fabric and hair because it's sampling.
The reason you might not is that it wants a full sampler stack, and it's slow.
How it works
You hand it a checkpoint path from Save AV Checkpoint plus model, conditioning, noise, sampler, sigmas and video_vae - yes, the whole sampler rig, because it is going to sample. The work is delegated to the external MMH3UltimateUpscale node class with a tiled parameter set built from your widget values, then the refined AV latent is decoded to MP4 via the pack's vendored streaming saver (one decode group at a time, so the peak is a chunk rather than the film), then ffmpeg trims the technical prefix and, for cut joins, the overlap - and the result is validated: exact frame count, exact canvas, audio present. Only then does it get published as segment_00000.mp4 with a manifest.
The 32-alignment is not cosmetic. The internal upscale canvas is snapped up to a multiple of 32, and the node refuses to run if your target is smaller than the native H3 canvas - this is an upscaler, not a resizer.
The knobs that matter
- target_width / target_height - delivery size. Pick it before you start; the whole stage is priced in tiles × frames.
- tile_width / tile_height - 512×384 default. Smaller tiles mean lower peak VRAM and more chances for visible tile seams; overlap is the mitigation.
- spatial_overlap - 96 by default. This is your seam insurance.
- temporal_chunk_frames / temporal_overlap_frames - 68/17 by default, both on the 17-frame H3 grid. Chunk too short and motion within a chunk has no history; too long and you're back to OOM. 68 frames of context is about three seconds at 24 fps.
- upscaler_device / upscaler_precision -
cuda+fp16unless you're debugging. - decode_groups_per_chunk - how many latent groups get VAE-decoded per streaming step. Raise it for speed if you have headroom, lower it if the decode is what's killing you.
- upscaler_model - populated from
models/latent_upscale_models, filtered to.safetensorswhose names containminimax,h3and3d. If that dropdown is empty, you haven't installed the model, and the node will tell you exactly that.
There are two optional inputs, fun_control_param (H3 ControlNet) and inpaint_param. Both are strict: ControlNet requires its upscale mode set to per_tile, its own canvas to match the 32-aligned H3 canvas, and a guide that covers the full decoded source segment. Half-configured control params fail with an explanation rather than producing a soft result.
Outputs: segment_path, segment_manifest_path and report - all feeding Assemble Film or your own inspection.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/IAMCCS/IAMCCS-nodes.git
Then restart and hard-refresh. Two extras this node actually needs:
- Comfyui-MMH3-Ultimate-Upscale - the node class it calls. Without it you get a runtime error naming the missing pack, which is at least a clear failure.
- ffmpeg on PATH plus a current PyAV, since trimming and frame validation both depend on them.
And, per the pack's README, run Stage 1 and Stage 2 as separate queue prompts. Same graph, two runs: the first generation's model and decoded batch need to be gone before the tiled pass allocates anything.
Traps
The failures here are almost all arithmetic, and the node is loud about them, which is a mercy. It refuses to overwrite existing output, so re-running the same render_id + segment_index needs a decision from you rather than a silent replace. It refuses a checkpoint whose SHA-256 changed. Crossfade joins need at least two overlap frames and an overlap shorter than every segment - mix cut and crossfade across segments and the assembler will stop you.
The one that isn't arithmetic: tiling plus resampling means your guide matters more than your settings. If the low-res source has already smoothed the detail away, no amount of tile tuning invents it back. That's the general rule from the upscaling docs - generative upscalers rewrite what they touch, and running one per tile per time chunk is a lot of rewriting. Watch faces.
Inputs (20)
| Name | Type | Default | Description |
|---|---|---|---|
| checkpoint_path | STRING | — | |
| model | MODEL | — | |
| conditioning | CONDITIONING | — | |
| noise | NOISE | — | |
| sampler | SAMPLER | — | |
| sigmas | SIGMAS | — | |
| video_vae | VAE | — | |
| upscaler_model | COMBO | 1 options: | |
| target_width | INT | 1920256–3840 | — |
| target_height | INT | 1080256–2160 | — |
| tile_width | INT | 512128–2048 | — |
| tile_height | INT | 384128–2048 | — |
| spatial_overlap | INT | 960–512 | — |
| temporal_chunk_frames | INT | 6817–340 | — |
| temporal_overlap_frames | INT | 170–170 | — |
| upscaler_device | COMBO | cuda | 2 options: cuda, cpu |
| upscaler_precision | COMBO | fp16 | 3 options: fp16, bf16, fp32 |
| decode_groups_per_chunk | INT | 11–8 | — |
| fun_control_paramopt | H3_FUN_CONTROL_PARAM | — | |
| inpaint_paramopt | H3_INPAINT_PARAM | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| segment_path | STRING | — |
| segment_manifest_path | STRING | — |
| report | STRING | — |