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

OpenCV处理RTSP帧后,如何用FFmpeg将JPEG帧转H.264 RTSP流?

问题描述

我有一个输入RTSP流,想用OpenCV逐帧处理,处理完成后基于这些帧创建独立的RTSP流。需通过标准输入(STDIN)将生成的JPEG图像管道传输给FFmpeg,且中间帧必须为JPEG格式,流程如下:
RTSP输入 → 生成JPEG作为输入 → 处理后输出JPEG → RTSP输出

当前遇到的问题与编解码器相关,FFmpeg输出错误信息显示连接失败,以下是我的代码和FFmpeg输出:

我的Python代码

def open_ffmpeg_stream_process():
    args = (
        "ffmpeg -re -stream_loop -1 "
        "-f jpeg_pipe "
        "-s 512x288 "
        "-i pipe:0 "
        "-c:v h264 "
        "-f rtsp "
        "rtsp://localhost:8100/out0"
    ).split()
    return subprocess.Popen(args, stdin=subprocess.PIPE)

video_source = cv2.VideoCapture('rtsp://localhost:9100/in0')

frame_cnt = 0
FRAME_SKIP = 30

ffmpeg_process = open_ffmpeg_stream_process()
while video_source.isOpened():

    frame_cnt += 1
    if frame_cnt % FRAME_SKIP:
      continue
    else:
      frame_cnt = 0

    _, frame = video_source.read()
    _, jpg = cv2.imencode('.jpg', frame)

    # 在这里对JPEG进行处理,输出仍是JPEG

    ffmpeg_process.stdin.write(jpg.astype(np.uint8).tobytes())

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

video_source.release()

FFmpeg输出信息

ffmpeg version 4.4.2-0ubuntu0.22.04.1 Copyright (c) 2000-2021 the FFmpeg developers
  built with gcc 11 (Ubuntu 11.2.0-19ubuntu1)
  configuration: ---- noisy configuration stuff ----
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
  libpostproc    55.  9.100 / 55.  9.100
Input #0, jpeg_pipe, from 'pipe:0':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: mjpeg, rgb24(bt470bg/unknown/unknown), 512x288, 25 fps, 25 tbr, 25 tbn, 25 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (mjpeg (native) -> h264 (libx264))
[libx264 @ 0x562a1ffc5840] using SAR=1/1
[libx264 @ 0x562a1ffc5840] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 0x562a1ffc5840] profile High, level 3.1, 4:2:0, 8-bit
[libx264 @ 0x562a1ffc5840] 264 - core 163 r3060 5db6aa6 - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=18 lookahead_threads=3 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
[tcp @ 0x562a20826c00] Connection to tcp://localhost:8100?timeout=0 failed: Connection refused
Could not write header for output file #0 (incorrect codec parameters ?): Connection refused
Error initializing output stream 0:0 -- 
Conversion failed!

我需要解决的问题:如何通过FFmpeg从一系列JPEG帧创建H.264编码的RTSP流?也欢迎对我的代码提出改进意见。

编辑:我发现单独执行FFmpeg命令也无法工作。


解决方案

1. 解决RTSP连接拒绝问题

错误中的Connection refused是核心问题:FFmpeg仅作为RTSP推流客户端,无法自行提供RTSP服务,必须先启动一个RTSP服务器来接收推流。推荐使用rtsp-simple-server:

  • 安装后直接运行,默认监听8554端口,可修改配置文件调整端口,或直接将推流地址改为rtsp://localhost:8554/out0

2. 优化FFmpeg命令

原命令存在多处不合理,调整后的命令如下:

ffmpeg -re -f jpeg_pipe -s 512x288 -r 25 -i pipe:0 -c:v libx264 -preset ultrafast -tune zerolatency -f rtsp rtsp://localhost:8554/out0
  • 移除-stream_loop -1:该参数用于循环读取文件,管道实时输入无需循环
  • 添加-r 25:明确指定帧率,避免FFmpeg自动猜测出错,需与输入JPEG的实际帧率匹配
  • 替换-c:v h264为-c:v libx264:明确指定使用libx264编码器,避免系统默认编码器不兼容
  • 添加-preset ultrafast和-tune zerolatency:针对实时推流优化,降低延迟,适配RTSP场景

3. 优化Python代码

(1)修正帧跳过逻辑

原代码的帧跳过逻辑本身没问题,但需注意:FRAME_SKIP=30会导致每30帧仅处理1帧,最终推流帧率极低,需根据需求调整该值。

(2)处理管道缓冲问题

直接写入管道可能因缓冲导致延迟,建议每次写入后调用flush():

ffmpeg_process.stdin.write(jpg.astype(np.uint8).tobytes())
ffmpeg_process.stdin.flush()

(3)完善资源清理与异常处理

添加异常捕获与资源释放逻辑,避免进程残留:

try:
    while video_source.isOpened():
        frame_cnt += 1
        if frame_cnt % FRAME_SKIP:
            continue
        else:
            frame_cnt = 0

        ret, frame = video_source.read()
        if not ret:
            break
            
        _, jpg = cv2.imencode('.jpg', frame)
        # 在这里对JPEG进行处理,输出仍是JPEG

        ffmpeg_process.stdin.write(jpg.astype(np.uint8).tobytes())
        ffmpeg_process.stdin.flush()

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
except Exception as e:
    print(f"执行出错: {e}")
finally:
    video_source.release()
    cv2.destroyAllWindows()
    ffmpeg_process.stdin.close()
    ffmpeg_process.wait()

(4)JPEG处理注意事项

若处理后的JPEG尺寸与原帧不同,需同步修改FFmpeg命令中的-s参数,否则会出现画面变形或编码错误。

4. 验证流程

  1. 启动RTSP服务器(如rtsp-simple-server)
  2. 运行修改后的Python代码
  3. 用VLC或其他RTSP播放器连接rtsp://localhost:8554/out0,检查播放是否正常

内容的提问来源于stack exchange,提问作者Michael Schmidt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:46:06