Search code examples
gstreamer-1.0

GStreamer 1.16.0 problem linking tsdemux to h264parse


So, this works:

gst-launch-1.0 filesrc location=Truck.H264 ! tsdemux ! h264parse ! avdec_h264 ! xvimagesink

And this works:

GstElement* pipeline = gst_parse_launch_full(
        "gst-launch-1.0 filesrc location=Truck.H264 ! tsdemux ! h264parse ! avdec_h264 ! xvimagesink",
        NULL, GST_PARSE_FLAG_NONE, NULL );

But this does not work:

GstElement* pipeline = gst_pipeline_new(nullptr);
GstElement* filesrc = gst_element_factory_make("filesrc", nullptr);
g_object_set( G_OBJECT(filesrc), "location", "Truck.H264", NULL);
GstElement* tsdemux = gst_element_factory_make("tsdemux", nullptr);
GstElement* h264parse = gst_element_factory_make("h264parse", nullptr);
GstElement* avdec_h264 = gst_element_factory_make("avdec_h264", nullptr);
GstElement* xvimagesink = gst_element_factory_make("xvimagesink", nullptr);
gst_bin_add_many(GST_BIN(pipeline), filesrc, tsdemux, queue, h264parse, avdec_h264, xvimagesink, nullptr);
gst_element_link_many(filesrc, tsdemux, h264parse, avdec_h264, xvimagesink, nullptr);

Now in my inexperienced mind these are all the same and should work the same way. I guess not though.

So I broke the linking down into separate steps and found the problem is here:

gst_element_link(tsdemux, h264parse);

I figured maybe gst_element_link is not as smart at gst_parse_launch_full and doesn't know which pads to link up so I tried:

gst_element_link_pads(tsdemux,"video_%01x_%05x", h264parse, "sink");

And:

GstCaps* caps=gst_caps_new_simple("video/x-h264",
        "stream-format",G_TYPE_STRING,"byte-stream",
        "alignment",G_TYPE_STRING,"nal",
        nullptr);
gst_element_link_filtered(tsdemux, h264parse, caps);

But that didn't work.

I tried sticking a queue between tsdemux and h264parse, but then the error moved to linking tsdemux and the queue:

gst_element_link(tsdemux, queue);

I thought I could link anything to a queue. I guess not.

I tried some other silly things that I didn't think would work, and they didn't, and now I am out of ideas.

I'm probably missing something that every gstreamer programmer knows. If you are one of them, could you please share it with me?


Solution

  • OK, I'm a little wiser today. The embarrassing part is that I read this in the documentation and didn't realize the importance of it.

    The answer is that not all elements are created with their pads. Sometimes pads are created dynamically when they are needed. The important part is that I can't link an element until its pads are created. So to do that I had to create a function to link the elements when the pad is made like so:

    static void linkElements(GstElement* element,GstPad* sourcePad, gpointer sinkElement){
        GstPad* sinkPad=gst_element_get_static_pad((GstElement*)sinkElement,"sink");
        gst_pad_link(sourcePad,sinkPad);
        gst_object_unref(sinkPad);
    }
    

    Then I replaced the link element command:

    gst_element_link(tsdemux, h264parse);
    

    with a command that will get my linkElements function called when a "pad-added" event is thrown:

    g_signal_connect(tsdemux,"pad-added",G_CALLBACK(linkElements),h264parse);