Files
ffmpeg/main2.py
2026-02-10 14:35:18 +03:00

132 lines
4.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import ffmpeg
import threading
import time
import sys
from datetime import datetime
LOGLEVEL = "info" # поставь "debug" для диагностики
# 1) ВХОД от vMix: ffmpeg слушает, vMix звонит
IN_URL = "srt://0.0.0.0:9000?mode=listener&reuseaddr=1&transtype=live"
# 2) ЛОКАЛЬНЫЙ буфер (UDP внутри одного ПК)
# Любой свободный порт, лучше 10000+
LOCAL_UDP_OUT = "udp://127.0.0.1:10000?pkt_size=1316&fifo_size=5000000&overrun_nonfatal=1"
LOCAL_UDP_IN = "udp://127.0.0.1:10000?fifo_size=5000000&overrun_nonfatal=1"
# 3) ВЫХОД: вариант A (рекомендую для VLC/мобилы) — OUT listener, клиенты подключаются caller
OUT_URL = "srt://0.0.0.0:9001?mode=listener&reuseaddr=1&transtype=live"
# Если тебе нужен OUT caller на конкретное устройство, используй вместо этого:
# OUT_URL = "srt://10.10.1.238:9001?mode=caller&latency=200000&transtype=live&connect_timeout=5000"
def now():
return datetime.now().strftime("%H:%M:%S")
def pump_stderr(proc, tag):
"""Читает stderr, чтобы процесс не подвис из-за заполненного буфера."""
try:
for raw in iter(proc.stderr.readline, b""):
if not raw:
break
line = raw.decode("utf-8", errors="replace").rstrip("\n")
if line:
print(f"[{now()}] {tag}: {line}")
except Exception:
pass
def start_ingest():
"""
SRT-IN -> UDP localhost (не зависит от OUT!)
"""
stream = (
ffmpeg
.input(IN_URL)
.output(LOCAL_UDP_OUT, format="mpegts", codec="copy")
.global_args(
"-hide_banner",
"-loglevel", LOGLEVEL,
"-fflags", "+genpts",
"-flags", "low_delay",
)
)
proc = stream.run_async(pipe_stderr=True)
threading.Thread(target=pump_stderr, args=(proc, "INGEST"), daemon=True).start()
return proc
def start_egress():
"""
UDP localhost -> SRT-OUT
(можно падать/перезапускаться сколько угодно — IN не трогаем)
"""
stream = (
ffmpeg
.input(LOCAL_UDP_IN, format="mpegts")
.output(OUT_URL, format="mpegts", codec="copy")
.global_args(
"-hide_banner",
"-loglevel", LOGLEVEL,
"-fflags", "+genpts",
"-flags", "low_delay",
)
)
proc = stream.run_async(pipe_stderr=True)
threading.Thread(target=pump_stderr, args=(proc, "EGRESS"), daemon=True).start()
return proc
def run_forever():
# INGEST: держим почти “вечно”, перезапускаем только если упал вход
ingest_backoff = 1.0
ingest_backoff_max = 10.0
# EGRESS: можно перезапускать часто (если клиент/сеть отвалилась)
egress_backoff = 0.5
egress_backoff_max = 5.0
ingest_proc = None
while True:
# 1) Убедимся, что INGEST жив
if ingest_proc is None or ingest_proc.poll() is not None:
if ingest_proc is not None:
print(f"[{now()}] INGEST exited rc={ingest_proc.returncode}")
print(f"[{now()}] Restarting INGEST in {ingest_backoff:.1f}s...\n")
time.sleep(ingest_backoff)
ingest_backoff = min(ingest_backoff * 1.5, ingest_backoff_max)
print(f"[{now()}] Starting INGEST...")
try:
ingest_proc = start_ingest()
ingest_backoff = 1.0 # сброс после успешного запуска
except FileNotFoundError:
print(f"[{now()}] ERROR: ffmpeg.exe not found (PATH).")
sys.exit(2)
except Exception as e:
print(f"[{now()}] ERROR starting INGEST: {e}")
time.sleep(ingest_backoff)
continue
# 2) Поднимаем/держим EGRESS отдельно
print(f"[{now()}] Starting EGRESS...")
try:
egress_proc = start_egress()
except Exception as e:
print(f"[{now()}] ERROR starting EGRESS: {e}")
time.sleep(egress_backoff)
egress_backoff = min(egress_backoff * 1.5, egress_backoff_max)
continue
rc = egress_proc.wait()
print(f"[{now()}] EGRESS exited rc={rc}")
print(f"[{now()}] Restarting EGRESS in {egress_backoff:.1f}s...\n")
time.sleep(egress_backoff)
egress_backoff = min(egress_backoff * 1.5, egress_backoff_max)
if __name__ == "__main__":
try:
run_forever()
except KeyboardInterrupt:
sys.exit(0)