MCPcopy Create free account
hub / github.com/banodoco/Steerable-Motion / WanVideoBlenderNode

Class WanVideoBlenderNode

SteerableMotion.py:994–1052  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

992 return (frame_number,)
993
994class WanVideoBlenderNode:
995 @classmethod
996 def INPUT_TYPES(s):
997 return {
998 "required": {
999 "overlap_frames": ("INT", {"default": 10, "min": 1, "max": 1000, "step": 1}),
1000 "video_1": ("IMAGE",),
1001 "video_2": ("IMAGE",),
1002 },
1003 }
1004
1005 RETURN_TYPES = ("IMAGE",)
1006 RETURN_NAMES = ("blended_video_frames",)
1007 FUNCTION = "blend_videos"
1008 CATEGORY = "Steerable-Motion"
1009 DESCRIPTION = "Blends two input videos with a cross-fade. The resolution of the second clip is resized to match the first."
1010
1011 def _resize_video(self, video, target_height, target_width):
1012 """Resize a batch of frames (B,H,W,C) to (target_height,target_width) using Lanczos."""
1013 if video.shape[1] == target_height and video.shape[2] == target_width:
1014 return video
1015 # (B, H, W, C) -> (B, C, H, W)
1016 video_permuted = video.permute(0, 3, 1, 2)
1017 resized = common_upscale(video_permuted, target_width, target_height, "lanczos", "disabled") # (B, C, H, W)
1018 return resized.permute(0, 2, 3, 1)
1019
1020 def _cross_fade(self, tail, head, overlap_frames):
1021 """Blend two tensors of shape (overlap_frames,H,W,C) using linear alpha."""
1022 device, dtype = tail.device, tail.dtype
1023 alphas = torch.linspace(0, 1, overlap_frames, device=device, dtype=dtype).view(-1, 1, 1, 1)
1024 blended = tail * (1 - alphas) + head * alphas
1025 return blended
1026
1027 def blend_videos(self, overlap_frames, video_1, video_2):
1028 if video_1 is None or video_2 is None:
1029 raise ValueError("Both video_1 and video_2 are required.")
1030
1031 # Reference dimensions and properties from first video
1032 ref_h, ref_w = video_1.shape[1:3]
1033
1034 # Ensure second video matches size
1035 video_2_resized = self._resize_video(video_2, ref_h, ref_w)
1036
1037 if video_1.shape[0] < overlap_frames or video_2_resized.shape[0] < overlap_frames:
1038 raise ValueError(f"One of the videos is shorter than overlap_frames={overlap_frames}.")
1039
1040 # Extract segments for blending
1041 tail = video_1[-overlap_frames:]
1042 head = video_2_resized[:overlap_frames]
1043 blended = self._cross_fade(tail, head, overlap_frames)
1044
1045 # Assemble new timeline
1046 final_video = torch.cat([
1047 video_1[:-overlap_frames],
1048 blended,
1049 video_2_resized[overlap_frames:]
1050 ], dim=0)
1051

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected