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"