Gstreamer sometimes pad link fails after even after linking pads in new_pad added signal callback

Please provide complete information as applicable to your setup.

• Hardware Platform (Jetson / GPU)
• DeepStream Version 5.0
Code in Python

I’m trying to read a mjpeg stream from an ip camera using my custom pipeline where I have,

  • Bin having rtspsrc, rtpjpegdepay, jpegdec, nvvidconv
  • nvstreammux
  • rest of the elements

The pipeline:

gst-launch-1.0 rtspsrc location="$RTSP_PATH" ! rtpjpegdepay ! jpegdec ! nvvidconv ! autovideosink

works fine and shows my ip stream,
but the same pipeline implemented in python, where I did the following procedure

  1. Created Pipeline, a custom bin with rtspsrc ! rtpjpegdepay ! jpegdec ! nvvidconv and added ghostpad for bin and set target as vvidconv’s sink pad.
  2. Next trying to link rtspsrc new “sometimes” src pad with static sink pad of rtpjpegdepay but somehow caps negotiation fails and results not linked.

Cropped Main function :


def main(args):
    # Check input arguments
    global system_start_date
    if len(args) < 2:       # Check the command if camera information given or not.
        sys.stderr.write("usage: %s <uri1> [uri2] ... [uriN]\n" % args[0])
        sys.exit(1)

    for i in range(0,len(args)-1):
        fps_streams["stream{0}".format(i)]=GETFPS(i)
    number_sources=len(args)-1

    load_pickle()   # load pickle and check excel sheet for 1 time. 
    check_excel()
    system_start_date = date.today()

    # Standard GStreamer initialization
    GObject.threads_init()  # Create thread for GObject
    Gst.init(None)

    # Create gstreamer elements */
    # Create Pipeline element that will form a connection of other elements
    print("Creating Pipeline \n ")
    pipeline = Gst.Pipeline()   
    is_live = False

    if not pipeline:
        sys.stderr.write(" Unable to create Pipeline \n")
    print("Creating streamux \n ")

    # Create nvstreammux instance to form batches from one or more sources.
    streammux = Gst.ElementFactory.make("nvstreammux", "Stream-muxer")      # stream mux use to display videos in one display. If we have 4 video then it divide's 1 screen for 4 videos.
    if not streammux:
        sys.stderr.write(" Unable to create NvStreamMux \n")

    pipeline.add(streammux)
    for i in range(number_sources):     # check how many cameras are connected
        print("Creating source_bin ",i," \n ")
        uri_name=args[i+1]
        if uri_name.find("rtsp://") == 0 :  # check if the streaming is RTSP link 
            is_live = True
        # source_bin=create_source_bin(i, uri_name)
        source_bin=make_video_source(i,uri_name)
        
        if not source_bin:
            sys.stderr.write("Unable to create source bin \n")
        pipeline.add(source_bin)
        padname="sink_%u" %i
        sinkpad= streammux.get_request_pad(padname) # set windows according to camera 
        if not sinkpad:
            sys.stderr.write("Unable to create sink pad bin \n")
        srcpad=source_bin.get_static_pad("src")
        if not srcpad:
            sys.stderr.write("Unable to create src pad bin \n")

        srcpad.link(sinkpad)

Create source bin:

def make_video_source(i, uri):

    dict_data = {}

    print(f'Creating source bin for source {i} : {uri}')
    "Make a bin with a video source in it, defaulting to first webcamera "
    bin_name="source-bin-%02d" %i
    nbin = None
    nbin = Gst.Bin.new(bin_name)
    if not nbin:
        print("Unable to create source bin ")
    else:
        print(f'created bin: {bin}')


    ### Create elements
    source = Gst.ElementFactory.make("rtspsrc", f'source_{i}')
    
    camera1caps = Gst.Caps.from_string("application/x-rtp, encoding-name=JPEG,media=video")
    capsfilter = Gst.ElementFactory.make("capsfilter", f'filter_{i}') 
   
    depay = Gst.ElementFactory.make("rtpjpegdepay", f'depay_{i}')
    decoder = Gst.ElementFactory.make("jpegdec", f'decode_{i}')
    conv = Gst.ElementFactory.make("nvvidconv", f'nvvidconv_{i}')

    

    ### set properties
    source.set_property("location", uri)
    capsfilter.set_property("caps", camera1caps)

    ### Add elements to Gst Bin
    Gst.Bin.add(nbin, source)
    Gst.Bin.add(nbin, capsfilter)
    Gst.Bin.add(nbin, depay)
    Gst.Bin.add(nbin, decoder)
    Gst.Bin.add(nbin, conv)

    ### link elements
    capsfilter.link(depay)
    depay.link(decoder)
    decoder.link(conv)

    dict_data['nbin'] = nbin
    dict_data['capsfilter'] = capsfilter
    dict_data['source'] = source
    dict_data['depay'] = depay
    dict_data['decoder'] = decoder
    dict_data['conv'] = conv

    ### Add signal handler
    source.connect("pad-added", on_new_pad_added, dict_data)

    # Add ghost source pad to nbin
    print(f'Info:\nCreating Ghostpad and linking its src to conv src pad')
    conv_src_pad = conv.get_static_pad("src")

    bin_ghost_pad_ret = nbin.add_pad(Gst.GhostPad.new("src", conv_src_pad))
    if not bin_ghost_pad_ret:
        print(f'Failed to add ghost and link pad in source bin')
        return None
    else:

        bin_ghost_src_pad = nbin.get_static_pad("src")
        bin_ghost_src_pad.set_active(True)
        print(f'bin_ghost_src_pad: {bin_ghost_src_pad}')
        print(f'bin_ghost_src_pad name : {bin_ghost_src_pad.get_name()}')
        print(f'Created  src ghost pad and linked to : conv src pad, {conv_src_pad}')
        if (not bin_ghost_src_pad):
            print("Failed to get recently added src ghost pad src of bin. Exiting.\n")
            return None 
    
    # release the src 
    (conv_src_pad).unref()        # GST_OBJECT/GObject might cause error

    return nbin

Pad added callback:

def on_new_pad_added(element, new_pad, dict_data):
  
    peer_sink_element =  dict_data[‘capsfilter’]

    peer_sink_pad = peer_sink_element.get_static_pad("sink")
   
    if(peer_sink_pad.is_linked()):
        print("peer_sink_element is already linked. Ignoring.\n")
        return
    else:
        print("peer_sink_element is not linked already. Continuing linking.\n")
    
   

    # check pad type/name
    if(new_pad_type.find("application/x-rtp")!=-1):

        print(f'found application/x-rtp in caps')
        if not new_pad.is_linked():
            
            print(f'Incomming src pad is not linked. Linking...')
            # if the other pad is linked anywhere, unlink it.
            if peer_sink_pad.is_linked():
                print(f'Peer sink pad is linked. Not Linking...')
                peer_sink_pad.get_peer().unlink(peer_sink_pad)
            else:
                print(f'Peer sink pad is also not linked. Linking...')

            # try to link the pad 
            if not new_pad.link(peer_sink_pad):
                # sys.stderr.write("Failed to link decoder src pad to source bin ghost pad\n")
                print(f'Failed to link decoder src pad to source bin ghost pad')
                peer_sink_pad.set_active(True)

            else:
                print(f'Sucessfully connected new rtspsrc pad to depay pad')
                new_pad.set_active(True)

                
        else:
            print(f'Incomming src pad is already linked. Not Linking...')


    else:
        print(f'Not found expected caps type : application/x-rtp in caps')

Output Glimse:

Info: source element: rtspsrc
source : <__gi__.GstRTSPSrc object at 0x7f7e248a68 (GstRTSPSrc at 0x3ebb2ff0)>
source element name - source_0
source element static src pad quieried with new pads name - <Gst.GhostPad object at 0x7f7e24b5a0 (GstGhostPad at 0x3f7f97a0)>
source element static src pad caps quieried with new pads name - application/x-rtp, media=(string)video, payload=(int)26, clock-rate=(int)90000, a-tool=(string)"LIVE555\ Streaming\ Media\ v2016.11.28", a-type=(string)broadcast, x-qt-text-nam=(string)"Mobotix\ IP-Camera\ \(MJPEG\ stream\)", x-qt-text-inf=(string)stream1/mobotix.mjpeg, clock-base=(uint)1720525291, seqnum-base=(uint)175, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1, ssrc=(uint)2305927607
source element src pads list - [<Gst.GhostPad object at 0x7f7e24b5a0 (GstGhostPad at 0x3f7f97a0)>]
source element src pad[0] name - recv_rtp_src_0_2305927607_26

Info: peer element: depay
peer_sink_element : <__gi__.GstCapsFilter object at 0x7f7e2484c8 (GstCapsFilter at 0x3f7ce170)>
peer_sink_element name : filter_0
peer_sink_element sink pad name: sink

Info: incomming pad
new src pad name: recv_rtp_src_0_2305927607_26
new src pads caps : application/x-rtp, media=(string)video, payload=(int)26, clock-rate=(int)90000, a-tool=(string)"LIVE555\ Streaming\ Media\ v2016.11.28", a-type=(string)broadcast, x-qt-text-nam=(string)"Mobotix\ IP-Camera\ \(MJPEG\ stream\)", x-qt-text-inf=(string)stream1/mobotix.mjpeg, clock-base=(uint)1720525291, seqnum-base=(uint)175, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1, ssrc=(uint)2305927607


More Detailed information on incomming src from source_0 wanting to link to filter_0 caps


source new_pad_src_caps : application/x-rtp, media=(string)video, payload=(int)26, clock-rate=(int)90000, a-tool=(string)"LIVE555\ Streaming\ Media\ v2016.11.28", a-type=(string)broadcast, x-qt-text-nam=(string)"Mobotix\ IP-Camera\ \(MJPEG\ stream\)", x-qt-text-inf=(string)stream1/mobotix.mjpeg, clock-base=(uint)1720525291, seqnum-base=(uint)175, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1, ssrc=(uint)2305927607

source new_pad_src_struct : application/x-rtp, media=(string)video, payload=(int)26, clock-rate=(int)90000, a-tool=(string)"LIVE555\ Streaming\ Media\ v2016.11.28", a-type=(string)broadcast, x-qt-text-nam=(string)"Mobotix\ IP-Camera\ \(MJPEG\ stream\)", x-qt-text-inf=(string)stream1/mobotix.mjpeg, clock-base=(uint)1720525291, seqnum-base=(uint)175, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1, ssrc=(uint)2305927607;

source new_pad_src_type : application/x-rtp

Are you familiar with gstreamer programming(https://gstreamer.freedesktop.org/)? How much do you know about gst-python(https://gstreamer.freedesktop.org/modules/gst-python.html)?

Please make sure you are familiar with gstreamer knowldge and coding skills and knowledge for gst-python before you start with pyds.

Yes, I’m familiar with gstreamer programming. Researched thoroughly but still cannot identify the cause of this error.

I’ve tried using uridecodebin too and it does not work with mjpeg stream.

Here’s the image I generated by running the pipeline : uridecodein uri="$RTSP_PATH" ! autovideosink

It uses rtpjpegdepay and nvjpegdec for jpeg streams but still results in error. Then I also tried to set boolean property “Deepstream” for nvjpegdec to true which claims to support jpeg format but still fails with uridecodebin.

I am trying to copy what uridecodebin does. Thats the reason I am trying to set manual bin just like uridecodebin with rtspsrc, rtpjpegdepay and jpegdec(/nvjpegdec) but the main problem seems in not able to link rtspsrc to rtpjpegdepay for some unknown reason even when it is linked from new_pad added signal comming from rtspsrc.

  • Rtspsrc and rtpjpegdepay pads capabilities also match.
  • I’ve even tried to apply caps filter after rtspsrc element with “application/x-rtp”.
  • Also tried to add queue after rtspsrc elemenet.

Nothing seems to work!

How come it is possible to work in command prompt and is also seen in the pipeline image, yet not link in the provided python code.

Am I missing something ?

Which platform are you working on?

Since you know something about gstreamer. Please refer to the c/c++ sample code in /opt/nvidia/deepstream/deepstream/sources/apps/apps-common/src/deepstream_source_bin.c. You can implement similar logic with python to select ‘image’ instead of ‘video’ with “select-stream” signal callback.

https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good/html/gst-plugins-good-plugins-rtspsrc.html

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.