This commit is contained in:
eric
2025-09-27 11:07:42 +08:00
parent da57df6a93
commit 1e9a0759e1
3 changed files with 178 additions and 91 deletions

72
main.py
View File

@@ -781,6 +781,58 @@ def direct_download_stream(source_url: str, save_path: str, record_name: str, li
logger.error(f"FLV下载错误: {e} 发生错误的行数: {e.__traceback__.tb_lineno}")
return False
import asyncio
import datetime
import subprocess
async def check_subprocess_with_heartbeat(record_name: str,
record_url: str,
ffmpeg_command: list,
save_type: str,
script_command: str | None = None,
heartbeat_timeout: int = 10) -> bool:
"""
启动 ffmpeg 子进程并进行心跳检测:
- 每 heartbeat_timeout 秒内必须有输出,否则认为卡死,直接 kill。
- 进程退出 returncode=0 正常,否则异常。
"""
process = await asyncio.create_subprocess_exec(
*ffmpeg_command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
last_heartbeat = datetime.datetime.now()
async def read_stream(stream, name):
nonlocal last_heartbeat
async for line in stream:
decoded = line.decode(errors="ignore").strip()
if decoded:
last_heartbeat = datetime.datetime.now()
# 可根据需要过滤/解析码率、fps
print(f"[{record_name}][{name}] {decoded}")
# 并行读取 stdout 和 stderr
asyncio.create_task(read_stream(process.stdout, "stdout"))
asyncio.create_task(read_stream(process.stderr, "stderr"))
while True:
# 检查进程是否退出
if process.returncode is not None:
break
# 检查心跳超时
now = datetime.datetime.now()
if (now - last_heartbeat).total_seconds() > heartbeat_timeout:
print(f"[心跳超时] {record_name}: {heartbeat_timeout}s 无数据,强制重启 ffmpeg")
process.kill()
await process.wait()
return False
await asyncio.sleep(2)
return process.returncode == 0
def check_subprocess(record_name: str, record_url: str, ffmpeg_command: list, save_type: str,
script_command: str | None = None) -> bool:
@@ -1237,13 +1289,19 @@ def start_record(url_data: tuple, count_variable: int = -1) -> None:
]
ffmpeg_command.extend(command)
comment_end = check_subprocess(
record_name,
record_url,
ffmpeg_command,
record_save_type,
custom_script
)
# comment_end = check_subprocess(
# record_name,
# record_url,
# ffmpeg_command,
# record_save_type,
# custom_script
# )
comment_end = asyncio.run(
check_subprocess_with_heartbeat(
record_name, record_url, ffmpeg_command, record_save_type, custom_script, heartbeat_timeout=15
)
)
if comment_end:
return