You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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代码未检测,继续往无效管道写数据
  • 待推送视频的分辨率/帧率不一致,导致流参数突变引发服务器断开

修复步骤

  1. 添加子进程存活检测
    每次写帧前检查FFmpeg进程状态,若已退出则重启:

    if p.poll() is not None:
        # 进程已终止,重新启动
        p = subprocess.Popen(command, stdin=subprocess.PIPE)
    
  2. 严格控制推送帧率
    原代码的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)
    
  3. 统一视频流参数
    确保所有待推送视频的分辨率、帧率一致。若无法提前处理,可在FFmpeg命令中固定参数(不依赖第一个视频的属性),避免流参数突变。

  4. 捕获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())
    
  5. 优化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 07:32:20