Unable to link elements(rtspsrc -> rtpjpegdepay) from child_added signal callback

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Unable to link elements(rtspsrc -> rtpjpegdepay) from child_added signal callback

parthlathiya
I'm trying to get an MJPEG encoded RTSP stream from Mobotix brand camera using python script and gstreamer.
1st Try:
    Tried using uridecodebin ! autovideosink but gave internal data stream error for mjpeg format.
   
2nd Try:
    Tried looking up what elements are used for jpeg decoding (nvjpegdecoder) inside uridecodebin. Also tried to set property "DeepStream" to True in nvjpegdec element but still not worked.

3rd Try:
    Created a custom bin with elements to support jpeg stream over RTSP sources.
    The cutom bin ghost src pad is also set to target src pad of nvvidconv element when the bin is created.
    The pipeline consists a custom bin (just like
    uridecodebin, that has rtspsrc ! rtpjpegdepay ! jpegdec ! nvvidconv) and autovideosink. My main aim is to stream an
    RTSP stream encoded in MJPEG format.

    I also verified the rtspsrc has src template that has capability of application/rtp as well as
    rtpjpegday has the sink pad's capability as application/rtp using gst-inspect-1.0 <element_name> command. So technically it should work but still the linking fails.

    rtspsrc : Receive data over the network via RTSP
        src : application/x-rtp
            application/x-rdt

    rtpjpegdepay: Extracts JPEG video from RTP packets (RFC 2435)
        sink : application/x-rtp
        src  : image/jpeg

I've also added the pad_added signal handler for rtspsrc and tried to link rtspsrc and rtpjpegdepay src and sink pads in the callback function but it fails
somehow.


Note: I've also tried to run the pipeline from the command line and it successfully shows the video stream, but linking always fails
in python code.
```
gst-launch-1.0 rtspsrc location=$RTSP_PATH ! rtpjpegdepay ! jpegdec ! nvvidconv ! autovideosink           # program pipeline
```

And here's the Debugging graph that it produces


Here is a snippet of main function
<nabble_embed> def main(args): 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 # Standard GStreamer initialization GObject.threads_init() # Create thread for GObject Gst.init(None) # Create Pipeline element that will form a connection of other elements pipeline = Gst.Pipeline() is_live = False if not pipeline: sys.stderr.write(" Unable to create Pipeline \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 uri_name=args[i+1] if uri_name.find("rtsp://") == 0 : # check if the streaming is RTSP link is_live = True 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) . . . </nabble_embed>

Custom Bin Video source:
<nabble_embed> def make_video_source(i, uri): dict_data = {} bin_name="source-bin-%02d" %i nbin = None nbin = Gst.Bin.new(bin_name) ### Create elements source = Gst.ElementFactory.make("rtspsrc", f'source_{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) ### Add elements to Gst Bin Gst.Bin.add(nbin, source) Gst.Bin.add(nbin, depay) Gst.Bin.add(nbin, decoder) Gst.Bin.add(nbin, conv) ### link elements depay.link(decoder) decoder.link(conv) dict_data['nbin'] = nbin 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 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") 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 </nabble_embed>

New Pad added signal handler:
<nabble_embed> def on_new_pad_added(element, new_pad, dict_data): peer_sink_element = dict_data['depay'] peer_sink_pad = peer_sink_element.get_static_pad("sink") # peer_sink_pad.use_fixed_caps() 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") print('\n\n\n') print(f'---------------- new padd added ----------------') print(f'\nInfo') print(f'source element name - {element.get_name()}') print(f'source : {element}') print(f'\nInfo: peer element') print(f'peer_sink_element name : {peer_sink_element.get_name()}') print(f'peer_sink_element : {peer_sink_element}') print(f'\nInfo: incomming pad') print(f'new src pad name: {new_pad.get_name()}') # 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(): # 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): print(f'Failed to link decoder src pad to source bin ghost pad') </nabble_embed>

Here's some of the log
<nabble_embed> ---------------- rtspsrc new padd added ---------------- Info: source element name - source_0 source : <__gi__.GstRTSPSrc object at 0x7f882e5c18 (GstRTSPSrc at 0xaa3e5d0)> Info: peer element peer_sink_element element name : depay_0 peer_sink_element : <__gi__.GstRtpJPEGSrc object at 0x7f88280678 (GstQueue at 0xb6540d0)> Info: incomming pad new src pad name : recv_rtp_src_0_1697348806_26 found rtp in caps 0:02:44.151083610 16703 0xaabb0a0 INFO GST_PADS gstpad.c:2378:gst_pad_link_prepare: trying to link source_0:recv_rtp_src_0_1697348806_26 and queue_0:sink 0:02:44.151197361 16703 0xaabb0a0 INFO GST_PADS gstpad.c:2586:gst_pad_link_full: linked source_0:recv_rtp_src_0_1697348806_26 and queue_0:sink, successful 0:02:44.151224757 16703 0xaabb0a0 INFO GST_EVENT gstevent.c:1517:gst_event_new_reconfigure: creating reconfigure event Failed to link decoder src pad to source bin ghost pad </nabble_embed>

Where am I going wrong in linking?