picam.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import os
  2. import subprocess
  3. import time
  4. import re
  5. from setting import RTMP_URL, CAM_NAME, AUDIO_DEVICE, FONT_PATH
  6. # --- 配置参数 ---
  7. # 替换为你的 ffmpeg 命令(建议先在终端测试成功)
  8. FFMPEG_CMD = [
  9. 'ffmpeg',
  10. '-hide_banner',
  11. '-thread_queue_size', '2048',
  12. '-f', 'video4linux2',
  13. '-video_size', '1024x768',
  14. '-framerate', '25',
  15. '-i', '/dev/video0',
  16. '-thread_queue_size', '8192',
  17. '-f', 'alsa',
  18. '-ac', '1',
  19. '-i', AUDIO_DEVICE,
  20. '-vcodec', 'libx264',
  21. '-acodec', 'aac',
  22. '-b:v', '4M',
  23. '-b:a', '128K',
  24. '-max_delay', '1000000',
  25. '-g', '50',
  26. '-preset:v', 'ultrafast',
  27. '-tune:v', 'zerolatency',
  28. '-vf', (
  29. f"drawtext=fontfile={FONT_PATH}:"
  30. f"text='{CAM_NAME} | %{{localtime\\:%Y-%m-%d %H\\\\\\:%M\\\\\\:%S}}':"
  31. "x=20:y=20:fontsize=28:fontcolor=yellow:shadowcolor=black:shadowx=2:shadowy=2"
  32. ),
  33. '-f', 'flv',
  34. RTMP_URL
  35. ]
  36. RESTART_DELAY = 5 # 重启间隔(秒)
  37. def monitor_stream():
  38. while True:
  39. # 杀死所有属于当前用户的 ffmpeg 进程,防止冲突
  40. os.system("pkill -9 ffmpeg > /dev/null 2>&1")
  41. print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 正在启动 FFmpeg 推流...")
  42. # 启动进程,将 stderr 重定向以便监控状态
  43. process = subprocess.Popen(
  44. FFMPEG_CMD,
  45. stdout=subprocess.PIPE,
  46. stderr=subprocess.STDOUT,
  47. universal_newlines=True,
  48. bufsize=1
  49. )
  50. try:
  51. # 实时读取 FFmpeg 输出的状态行
  52. while True:
  53. line = process.stdout.readline()
  54. if not line:
  55. break
  56. # 监控推流状态(例如抓取 fps 和 bitrate)
  57. if "frame=" in line:
  58. # 使用正则或字符串切片提取关键信息
  59. stats = re.findall(r'(frame=.*?bitrate=.*?speed=.*?x)', line)
  60. if stats:
  61. print(f"\r推流中: {stats[0].strip()}", end="")
  62. else:
  63. print(f"\n[FFmpeg 日志] {line.strip()}")
  64. # 检查进程是否意外退出
  65. if process.poll() is not None:
  66. break
  67. except Exception as e:
  68. print(f"\n监控异常: {e}")
  69. finally:
  70. # 确保彻底杀死进程
  71. if process.poll() is None:
  72. process.terminate()
  73. try:
  74. process.wait(timeout=5)
  75. except subprocess.TimeoutExpired:
  76. process.kill()
  77. print(f"[{time.strftime('%H:%M:%S')}] FFmpeg 进程已结束,{RESTART_DELAY}秒后重启...")
  78. time.sleep(RESTART_DELAY)
  79. if __name__ == "__main__":
  80. try:
  81. monitor_stream()
  82. except KeyboardInterrupt:
  83. print("用户手动停止,程序退出。")