Nodes/ComfyUi-MpiNodes/Mpi H3 Decode AV
ComfyUI Node

Mpi H3 Decode AV

Finish a MiniMax H3 inpaint without smearing the rest of the frame

By MadPonyInteractive·Created 11 months ago·Updated a day ago· 3
Mpi H3 Decode AV
  • samples
  • vae
  • images
  • mask
  • images
mask_start0
mask_end-1
feather11

If you've used MiniMax H3 in ComfyUI - the 33B open-weights video model with the jointly generated soundtrack - you'll have hit its one structural quirk fast. Core encodes video and audio separately and gives you no way to join them back into the single AV latent that everything downstream expects. This node is the return half of the pack's answer. Its sibling MpiH3EncodeAV packs your frames, your soundtrack and your inpainting mask into one joint AV latent; you sample; and MpiH3DecodeAV decodes the video half and composites it back over your original footage through the same mask.

What comes back is your original clip, changed only inside the mask - bit-identical pixels everywhere you didn't ask to touch, which is exactly what instruction-edit models can't give you and why masked inpainting still has a job.

The trick: original pixels, not a VAE round trip

Here's the move that makes this node worth more than a plain decode. A normal decode of the sampled latent gives you a VAE round trip of everything, quietly softening the parts you never asked to change. This node decodes only the video half and composites it through the mask, so everything outside the mask is the original pixel, byte for byte. For H3 object removal or fixing a subject that walked out of shot, that's the entire game.

The audio half is deliberately not decoded - there's no audio_vae input and that's not an oversight. The encode masks audio all-keep, so the soundtrack that comes back would be identical to the one that went in; a round trip through the audio VAE could only make it worse. You wire your original AUDIO straight past this node to the combine.

The inputs that matter

Required: samples (the sampled AV latent), vae (the H3 video VAE), and images - the original frames the encode was given, not the decode. Everything outside the mask is taken from images.

Optional: mask - the same mask the encode got (1 = regenerate, 0 = keep). Leave it unconnected and you get the raw decode, no compositing. mask_start / mask_end place a range-only mask on the right frames and must match the encode's. feather (default 11, pixels, 0 = hard cut) softens the seam.

One output: images, the composited clip, ready for the save or the next stage.

How the feather actually behaves

feather is dilate-then-Gaussian, transcribed from LanPaint's blend_overlap. The order matters: dilating before smoothing puts the whole ramp outside the mask you drew, so the inpainted content keeps full strength at its own edge - a plain blur ramps inward too and reads as the inpaint not having taken. One deliberate divergence: replicate instead of zero padding, so a mask touching the frame border (a subject leaving frame) isn't faded away there, where LanPaint drops it to 0.58.

The 17k+5 trap

H3 only generates frame counts on a 17k+5 grid at 24 fps - 5, 22, 39, 56… An inpaint needs the clip to survive the encode→decode round trip frame-for-frame, and off-grid clips don't: 6 frames come back as 5, the VAE dropping the sixth without complaint. The encode raises on off-grid masked clips naming the nearest valid count, and this node independently raises when the latent decodes to a different number of frames than your images. Fix it with MpiH3Length (same pack) - snap the clip to the grid before encoding.

Install

In ComfyUi-MpiNodes by Mad Pony Interactive - search "ComfyUi-MpiNodes" in ComfyUI Manager and restart, or:

cd ComfyUI/custom_nodes
git clone https://github.com/MadPonyInteractive/ComfyUi-MpiNodes

No pip deps, no model downloads. You still need the H3 weights and its VAE via the usual ComfyUI loaders - this node just operates on what they produce. Worth knowing the pack went AGPL-3.0 at 1.2.7 (MIT before that), which only matters if you plan to redistribute.

Common issues

  • "The latent decodes to N frames but M original frames were given." Clip isn't on the 17k+5 grid. Snap it with MpiH3Length and re-encode.
  • "carries video only." You fed a plain video latent, not the joint AV pair - the encode needs an audio_vae and the clip's soundtrack.
  • Seam visible. Nudge feather up; for a deliberately hard boundary set it to 0.
  • Everything outside the mask looks re-generated. You wired the decoded frames into images - the node composites onto whatever you hand it, so feed it the originals.
CategoryMpiNodes/Utils

Inputs (7)

NameTypeDefaultDescription
samplesLATENTThe sampled AV latent.
vaeVAEThe H3 video VAE.
imagesIMAGEThe ORIGINAL frames the encode was given. Everything outside the mask is taken from here, not from the decode.
maskoptMASKThe SAME mask the encode was given (1 = regenerate, 0 = keep). Unconnected returns the decode whole, with no compositing.
mask_startoptINT00–100000Must match the encode's mask_start.
mask_endoptINT-1-1–100000Must match the encode's mask_end.
featheroptINT110–101Softens the mask edge, in pixels, so the seam does not show (0 = hard cut). Dilate then Gaussian, matching the LanPaint blend_overlap: the ramp sits OUTSIDE the mask you drew, so the inpainted content keeps full strength at its own edge.

Outputs (1)

NameTypeDescription
imagesIMAGE