Add split_index validation, auto-middle mode, and merge bounds checks

- Middle Extend: split_index=0 now auto-splits at B//2 instead of empty first half
- Middle Extend/Replace: raise ValueError when split_index >= frame count
- Merge blend loops: add bounds checks to prevent index-out-of-bounds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 19:40:30 +01:00
parent a164fbeb87
commit 8b5b99a5b0
2 changed files with 30 additions and 2 deletions

View File

@@ -145,11 +145,15 @@ Blend methods:
# Blend across full left context zone
for j in range(left_ctx):
if trim_start + j >= source_clip.shape[0]:
break
alpha = (j + 1) / (left_ctx + 1)
result[trim_start + j] = blend_frame(source_clip[trim_start + j], vace_output[j], alpha)
# Blend across full right context zone
for j in range(right_ctx):
if trim_end - right_ctx + j >= right_orig.shape[0]:
break
alpha = 1.0 - (j + 1) / (right_ctx + 1)
frame_idx = V - right_ctx + j
result[trim_start + frame_idx] = blend_frame(right_orig[trim_end - right_ctx + j], vace_output[frame_idx], alpha)

View File

@@ -86,7 +86,7 @@ If your source is longer, use VACE Source Prep upstream to trim it first."""
"default": 0,
"min": -10000,
"max": 10000,
"description": "Where to split the source. End: trim from end (e.g. -16). Pre: reference frames from start (e.g. 24). Middle: split frame index. Unused by Edge/Join. Bidirectional: frames before clip (0 = even split). Frame Interpolation: new frames per gap. Replace/Inpaint: start index of replace region. Unused by Video Inpaint and Keyframe.",
"description": "Where to split the source. Middle: split frame index (0 = auto-middle). Bidirectional: frames before clip (0 = even split). Frame Interpolation: new frames per gap. Replace/Inpaint: start index of replace region. Unused by End/Pre/Edge/Join/Video Inpaint/Keyframe.",
},
),
"edge_frames": (
@@ -152,6 +152,13 @@ If your source is longer, use VACE Source Prep upstream to trim it first."""
return (control_frames, mask, frames_to_generate)
elif mode == "Middle Extend":
if split_index <= 0:
split_index = B // 2
if split_index >= B:
raise ValueError(
f"Middle Extend: split_index ({split_index}) is out of range — "
f"source_clip only has {B} frames. Use 0 for auto-middle."
)
image_a = source_clip[:split_index]
image_b = source_clip[split_index:]
a_count = image_a.shape[0]
@@ -211,6 +218,11 @@ If your source is longer, use VACE Source Prep upstream to trim it first."""
return (control_frames, mask, frames_to_generate)
elif mode == "Replace/Inpaint":
if split_index >= B:
raise ValueError(
f"Replace/Inpaint: split_index ({split_index}) is out of range — "
f"source_clip only has {B} frames."
)
start = max(0, min(split_index, B))
length = max(0, min(edge_frames, B - start))
end = start + length
@@ -348,7 +360,7 @@ input_left / input_right (0 = use all available):
"default": 0,
"min": -10000,
"max": 10000,
"description": "Split position in the full source video. Same meaning as mask generator's split_index.",
"description": "Split position in the full source video (0 = auto-middle for Middle Extend). Same meaning as mask generator's split_index.",
},
),
"input_left": (
@@ -450,6 +462,13 @@ input_left / input_right (0 = use all available):
return (output, mode, output.shape[0], edge_frames, trim_mask(0, end), kp_out, pipe)
elif mode == "Middle Extend":
if split_index <= 0:
split_index = B // 2
if split_index >= B:
raise ValueError(
f"Middle Extend: split_index ({split_index}) is out of range — "
f"source_clip only has {B} frames. Use 0 for auto-middle."
)
left_start = max(0, split_index - input_left) if input_left > 0 else 0
right_end = min(B, split_index + input_right) if input_right > 0 else B
output = source_clip[left_start:right_end]
@@ -510,6 +529,11 @@ input_left / input_right (0 = use all available):
return (source_clip, mode, split_index, edge_frames, trim_mask(0, B), kp_out, pipe)
elif mode == "Replace/Inpaint":
if split_index >= B:
raise ValueError(
f"Replace/Inpaint: split_index ({split_index}) is out of range — "
f"source_clip only has {B} frames."
)
start = max(0, min(split_index, B))
end_idx = min(start + edge_frames, B)
length = end_idx - start