feat(video): 添加视频缩放特效功能支持

- 在 EffectConfig 中新增 zoom 特效类型及参数解析
- 实现 get_zoom_params 方法用于获取缩放效果参数
- 更新文档注释说明 zoom 特效使用格式示例
- 修改渲染逻辑支持 zoom 特效的 filter_complex 处理
- 添加缩放特效的视频滤镜构建实现
- 统一处理 cameraShot 和 zoom 特效的效果叠加逻辑
This commit is contained in:
2026-02-07 01:25:20 +08:00
parent 88aa3adca1
commit ad4a9cc869
2 changed files with 76 additions and 12 deletions

View File

@@ -491,7 +491,10 @@ class RenderSegmentVideoHandler(BaseHandler):
# 解析 effects
effects = render_spec.get_effects()
has_camera_shot = any(e.effect_type == 'cameraShot' for e in effects)
has_complex_effect = any(
effect.effect_type in {'cameraShot', 'zoom'}
for effect in effects
)
# 硬件加速时需要先 hwdownload(将 GPU 表面下载到系统内存)
hwaccel_prefix = self.get_hwaccel_filter_prefix()
@@ -541,9 +544,8 @@ class RenderSegmentVideoHandler(BaseHandler):
)
filters.append(scale_filter)
# 5. 特效处理(cameraShot 需要特殊处理
if has_camera_shot:
# cameraShot 需要使用 filter_complex 格式
# 5. 特效处理(cameraShot / zoom 需要使用 filter_complex
if has_complex_effect:
return self._build_filter_complex_with_effects(
base_filters=filters,
effects=effects,
@@ -624,7 +626,7 @@ class RenderSegmentVideoHandler(BaseHandler):
"""
构建包含特效的 filter_complex 滤镜图
cameraShot 效果需要使用 split/freezeframes/concat 滤镜组合
cameraShot / zoom 效果都在此处统一处理并按 effects 顺序叠加
Args:
base_filters: 基础滤镜列表
@@ -695,6 +697,31 @@ class RenderSegmentVideoHandler(BaseHandler):
f"{frozen_out}{rest_out}concat=n=2:v=1:a=0{effect_output}"
)
current_output = effect_output
effect_idx += 1
elif effect.effect_type == 'zoom':
start_sec, scale_factor, duration_sec = effect.get_zoom_params()
if start_sec < 0 or scale_factor <= 1.0 or duration_sec <= 0:
continue
zoom_end_sec = start_sec + duration_sec
base_out = f'[eff{effect_idx}_base]'
zoom_source_out = f'[eff{effect_idx}_zoom_src]'
zoom_scaled_out = f'[eff{effect_idx}_zoom_scaled]'
effect_output = f'[v_eff{effect_idx}]'
zoom_enable = f"'between(t,{start_sec},{zoom_end_sec})'"
filter_parts.append(
f"{current_output}split=2{base_out}{zoom_source_out}"
)
filter_parts.append(
f"{zoom_source_out}scale=iw*{scale_factor}:ih*{scale_factor},"
f"crop={width}:{height}:(in_w-{width})/2:(in_h-{height})/2{zoom_scaled_out}"
)
filter_parts.append(
f"{base_out}{zoom_scaled_out}overlay=0:0:enable={zoom_enable}{effect_output}"
)
current_output = effect_output
effect_idx += 1