Ubuntu下Python+FFmpeg推RTMP流遇BrokenPipeError[Errno32]求助
解决Ubuntu下Python+FFmpeg推RTMP流出现BrokenPipeError的问题
你的脚本在Windows正常运行但Ubuntu上报错,核心原因是环境差异导致FFmpeg进程异常退出,进而触发管道写入错误。以下是针对性修复方案:
1. 移除shell=True并捕获FFmpeg错误输出
Ubuntu下使用shell=True会额外启动shell进程,容易引发管道异常,且无法获取FFmpeg的错误日志,不利于排查问题。修改子进程启动代码:
# 去掉shell=True,同时捕获stdout/stderr以便查看FFmpeg运行日志 p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
2. 禁用cv2.imshow(无头服务器环境适配)
Ubuntu服务器通常没有图形界面,cv2.imshow因无法创建窗口会直接报错,中断整个推流流程。直接删除以下两行代码:
# cv2.imshow('frame', frame) # cv2.waitKey(1)
3. 匹配实际帧率并调整编码预设
脚本中强制指定-r 30,但实际摄像头帧率可能与该值不符,会导致FFmpeg帧处理速度不匹配引发管道中断。同时preset slow在服务器上CPU占用过高,容易导致进程卡顿退出:
# 替换为实际捕获的帧率,编码预设改用ultrafast降低CPU负载 command = ['ffmpeg', '-y', '-f', 'rawvideo', '-vcodec', 'rawvideo', '-pix_fmt', 'bgr24', '-s', "{}x{}".format(width, height), '-r', str(fps), # 使用摄像头实际帧率 '-i', '-', '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-preset', 'ultrafast', # 服务器实时推流推荐用该预设 '-threads', '0', '-f', 'flv', rtmp_url]
4. 捕获管道异常并清理资源
当FFmpeg进程异常退出后,写入管道会触发BrokenPipeError,需要捕获该异常并及时清理子进程:
while cap.isOpened(): ret, frame = cap.read() if not ret: print("读取帧失败") break try: p.stdin.write(frame.tobytes()) p.stdin.flush() # 强制刷新管道,确保数据及时写入 except BrokenPipeError: print("FFmpeg进程已退出,终止推流") # 打印FFmpeg错误日志排查问题 stderr_output = p.stderr.read() if stderr_output: print("FFmpeg错误详情:\n", stderr_output.decode('utf-8', errors='ignore')) break # 循环结束后释放所有资源 cap.release() if p.poll() is None: p.stdin.close() p.terminate() p.wait()
5. 检查摄像头设备权限
如果使用本地摄像头(path=0),需要确保当前用户有权限访问/dev/video0:
# 将当前用户加入video组 sudo usermod -aG video $USER # 注销后重新登录生效
修改后的完整脚本
import subprocess import cv2 rtmp_url = "rtmp://..." path = 0 cap = cv2.VideoCapture(path) # 采集视频基础信息 fps = int(cap.get(cv2.CAP_PROP_FPS)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # FFmpeg推流命令 command = ['ffmpeg', '-y', '-f', 'rawvideo', '-vcodec', 'rawvideo', '-pix_fmt', 'bgr24', '-s', f"{width}x{height}", '-r', str(fps), '-i', '-', '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-preset', 'ultrafast', '-threads', '0', '-f', 'flv', rtmp_url] # 启动FFmpeg子进程 p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) while cap.isOpened(): ret, frame = cap.read() if not ret: print("读取帧失败") break try: p.stdin.write(frame.tobytes()) p.stdin.flush() except BrokenPipeError: print("FFmpeg进程异常退出,停止推流") err_msg = p.stderr.read().decode('utf-8', errors='ignore') if err_msg: print("FFmpeg错误日志:\n", err_msg) break # 释放资源 cap.release() if p.poll() is None: p.stdin.close() p.terminate() p.wait()
内容的提问来源于stack exchange,提问作者Loc Bui Nhien
相关产品推荐
相关产品推荐

