P1-1: 一键生成P0效果层补齐 - 模板配置注入(BGM/字幕/ASR) + 直通模式调速修复 #465
@@ -759,6 +759,19 @@ class UnifiedRenderService:
|
||||
plan_config = getattr(self.plan, "config", None) or {}
|
||||
if isinstance(plan_config, dict) and plan_config.get("stickers"):
|
||||
return False
|
||||
|
||||
# 有水印时禁用直通(图片水印需要额外输入,统一走 filter_complex)
|
||||
try:
|
||||
from video_processing.watermark_engine import WatermarkConfig
|
||||
|
||||
wm_config = WatermarkConfig.from_dict(plan_config.get("watermark"))
|
||||
if wm_config is not None and wm_config.validate()[0]:
|
||||
return False
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 有调速时仍然可以走直通(视频调速通过 setpts 实现,单输入即可)
|
||||
|
||||
return True
|
||||
|
||||
def _can_use_stream_copy(
|
||||
@@ -971,6 +984,11 @@ class UnifiedRenderService:
|
||||
filters.append(f"trim=duration={effective_duration}")
|
||||
filters.append("setpts=PTS-STARTPTS")
|
||||
|
||||
# 调速 — 与 filter_complex 路径一致
|
||||
speed = UnifiedRenderService._clip_speed(clip)
|
||||
if abs(speed - 1.0) >= 1e-6:
|
||||
filters.append(f"setpts=PTS/{speed:.4f}")
|
||||
|
||||
# 倒放滤镜
|
||||
reverse_config = ReverseConfig.from_dict(clip.config.get("reverse"))
|
||||
if reverse_config.enabled and reverse_config.reverse_video:
|
||||
|
||||
@@ -774,6 +774,47 @@ def _validate_template_exists(template_id: str) -> None:
|
||||
session.close()
|
||||
|
||||
|
||||
def _load_template_plan_config(template_id: str) -> dict:
|
||||
"""从模板加载 plan 级配置(BGM、字幕、滤镜等效果层)。
|
||||
|
||||
模板不存在时返回空 dict,不阻塞主流程。
|
||||
"""
|
||||
if not template_id:
|
||||
return {}
|
||||
try:
|
||||
from packages.adapters.sqlalchemy_impl.models import TemplateModel
|
||||
|
||||
session = SessionLocal()
|
||||
try:
|
||||
template = (
|
||||
session.query(TemplateModel)
|
||||
.filter(
|
||||
TemplateModel.id == template_id,
|
||||
TemplateModel.is_active.is_(True),
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if template is None:
|
||||
logger.warning("模板不存在,跳过配置加载: template_id=%s", template_id)
|
||||
return {}
|
||||
config = template.config or {}
|
||||
if isinstance(config, str):
|
||||
import json
|
||||
|
||||
config = json.loads(config)
|
||||
logger.info(
|
||||
"模板配置加载成功: template_id=%s keys=%s",
|
||||
template_id,
|
||||
list(config.keys()),
|
||||
)
|
||||
return config
|
||||
finally:
|
||||
session.close()
|
||||
except Exception as e:
|
||||
logger.warning("加载模板配置失败,跳过: template_id=%s err=%s", template_id, e)
|
||||
return {}
|
||||
|
||||
|
||||
# ── 渲染引擎选择 ─────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -1032,6 +1073,19 @@ def _render_video(
|
||||
mode=editing_mode.value,
|
||||
)
|
||||
|
||||
# 注入模板配置(BGM、字幕等效果层)
|
||||
if template_id:
|
||||
template_config = _load_template_plan_config(template_id)
|
||||
if template_config:
|
||||
# 合并:现有 config 优先级更高(目前为空,模板配置直接生效)
|
||||
base_config = virtual_plan.config or {}
|
||||
virtual_plan.config = {**template_config, **base_config}
|
||||
logger.info(
|
||||
"[task_id=%s] [渲染] 模板配置已注入: keys=%s",
|
||||
task_id,
|
||||
list(template_config.keys()),
|
||||
)
|
||||
|
||||
total_duration = sum(c.duration for c in virtual_clips)
|
||||
logger.info(
|
||||
"[task_id=%s] [剪辑计划] 片段数=%d, 总时长=%.1fs",
|
||||
|
||||
Reference in New Issue
Block a user