File size: 2,373 Bytes
3e3d7b1 fe7106b 3e3d7b1 fe7106b 3e3d7b1 9845310 fe7106b 9845310 fe7106b 9845310 fe7106b 9845310 3e3d7b1 9845310 3e3d7b1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | from __future__ import annotations
class TransitionBuilder:
"""Build FFmpeg xfade filters for scene joins."""
TRANSITIONS = {
"basic": "fade",
"fade": "fade",
"zoom": "zoomin",
"slide": "slideleft",
"slide_left": "slideleft",
"slide_right": "slideright",
"slide_up": "slideup",
"slide_down": "slidedown",
"push": "slideup",
"blur": "fade",
"whip": "smoothleft",
"dissolve": "dissolve",
"flash": "fadewhite",
"glitch": "hlslice",
"light_leak": "fadewhite",
"film_burn": "fadegrays",
"camera_shake": "smoothleft",
"spin": "circleopen",
"3d_flip": "vertopen",
"flip": "vertopen",
"cube": "rectcrop",
"ripple": "radial",
"ink": "distance",
"morph": "dissolve",
"stretch": "squeezeh",
"liquid": "pixelize",
"elastic": "smoothup",
"motion_blur": "smoothleft",
"wipe": "wipeleft",
"wipe_left": "wipeleft",
"wipe_right": "wiperight",
"wipe_up": "wipeup",
"wipe_down": "wipedown",
"smooth_left": "smoothleft",
"smooth_right": "smoothright",
"fadeblack": "fadeblack",
"fade_white": "fadewhite",
"pixel": "pixelize",
}
def map_transition(self, name: str) -> str:
return self.TRANSITIONS.get(name, "fade")
def list_transitions(self) -> list[str]:
return list(self.TRANSITIONS.keys())
def xfade_chain(self, stream_count: int, durations: list[float], transitions: list[str], transition_duration: float = 0.45) -> tuple[str, str]:
if stream_count <= 1:
return "", "[0:v]"
filters: list[str] = []
current = "[0:v]"
offset = max(0.1, durations[0] - transition_duration)
for idx in range(1, stream_count):
out = f"[vx{idx}]"
transition = self.map_transition(transitions[idx - 1] if idx - 1 < len(transitions) else "fade")
filters.append(
f"{current}[{idx}:v]xfade=transition={transition}:duration={transition_duration}:offset={offset:.3f}{out}"
)
current = out
if idx < len(durations):
offset += max(0.1, durations[idx] - transition_duration)
return ";".join(filters), current
|