Files
FrameTour-RenderWorker/entity/effects/camera_shot.py
2025-09-24 10:50:34 +08:00

100 lines
2.9 KiB
Python

from typing import List
from .base import EffectProcessor
class CameraShotEffect(EffectProcessor):
"""相机镜头效果处理器"""
def validate_params(self) -> bool:
"""验证参数:start_time,duration,rotate_deg"""
params = self.parse_params()
if not params:
return True # 使用默认参数
# 参数格式: "start_time,duration,rotate_deg"
if len(params) > 3:
return False
try:
for i, param in enumerate(params):
if param == "":
continue
if i == 2: # rotate_deg
int(param)
else: # start_time, duration
float(param)
return True
except ValueError:
return False
def generate_filter_args(
self, video_input: str, effect_index: int
) -> tuple[List[str], str]:
"""生成相机镜头效果的滤镜参数"""
if not self.validate_params():
return [], video_input
params = self.parse_params()
# 设置默认值
start = 3.0
duration = 1.0
rotate_deg = 0
if len(params) >= 1 and params[0] != "":
start = float(params[0])
if len(params) >= 2 and params[1] != "":
duration = float(params[1])
if len(params) >= 3 and params[2] != "":
rotate_deg = int(params[2])
filter_args = []
# 生成输出流标识符
start_out_str = "[eff_s]"
mid_out_str = "[eff_m]"
end_out_str = "[eff_e]"
final_output = f"[v_eff{effect_index}]"
# 分割视频流为三部分
filter_args.append(
f"{video_input}split=3{start_out_str}{mid_out_str}{end_out_str}"
)
# 选择开始部分帧
filter_args.append(
f"{start_out_str}select=lt(n\\,"
f"{int(start * self.frame_rate)}){start_out_str}"
)
# 选择结束部分帧
filter_args.append(
f"{end_out_str}select=gt(n\\,"
f"{int(start * self.frame_rate)}){end_out_str}"
)
# 选择中间特定帧并扩展
filter_args.append(
f"{mid_out_str}select=eq(n\\,"
f"{int(start * self.frame_rate)}){mid_out_str}"
)
filter_args.append(
f"{mid_out_str}tpad=start_mode=clone:"
f"start_duration={duration:.4f}{mid_out_str}"
)
# 如果需要旋转
if rotate_deg != 0:
filter_args.append(f"{mid_out_str}rotate=PI*{rotate_deg}/180{mid_out_str}")
# 连接三部分
filter_args.append(
f"{start_out_str}{mid_out_str}{end_out_str}concat=n=3:v=1:a=0,"
f"setpts=N/{self.frame_rate}/TB{final_output}"
)
return filter_args, final_output
def get_effect_name(self) -> str:
return "cameraShot"