Nodes/H3 Latent Relay/🔗 H3 Relay · Trim AV
ComfyUI Node

🔗 H3 Relay · Trim AV

Cut the replay out of the join — and cut the audio with it

By ZenHG·Created about a month ago·Updated 2 days ago· 36
🔗 H3 Relay · Trim AV
  • images
  • audio
  • images
  • audio
  • report
  • prev_tail
◄trim_frames-1►
◄fps24.000►
◄settle_frames0►
◄seam_ghost0►
◄seam_ghost_alpha0.50►
◄settle_sharpen0.00►
◄settle_sharpen_frames24►
◄lowfreq_pull0.00►
◄lowfreq_frames12►
◄lowfreq_blur16►
◄deconv_strength0.00►
◄deconv_radius1.5►
◄detail_borrow0.00►
◄detail_blur9►
◄hist_match0.00►
◄wb_match0.00►
◄match_prev0.00►
◄match_prev_frames12►
◄match_prev_gain_max1.15►
◄match_prev_offset_max0.06►
◄run_id►
◄save_pcmtrue►
◄diagnosticsfalse►

Here's the thing nobody tells you about latent continuation: the first N frames of a continued segment aren't new content. They're the model's regeneration of the previous segment's tail - same shot, sampled twice, around 6/255 mean absolute error per frame. Measured properly, segment B's first frame matches frame −22 of segment A at MAE 3.09, while the next-best candidate sits at 17.5. A real match, not coincidence.

The consequence is that if you just concatenate the two segments, you get about 0.92 seconds of the same action playing twice. H3RelayTrimAV cuts it. It takes the decoded frames, drops the overlap off the head, and cuts the audio by the same number of samples so the two don't drift apart. Framing it as "trim" undersells it slightly - it's the node that keeps your A/V in sync across a whole film.

The amount is automatic: wire the bridge's trim_frames output into this node's trim_frames input. On segment 1 the bridge passes through and hands over 0; from segment 2 onward it's the pin count (22, typically). Type a number in by hand and you'll eventually disagree with the bridge - the input's own tooltip says as much.

Inputs you actually touch

Required: images (from your VAEDecode), trim_frames (from the bridge - don't type it), fps (24, leave it).

audio is optional in the schema and mandatory in practice: feed it from VAEDecodeAudio. Without it, the picture gets cropped and the sound doesn't, and the audio ends up longer than the video by the trim amount - about 0.9 s per seam, compounding. If the node's report line says it found no audio wired, take that seriously; it can detect a missing input, but it cannot detect a downstream wire you've left dangling, which is why the pack ships a workflow checker for that specific mistake.

Then the one parameter with a real recommendation attached: settle_frames stays at 0. Historically people cropped the extra "settle" frames that follow the pinned region - the model replays a few frames before switching to new content, and they're a bit soft. Cropping them makes the seam jump. Measured on the same segment, varying only this value: crop 0 → seam jump 0.020 (essentially invisible), crop 8 → 0.044, crop 16 → 0.055. What you leave in is a sharpness gradient, and the eye is extremely forgiving of those. Trading a gradient for a discontinuity is a bad deal, so 0 is now the default. -1 measures a cut point automatically (fixes softness, introduces jumps - inspect it), and a positive N crops a fixed number of frames, which you'd only do to keep segments equal length.

save_pcm (on) writes an extra ~2 MB PCM sidecar per segment so concatenation reads lossless audio instead of decoding the AAC track in the mp4 and re-encoding it - your finished film's audio is then one generation, not two. A failed write only logs. diagnostics (off) turns on three read-only reporting paths: DTW alignment cost, a crop-versus-jump curve, and appearance drift. Pure printing, ~0.4 s of CPU per segment, zero GPU, no effect on any output.

Outputs: images, audio, report, and prev_tail - the last frame of the pinned region, i.e. the frame on the other side of the seam. prev_tail feeds the Post node's guide. Whether it's genuinely the previous segment's final frame depends on which bridge route you used, and the pack is upfront about that: under the bit-exact copy bridge it is; under conditioning-only pinning it's a redraw and therefore approximate.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/ZenHG/ComfyUI-H3-Latent-Relay.git

Or ComfyUI Manager → Custom Nodes Manager → search h3-latent-relay. Restart the backend process. Nothing to download; this node works on decoded tensors and needs no models beyond what ComfyUI and H3 already provide.

Where it goes wrong

"Asked to crop N frames but this segment only has M" means trim_frames got the wrong value - usually hand-filled, or wired from the wrong output. Take it from the bridge.

Segment looks like it starts over. Trim AV isn't connected, or its trim_frames isn't fed by the bridge. The pack's own troubleshooting table names this as the number-one wiring mistake.

Audio and picture diverge progressively from segment 3. The tell is that it isn't constant - each seam adds to it. Almost always the save node's audio input is fed straight from VAEDecodeAudio instead of from this node's output, so the picture gets trimmed and the track doesn't.

seam_ghost and settle_sharpen. seam_ghost blends the first frame with the previous segment's last frame, and it's off because it doesn't help: total displacement dropped 7% while the number of anomalous frames doubled, so instead of one jump you get two. Fix the cause - reduce cropping - or repair softness in the image domain (Post's settle_auto), which can't introduce a jump because it doesn't touch the timeline.

CategoryH3 Latent Relay

Inputs (25)

NameTypeDefaultDescription
imagesIMAGE【接法】接本段画面解码(VAEDecode)的输出。 收到的是含重复开头的完整画面,它把重复部分裁掉。
trim_framesINT-1-1–362【不用填】从 Copy Bridge 第 3 路输出接线。 接上线:第 1 段自动 0,第 2 段起自动等于拷贝帧数。 -1(默认)= 未接线,运行时报错并说明怎么接; 0 = 明确不裁(首段 / 独立段)。
fpsFLOAT24.0001–120【不用动】H3 固定 24 帧/秒,音频按这个换算一起裁。
audiooptAUDIO【务必接线】从音频解码(VAEDecodeAudio)接过来。 画面和声音按同一帧数一起裁,音画才不会串位。 不接的话声音会比画面长出一截。
settle_framesoptINT0-1–36【保持 0】裁不裁「沉降区」:复制区之后模型还会先复现上一段几帧。 那几帧略糊,但裁它们正是缝处跳帧的源头(实测裁 0 帧跳 0.020、裁 16 帧 0.055)。 · 0(默认)= 只裁复制区,缝处无跳;-1 = 自动;N = 固定多裁 N 帧。
seam_ghostoptINT00–6【保持 0】把裁后首帧换成「上段末帧 ⊕ 本段首帧」的混合。 实测它只把一跳拆成两跳、总位移没减 ⇒ 观感是「卡两下」,比单帧瞬跳更明显。 · 0(默认)= 关;大于 0 = 开(确知有收益时用)。
seam_ghost_alphaoptFLOAT0.500–1【仅重影档】上段末帧的权重(0.5 = 对半)。默认档下无效。
settle_sharpenoptFLOAT0.000–1.5【按需开】糊区锐化:对裁后开头几帧做锐化,强度从缝端最强衰减到 0。 · 0(默认)= 关;0.4~1.0 推荐(先试 0.6,再看有没有白边或噪点)。 ⚠ 只能恢复对比度,救不回丢掉的细节。
settle_sharpen_framesoptINT240–64【配合糊区锐化】作用帧数(从裁后首帧起,强度衰减到 0)。 默认 24 帧约 1 秒;实测糊区 16~20 帧内回到基准。
lowfreq_pulloptFLOAT0.000–1【按需开】低频残差:把本段开头几帧的色档/亮度拉向上段末帧。 只动低频 ⇒ 不复制姿态、无重影。 0(默认)= 关;0.7 = 中等;1.0 = 最强(缝点阶跃可到 0.0011)。 ⚠ 与「跨段统计匹配」作用重叠,二选一。
lowfreq_framesoptINT120–48【配合低频残差】作用帧数(权重衰减到 0)。 参考实现用 12 帧,实测缝区影响就在前 12 帧内。
lowfreq_bluroptINT168–128【低频尺度】默认 16 就够。 16 → 12 帧约 1.6 秒;64 → 同一段约 22 秒,而缝点阶跃只从 0.0024 降到 0.0011。 ⇒ 除非专治大面积色档漂移,别加到 64;32 是折中。
deconv_strengthoptFLOAT0.000–1【按需开】本段开头反卷积去模糊:按假设的模糊核逆推原始信号。 与锐化的区别:锐化只是放大高频(噪声一起放大),反卷积理论上能还原细节。 0(默认)= 关;0.5~1.0 = 混合比。太大易出振铃。
deconv_radiusoptFLOAT1.50.5–6【配合反卷积】假设的模糊半径(像素)。糊得越重越大;太大易出振铃。
detail_borrowoptFLOAT0.000–1【按需开】段体高频迁移:本段开头保留自己的低频,高频换成段体的结构。 与低频残差互补。0(默认)= 关。 ⚠ 本段开头与段体差异大时会带出纹理错位。
detail_bluroptINT93–64【配合高频迁移】高频分离尺度:越大被搬走的高频越粗。
hist_matchoptFLOAT0.000–1【按需开】直方图匹配:把本段开头的色阶分布对齐到段体。 比低频残差更强 —— 那个只对齐均值,这个对齐整条分布。 0(默认)= 关;1 = 完全对齐。
wb_matchoptFLOAT0.000–1【按需开】灰世界白平衡:把本段开头的 R:G:B 比例(色温)对齐到段体。 与低频残差正交(那个管亮度总量)。对症色温滑档;增益限幅 ±25%。 0(默认)= 关。
match_prevoptFLOAT0.000–1【按需开】跨段统计匹配:把本段开头的亮度/色档对齐上段尾部走向。 只对齐统计量、不复制姿态 ⇒ 无重影;带噪声闸,不会把好帧修坏。 0(默认)= 关;建议 0.5。 ⚠ 目前只有负向证据:近似参照路线实测更差(0.0007→0.0039); 拷贝桥下尚无正向实测 ⇒ 别默认开。
match_prev_framesoptINT121–96【配合跨段统计匹配】作用帧数:从裁后首帧起,权重衰减到 0。
match_prev_gain_maxoptFLOAT1.151–2【护栏】逐通道对比度增益上限,防止把已对好的内容改坏。
match_prev_offset_maxoptFLOAT0.060–0.3【护栏】逐通道亮度/色度偏移上限,防止整段换色。
run_idoptSTRING【观测】可留空:与 Latent Save 一致的片名。 填了才会把每段的外观统计写进 <run>/appearance_log.jsonl。
save_pcmoptBOOLEANtrue【建议保持开】开(默认)= 额外存一份无损 PCM。 拼接直读它 ⇒ 音频只编码一代;关 = 不写(每段约 2 MB),退回 mp4 解码。
diagnosticsoptBOOLEANfalse【默认关】三路只读观测,都不参与裁量,关掉不改变任何输出(纯打印): · 段间对齐代价;· 裁量→跳跃曲线;· 外观三元组 + 漂移曲线(需填 run_id)。 开 = 多约 0.4 秒/段 CPU,零 GPU。

Outputs (4)

NameTypeDescription
imagesIMAGE—
audioAUDIO—
reportSTRING—
prev_tailIMAGE—