's'
This commit is contained in:
72
main.py
72
main.py
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user