wip(#1749): render_audio 四路 apad 静音补齐 + stream-copy tpad + worker 重渲传配音时长(checkpoint)
This commit is contained in:
@@ -47,13 +47,23 @@ class RenderContext:
|
||||
|
||||
|
||||
def clip_effective_duration(clip: ResolvedClip) -> float:
|
||||
"""计算 clip 的有效时长.
|
||||
"""计算 clip 的有效时长(#1749:目标段长始终为准)。
|
||||
|
||||
与 UnifiedRenderService._clip_effective_duration 逻辑一致。
|
||||
与 UnifiedRenderService._clip_effective_duration 逻辑一致;素材短于段长的
|
||||
部分由末帧冻结 tpad / 音频 apad 铺满,不在此处钳制。
|
||||
"""
|
||||
if clip.duration > 0:
|
||||
return min(clip.duration, clip.actual_duration) if clip.actual_duration > 0 else clip.duration
|
||||
return clip.actual_duration if clip.actual_duration > 0 else 0.0
|
||||
return float(clip.duration)
|
||||
return float(clip.actual_duration) if clip.actual_duration > 0 else 0.0
|
||||
|
||||
|
||||
def _clip_freeze_seconds(clip: ResolvedClip) -> float:
|
||||
"""读取 #1749 末帧冻结秒数(_resolve_clips 写入 config['_freeze_seconds'])。"""
|
||||
cfg = getattr(clip, "config", None) or {}
|
||||
try:
|
||||
return max(0.0, float(cfg.get("_freeze_seconds", 0.0) or 0.0))
|
||||
except (TypeError, ValueError):
|
||||
return 0.0
|
||||
|
||||
|
||||
def clip_has_audio(ctx: RenderContext, clip: ResolvedClip) -> bool:
|
||||
@@ -273,6 +283,9 @@ def concat_main_audio(
|
||||
if video_duration > 0 and (final_duration <= 0 or final_duration > video_duration):
|
||||
final_duration = video_duration
|
||||
|
||||
# #1749 末帧冻结秒数(音频需 apad 补静音与视频等长)
|
||||
freeze_seconds = _clip_freeze_seconds(clip)
|
||||
|
||||
# 音频倒放
|
||||
reverse_config = ReverseConfig.from_dict(clip.config.get("reverse"))
|
||||
has_reverse = reverse_config.enabled and reverse_config.reverse_audio
|
||||
@@ -281,20 +294,30 @@ def concat_main_audio(
|
||||
if not has_speed and not has_reverse:
|
||||
# 无调速无倒放:根据是否需要裁剪/音量选择最高效的路径。
|
||||
vol = _clip_volume(clip)
|
||||
need_trim = trim_start > 0 or (effective_duration > 0 and final_duration < adjusted_duration)
|
||||
need_trim = (
|
||||
trim_start > 0
|
||||
or freeze_seconds > 0
|
||||
or (effective_duration > 0 and final_duration < adjusted_duration)
|
||||
)
|
||||
need_volume = abs(vol - 1.0) >= 1e-6
|
||||
|
||||
if need_trim:
|
||||
# 需要裁剪:用 atrim 滤镜在滤镜链中精确裁剪(采样点级精度,不浪费解码)。
|
||||
# 滤镜顺序:atrim → asetpts → volume(先裁剪再调音量,避免处理被丢弃的数据)。
|
||||
# 滤镜顺序:atrim → asetpts → apad(冻结补静音) → volume。
|
||||
af_parts: list[str] = []
|
||||
if trim_start > 0 and effective_duration > 0:
|
||||
af_parts.append(f"atrim=start={trim_start:.3f}:duration={final_duration:.3f}")
|
||||
# 冻结场景:素材内可用时长 = 目标段长 − freeze(截掉超出素材的部分后补静音)
|
||||
atrim_dur = final_duration
|
||||
if freeze_seconds > 0:
|
||||
atrim_dur = max(0.0, final_duration - freeze_seconds)
|
||||
if trim_start > 0 and atrim_dur > 0:
|
||||
af_parts.append(f"atrim=start={trim_start:.3f}:duration={atrim_dur:.3f}")
|
||||
elif trim_start > 0:
|
||||
af_parts.append(f"atrim=start={trim_start:.3f}")
|
||||
elif final_duration > 0:
|
||||
af_parts.append(f"atrim=duration={final_duration:.3f}")
|
||||
elif atrim_dur > 0:
|
||||
af_parts.append(f"atrim=duration={atrim_dur:.3f}")
|
||||
af_parts.append("asetpts=PTS-STARTPTS")
|
||||
if freeze_seconds > 0:
|
||||
af_parts.append(f"apad=whole_dur={final_duration:.3f}")
|
||||
if need_volume:
|
||||
af_parts.append(f"volume={vol:.4f}")
|
||||
command = [
|
||||
@@ -334,8 +357,13 @@ def concat_main_audio(
|
||||
"-ac",
|
||||
"2",
|
||||
]
|
||||
af_simple: list[str] = []
|
||||
if need_volume:
|
||||
command.extend(["-af", f"volume={vol:.4f}"])
|
||||
af_simple.append(f"volume={vol:.4f}")
|
||||
if freeze_seconds > 0:
|
||||
af_simple.append(f"apad=whole_dur={final_duration:.3f}")
|
||||
if af_simple:
|
||||
command.extend(["-af", ",".join(af_simple)])
|
||||
if final_duration > 0:
|
||||
command.extend(["-t", f"{final_duration:.3f}"])
|
||||
command.append(str(output_path))
|
||||
@@ -369,6 +397,10 @@ def concat_main_audio(
|
||||
if abs(vol - 1.0) >= 1e-6:
|
||||
audio_filters.append(f"volume={vol:.4f}")
|
||||
|
||||
# #1749 冻结补静音(调速后时长已变,apad 补齐到最终时长)
|
||||
if freeze_seconds > 0:
|
||||
audio_filters.append(f"apad=whole_dur={final_duration:.3f}")
|
||||
|
||||
# aformat 归一化:统一输出格式为 48000Hz + stereo + fltp
|
||||
audio_filters.append("aformat=sample_rates=48000:channel_layouts=stereo:sample_fmts=fltp")
|
||||
|
||||
@@ -410,10 +442,13 @@ def concat_main_audio(
|
||||
speed = getattr(clip, "playback_speed", 1.0) or 1.0
|
||||
if not isinstance(speed, (int, float)) or speed <= 0:
|
||||
speed = 1.0
|
||||
# #1749 末帧冻结:素材内可用时长 = 目标段长 − freeze,apad 补静音
|
||||
freeze_seconds = _clip_freeze_seconds(clip)
|
||||
atrim_dur = max(0.0, effective_duration - freeze_seconds) if freeze_seconds > 0 else effective_duration
|
||||
|
||||
audio_filters: list[str] = []
|
||||
if effective_duration > 0:
|
||||
audio_filters.append(f"atrim=start={trim_start:.3f}:duration={effective_duration:.3f}")
|
||||
audio_filters.append(f"atrim=start={trim_start:.3f}:duration={atrim_dur:.3f}")
|
||||
audio_filters.append("asetpts=PTS-STARTPTS")
|
||||
|
||||
# 音频调速 — atempo 多级串联
|
||||
@@ -435,6 +470,10 @@ def concat_main_audio(
|
||||
if reverse_filter:
|
||||
audio_filters.append(reverse_filter)
|
||||
|
||||
# #1749 冻结补静音:视频 tpad 延长后音频等长补齐(concat 时间轴对齐)
|
||||
if freeze_seconds > 0:
|
||||
audio_filters.append(f"apad=whole_dur={effective_duration:.3f}")
|
||||
|
||||
# 音量(0=静音,1=原声)
|
||||
vol = _clip_volume(clip)
|
||||
if abs(vol - 1.0) >= 1e-6:
|
||||
@@ -506,12 +545,17 @@ def mix_with_independent_audio(
|
||||
input_args.extend(["-i", str(clip.local_path)])
|
||||
effective_duration = clip_effective_duration(clip)
|
||||
trim_start = getattr(clip, "start_time", 0) or 0
|
||||
freeze_seconds = _clip_freeze_seconds(clip)
|
||||
atrim_dur = max(0.0, effective_duration - freeze_seconds) if freeze_seconds > 0 else effective_duration
|
||||
clip_filters = []
|
||||
if effective_duration > 0:
|
||||
clip_filters.append(f"atrim=start={trim_start:.3f}:duration={effective_duration:.3f}")
|
||||
clip_filters.append(f"atrim=start={trim_start:.3f}:duration={atrim_dur:.3f}")
|
||||
clip_filters.append("asetpts=PTS-STARTPTS")
|
||||
else:
|
||||
clip_filters.append("asetpts=PTS-STARTPTS")
|
||||
# #1749 冻结补静音(与视频 tpad 等长)
|
||||
if freeze_seconds > 0:
|
||||
clip_filters.append(f"apad=whole_dur={effective_duration:.3f}")
|
||||
vol = _clip_volume(clip)
|
||||
if abs(vol - 1.0) >= 1e-6:
|
||||
clip_filters.append(f"volume={vol:.4f}")
|
||||
|
||||
@@ -1297,10 +1297,16 @@ class UnifiedRenderService:
|
||||
|
||||
# trim
|
||||
effective_duration = UnifiedRenderService._clip_effective_duration(clip)
|
||||
freeze_seconds = float((clip.config or {}).get("_freeze_seconds", 0.0) or 0.0)
|
||||
# #1749 冻结时素材内截取时长 = 目标段长 − freeze
|
||||
trim_dur = max(0.0, effective_duration - freeze_seconds) if freeze_seconds > 0 else effective_duration
|
||||
|
||||
if effective_duration > 0:
|
||||
filters.append(f"trim=duration={effective_duration}")
|
||||
if trim_dur > 0:
|
||||
filters.append(f"trim=duration={trim_dur}")
|
||||
filters.append("setpts=PTS-STARTPTS")
|
||||
# #1749 末帧冻结(禁慢放)
|
||||
if freeze_seconds > 0:
|
||||
filters.append(f"tpad=stop_mode=clone:stop_duration={freeze_seconds:.3f}")
|
||||
|
||||
# 调速 — 与 filter_complex 路径一致
|
||||
speed = UnifiedRenderService._clip_speed(clip)
|
||||
|
||||
@@ -535,11 +535,17 @@ def _reselect_plan_for_batch_retry(task_id: str, plan_id: str, task_info: dict)
|
||||
try:
|
||||
svc = EditPlanService(db)
|
||||
asset_pool = list(task_info.get("task_asset_ids") or [])
|
||||
_voice_dur = 0.0
|
||||
try:
|
||||
_voice_dur = float(task_info.get("voice_duration", 0.0) or 0.0)
|
||||
except (TypeError, ValueError):
|
||||
_voice_dur = 0.0
|
||||
new_plan = svc.reselect_plan_for_variant(
|
||||
plan_id,
|
||||
asset_pool,
|
||||
created_by_user_id=task_info.get("user_id", ""),
|
||||
name_suffix="重渲变体",
|
||||
voice_duration=_voice_dur,
|
||||
)
|
||||
return new_plan.id
|
||||
finally:
|
||||
|
||||
Reference in New Issue
Block a user