's'
This commit is contained in:
@@ -11,6 +11,7 @@ stats_interval_sec = 10
|
|||||||
|
|
||||||
# ===== 其次:音频版权处理 =====
|
# ===== 其次:音频版权处理 =====
|
||||||
# 是否启用 Demucs 人声分离(防 YouTube Content ID 版权识别)
|
# 是否启用 Demucs 人声分离(防 YouTube Content ID 版权识别)
|
||||||
|
# 若推流几十秒后断流(YouTube 显示 no data),可设为 否 使用原始音频
|
||||||
# 是 = 启用,只保留人声;否 = 使用原始音频
|
# 是 = 启用,只保留人声;否 = 使用原始音频
|
||||||
enable_demucs = 是
|
enable_demucs = 是
|
||||||
|
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ def _load_demucs_model(use_gpu: bool):
|
|||||||
# Demucs 模型采样率
|
# Demucs 模型采样率
|
||||||
DEMUCS_SAMPLE_RATE = 44100
|
DEMUCS_SAMPLE_RATE = 44100
|
||||||
DEMUCS_CHANNELS = 2
|
DEMUCS_CHANNELS = 2
|
||||||
# 每次处理的音频长度(秒),影响延迟与质量
|
# 每次处理的音频长度(秒),1.0 更易实时,2.0 质量更好但 P40 可能跟不上
|
||||||
DEMUCS_CHUNK_SEC = 2.0
|
DEMUCS_CHUNK_SEC = 1.0
|
||||||
# 字节 per sample (s16le: 2 bytes)
|
# 字节 per sample (s16le: 2 bytes)
|
||||||
BYTES_PER_SAMPLE = 2
|
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:
|
if wav.dim() == 2:
|
||||||
wav = wav.unsqueeze(0)
|
wav = wav.unsqueeze(0)
|
||||||
with torch.no_grad():
|
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)
|
# out: (batch, sources, channels, samples)
|
||||||
# sources: [drums=0, bass=1, other=2, vocals=3]
|
# sources: [drums=0, bass=1, other=2, vocals=3]
|
||||||
vocals = out[0, 3]
|
vocals = out[0, 3]
|
||||||
@@ -269,19 +269,27 @@ def run_demucs_pipeline(
|
|||||||
"-b:v", f"{nvenc_params.get('video_bitrate_k', 4500)}k",
|
"-b:v", f"{nvenc_params.get('video_bitrate_k', 4500)}k",
|
||||||
"-maxrate", f"{nvenc_params.get('video_bitrate_k', 4500)+500}k",
|
"-maxrate", f"{nvenc_params.get('video_bitrate_k', 4500)+500}k",
|
||||||
"-bufsize", f"{nvenc_params.get('video_bitrate_k', 4500)*2}k",
|
"-bufsize", f"{nvenc_params.get('video_bitrate_k', 4500)*2}k",
|
||||||
"-vsync", "cfr", "-g", "60", "-keyint_min", "60", "-r", "30",
|
"-fps_mode", "cfr", "-g", "60", "-keyint_min", "60", "-r", "30",
|
||||||
"-bf", "0", "-sc_threshold", "0",
|
"-bf", "0",
|
||||||
"-x264-params", "force-cfr=1:scenecut=0:open_gop=0:sync-lookahead=0",
|
|
||||||
"-pix_fmt", "yuv420p",
|
"-pix_fmt", "yuv420p",
|
||||||
"-c:a", "aac", "-b:a", "128k", "-ar", "48000", "-ac", "2",
|
"-c:a", "aac", "-b:a", "128k", "-ar", "48000", "-ac", "2",
|
||||||
"-af", "lowpass=f=9000,aresample=async=1:first_pts=0",
|
"-af", "lowpass=f=9000,aresample=async=1:first_pts=0",
|
||||||
"-flags", "+global_header", "-flvflags", "no_duration_filesize",
|
"-flags", "+global_header", "-flvflags", "no_duration_filesize",
|
||||||
"-f", "flv", youtube_rtmp,
|
"-f", "flv", youtube_rtmp,
|
||||||
]
|
]
|
||||||
if nvenc_params.get("tune_param"):
|
# NVENC 用 tune_param;libx264 用 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")
|
idx = ffmpeg_out_cmd.index("-profile:v")
|
||||||
for p in reversed(nvenc_params["tune_param"]):
|
for p in reversed(nvenc_params["tune_param"]):
|
||||||
ffmpeg_out_cmd.insert(idx, p)
|
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_v = None
|
||||||
proc_a = None
|
proc_a = None
|
||||||
@@ -385,7 +393,8 @@ def run_demucs_pipeline(
|
|||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
# 若 proc_out(推流进程)已异常退出,立即报告
|
# 若 proc_out(推流进程)已异常退出,立即报告
|
||||||
if proc_out.poll() is not None and proc_out.returncode != 0:
|
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
|
break
|
||||||
if time.time() - getattr(proc_v, "last_out_ts", time.time()) > stale_output_seconds:
|
if time.time() - getattr(proc_v, "last_out_ts", time.time()) > stale_output_seconds:
|
||||||
print("[WARN] 长时间无任何日志,强制重启进程")
|
print("[WARN] 长时间无任何日志,强制重启进程")
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ def start_douyin_youtube_ffplay(
|
|||||||
"-profile:v", "high",
|
"-profile:v", "high",
|
||||||
# 720p,画质优先,YouTube 推荐 3-8 Mbps
|
# 720p,画质优先,YouTube 推荐 3-8 Mbps
|
||||||
"-b:v", f"{br_k}k", "-maxrate", f"{br_k+500}k", "-bufsize", f"{br_k*2}k",
|
"-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",
|
"-g", "60", "-keyint_min", "60",
|
||||||
"-r", "30",
|
"-r", "30",
|
||||||
"-bf", "0",
|
"-bf", "0",
|
||||||
|
|||||||
Reference in New Issue
Block a user