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

如何用Python实现同一端口下多视频RTSP流发布?

同一端口下创建多个RTSP流的解决方案

首先明确:完全可以在同一个端口下运行多个RTSP流,每个流通过不同的挂载路径区分(比如你提到的rtsp://12.0.0.1:8554/test和rtsp://12.0.0.1:8554/test2)。你的代码问题出在创建了两个独立的RTSP服务器实例,它们都试图绑定同一个端口,导致端口冲突,第二个服务器根本启动不起来,所以只有第一个流能工作。

问题分析

你的代码里,每个线程都实例化了一个GstServer(继承自RTSPServer),并且都设置了同一个端口8012。当第一个服务器绑定端口后,第二个服务器尝试绑定同一个端口时会失败(系统会返回"地址已在使用"的错误,只是你的代码没做错误处理所以没看到)。这就是第二个流无法生成的核心原因。

正确的做法是:只创建一个RTSP服务器实例,然后给它添加多个不同挂载路径的媒体工厂(MediaFactory),每个工厂对应一个视频流。

修复后的代码

import cv2
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GObject

class SensorFactory(GstRtspServer.RTSPMediaFactory):
    def __init__(self, video, **properties):
        super(SensorFactory, self).__init__(**properties)
        self.cap = cv2.VideoCapture(video)
        self.number_frames = 0
        self.fps = 30
        self.duration = 1 / self.fps * Gst.SECOND  # 帧的持续时间(纳秒)
        self.launch_string = 'appsrc name=source block=true format=GST_FORMAT_TIME ' \
            'caps=video/x-raw,format=BGR,width=600,height=600,framerate={}/1 ' \
            '! videoconvert ! video/x-raw,format=I420 ' \
            '! x264enc speed-preset=ultrafast tune=zerolatency ' \
            '! rtph264pay config-interval=1 name=pay0 pt=96'.format(self.fps)

    def on_need_data(self, src, length):
        if self.cap.isOpened():
            ret, frame = self.cap.read()
            if not ret:
                # 视频读取完毕后重置到开头循环播放(可选逻辑,可根据需求删除)
                self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
                return
            frame = cv2.resize(frame, (600, 600))
            data = frame.tobytes()  # 替换tostring(),符合Python3规范
            buf = Gst.Buffer.new_allocate(None, len(data), None)
            buf.fill(0, data)
            buf.duration = self.duration
            timestamp = self.number_frames * self.duration
            buf.pts = buf.dts = int(timestamp)
            buf.offset = timestamp
            self.number_frames += 1
            retval = src.emit('push-buffer', buf)
            if retval != Gst.FlowReturn.OK:
                print(f"推送帧失败: {retval}")

    def do_create_element(self, url):
        return Gst.parse_launch(self.launch_string)

    def do_configure(self, rtsp_media):
        self.number_frames = 0
        appsrc = rtsp_media.get_element().get_child_by_name('source')
        appsrc.connect('need-data', self.on_need_data)

class GstServer(GstRtspServer.RTSPServer):
    def __init__(self, port="8012", **properties):
        super(GstServer, self).__init__(**properties)
        self.set_service(port)
        self.mount_points = self.get_mount_points()

    def add_stream(self, video_path, stream_name):
        # 为每个流创建独立的工厂实例
        factory = SensorFactory(video_path)
        factory.set_shared(True)  # 允许多个客户端同时连接同一个流
        self.mount_points.add_factory(f"/{stream_name}", factory)

if __name__ == "__main__":
    video_path = '/home/root1/Documents/test_videos/videoplayback.mp4'
    stream1_name = 'test'
    stream2_name = 'test1'

    GObject.threads_init()
    Gst.init(None)

    # 只创建一个服务器实例,避免端口冲突
    server = GstServer(port="8012")
    # 向服务器添加两个不同的流
    server.add_stream(video_path, stream1_name)
    server.add_stream(video_path, stream2_name)

    # 启动服务器
    server.attach(None)
    print(f"RTSP服务器启动,端口8012,可用流地址:")
    print(f"rtsp://12.0.0.1:8012/{stream1_name}")
    print(f"rtsp://12.0.0.1:8012/{stream2_name}")

    # 启动主循环处理事件
    loop = GObject.MainLoop()
    loop.run()

关键修改说明

  1. 单服务器实例:只初始化一个GstServer绑定目标端口,彻底避免端口冲突问题。
  2. 多流挂载机制:通过add_stream方法为服务器添加多个独立的SensorFactory,每个工厂对应一个唯一的流路径。
  3. 优化细节:添加视频循环播放逻辑、替换Python3过时API、增加错误提示,提升代码健壮性。

现在你可以通过rtsp://12.0.0.1:8012/test和rtsp://12.0.0.1:8012/test1访问两个独立的RTSP流,它们共用同一个端口正常工作。

内容的提问来源于stack exchange,提问作者belgin vinoj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:24:30