feat(video): 添加视频特效处理功能

- 在常量模块中定义支持的特效类型(相机定格、缩放、模糊)
- 在任务域中创建Effect数据类,支持从字符串解析特效配置
- 实现cameraShot特效参数解析和默认值处理
- 扩展RenderSpec类,添加获取特效列表的方法
- 修改视频渲染处理器,集成特效滤镜构建逻辑
- 实现cameraShot特效的filter_complex滤镜图构建
- 添加fps参数支持和overlay检测逻辑优化
- 完成特效与转场overlap的兼容处理
This commit is contained in:
2026-01-13 09:31:39 +08:00
parent 9c6186ecd3
commit a26c44a3cd
3 changed files with 216 additions and 5 deletions

View File

@@ -34,6 +34,13 @@ TRANSITION_TYPES = {
'slidedown': 'slidedown', # 向下滑动
}
# 支持的特效类型
EFFECT_TYPES = {
'cameraShot', # 相机定格效果
'zoom', # 缩放效果(预留)
'blur', # 模糊效果(预留)
}
class TaskStatus(Enum):
"""任务状态枚举"""
@@ -76,6 +83,70 @@ class TransitionConfig:
return TRANSITION_TYPES.get(self.type, 'fade')
@dataclass
class Effect:
"""
特效配置
格式:type:params
例如:cameraShot:3,1 表示在第3秒定格1秒
"""
effect_type: str # 效果类型
params: str = "" # 参数字符串
@classmethod
def from_string(cls, effect_str: str) -> Optional['Effect']:
"""
从字符串解析 Effect
格式:type:params 或 type(无参数时)
"""
if not effect_str:
return None
parts = effect_str.split(':', 1)
effect_type = parts[0].strip()
if effect_type not in EFFECT_TYPES:
return None
params = parts[1].strip() if len(parts) > 1 else ""
return cls(effect_type=effect_type, params=params)
@classmethod
def parse_effects(cls, effects_str: Optional[str]) -> List['Effect']:
"""
解析效果字符串
格式:effect1|effect2|effect3
例如:cameraShot:3,1|blur:5
"""
if not effects_str:
return []
effects = []
for part in effects_str.split('|'):
effect = cls.from_string(part.strip())
if effect:
effects.append(effect)
return effects
def get_camera_shot_params(self) -> tuple:
"""
获取 cameraShot 效果参数
Returns:
(start_sec, duration_sec): 开始时间和持续时间(秒)
"""
if self.effect_type != 'cameraShot':
return (0, 0)
if not self.params:
return (3, 1) # 默认值
parts = self.params.split(',')
try:
start = int(parts[0]) if len(parts) >= 1 else 3
duration = int(parts[1]) if len(parts) >= 2 else 1
return (start, duration)
except ValueError:
return (3, 1)
@dataclass
class RenderSpec:
"""
@@ -137,6 +208,10 @@ class RenderSpec:
return self.transition_out.get_overlap_ms()
return 0
def get_effects(self) -> List['Effect']:
"""获取解析后的特效列表"""
return Effect.parse_effects(self.effects)
@dataclass
class OutputSpec: