如何让 RTSP 流显示在多个设备上?

How can I get the RTSP stream to show up on multiple devices?

提问人:NevMthw 提问时间:11/17/2023 最后编辑:NevMthw 更新时间:11/20/2023 访问量:70

问:

我有一个使用 gstreamer RTSP 服务器的代码,我正在尝试从图像/帧创建一些 rtsp 流。该实现工作正常,并将图像转换为 RTSP 流。

这个过程是我运行脚本,服务器现在处于活动状态,然后我可以在另一台机器上使用我当前机器 IP 的 RTSP 流。

问题:

  1. 我想知道如何更改rtsp端口并从config.json文件中获取它。出于某种原因,即使我没有明确说明使用该端口,使用的默认端口也是 8554。
  2. 在不同端口的帮助下,我是否能够通过一个 RTSP 服务器使用多个 rtsp 流?例如,如果我通过 VLC 流式传输相同的 RTSP URL,我当前的实现无法在多台计算机上工作。

这是我到目前为止的代码:

class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):
    def __init__(self, source):
        GstRtspServer.RTSPMediaFactory.__init__(self)
        self.source = source

    def do_create_element(self, url):
        image_folder = self.source.get("image_folder", None)

        if image_folder:
            # print('Image folder paths:', image_folder)
            pipeline = f"multifilesrc location={image_folder}/%d.jpg index=1 caps=\"image/jpeg,framerate=30/1\" ! jpegdec ! videoconvert ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast ! rtph264pay name=pay0 config-interval=1 pt=96"
        else:
            print("Invalid source. Specify 'image_folder' in the configuration.")
            return None
    
        print("Element created:", pipeline)
        return Gst.parse_launch(pipeline)

class GstreamerRtspServer():
    def __init__(self, sources):
        self.rtspServer = GstRtspServer.RTSPServer()
        self.mountPoints = self.rtspServer.get_mount_points()
        self.create_rtsp_streams(sources)

    def create_rtsp_streams(self, sources):
        for source in sources:
            rtsp_port = source["rtsp_port"]
            rtsp_mount_point = source["rtsp_mount_point"]
            print(rtsp_mount_point)
            print(rtsp_port)

            factory = TestRtspMediaFactory(source)
            factory.set_shared(True)
            self.mountPoints.add_factory(rtsp_mount_point, factory)

        self.rtspServer.attach(None)

def main(config_file):
    with open(config_file, 'r') as f:
        config = json.load(f)

    sources = config.get("sources", [])
    
    s = GstreamerRtspServer(sources)
    loop = GLib.MainLoop()
    loop.run()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Run RTSP server for multiple video sources.")
    parser.add_argument("--config", required=True, help="Path to the JSON configuration file.")
    args = parser.parse_args()
    
    main(args.config)

这是我的config.json文件:

{
    "sources": [
        {
            "image_folder": "/path/to/another/image/folder",
            "rtsp_port": 4000,
            "rtsp_mount_point": "/stream1"
        },
        {
            "image_folder": "/path/to/another/image/folder",
            "rtsp_port": 8555,
            "rtsp_mount_point": "/stream2"
        }
    ]
}
gstreamer rtsp 服务器

评论

0赞 NevMthw 11/17/2023
我看了一下这个端口问题的解决方案,但没有运气:stackoverflow.com/questions/52662203/......

答:

1赞 SeB 11/19/2023 #1
  1. 要设置服务器使用的端口,请使用 RtspServer 的方法。set_service

  2. 您不需要为不同的客户端指定不同的端口,RTSP服务器将与客户端协商并管理实际的端口和传输协议。客户端可以使用 stream1、stream2 仅使用 URI 选择流。

因此,在修改您的 json 配置文件后:

{
    "server": {
            "port": "8556"
    },
        
    "sources": [
        {
            "image_folder": "/home/neville/Documents/convert_rtsp_video/frames",
            "rtsp_mount_point": "/stream1"
        },
        {
            "image_folder": "/path/to/another/image/folder",
            "rtsp_mount_point": "/stream2"
        }
    ]
}

并将代码修改为:

#!/usr/bin/env python3

import argparse
import json
import gi
gi.require_version('Gst','1.0')
gi.require_version('GstVideo','1.0')
gi.require_version('GstRtspServer','1.0')
from gi.repository import GObject, GLib, Gst, GstVideo, GstRtspServer


class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):
    def __init__(self, source):
        GstRtspServer.RTSPMediaFactory.__init__(self)
        self.source = source

    def do_create_element(self, url):
        image_folder = self.source.get("image_folder", None)

        if image_folder:
            # print('Image folder paths:', image_folder)
            pipeline = f"multifilesrc location={image_folder}/%d.jpg index=1 loop=1 caps=\"image/jpeg,framerate=30/1\" ! jpegdec ! videoconvert ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=30 ! rtph264pay name=pay0 config-interval=1 pt=96"

        else:
            print("Invalid source. Specify 'image_folder' in the configuration.")
            return None
    
        print("Element created:", pipeline)
        return Gst.parse_launch(pipeline)
        

class GstreamerRtspServer():
    def __init__(self, server_conf, sources):
        self.rtspServer = GstRtspServer.RTSPServer()
        self.rtspServer.set_service(server_conf["port"])
        print("RTSP Server on port", server_conf["port"]) 
        self.mountPoints = self.rtspServer.get_mount_points()
        self.create_rtsp_streams(sources)

    def create_rtsp_streams(self, sources):
        for source in sources:
            rtsp_mount_point = source["rtsp_mount_point"]
            print(rtsp_mount_point)

            factory = TestRtspMediaFactory(source)
            factory.set_shared(True)
            self.mountPoints.add_factory(rtsp_mount_point, factory)

        self.rtspServer.attach(None)

def main(config_file):
    with open(config_file, 'r') as f:
        config = json.load(f)

    server_conf = config.get("server", {})
    sources = config.get("sources", [])
    
    s = GstreamerRtspServer(server_conf,sources)
    loop = GLib.MainLoop()
    loop.run()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Run RTSP server for multiple video sources.")
    parser.add_argument("--config", required=True, help="Path to the JSON configuration file.")
    args = parser.parse_args()
    Gst.init(None)
    main(args.config)

它适用于 localhost 上的 2 个客户端(每个流一个)和远程主机上的其他 2 个客户端。

评论

0赞 NevMthw 11/20/2023
嗨,@SeB感谢您的回答,它现在似乎正在工作。但是,我对您添加的管道更改有一些疑问。该怎么办?另外,您对 gstreamer 文档或 rtsp 相关概念有什么建议吗?为了便于理解,普通的 gstreamer 文档没有太多内容。key-int-max=30
0赞 NevMthw 11/20/2023
另外,上次每次流开始时都会不断创建元素,但现在它只创建一次,那么您认为这会有什么变化?另外,我当时正在循环浏览 vlc,所以也许就是这样,.最后,这与什么有关?vlc rtsp://127.0.0.1:8556/stream1 --loopGst.init(None)
1赞 SeB 11/21/2023
关于我对原始管道所做的更改:我使用了带有循环选项的 multifilesrc,因为我刚刚生成了包含 3000 张图像的图像文件夹。我添加了 key-int-max=30,以便编码器每 30 帧发送一个关键帧,这有助于接收器更快地显示。Gst.init 用于初始化 gstreamer(也可以解析一些 gstreamer 参数)。对于文档,您会发现许多 from 命令,这些命令将列出主机中可用的插件和元素。使用给定元素作为参数,它将显示支持的输入/输出格式和属性:.gst-inspect-1.0gst-inspect-1.0 x264enc
1赞 SeB 11/21/2023
您还可以在网上找到许多文档。请参见 : github.com/GStreamer/gstreamer#where-to-start
0赞 NevMthw 11/22/2023
哦,好的,非常感谢@SeB。感谢您的帮助!