fix: volume=0 clips retained with silence filter to preserve A/V sync
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 44s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m24s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 40s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m29s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 51s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m49s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m4s
AI Code Review / AI Code Review (pull_request) Failing after 2m7s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 2m17s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m35s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 4m26s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m41s
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s

- render_audio.py: stop filtering out volume=0 clips from concat; they produce silence via volume=0 filter, keeping timeline aligned
- unified_render_service.py: probe audio regardless of volume; volume=0 applied as filter, not by dropping stream
- test: update test_silent_clip to verify volume=0 clip retained with volume=0 filter
This commit is contained in:
xiaoxia
2026-08-24 00:36:17 +08:00
parent 0081ce7641
commit 115455bacc
3 changed files with 12 additions and 8 deletions
+3 -2
View File
@@ -135,8 +135,9 @@ def mix_audio(
audio_clips = layer_map["audio"].clips
# ── 保留源视频原声:过滤掉无音频流的 main clip(图片/无声素材) ──
# 每个 clip 按 config.volume 控制音量(0=静音,1=原声),静音 clip 不送入 concat
main_clips = [c for c in main_clips if clip_has_audio(ctx, c) and _clip_volume(c) > 0]
# 注意:volume=0 的 clip 不能移除——移除会导致后续 clip 音频时间轴前移、音画不同步。
# volume=0 通过滤镜链生成静音流,保持时间轴对齐。
main_clips = [c for c in main_clips if clip_has_audio(ctx, c)]
# ── 防御:过滤掉无音频流的独立音频轨 ──
audio_clips = [c for c in audio_clips if clip_has_audio(ctx, c)]
@@ -1277,9 +1277,9 @@ class UnifiedRenderService:
]
# 音频处理:background 通常是图片无音频,跳过;其他角色先探测是否真有音频流。
# volume=0 表示该片段静音,直接丢弃音频(与多片段 mix_audio 行为一致)
# volume=0 不丢弃音频流,而是保留后通过 volume=0 滤镜静音,保持时间轴对齐
clip_volume = UnifiedRenderService._clip_volume(clip)
if role != "background" and clip_volume > 0:
if role != "background":
try:
has_audio = probe_has_audio(clip.local_path)
except Exception as e:
+7 -4
View File
@@ -123,8 +123,8 @@ class TestOriginalAudioRetained:
assert "asset_tts1.mp4" in cmd_str
assert "volume=0.5" in cmd_str
def test_silent_clip_volume_zero_excluded(self):
"""volume=0 的素材不送入原声 concat。"""
def test_silent_clip_volume_zero_retained_with_silence_filter(self):
"""volume=0 的素材必须保留在 concat 中(用 volume=0 滤镜静音),不能移除以避免音画不同步"""
clips = [_clip("mute", order=0, config={"volume": 0})]
svc = _service(clips)
with (
@@ -135,8 +135,11 @@ class TestOriginalAudioRetained:
):
result = mix_audio(_ctx(), _layers(svc, clips), 5.0)
assert result is None
mock_run.assert_not_called()
# 有音频流 → 应生成音频文件,且 ffmpeg 命令包含 volume=0.0000 静音滤镜
assert result is not None
mock_run.assert_called_once()
cmd_str = " ".join(mock_run.call_args[0][0])
assert "volume=0" in cmd_str
def test_no_audio_stream_returns_none(self):
clips = [_clip("c1")]