初始化提交
This commit is contained in:
73
app/services/utils/video_effects.py
Normal file
73
app/services/utils/video_effects.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from moviepy import Clip, ColorClip, CompositeVideoClip, vfx
|
||||
|
||||
|
||||
# FadeIn
|
||||
def fadein_transition(clip: Clip, t: float) -> Clip:
|
||||
return clip.with_effects([vfx.FadeIn(t)])
|
||||
|
||||
|
||||
# FadeOut
|
||||
def fadeout_transition(clip: Clip, t: float) -> Clip:
|
||||
return clip.with_effects([vfx.FadeOut(t)])
|
||||
|
||||
|
||||
# SlideIn
|
||||
def slidein_transition(clip: Clip, t: float, side: str) -> Clip:
|
||||
width, height = clip.size
|
||||
|
||||
# MoviePy 内置 SlideIn 在当前这条处理链里对全屏素材不稳定,
|
||||
# 会出现“逻辑上应用了转场,但画面几乎看不出变化”的情况。
|
||||
# 这里改成显式黑底 + 位移动画,保证转场效果可见且行为可控。
|
||||
def position(current_time: float):
|
||||
progress = min(max(current_time / max(t, 0.001), 0), 1)
|
||||
|
||||
if side == "left":
|
||||
return (-width + width * progress, 0)
|
||||
if side == "right":
|
||||
return (width - width * progress, 0)
|
||||
if side == "top":
|
||||
return (0, -height + height * progress)
|
||||
if side == "bottom":
|
||||
return (0, height - height * progress)
|
||||
return (0, 0)
|
||||
|
||||
background = ColorClip(size=(width, height), color=(0, 0, 0)).with_duration(
|
||||
clip.duration
|
||||
)
|
||||
moving_clip = clip.with_position(position)
|
||||
return CompositeVideoClip([background, moving_clip], size=(width, height)).with_duration(
|
||||
clip.duration
|
||||
)
|
||||
|
||||
|
||||
# SlideOut
|
||||
def slideout_transition(clip: Clip, t: float, side: str) -> Clip:
|
||||
width, height = clip.size
|
||||
transition_start = max(clip.duration - t, 0)
|
||||
|
||||
# SlideOut 同样改成显式位移,保证片段末尾能稳定滑出画面。
|
||||
def position(current_time: float):
|
||||
if current_time <= transition_start:
|
||||
return (0, 0)
|
||||
|
||||
progress = min(
|
||||
max((current_time - transition_start) / max(t, 0.001), 0), 1
|
||||
)
|
||||
|
||||
if side == "left":
|
||||
return (-width * progress, 0)
|
||||
if side == "right":
|
||||
return (width * progress, 0)
|
||||
if side == "top":
|
||||
return (0, -height * progress)
|
||||
if side == "bottom":
|
||||
return (0, height * progress)
|
||||
return (0, 0)
|
||||
|
||||
background = ColorClip(size=(width, height), color=(0, 0, 0)).with_duration(
|
||||
clip.duration
|
||||
)
|
||||
moving_clip = clip.with_position(position)
|
||||
return CompositeVideoClip([background, moving_clip], size=(width, height)).with_duration(
|
||||
clip.duration
|
||||
)
|
||||
Reference in New Issue
Block a user