You've already forked FrameTour-RenderWorker
feat(video): 添加视频特效处理功能
- 在常量模块中定义支持的特效类型(相机定格、缩放、模糊) - 在任务域中创建Effect数据类,支持从字符串解析特效配置 - 实现cameraShot特效参数解析和默认值处理 - 扩展RenderSpec类,添加获取特效列表的方法 - 修改视频渲染处理器,集成特效滤镜构建逻辑 - 实现cameraShot特效的filter_complex滤镜图构建 - 添加fps参数支持和overlay检测逻辑优化 - 完成特效与转场overlap的兼容处理
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user