This commit is contained in:
eric
2026-03-19 03:24:58 -05:00
parent 7a03a670bc
commit def681cbe3
3 changed files with 19 additions and 9 deletions

View File

@@ -11,6 +11,7 @@ stats_interval_sec = 10
# ===== 其次:音频版权处理 =====
# 是否启用 Demucs 人声分离(防 YouTube Content ID 版权识别)
# 若推流几十秒后断流(YouTube 显示 no data),可设为 否 使用原始音频
# 是 = 启用,只保留人声;否 = 使用原始音频
enable_demucs =

View File

@@ -69,8 +69,8 @@ def _load_demucs_model(use_gpu: bool):
# Demucs 模型采样率
DEMUCS_SAMPLE_RATE = 44100
DEMUCS_CHANNELS = 2
# 每次处理的音频长度(秒),影响延迟与质量
DEMUCS_CHUNK_SEC = 2.0
# 每次处理的音频长度(秒),1.0 更易实时2.0 质量更好但 P40 可能跟不上
DEMUCS_CHUNK_SEC = 1.0
# 字节 per sample (s16le: 2 bytes)
BYTES_PER_SAMPLE = 2
@@ -92,7 +92,7 @@ def _demucs_separate_vocals(model, audio_chunk, device, vocal_mix_ratio=1.0, mix
if wav.dim() == 2:
wav = wav.unsqueeze(0)
with torch.no_grad():
out = apply_model(model, wav, device=device, progress=False, overlap=0.25)
out = apply_model(model, wav, device=device, progress=False, overlap=0.1)
# out: (batch, sources, channels, samples)
# sources: [drums=0, bass=1, other=2, vocals=3]
vocals = out[0, 3]
@@ -269,19 +269,27 @@ def run_demucs_pipeline(
"-b:v", f"{nvenc_params.get('video_bitrate_k', 4500)}k",
"-maxrate", f"{nvenc_params.get('video_bitrate_k', 4500)+500}k",
"-bufsize", f"{nvenc_params.get('video_bitrate_k', 4500)*2}k",
"-vsync", "cfr", "-g", "60", "-keyint_min", "60", "-r", "30",
"-bf", "0", "-sc_threshold", "0",
"-x264-params", "force-cfr=1:scenecut=0:open_gop=0:sync-lookahead=0",
"-fps_mode", "cfr", "-g", "60", "-keyint_min", "60", "-r", "30",
"-bf", "0",
"-pix_fmt", "yuv420p",
"-c:a", "aac", "-b:a", "128k", "-ar", "48000", "-ac", "2",
"-af", "lowpass=f=9000,aresample=async=1:first_pts=0",
"-flags", "+global_header", "-flvflags", "no_duration_filesize",
"-f", "flv", youtube_rtmp,
]
if nvenc_params.get("tune_param"):
# NVENC 用 tune_paramlibx264 用 sc_threshold + x264-params
codec = nvenc_params.get("codec_v", "libx264")
if nvenc_params.get("tune_param") and codec == "h264_nvenc":
idx = ffmpeg_out_cmd.index("-profile:v")
for p in reversed(nvenc_params["tune_param"]):
ffmpeg_out_cmd.insert(idx, p)
elif codec == "libx264":
idx = ffmpeg_out_cmd.index("-bf")
ffmpeg_out_cmd.insert(idx + 2, "-sc_threshold")
ffmpeg_out_cmd.insert(idx + 3, "0")
idx = ffmpeg_out_cmd.index("-pix_fmt")
ffmpeg_out_cmd.insert(idx, "-x264-params")
ffmpeg_out_cmd.insert(idx + 1, "force-cfr=1:scenecut=0:open_gop=0:sync-lookahead=0")
proc_v = None
proc_a = None
@@ -385,7 +393,8 @@ def run_demucs_pipeline(
except queue.Empty:
# 若 proc_out推流进程已异常退出立即报告
if proc_out.poll() is not None and proc_out.returncode != 0:
print(f"[ERROR] YouTube 推流进程已退出,返回码: {proc_out.returncode}")
print(f"[ERROR] YouTube 推流进程已退出,返回码: {proc_out.returncode},可能是 Demucs 处理跟不上或网络问题")
print(f"[TIP] 若频繁断流,可尝试 config/youtube.ini 中设置 enable_demucs = 否 使用原始音频")
break
if time.time() - getattr(proc_v, "last_out_ts", time.time()) > stale_output_seconds:
print("[WARN] 长时间无任何日志,强制重启进程")

View File

@@ -258,7 +258,7 @@ def start_douyin_youtube_ffplay(
"-profile:v", "high",
# 720p画质优先YouTube 推荐 3-8 Mbps
"-b:v", f"{br_k}k", "-maxrate", f"{br_k+500}k", "-bufsize", f"{br_k*2}k",
"-vsync", "cfr",
"-fps_mode", "cfr",
"-g", "60", "-keyint_min", "60",
"-r", "30",
"-bf", "0",