Search code examples
gstreamerrtsp

gstreamer 1.0 rtspsrc to rtph264depay cannot link


I am trying to connect to a ubiquiti camera and successfully with the following command with gstreamer.

gst-launch-1.0 --gst-debug=4 rtspsrc location="rtsp://:554/live/ch00_0" ! rtph264depay ! h264parse ! openh264dec ! d3dvideosink

I look at the debug and it says could not link pads rtspsrc to rtph264depay. Picture

but it gets the stream alright and can see the video. when I put this into a c project it says cannot link source to rtph264parse. I looked around it says to use a dynamic pad with the following code

static void on_pad_added (GstElement *element, GstPad *pad, gpointer data)
{
    GstPad *sinkpad;
    GstElement *decoder = (GstElement *) data;
    /* We can now link this pad with the rtsp-decoder sink pad */
    g_print ("Dynamic pad created, linking source/demuxer\n");
    sinkpad = gst_element_get_static_pad (decoder, "sink");
    gst_pad_link (pad, sinkpad);
    gst_object_unref (sinkpad);
}

int main(int argc, char *argv[])
{
   /* Initialize GStreamer */
   gst_init(&argc,&argv);

   /* Build Pipeline */ 
   pipel.pipeline = gst_pipeline_new("My pipeline");
   pipel.source = gst_element_factory_make ("rtspsrc","source");
   g_object_set (G_OBJECT (pipel.source), "latency",2000,NULL);
   pipel.rtppay = gst_element_factory_make( "rtph264depay", "depayl");
   pipel.parse = gst_element_factory_make("h264parse","parse");
   pipel.filter1 = gst_element_factory_make("capsfilter","filter");
   pipel.decodebin = gst_element_factory_make ("openh264dec","decode");
   pipel.sink = gst_element_factory_make("d3dvideosink","sink");

   g_object_set (G_OBJECT (pipel.sink), "sync",FALSE,NULL);

   //create_uri(url,url_size,ip_address,port);
   g_object_set(GST_OBJECT(pipel.source),"location","rtsp://<IP>:554/live/ch00_0",NULL);

   filtercaps = gst_caps_from_string("application/x-rtp");
   g_object_set (G_OBJECT (pipel.filter1), "caps",filtercaps,NULL);

   gst_caps_unref(filtercaps);

   gst_bin_add_many (GST_BIN (pipel.pipeline),pipel.source
                                          ,pipel.rtppay
                                          ,pipel.parse
                                          ,pipel.decodebin
                                          ,pipel.sink
                                          ,NULL);
   if(!gst_element_link(pipel.source,pipel.rtppay))
        printf("\nFailed source to rtppay\n");
   if(!gst_element_link_many(pipel.parse,pipel.decodebin,pipel.sink,NULL))
        printf("\nFailed to link parse to sink");

    g_signal_connect(pipel.rtppay, "pad-added", G_CALLBACK(on_pad_added), pipel.parse);
}

Solution

  • static void cb_new_rtspsrc_pad(GstElement *element,GstPad*pad,gpointer  data)
    {
        gchar *name;
        GstCaps * p_caps;
        gchar * description;
        GstElement *p_rtph264depay;
    
        name = gst_pad_get_name(pad);
        g_print("A new pad %s was created\n", name);
    
        // here, you would setup a new pad link for the newly created pad
        // sooo, now find that rtph264depay is needed and link them?
        p_caps = gst_pad_get_pad_template_caps (pad);
    
        description = gst_caps_to_string(p_caps);
        printf("%s\n",p_caps,", ",description,"\n");
        g_free(description);
    
        p_rtph264depay = GST_ELEMENT(data);
    
        // try to link the pads then ...
        if(!gst_element_link_pads(element, name, p_rtph264depay, "sink"))
        {
            printf("Failed to link elements 3\n");
        }
    
        g_free(name);
    }
    
    /* ---------- Main --------------- */
    int main(int argc, char *argv[])
    {
        /* Initialize GStreamer */
        gst_init(&argc,&argv);
    
        /* Build Pipeline */ 
        pipel.pipeline = gst_pipeline_new("My pipeline");
    
        creating_pipeline(ip_address,port);
    
        pipel.source = gst_element_factory_make ("rtspsrc","source");
        g_object_set (G_OBJECT (pipel.source), "latency",2000,NULL);
        pipel.rtppay = gst_element_factory_make( "rtph264depay", "depayl");
        pipel.parse = gst_element_factory_make("h264parse","parse");
        pipel.filter1 = gst_element_factory_make("capsfilter","filter");
        pipel.decodebin = gst_element_factory_make ("openh264dec","decode");
        pipel.sink = gst_element_factory_make("d3dvideosink","sink");
    
        g_object_set (G_OBJECT (pipel.sink), "sync",FALSE,NULL);
    
        //create_uri(url,url_size,ip_address,port);
        g_object_set(GST_OBJECT(pipel.source),"location","rtsp://<ip>:554/live/ch00_0",NULL);
    
        filtercaps = gst_caps_from_string("application/x-rtp");
        g_object_set (G_OBJECT (pipel.filter1), "caps",filtercaps,NULL);
    
        gst_caps_unref(filtercaps);
    
        gst_bin_add_many (GST_BIN (pipel.pipeline),pipel.source
                ,pipel.rtppay
                ,NULL);
        // listen for newly created pads
        g_signal_connect(pipel.source, "pad-added", G_CALLBACK(cb_new_rtspsrc_pad),pipel.rtppay);
        gst_bin_add_many (GST_BIN (pipel.pipeline),pipel.parse,NULL);
        if(!gst_element_link(pipel.rtppay,pipel.parse))
            printf("\nNOPE\n");
    
        gst_bin_add_many (GST_BIN (pipel.pipeline),pipel.decodebin
                ,pipel.sink
                ,NULL);
    
        if(!gst_element_link_many(pipel.parse,pipel.decodebin,pipel.sink,NULL))
            printf("\nFailed to link parse to sink");
    
        g_signal_connect(pipel.rtppay, "pad-added", G_CALLBACK(on_pad_added), pipel.parse);
    }
    

    Works Now!

    • use cb_new_rtspsrc_pad to add the pad dynamically
    • add the parse to bin
    • link up between rtppay and parse
    • add the necessary elements the rest of the string to make it work.