You've already forked FrameTour-RenderWorker
89 lines
3.1 KiB
Python
89 lines
3.1 KiB
Python
from typing import List
|
|
import json
|
|
from .base import EffectProcessor
|
|
|
|
class ZoomEffect(EffectProcessor):
|
|
"""缩放效果处理器"""
|
|
|
|
def validate_params(self) -> bool:
|
|
"""验证参数:start_time,zoom_factor,duration"""
|
|
params = self.parse_params()
|
|
if len(params) < 3:
|
|
return False
|
|
|
|
try:
|
|
start_time = float(params[0])
|
|
zoom_factor = float(params[1])
|
|
duration = float(params[2])
|
|
|
|
return (start_time >= 0 and
|
|
zoom_factor > 0 and
|
|
duration >= 0)
|
|
except (ValueError, IndexError):
|
|
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_time = float(params[0])
|
|
zoom_factor = float(params[1])
|
|
duration = float(params[2])
|
|
|
|
if zoom_factor == 1:
|
|
return [], video_input # 不需要缩放
|
|
|
|
output_stream = f"[v_eff{effect_index}]"
|
|
|
|
# 获取缩放中心点
|
|
center_x, center_y = self._get_zoom_center()
|
|
|
|
filter_args = []
|
|
|
|
if duration == 0:
|
|
# 静态缩放(整个视频时长)
|
|
x_expr = f"({center_x})-(ow*zoom)/2"
|
|
y_expr = f"({center_y})-(oh*zoom)/2"
|
|
filter_args.append(
|
|
f"{video_input}trim=start={start_time},zoompan=z={zoom_factor}:x={x_expr}:y={y_expr}:d=1{output_stream}"
|
|
)
|
|
else:
|
|
# 动态缩放(指定时间段内)
|
|
zoom_expr = f"if(between(t\\,{start_time}\\,{start_time + duration})\\,{zoom_factor}\\,1)"
|
|
x_expr = f"({center_x})-(ow*zoom)/2"
|
|
y_expr = f"({center_y})-(oh*zoom)/2"
|
|
filter_args.append(
|
|
f"{video_input}zoompan=z={zoom_expr}:x={x_expr}:y={y_expr}:d=1{output_stream}"
|
|
)
|
|
|
|
return filter_args, output_stream
|
|
|
|
def _get_zoom_center(self) -> tuple[str, str]:
|
|
"""获取缩放中心点坐标表达式"""
|
|
# 默认中心点
|
|
center_x = "iw/2"
|
|
center_y = "ih/2"
|
|
|
|
pos_json = self.get_pos_json()
|
|
if pos_json:
|
|
_f_x = pos_json.get('ltX', 0)
|
|
_f_x2 = pos_json.get('rbX', 0)
|
|
_f_y = pos_json.get('ltY', 0)
|
|
_f_y2 = pos_json.get('rbY', 0)
|
|
_v_w = pos_json.get('imgWidth', 1)
|
|
_v_h = pos_json.get('imgHeight', 1)
|
|
|
|
if _v_w > 0 and _v_h > 0:
|
|
# 计算坐标系统中的中心点
|
|
center_x_ratio = (_f_x + _f_x2) / (2 * _v_w)
|
|
center_y_ratio = (_f_y + _f_y2) / (2 * _v_h)
|
|
# 转换为视频坐标系统
|
|
center_x = f"iw*{center_x_ratio:.6f}"
|
|
center_y = f"ih*{center_y_ratio:.6f}"
|
|
|
|
return center_x, center_y
|
|
|
|
def get_effect_name(self) -> str:
|
|
return "zoom" |