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

OpenCV处理帧后用GStreamer推RTSP流无法连接及自定义流名问题

OpenCV帧处理后GStreamer输出RTSP流故障修复

故障表现

  • 测试代码运行无报错,但输出的RTSP流无法正常访问
  • VLC播放器无法建立连接,本地执行如下拉流命令时返回连接错误:
gst-launch-1.0 rtspsrc location=rtsp://localhost:8554 latency=100 ! 
queue ! rtph264depay ! h264parse ! avdec_h264 ! 
videoconvert ! videoscale ! video/x-raw,width=640,height=480 ! 
Xvimagesink

返回错误信息:

Setting pipeline to PAUSED ...

Pipeline is live and does not need PREROLL ...

Progress: (open) Opening Stream

Progress: (connect) Connecting to rtsp://localhost:8554

ERROR: from element /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0: Could not open resource for reading and writing.

Additional debug info:

gstrtspsrc.c(7469): gst_rtspsrc_retrieve_sdp (): /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0:

Failed to connect. (Generic error)

ERROR: pipeline doesn't want to preroll.

原有实现流程

  • 获取相机帧格式参数
  • 创建视频捕获实例
  • 获取本机当前IP地址
  • 配置RTSP推流管道字符串
  • 创建OpenCV VideoWriter实例
  • 循环读取相机帧,执行YOLO检测处理
  • 本地窗口展示处理结果
  • 将处理后的帧写入RTSP流

核心需求

  • 修复RTSP流无法连接的问题
  • 支持自定义流名称配置,实现形如rtsp://192.168.1.158:8554/test的带路径RTSP访问地址

原有问题代码

import subprocess as sb
import shlex as sh
import cv2
import socket
import time

def get_frame_format():
    command = 'v4l2-ctl -d /dev/video0 --list-formats-ext'
    args = sh.split(command)
    p = sb.Popen(args,  stdout=sb.PIPE,  stderr=sb.STDOUT)
    res = p.communicate()[0].split()

    fps = float(res[-2].decode('utf-8')[1:])
    size = list(map (int , res[19].decode('utf-8').split('x')))
    width = size[0]
    height = size[1]
    return fps,  width,  height

fps,  width,  height = get_frame_format()    

print (f"fps: {fps}, {type(fps)}\n, size: {width} {height}")

window_title = "USB Camera"
camera_id = "/dev/video0"
cam = cv2.VideoCapture(camera_id,  cv2.CAP_V4L2)

#Get current IP for RTSP
s = socket.socket(socket.AF_INET,  socket.SOCK_DGRAM)
s.connect(("8.8.8.8",  80))
ip_address = s.getsockname()[0]


pipe_out = 'appsrc is-live=True ! queue ! videoconvert ! video/x-raw, format=RGBA ! nvvidconv\
      ! omxh264enc insert-sps-pps=true ! video/x-h264, stream-format=byte-stream! h264parse \
      ! rtph264pay name=pay0 pt=96 config-interval=1 ! udpsink port=8554 host=192.168.1.158'


rtsp_out = cv2.VideoWriter(pipe_out,  fourcc=0,  apiPreference=cv2.CAP_GSTREAMER, fps=fps, 
                           frameSize=(1980, 1080),  isColor=True) 
time.sleep(2)
if not rtsp_out.isOpened() :
   print("Writer failed")
   exit()

print('Writer opened')

if cam.isOpened():
    try:
        window_handle = cv2.namedWindow(window_title, cv2.WINDOW_KEEPRATIO )
        while True:
            ok, frame = cam.read()

            # Here  frame neuro processing by yolo
            
            # Showing result on local machine
            if cv2.getWindowProperty(window_title,  cv2.WND_PROP_AUTOSIZE) >=0:
                frame_out =  cv2.resize(frame,  (1980, 1080))
                cv2.imshow(window_title, frame_out)

                # result streaming to rtsp 
                rtsp_out.write(frame_out)
             
            else:
                break
            key = cv2.waitKey(1) & 0xFF  
            if key == 27 or key == ord("q"):
                break
    finally:
        rtsp_out.release()
        cam.release()
        cv2.destroyAllWindows()
     
else:
    print("Camera doesn't open")

问题根因

  1. 核心逻辑错误:原管道末端使用udpsink直接发送裸UDP RTP包,没有启动RTSP服务端。RTSP协议需要专门的服务组件处理客户端的握手、SDP协商、流地址映射等流程,直接往端口发UDP流时,客户端发起的RTSP连接请求没有服务响应,必然报连接失败。
  2. 格式不匹配:管道中指定输入帧格式为RGBA,但OpenCV通过GStreamer appsrc输出的帧默认是BGR格式,会导致编码异常。
  3. 参数硬编码:管道中硬编码了主机IP、输出分辨率为1980x1080,和之前动态获取的本机IP、相机参数不匹配,容易出现兼容性问题。

修复方案

前置依赖安装

先安装GStreamer RTSP服务组件,以Ubuntu/Jetson平台为例:

sudo apt update
sudo apt install -y gstreamer1.0-rtsp-server gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly python3-gi

如果使用Jetson平台的硬件编码器,确认nvvidconv、omxh264enc插件可用;x86平台可替换为x264enc软编码。

修复后可运行代码

代码中通过GstRtspServer创建RTSP服务,自定义挂载路径为/test,最终访问地址为rtsp://[本机IP]:8554/test,同时修正了帧格式、参数硬编码问题:

import cv2
import socket
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GLib
import threading

# 初始化GStreamer
Gst.init(None)

# 可自定义配置参数
RTSP_PORT = 8554
STREAM_PATH = "/test"
CAMERA_ID = "/dev/video0"
OUTPUT_WIDTH = 1980
OUTPUT_HEIGHT = 1080
FPS = 30

# 获取本机IP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
LOCAL_IP = s.getsockname()[0]
s.close()
print(f"RTSP访问地址: rtsp://{LOCAL_IP}:{RTSP_PORT}{STREAM_PATH}")

# 构建编码管道,Jetson硬件编码版本,x86可替换nvvidconv/omxh264enc为videoconvert/x264enc
PIPELINE = f"""
appsrc name=source is-live=true block=true format=GST_FORMAT_TIME caps=video/x-raw,format=BGR,width={OUTPUT_WIDTH},height={OUTPUT_HEIGHT},framerate={FPS}/1 !
queue ! videoconvert ! video/x-raw,format=I420 ! nvvidconv !
omxh264enc insert-sps-pps=true bitrate=4000000 ! h264parse !
rtph264pay name=pay0 pt=96 config-interval=1
"""

# 定义RTSP媒体工厂
class CameraFactory(GstRtspServer.RTSPMediaFactory):
    def __init__(self):
        super().__init__()
        self.set_shared(True)  # 支持多客户端同时拉流
        self.appsrc = None
        self.set_launch(PIPELINE)
        self.frame_count = 0

    def do_configure(self, rtsp_media):
        self.appsrc = rtsp_media.get_element().get_by_name("source")

    def write_frame(self, frame):
        if not self.appsrc:
            return
        data = frame.tobytes()
        buf = Gst.Buffer.new_wrapped(data)
        buf.duration = Gst.SECOND // FPS
        buf.pts = buf.dts = Gst.util_uint64_scale(self.frame_count, Gst.SECOND, FPS)
        self.appsrc.emit("push-buffer", buf)
        self.frame_count += 1

# 启动RTSP服务
server = GstRtspServer.RTSPServer()
server.set_service(str(RTSP_PORT))
mounts = server.get_mount_points()
factory = CameraFactory()
mounts.add_factory(STREAM_PATH, factory)
server.attach(None)

# 启动GLib主循环(后台运行)
loop = GLib.MainLoop()
threading.Thread(target=loop.run, daemon=True).start()

# 打开相机
cam = cv2.VideoCapture(CAMERA_ID, cv2.CAP_V4L2)
if not cam.isOpened():
    print("相机打开失败")
    exit()

window_title = "Processed Stream"
cv2.namedWindow(window_title, cv2.WINDOW_KEEPRATIO)

try:
    while True:
        ret, frame = cam.read()
        if not ret:
            break
        # 此处插入YOLO检测处理逻辑
        frame_out = cv2.resize(frame, (OUTPUT_WIDTH, OUTPUT_HEIGHT))
        # 本地显示
        cv2.imshow(window_title, frame_out)
        # 写入RTSP流
        factory.write_frame(frame_out)

        key = cv2.waitKey(1) & 0xFF
        if key == 27 or key == ord('q'):
            break
finally:
    cam.release()
    cv2.destroyAllWindows()
    loop.quit()

验证方法

代码启动后,用VLC或gst-launch-1.0访问rtsp://[本机IP]:8554/test即可正常拉流,拉流命令示例:

gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/test latency=100 ! queue ! rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! autovideosink

内容的提问来源于stack exchange,提问作者Алексей Фадеев

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 21:24:30