使用FFmpeg+Python推流RTMP时遇转换失败及管道断裂问题求助
问题:FFmpeg推RTMP流时偶发断连错误
我用FFmpeg+Python子进程把视频帧推到Nginx搭建的RTMP服务器,读取ReceivedRecording目录下的视频文件拼接推送,大部分时候正常,但偶尔会出现以下错误导致程序停止:
[flv @ 0x55b933694b40] Failed to update header with correct duration. [flv @ 0x55b933694b40] Failed to update header with correct filesize.
以及
Conversion failed
随后抛出:
BrokenPipeError: [Errno 32] Broken pipe
实现代码
import subprocess import cv2 rtmp_url = "rtmp://..." path = 'ReceivedRecording' received_video_path = 'ReceivedRecording' while True: video_files = [filenames for filenames in sorted( os.listdir(received_video_path))] # Loop through the videos and concatenate them for filename in video_files[:len(video_files)-1]: video = cv2.VideoCapture(os.path.join(received_video_path, filename)) if p is None: fps = int(video.get(cv2.CAP_PROP_FPS)) width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)) # command and params for ffmpeg command = ['ffmpeg', '-y', '-f', 'rawvideo', '-vcodec', 'rawvideo', '-pix_fmt', 'bgr24', '-s', "{}x{}".format(width, height), '-re', '-r', '5', '-i', '-', # '-filter:v', 'setpts=4.0*PTS', '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-preset', 'ultrafast', '-tune','zerolatency', '-vsync','vfr', # '-crf','23', '-f', 'flv', rtmp_url] # using subprocess and pipe to fetch frame data p = subprocess.Popen(command, stdin=subprocess.PIPE) else: # Loop through the frames of each video while True: start_time = time.time() ret, frame = video.read() if not ret: # End of video, move to next video video.release() break p.stdin.write(frame.tobytes()) os.remove(os.path.join(received_video_path, filename))
Nginx RTMP配置
rtmp { server { listen 1935; chunk_size 7096; application live { live on; record off; push rtmp://...; } } }
日志文件内容
av_interleaved_write_frame(): Connection reset by peer No more output streams to write to, finishing. [flv @ 0x5561d1ca9b40] Failed to update header with correct duration. [flv @ 0x5561d1ca9b40] Failed to update header with correct filesize. Error writing trailer of rtmp://...: Connection reset by peer frame= 1 fps=0.0 q=20.0 Lsize= 1024kB time=00:00:00.00 bitrate=8390776.0kbits/s speed=0.00619x video:1053kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown Input file #0 (pipe:): Input stream #0:0 (video): 1 packets read (11059200 bytes); 1 frames decoded; Total: 1 packets (11059200 bytes) demuxed Output file #0 (rtmp://...): Output stream #0:0 (video): 1 frames encoded; 1 packets muxed (1077799 bytes); Total: 1 packets (1077799 bytes) muxed 1 frames successfully decoded, 0 decoding errors [AVIOContext @ 0x5561d1cad380] Statistics: 0 seeks, 35 writeouts [rtmp @ 0x5561d1cb7b80] Deleting stream... [libx264 @ 0x5561d1caae40] frame I:1 Avg QP:20.00 size:1077192 [libx264 @ 0x5561d1caae40] mb I I16..4: 100.0% 0.0% 0.0% [libx264 @ 0x5561d1caae40] coded y,uvDC,uvAC intra: 92.2% 50.5% 10.2% [libx264 @ 0x5561d1caae40] i16 v,h,dc,p: 34% 16% 37% 12% [libx264 @ 0x5561d1caae40] i8c dc,h,v,p: 35% 23% 33% 9% [libx264 @ 0x5561d1caae40] kb/s:43087.68 [AVIOContext @ 0x5561d1ca6a80] Statistics: 11059200 bytes read, 0 seeks Conversion failed!
问题分析与解决办法
错误根源
日志里的Connection reset by peer是核心问题——RTMP连接被服务器主动断开,后续的FLV头更新失败、BrokenPipe都是连接断开后的连锁反应。触发场景包括:
- 推送帧间隔过长或断帧,触发Nginx RTMP超时机制
- FFmpeg子进程异常退出,但Python代码未检测,继续往无效管道写数据
- 待推送视频的分辨率/帧率不一致,导致流参数突变引发服务器断开
修复步骤
添加子进程存活检测
每次写帧前检查FFmpeg进程状态,若已退出则重启:if p.poll() is not None: # 进程已终止,重新启动 p = subprocess.Popen(command, stdin=subprocess.PIPE)严格控制推送帧率
原代码的start_time未实际使用,导致推送速率可能失控。添加帧率控制逻辑:frame_interval = 1.0 / 5 # 对应设定的5fps elapsed_time = time.time() - start_time if elapsed_time < frame_interval: time.sleep(frame_interval - elapsed_time)统一视频流参数
确保所有待推送视频的分辨率、帧率一致。若无法提前处理,可在FFmpeg命令中固定参数(不依赖第一个视频的属性),避免流参数突变。捕获BrokenPipe异常并重启
给写管道操作添加异常捕获,出现断连时立即重启FFmpeg:try: p.stdin.write(frame.tobytes()) p.stdin.flush() # 强制刷新缓冲区,避免帧堆积 except BrokenPipeError: p.kill() p = subprocess.Popen(command, stdin=subprocess.PIPE) p.stdin.write(frame.tobytes())优化FFmpeg参数
添加时间戳修正参数,避免流时序问题:command = ['ffmpeg', '-y', '-f', 'rawvideo', '-vcodec', 'rawvideo', '-pix_fmt', 'bgr24', '-s', "{}x{}".format(width, height), '-re', '-r', '5', '-i', '-', '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-preset', 'ultrafast', '-tune','zerolatency', '-vsync','vfr', '-avoid_negative_ts', 'make_zero', # 新增:修正时间戳 '-f', 'flv', rtmp_url]
内容的提问来源于stack exchange,提问作者Loc Bui Nhien
相关产品推荐
相关产品推荐

