diff --git a/merge_node.py b/merge_node.py index c851c2e..3b01c1e 100644 --- a/merge_node.py +++ b/merge_node.py @@ -106,9 +106,12 @@ Blend methods: "blend_method": (["optical_flow", "alpha", "none"], {"default": "optical_flow", "description": "Blending method at seams."}), "of_preset": (["fast", "balanced", "quality", "max"], {"default": "balanced", "description": "Optical flow quality preset."}), }, + "optional": { + "original_clip_2": ("IMAGE", {"description": "Second original clip for Join Extend with two separate clips."}), + }, } - def merge(self, original_clip, vace_output, vace_pipe, blend_method, of_preset): + def merge(self, original_clip, vace_output, vace_pipe, blend_method, of_preset, original_clip_2=None): mode = vace_pipe["mode"] trim_start = vace_pipe["trim_start"] trim_end = vace_pipe["trim_end"] @@ -120,9 +123,15 @@ Blend methods: return (vace_output,) # Splice modes: reconstruct full video + two_clip = vace_pipe.get("two_clip", False) V = vace_output.shape[0] head = original_clip[:trim_start] - tail = original_clip[trim_end:] + if two_clip and original_clip_2 is not None: + tail = original_clip_2[trim_end:] + right_orig = original_clip_2 + else: + tail = original_clip[trim_end:] + right_orig = original_clip result = torch.cat([head, vace_output, tail], dim=0) if blend_method == "none" or (left_ctx == 0 and right_ctx == 0): @@ -142,7 +151,7 @@ Blend methods: for j in range(right_ctx): alpha = 1.0 - (j + 1) / (right_ctx + 1) frame_idx = V - right_ctx + j - result[trim_start + frame_idx] = blend_frame(original_clip[trim_end - right_ctx + j], vace_output[frame_idx], alpha) + result[trim_start + frame_idx] = blend_frame(right_orig[trim_end - right_ctx + j], vace_output[frame_idx], alpha) return (result,) diff --git a/nodes.py b/nodes.py index b677814..8b34903 100644 --- a/nodes.py +++ b/nodes.py @@ -323,7 +323,7 @@ input_left / input_right (0 = use all available): Pre Extend: input_right = leading reference frames to keep Middle Extend: input_left/input_right = frames each side of split Edge Extend: input_left/input_right = start/end edge size (overrides edge_frames) - Join Extend: input_left/input_right = edge context from each half + Join Extend: input_left/input_right = edge context from each half (or each clip if source_clip_2 connected) Bidirectional: input_left = trailing context frames to keep Frame Interpolation: pass-through (no trimming) Replace/Inpaint: input_left/input_right = context frames around replace region @@ -385,6 +385,12 @@ input_left / input_right (0 = use all available): ), }, "optional": { + "source_clip_2": ( + "IMAGE", + { + "description": "Second clip for Join Extend — join two separate clips instead of splitting one in half.", + }, + ), "inpaint_mask": ( "MASK", { @@ -401,7 +407,7 @@ input_left / input_right (0 = use all available): }, } - def prepare(self, source_clip, mode, split_index, input_left, input_right, edge_frames, inpaint_mask=None, keyframe_positions=None): + def prepare(self, source_clip, mode, split_index, input_left, input_right, edge_frames, source_clip_2=None, inpaint_mask=None, keyframe_positions=None): B, H, W, C = source_clip.shape dev = source_clip.device @@ -464,9 +470,13 @@ input_left / input_right (0 = use all available): return (output, mode, 0, sym, mask_ph(), kp_out, pipe) elif mode == "Join Extend": - half = B // 2 - first_half = source_clip[:half] - second_half = source_clip[half:] + if source_clip_2 is not None: + first_half = source_clip + second_half = source_clip_2 + else: + half = B // 2 + first_half = source_clip[:half] + second_half = source_clip[half:] eff_left = input_left if input_left > 0 else edge_frames eff_right = input_right if input_right > 0 else edge_frames eff_left = min(eff_left, first_half.shape[0]) @@ -475,7 +485,14 @@ input_left / input_right (0 = use all available): part_2 = first_half[-sym:] part_3 = second_half[:sym] output = torch.cat([part_2, part_3], dim=0) - pipe = {"mode": mode, "trim_start": half - sym, "trim_end": half + sym, "left_ctx": sym, "right_ctx": sym} + two_clip = source_clip_2 is not None + if two_clip: + trim_start = first_half.shape[0] - sym + trim_end = sym + else: + trim_start = half - sym + trim_end = half + sym + pipe = {"mode": mode, "trim_start": trim_start, "trim_end": trim_end, "left_ctx": sym, "right_ctx": sym, "two_clip": two_clip} return (output, mode, 0, sym, mask_ph(), kp_out, pipe) elif mode == "Bidirectional Extend":