s
This commit is contained in:
@@ -126,11 +126,11 @@ def _resolve_youtube_push_config_file(config_file: str | None = None, *, base_di
|
|||||||
def _load_youtube_push_settings(config_file: str) -> dict[str, str | bool]:
|
def _load_youtube_push_settings(config_file: str) -> dict[str, str | bool]:
|
||||||
settings: dict[str, str | bool] = {
|
settings: dict[str, str | bool] = {
|
||||||
"use_rtmps": True,
|
"use_rtmps": True,
|
||||||
"b_v": "2800k",
|
"b_v": "4000k",
|
||||||
"maxrate": "3200k",
|
"maxrate": "4500k",
|
||||||
"bufsize": "5600k",
|
"bufsize": "8000k",
|
||||||
"stream_key": "",
|
"stream_key": "",
|
||||||
"fast_audio": True,
|
"fast_audio": False,
|
||||||
}
|
}
|
||||||
if not os.path.exists(config_file):
|
if not os.path.exists(config_file):
|
||||||
return settings
|
return settings
|
||||||
@@ -144,8 +144,8 @@ def _load_youtube_push_settings(config_file: str) -> dict[str, str | bool]:
|
|||||||
v = (v or "").strip()
|
v = (v or "").strip()
|
||||||
if k == "rtmps" and v.lower() in ("0", "false", "否"):
|
if k == "rtmps" and v.lower() in ("0", "false", "否"):
|
||||||
settings["use_rtmps"] = False
|
settings["use_rtmps"] = False
|
||||||
elif k == "fast_audio" and v.lower() in ("1", "true", "yes", "是", "开", "on"):
|
elif k == "fast_audio":
|
||||||
settings["fast_audio"] = True
|
settings["fast_audio"] = v.lower() in ("1", "true", "yes", "是", "开", "on")
|
||||||
elif k == "bitrate" and v:
|
elif k == "bitrate" and v:
|
||||||
try:
|
try:
|
||||||
n = int(v)
|
n = int(v)
|
||||||
@@ -182,10 +182,10 @@ def start_douyin_youtube_ffplay(
|
|||||||
rtmps_base = "rtmps://a.rtmp.youtube.com/live2/"
|
rtmps_base = "rtmps://a.rtmp.youtube.com/live2/"
|
||||||
rtmp_base = "rtmp://a.rtmp.youtube.com/live2/"
|
rtmp_base = "rtmp://a.rtmp.youtube.com/live2/"
|
||||||
use_rtmps = True
|
use_rtmps = True
|
||||||
# 720p 竖屏 YouTube 建议 4–6 Mbps,偏低易触发「数据不足/卡顿」提示
|
# 720p 竖屏,符合 YouTube 推荐:4–6 Mbps、2s 关键帧、AAC 128k
|
||||||
b_v, maxrate, bufsize = "2800k", "3200k", "5600k"
|
b_v, maxrate, bufsize = "4000k", "4500k", "8000k"
|
||||||
stream_key = None
|
stream_key = None
|
||||||
fast_audio = True # 默认轻量音频链,必要时可在配置里关闭
|
fast_audio = False # 默认恢复强化音频链,必要时可在配置里开启轻量模式
|
||||||
|
|
||||||
if os.path.exists(config_file):
|
if os.path.exists(config_file):
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
@@ -195,8 +195,8 @@ def start_douyin_youtube_ffplay(
|
|||||||
v = (v or "").strip()
|
v = (v or "").strip()
|
||||||
if k == "rtmps" and v.lower() in ("0", "false", "否"):
|
if k == "rtmps" and v.lower() in ("0", "false", "否"):
|
||||||
use_rtmps = False
|
use_rtmps = False
|
||||||
elif k == "fast_audio" and v.lower() in ("1", "true", "yes", "是", "开", "on"):
|
elif k == "fast_audio":
|
||||||
fast_audio = True
|
fast_audio = v.lower() in ("1", "true", "yes", "是", "开", "on")
|
||||||
elif k == "bitrate" and v:
|
elif k == "bitrate" and v:
|
||||||
try:
|
try:
|
||||||
n = int(v)
|
n = int(v)
|
||||||
@@ -342,14 +342,13 @@ def start_douyin_youtube_ffplay(
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[WARN] NVENC 检测失败,回退软件编码: {e}")
|
print(f"[WARN] NVENC 检测失败,回退软件编码: {e}")
|
||||||
|
|
||||||
_cpu_n = os.cpu_count() or 4
|
_filter_threads = "4"
|
||||||
_filter_threads = str(min(2, max(1, _cpu_n // 2)))
|
|
||||||
|
|
||||||
# ====================== 开源音频处理:背景音乐弱化 + 防版权 ======================
|
# ====================== 开源音频处理:背景音乐弱化 + 防版权 ======================
|
||||||
_script_dir = os.path.dirname(os.path.abspath(__file__))
|
_script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
_ffmpeg_cwd = None
|
_ffmpeg_cwd = None
|
||||||
if fast_audio:
|
if fast_audio:
|
||||||
print("[INFO] fast_audio=开:轻量音频链(无 arnndn/长 EQ),减轻 CPU 以利 speed≥1.0")
|
print("[INFO] fast_audio=开:使用轻量音频链")
|
||||||
_af_chain = "afftdn=nf=-26:tn=1,aresample=async=1:first_pts=0"
|
_af_chain = "afftdn=nf=-26:tn=1,aresample=async=1:first_pts=0"
|
||||||
else:
|
else:
|
||||||
# 优先 RNNoise(arnndn),无模型则用 afftdn;aphaser 相位扰动可干扰 Content ID 指纹
|
# 优先 RNNoise(arnndn),无模型则用 afftdn;aphaser 相位扰动可干扰 Content ID 指纹
|
||||||
@@ -372,7 +371,7 @@ def start_douyin_youtube_ffplay(
|
|||||||
print("[INFO] 未找到 arnndn 模型,使用 afftdn 降噪(可克隆 richardpl/arnndn-models 到 arnndn-models/)")
|
print("[INFO] 未找到 arnndn 模型,使用 afftdn 降噪(可克隆 richardpl/arnndn-models 到 arnndn-models/)")
|
||||||
_af_denoise = "afftdn=nf=-26:tn=1,"
|
_af_denoise = "afftdn=nf=-26:tn=1,"
|
||||||
|
|
||||||
# 仅在明确需要时才启用重音频链,默认优先保 CPU
|
# 强化版:收紧带通 + 频率偏移 + 音高微调 + 多段 EQ + 相位扰动
|
||||||
_af_chain = (
|
_af_chain = (
|
||||||
_af_denoise
|
_af_denoise
|
||||||
+ "highpass=f=200,lowpass=f=3800,"
|
+ "highpass=f=200,lowpass=f=3800,"
|
||||||
@@ -389,14 +388,13 @@ def start_douyin_youtube_ffplay(
|
|||||||
+ "aresample=async=1:first_pts=0"
|
+ "aresample=async=1:first_pts=0"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 720p 竖屏低耗档:更低帧率和码率,优先保证 2 路并发可用
|
_video_mid = ["-vsync", "cfr", "-g", "60", "-keyint_min", "60", "-r", "30",
|
||||||
_video_mid = ["-vsync", "cfr", "-g", "30", "-keyint_min", "30", "-r", "15",
|
|
||||||
"-bf", "0", "-sc_threshold", "0"]
|
"-bf", "0", "-sc_threshold", "0"]
|
||||||
if codec_v == "libx264":
|
if codec_v == "libx264":
|
||||||
_video_mid += ["-x264-params", "force-cfr=1:scenecut=0:open_gop=0:sync-lookahead=0"]
|
_video_mid += ["-x264-params", "force-cfr=1:scenecut=0:open_gop=0:sync-lookahead=0"]
|
||||||
# -re:按源时间戳节奏拉流,避免突发过快;不用 realtime/arealtime(输入抖动时易让 YouTube 判为数据不足)
|
# -re:按源时间戳节奏拉流,避免突发过快;不用 realtime/arealtime(输入抖动时易让 YouTube 判为数据不足)
|
||||||
_vf_pad = (
|
_vf_pad = (
|
||||||
"fps=15,scale=720:1280:force_original_aspect_ratio=decrease:flags=bilinear,"
|
"fps=30,scale=720:1280:force_original_aspect_ratio=decrease:flags=bilinear,"
|
||||||
"pad=720:1280:(ow-iw)/2:(oh-ih)/2:black"
|
"pad=720:1280:(ow-iw)/2:(oh-ih)/2:black"
|
||||||
)
|
)
|
||||||
_ffmpeg_pre_input = []
|
_ffmpeg_pre_input = []
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class YoutubeRuntimeTests(unittest.TestCase):
|
|||||||
self.assertEqual(normalize_youtube_video_save_type("ts", "tiktok"), "TS")
|
self.assertEqual(normalize_youtube_video_save_type("ts", "tiktok"), "TS")
|
||||||
self.assertEqual(normalize_youtube_video_save_type("unknown", "tiktok"), "TS")
|
self.assertEqual(normalize_youtube_video_save_type("unknown", "tiktok"), "TS")
|
||||||
|
|
||||||
def test_push_defaults_use_lighter_profile(self) -> None:
|
def test_push_defaults_restore_full_profile(self) -> None:
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
from douyin_youtube_ffplay import _load_youtube_push_settings
|
from douyin_youtube_ffplay import _load_youtube_push_settings
|
||||||
@@ -27,8 +27,10 @@ class YoutubeRuntimeTests(unittest.TestCase):
|
|||||||
cfg = Path(tmp) / "youtube.ini"
|
cfg = Path(tmp) / "youtube.ini"
|
||||||
cfg.write_text("[youtube]\nkey = abc\n", encoding="utf-8")
|
cfg.write_text("[youtube]\nkey = abc\n", encoding="utf-8")
|
||||||
settings = _load_youtube_push_settings(str(cfg))
|
settings = _load_youtube_push_settings(str(cfg))
|
||||||
self.assertEqual(settings["b_v"], "2800k")
|
self.assertEqual(settings["b_v"], "4000k")
|
||||||
self.assertTrue(settings["fast_audio"])
|
self.assertEqual(settings["maxrate"], "4500k")
|
||||||
|
self.assertEqual(settings["bufsize"], "8000k")
|
||||||
|
self.assertFalse(settings["fast_audio"])
|
||||||
|
|
||||||
def test_arm_falls_back_from_vaapi_to_v4l2m2m(self) -> None:
|
def test_arm_falls_back_from_vaapi_to_v4l2m2m(self) -> None:
|
||||||
enc, note = resolve_live_video_encoder(
|
enc, note = resolve_live_video_encoder(
|
||||||
|
|||||||
Reference in New Issue
Block a user