[Switching between two RTSP source]

Phan Tai phantantai.dv at gmail.com
Wed Jan 17 03:03:08 UTC 2024


Hi all,
I would like to implement the RTSP proxy, which is input from multiple IP
cameras and output it to the rtsp://127.0.0.1:8554/stream . 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?

import gi
import time
import threading
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GObject, GLib
import os
import logging
import socket
# apt-get install gir1.2-gst-rtsp-server-1.0
# Set debug level for GStreamer
os.environ["GST_DEBUG"] = "2"
pipeline = None
# Configure logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s -
%(levelname)s - %(message)s')

def is_rtsp_uri_reachable(uri):
    """Check if the RTSP URI is reachable."""
    try:
        host, port = uri.split('/')[2].split(':')
        port = int(port)
        sock = socket.create_connection((host, port), timeout=1)
        sock.close()
        return True
    except:
        return False

def initialize_gstreamer():
    Gst.init(None)

def create_rtsp_server(ip_address, port):
    server = GstRtspServer.RTSPServer.new()
    server.set_address(ip_address)
    server.set_service(port)
    return server

def setup_media_factory(server, source_url):
    factory = GstRtspServer.RTSPMediaFactory.new()
    launch_string = f'( rtspsrc location={source_url} latency=0 !
rtph264depay ! rtph264pay name=pay0 pt=96 )'
    factory.set_launch(launch_string)
    factory.set_shared(True)
    server.get_mount_points().add_factory("/stream", factory)

def start_rtsp_server(server):
    server.attach(None)
    GLib.MainLoop().run()

def setup_media_factory_with_switching(server, primary_uri, secondary_uri,
check_interval=1):
    global pipeline  # Access the global pipeline variable


    pipeline_string = (
        'rtspsrc location={} name=primary latency=10 ! rtph264depay ! queue
! s.sink_0 '
        'rtspsrc location={} name=secondary latency=10 ! rtph264depay !
queue ! s.sink_1 '
        'input-selector name=s ! rtph264pay name=pay0 pt=96'
    ).format(primary_uri, secondary_uri)
    # pipeline_string = f"rtspsrc location={secondary_uri} name=primary
latency=0 ! rtph264depay ! rtph264pay name=pay0 pt=96"
    factory = GstRtspServer.RTSPMediaFactory.new()
    factory.set_launch(pipeline_string)
    factory.set_shared(True)
    server.get_mount_points().add_factory("/stream", factory)

    # Create and start the pipeline here
    pipeline = Gst.parse_launch(pipeline_string) # Create the pipeline with
the provided string


    def on_pad_added(src, new_pad):
        selector = pipeline.get_by_name('s')
        if src.get_name() == 'primary':
            sink_pad = selector.get_static_pad('sink_0')
        else:  # 'secondary'
            sink_pad = selector.get_static_pad('sink_1')
        new_pad.link(sink_pad)

    # Connect the pad-added signal for rtspsrc elements
    primary_src = pipeline.get_by_name('primary')
    secondary_src = pipeline.get_by_name('secondary')
    primary_src.connect("pad-added", on_pad_added)
    secondary_src.connect("pad-added", on_pad_added)




    selector = pipeline.get_by_name("s")
    new_pad = selector.get_static_pad("sink_0")
    selector.set_property("active-pad", new_pad)
    print("DEBUG PAD", new_pad)

    # Set the pipeline to playing state
    pipeline.set_state(Gst.State.PLAYING)

    time.sleep(60)
    selector = pipeline.get_by_name("s")
    new_pad = selector.get_static_pad("sink_1")
    selector.set_property("active-pad", new_pad)
    print(new_pad)
    print("DEBUG PAD", new_pad)

    time.sleep(60)
    selector = pipeline.get_by_name("s")
    new_pad = selector.get_static_pad("sink_0")
    selector.set_property("active-pad", new_pad)
    print(new_pad)
    print("DEBUG PAD", new_pad)





def stream_group(group_name, stream_type_dict):
    wifi_uri = stream_type_dict["wifi"]
    cellular_uri = stream_type_dict["5g"]
    server_ip = stream_type_dict["local"].split(":")[0]
    server_port = stream_type_dict["local"].split(":")[1]

    if is_rtsp_uri_reachable(wifi_uri) or
is_rtsp_uri_reachable(cellular_uri):
        server = create_rtsp_server(server_ip, server_port)

        def client_connected(server, client):
            logging.info(f"Client connected:
{client.get_connection().get_ip()}")
        server.connect("client-connected", client_connected)

        logging.info(f'Current streaming: {group_name}')
        logging.info(f'Local server at: {server_ip}:{server_port}')

        # Use setup_media_factory_with_switching instead of
setup_media_factory
        setup_media_factory_with_switching(server, wifi_uri, cellular_uri)

        # Start the RTSP server
        start_rtsp_server(server)


def main():
    initialize_gstreamer()
    pipeline = Gst.Pipeline.new("rtsp-pipeline")
    uri_groups = {
        "group-1": {"wifi": "rtsp://192.168.10.12:6554", "5g": "rtsp://
192.168.10.12:5554", "local": "127.0.0.1:8554"}
        # "group-2": {"wifi": "rtsp://192.168.10.12:6554", "5g": "rtsp://
10.45.0.2:6554", "local": "127.0.0.1:9554"}
    }

    threads = []
    for group, stream_type_dict in uri_groups.items():
        thread = threading.Thread(target=stream_group, args=(group,
stream_type_dict))
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()

if __name__ == "__main__":
    main()


This is the log when I run the script.

root at zoneminder-7b8c747c4f-897z6:/proxy# python3 test_3.py
2024-01-17 10:51:29,710 - INFO - Current streaming: group-1
2024-01-17 10:51:29,710 - INFO - Local server at: 127.0.0.1:8554
2024-01-17 10:51:30,385 - INFO - Client connected: 127.0.0.1
0:00:00.762880777 31899 0x7f27b006b000 WARN                 basesrc
gstbasesrc.c:3072:gst_base_src_loop:<udpsrc12> error: Internal data stream
error.
0:00:00.762913434 31899 0x7f27b006b000 WARN                 basesrc
gstbasesrc.c:3072:gst_base_src_loop:<udpsrc12> error: streaming stopped,
reason not-linked (-1)
0:00:00.763072020 31899 0x7f27b006b1e0 WARN                 basesrc
gstbasesrc.c:3072:gst_base_src_loop:<udpsrc9> error: Internal data stream
error.
0:00:00.763104396 31899 0x7f27b006b1e0 WARN                 basesrc
gstbasesrc.c:3072:gst_base_src_loop:<udpsrc9> error: streaming stopped,
reason not-linked (-1)
0:00:00.812964645 31899 0x7f27d005c4c0 WARN               rtspmedia
rtsp-media.c:4227:gst_rtsp_media_suspend: media 0x7f27c801c1e0 was not
prepared
0:00:01.795741592 31899 0x7f27b803db60 WARN                 basesrc
gstbasesrc.c:3072:gst_base_src_loop:<udpsrc7> error: Internal data stream
error.
0:00:01.795781974 31899 0x7f27b803db60 WARN                 basesrc
gstbasesrc.c:3072:gst_base_src_loop:<udpsrc7> error: streaming stopped,
reason not-linked (-1)
0:00:01.848348312 31899 0x7f27b006b0c0 WARN                 basesrc
gstbasesrc.c:3072:gst_base_src_loop:<udpsrc5> error: Internal data stream
error.
0:00:01.848397922 31899 0x7f27b006b0c0 WARN                 basesrc
gstbasesrc.c:3072:gst_base_src_loop:<udpsrc5> error: streaming stopped,
reason not-linked (-1)
0:00:27.229783740 31899 0x7f27b803e2a0 WARN                 rtspsrc
gstrtspsrc.c:3458:on_timeout_common:<primary> source 1da297f6, stream
1da297f6 in session 2 timed out
0:00:28.453660342 31899 0x7f27b803d980 WARN                 rtspsrc
gstrtspsrc.c:3458:on_timeout_common:<secondary> source 05055251, stream
05055251 in session 2 timed out


Thanks so much!
Best Regards,
Tai
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20240117/1dc5bf27/attachment-0001.htm>


More information about the gstreamer-devel mailing list