<div dir="ltr"><div dir="ltr"><div dir="ltr">Hi all,<br>I would like to implement the RTSP proxy, which is input from multiple IP cameras and output it to the rtsp://<a href="http://127.0.0.1:8554/stream">127.0.0.1:8554/stream</a> . I use an input-selector to switch between two sources every 1 minute. However, the RTSP client, which is ZoneMinder, can only show the primary source and does not change at all. Could you please help me to check my code to see any wrong there?<br><br>import gi<br>import time<br>import threading<br>gi.require_version('Gst', '1.0')<br>gi.require_version('GstRtspServer', '1.0')<br>from gi.repository import Gst, GstRtspServer, GObject, GLib<br>import os<br>import logging<br>import socket<br># apt-get install gir1.2-gst-rtsp-server-1.0<br># Set debug level for GStreamer<br>os.environ["GST_DEBUG"] = "2"<br>pipeline = None<br># Configure logging<br>logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')<br><br>def is_rtsp_uri_reachable(uri):<br>    """Check if the RTSP URI is reachable."""<br>    try:<br>        host, port = uri.split('/')[2].split(':')<br>        port = int(port)<br>        sock = socket.create_connection((host, port), timeout=1)<br>        sock.close()<br>        return True<br>    except:<br>        return False<br><br>def initialize_gstreamer():<br>    Gst.init(None)<br><br>def create_rtsp_server(ip_address, port):<br>    server = GstRtspServer.RTSPServer.new()<br>    server.set_address(ip_address)<br>    server.set_service(port)<br>    return server<br><br>def setup_media_factory(server, source_url):<br>    factory = GstRtspServer.RTSPMediaFactory.new()<br>    launch_string = f'( rtspsrc location={source_url} latency=0 ! rtph264depay ! rtph264pay name=pay0 pt=96 )'<br>    factory.set_launch(launch_string)<br>    factory.set_shared(True)<br>    server.get_mount_points().add_factory("/stream", factory)<br><br>def start_rtsp_server(server):<br>    server.attach(None)<br>    GLib.MainLoop().run()<br><br>def setup_media_factory_with_switching(server, primary_uri, secondary_uri, check_interval=1):<br>    global pipeline  # Access the global pipeline variable<br><br><br>    pipeline_string = (<br>        'rtspsrc location={} name=primary latency=10 ! rtph264depay ! queue ! s.sink_0 '<br>        'rtspsrc location={} name=secondary latency=10 ! rtph264depay ! queue ! s.sink_1 '<br>        'input-selector name=s ! rtph264pay name=pay0 pt=96'<br>    ).format(primary_uri, secondary_uri)<br>    # pipeline_string = f"rtspsrc location={secondary_uri} name=primary latency=0 ! rtph264depay ! rtph264pay name=pay0 pt=96"<br>    factory = GstRtspServer.RTSPMediaFactory.new()<br>    factory.set_launch(pipeline_string)<br>    factory.set_shared(True)<br>    server.get_mount_points().add_factory("/stream", factory)<br><br>    # Create and start the pipeline here<br>    pipeline = Gst.parse_launch(pipeline_string) # Create the pipeline with the provided string<br><br>    <br>    def on_pad_added(src, new_pad):<br>        selector = pipeline.get_by_name('s')<br>        if src.get_name() == 'primary':<br>            sink_pad = selector.get_static_pad('sink_0')<br>        else:  # 'secondary'<br>            sink_pad = selector.get_static_pad('sink_1')<br>        new_pad.link(sink_pad)<br><br>    # Connect the pad-added signal for rtspsrc elements<br>    primary_src = pipeline.get_by_name('primary')<br>    secondary_src = pipeline.get_by_name('secondary')<br>    primary_src.connect("pad-added", on_pad_added)<br>    secondary_src.connect("pad-added", on_pad_added)<br><br><br><br><br>    selector = pipeline.get_by_name("s")<br>    new_pad = selector.get_static_pad("sink_0")<br>    selector.set_property("active-pad", new_pad)<br>    print("DEBUG PAD", new_pad)<br><br>    # Set the pipeline to playing state<br>    pipeline.set_state(Gst.State.PLAYING)<br><br>    time.sleep(60)<br>    selector = pipeline.get_by_name("s")<br>    new_pad = selector.get_static_pad("sink_1")<br>    selector.set_property("active-pad", new_pad)<br>    print(new_pad)<br>    print("DEBUG PAD", new_pad)<br><br>    time.sleep(60)<br>    selector = pipeline.get_by_name("s")<br>    new_pad = selector.get_static_pad("sink_0")<br>    selector.set_property("active-pad", new_pad)<br>    print(new_pad)<br>    print("DEBUG PAD", new_pad)<br><br><br><br><br><br>def stream_group(group_name, stream_type_dict):<br>    wifi_uri = stream_type_dict["wifi"]<br>    cellular_uri = stream_type_dict["5g"]<br>    server_ip = stream_type_dict["local"].split(":")[0]<br>    server_port = stream_type_dict["local"].split(":")[1]<br><br>    if is_rtsp_uri_reachable(wifi_uri) or is_rtsp_uri_reachable(cellular_uri):<br>        server = create_rtsp_server(server_ip, server_port)<br><br>        def client_connected(server, client):<br>            <a href="http://logging.info">logging.info</a>(f"Client connected: {client.get_connection().get_ip()}")<br>        server.connect("client-connected", client_connected)  <br><br>        <a href="http://logging.info">logging.info</a>(f'Current streaming: {group_name}')<br>        <a href="http://logging.info">logging.info</a>(f'Local server at: {server_ip}:{server_port}')<br><br>        # Use setup_media_factory_with_switching instead of setup_media_factory<br>        setup_media_factory_with_switching(server, wifi_uri, cellular_uri)<br><br>        # Start the RTSP server<br>        start_rtsp_server(server)<br><br><br>def main():<br>    initialize_gstreamer()<br>    pipeline = Gst.Pipeline.new("rtsp-pipeline")<br>    uri_groups = {<br>        "group-1": {"wifi": "rtsp://<a href="http://192.168.10.12:6554">192.168.10.12:6554</a>", "5g": "rtsp://<a href="http://192.168.10.12:5554">192.168.10.12:5554</a>", "local": "<a href="http://127.0.0.1:8554">127.0.0.1:8554</a>"}<br>        # "group-2": {"wifi": "rtsp://<a href="http://192.168.10.12:6554">192.168.10.12:6554</a>", "5g": "rtsp://<a href="http://10.45.0.2:6554">10.45.0.2:6554</a>", "local": "<a href="http://127.0.0.1:9554">127.0.0.1:9554</a>"}<br>    }<br><br>    threads = []<br>    for group, stream_type_dict in uri_groups.items():<br>        thread = threading.Thread(target=stream_group, args=(group, stream_type_dict))<br>        thread.start()<br>        threads.append(thread)<br><br>    for thread in threads:<br>        thread.join()<br><br>if __name__ == "__main__":<br>    main()<br><br><br>This is the log when I run the script.<br><br>root@zoneminder-7b8c747c4f-897z6:/proxy# python3 test_3.py <br>2024-01-17 10:51:29,710 - INFO - Current streaming: group-1<br>2024-01-17 10:51:29,710 - INFO - Local server at: <a href="http://127.0.0.1:8554">127.0.0.1:8554</a><br>2024-01-17 10:51:30,385 - INFO - Client connected: 127.0.0.1<br>0:00:00.762880777 31899 0x7f27b006b000 WARN                 basesrc gstbasesrc.c:3072:gst_base_src_loop:<udpsrc12> error: Internal data stream error.<br>0:00:00.762913434 31899 0x7f27b006b000 WARN                 basesrc gstbasesrc.c:3072:gst_base_src_loop:<udpsrc12> error: streaming stopped, reason not-linked (-1)<br>0:00:00.763072020 31899 0x7f27b006b1e0 WARN                 basesrc gstbasesrc.c:3072:gst_base_src_loop:<udpsrc9> error: Internal data stream error.<br>0:00:00.763104396 31899 0x7f27b006b1e0 WARN                 basesrc gstbasesrc.c:3072:gst_base_src_loop:<udpsrc9> error: streaming stopped, reason not-linked (-1)<br>0:00:00.812964645 31899 0x7f27d005c4c0 WARN               rtspmedia rtsp-media.c:4227:gst_rtsp_media_suspend: media 0x7f27c801c1e0 was not prepared<br>0:00:01.795741592 31899 0x7f27b803db60 WARN                 basesrc gstbasesrc.c:3072:gst_base_src_loop:<udpsrc7> error: Internal data stream error.<br>0:00:01.795781974 31899 0x7f27b803db60 WARN                 basesrc gstbasesrc.c:3072:gst_base_src_loop:<udpsrc7> error: streaming stopped, reason not-linked (-1)<br>0:00:01.848348312 31899 0x7f27b006b0c0 WARN                 basesrc gstbasesrc.c:3072:gst_base_src_loop:<udpsrc5> error: Internal data stream error.<br>0:00:01.848397922 31899 0x7f27b006b0c0 WARN                 basesrc gstbasesrc.c:3072:gst_base_src_loop:<udpsrc5> error: streaming stopped, reason not-linked (-1)<br>0:00:27.229783740 31899 0x7f27b803e2a0 WARN                 rtspsrc gstrtspsrc.c:3458:on_timeout_common:<primary> source 1da297f6, stream 1da297f6 in session 2 timed out<br>0:00:28.453660342 31899 0x7f27b803d980 WARN                 rtspsrc gstrtspsrc.c:3458:on_timeout_common:<secondary> source 05055251, stream 05055251 in session 2 timed out<br><br><br>Thanks so much!<br>Best Regards,</div><div>Tai</div></div></div>