Linking Gstreamer elements

Please provide complete information as applicable to your setup.

• Hardware Platform (Jetson / GPU) : GPU
• DeepStream Version : 6.1

if (!gst_element_link_many(streammux, queue1, pgie, queue2, tracker, queue3, sgie1, queue4, sgie2, queue5, nvdslogger,
                         queue6, nvvidconv, queue7, nvosd, queue8, sink, NULL));
        {
            g_printerr("Elements could not be linked. Exiting.\n");
            return -1;
        }

Can somebody please help where I’m wrong in linking the elements as when I run the application it shows

Elements could not be linked. Exiting

I’m trying to perform ANPR on “nvinfer” not in “nvinferserver”. Also I’m not using titron.
Below is the code for elements creation

/* Standard GStreamer initialization */
    gst_init(&argc, &argv);
    loop = g_main_loop_new(NULL, FALSE);

    /* Create gstreamer elements */
    /* Create Pipeline element that will form a connection of other elements */
    pipeline = gst_pipeline_new("anpr-pipeline");

    /* Create nvstreammux instance to form batches from one or more sources. */
    streammux = gst_element_factory_make("nvstreammux", "stream-muxer");

    if (!pipeline || !streammux)
    {
        g_printerr("One element could not be created. Exiting.\n");
        return -1;
    }
    gst_bin_add(GST_BIN(pipeline), streammux);

    GList *src_list = NULL;

    if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
    {

        nvds_parse_source_list(&src_list, argv[1], "source-list");

        GList *temp = src_list;
        while (temp)
        {
            num_sources++;
            temp = temp->next;
        }
        g_list_free(temp);
    }
    else
    {
        num_sources = argc - 1;
    }

    for (i = 0; i < num_sources; i++)
    {
        GstPad *sinkpad, *srcpad;
        gchar pad_name[16] = {};

        GstElement *source_bin = NULL;
        if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
        {
            g_print("Now playing : %s\n", (char *)(src_list)->data);
            source_bin = create_source_bin(i, (char *)(src_list)->data);
        }
        else
        {
            source_bin = create_source_bin(i, argv[i + 1]);
        }
        if (!source_bin)
        {
            g_printerr("Failed to create source bin. Exiting.\n");
            return -1;
        }

        cout << i << endl;

        gst_bin_add(GST_BIN(pipeline), source_bin);

        g_snprintf(pad_name, 15, "sink_%u", i);
        sinkpad = gst_element_get_request_pad(streammux, pad_name);
        if (!sinkpad)
        {
            g_printerr("Streammux request sink pad failed. Exiting.\n");
            return -1;
        }

        srcpad = gst_element_get_static_pad(source_bin, "src");
        if (!srcpad)
        {
            g_printerr("Failed to get src pad of source bin. Exiting.\n");
            return -1;
        }

        if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK)
        {
            g_printerr("Failed to link source bin to stream muxer. Exiting.\n");
            return -1;
        }

        gst_object_unref(srcpad);
        gst_object_unref(sinkpad);

        if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
        {
            src_list = src_list->next;
            cout << "src_list: "<<src_list << endl;
        }
    }

    if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
    {
        g_list_free(src_list);
    }

    /* Use nvinfer to infer on batched frame. */
    pgie  = gst_element_factory_make("nvinfer", "primary-nvinference-engine");
    sgie1 = gst_element_factory_make("nvinfer","secondary-infer-engine1");
    sgie2 = gst_element_factory_make("nvinfer","secondary-infer-engine2");
    tracker = gst_element_factory_make("nvtracker", "nvtracker");

    /* Add queue elements between every two elements */
    queue1 = gst_element_factory_make("queue", "queue1");
    queue2 = gst_element_factory_make("queue", "queue2");
    queue3 = gst_element_factory_make("queue", "queue3");
    queue4 = gst_element_factory_make("queue", "queue4");
    queue5 = gst_element_factory_make("queue", "queue5");
    queue6 = gst_element_factory_make("queue", "queue6");
    queue7 = gst_element_factory_make("queue", "queue7");
    queue8 = gst_element_factory_make("queue", "queue8");

    /* Use nvdslogger for perf measurement. */
    nvdslogger = gst_element_factory_make("nvdslogger", "nvdslogger");

    /* Use nvtiler to composite the batched frames into a 2D tiled array based
     * on the source of the frames. */
    // tiler = gst_element_factory_make("nvmultistreamtiler", "nvtiler");

    /* Use convertor to convert from NV12 to RGBA as required by nvosd */
    nvvidconv = gst_element_factory_make("nvvideoconvert", "nvvideo-converter");

    /* Create OSD to draw on the converted RGBA buffer */
    nvosd = gst_element_factory_make("nvdsosd", "nv-onscreendisplay");

    if (PERF_MODE)
    {
        sink = gst_element_factory_make("fakesink", "nvvideo-renderer");
    }
    else
    {
        /* Finally render the osd output */
        // if (prop.integrated)
        // {
        //     transform = gst_element_factory_make("nvegltransform", "nvegl-transform");
        //     if (!transform)
        //     {
        //         g_printerr("One tegra element could not be created. Exiting.\n");
        //         return -1;
        //     }
        // }
        sink = gst_element_factory_make("fakesink", "nvvideo-renderer");
    }

    // if (!pgie || !nvdslogger || !tiler || !nvvidconv || !nvosd || !sink)
    // {
    //     g_printerr("One element could not be created. Exiting.\n");
    //     return -1;
    // }

    if (!pgie || !sgie1 || !tracker || !sgie2 || !nvdslogger || !nvvidconv || !nvosd || !sink)
    {
        g_printerr("One element could not be created. Exiting.\n");
        return -1;
    }

    if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
    {

        nvds_parse_streammux(streammux, argv[1], "streammux");

        nvds_parse_tracker(tracker, argv[1], "tracker");

        // g_object_set(G_OBJECT(pgie),
        //              "config-file-path", "./models/door_pgie_config.yml", NULL);

        // g_object_get(G_OBJECT(pgie), "batch-size", &pgie_batch_size, NULL);
        nvds_parse_gie(pgie, argv[1], "primary-gie");
        nvds_parse_gie(sgie1, argv[1], "secondary-gie-0");
        nvds_parse_gie(sgie2, argv[1], "secondary-gie-1");

        if (pgie_batch_size != num_sources)
        {
            g_printerr("WARNING: Overriding infer-config batch-size (%d) with number of sources (%d)\n",
                       pgie_batch_size, num_sources);
            g_object_set(G_OBJECT(pgie), "batch-size", num_sources, NULL);
        }

        nvds_parse_osd(nvosd, argv[1], "osd");

        // tiler_rows = (guint)sqrt(num_sources);
        // tiler_columns = (guint)ceil(1.0 * num_sources / tiler_rows);
        // g_object_set(G_OBJECT(tiler), "rows", tiler_rows, "columns", tiler_columns, NULL);

        // nvds_parse_tiler(tiler, argv[1], "tiler");
        // nvds_parse_egl_sink(sink, argv[1], "sink");
    }
    else
    {

        g_object_set(G_OBJECT(streammux), "batch-size", num_sources, NULL);

        g_object_set(G_OBJECT(streammux), "width", MUXER_OUTPUT_WIDTH, "height",
                     MUXER_OUTPUT_HEIGHT,
                     "batched-push-timeout", MUXER_BATCH_TIMEOUT_USEC, NULL);

        /* Configure the nvinfer element using the nvinfer config file. */
        g_object_set(G_OBJECT(pgie),
                     "config-file-path", "./models/door_pgie_config.txt", NULL);

        /* Override the batch-size set in the config file with the number of sources. */
        g_object_get(G_OBJECT(pgie), "batch-size", &pgie_batch_size, NULL);
        if (pgie_batch_size != num_sources)
        {
            g_printerr("WARNING: Overriding infer-config batch-size (%d) with number of sources (%d)\n",
                       pgie_batch_size, num_sources);
            g_object_set(G_OBJECT(pgie), "batch-size", num_sources, NULL);
        }

        // tiler_rows = (guint)sqrt(num_sources);
        // tiler_columns = (guint)ceil(1.0 * num_sources / tiler_rows);
        // /* we set the tiler properties here */
        // g_object_set(G_OBJECT(tiler), "rows", tiler_rows, "columns", tiler_columns,
        //              "width", TILED_OUTPUT_WIDTH, "height", TILED_OUTPUT_HEIGHT, NULL);

        // g_object_set(G_OBJECT(nvosd), "process-mode", OSD_PROCESS_MODE,
        //              "display-text", OSD_DISPLAY_TEXT, NULL);

        g_object_set(G_OBJECT(sink), "qos", 0, NULL);
    }

which sample are you testing or referring to? from the log, some elements linking failed.
could you provide more logs? please execute export GST_DEBUG=3 first, then run the application again. then maybe we will find which elements can’t link from the log.
or I suggest using gst-launch test the pipeline first by adding element one by one. please refer to the following whole pipeline command-line.
gst-launch-1.0 filesrc location=/opt/nvidia/deepstream/deepstream/samples/streams/sample_720p.mp4 ! qtdemux ! h264parse ! nvv4l2decoder ! mux.sink_0 nvstreammux name=mux batch-size=1 width=1280 height=720 ! nvinfer config-file-path=./dstest2_pgie_config.txt ! nvtracker tracker-width=640 tracker-height=384 ll-lib-file=/opt/nvidia/deepstream/deepstream/lib/libnvds_nvmultiobjecttracker.so enable-batch-process=1 ll-config-file=…/…/…/…/samples/configs/deepstream-app/config_tracker_NvDCF_perf.yml ! nvvideoconvert ! ‘video/x-raw(memory:NVMM),format=RGBA’ ! nvinfer config-file-path=./dstest2_sgie1_config.txt ! nvinfer config-file-path=./dstest2_sgie2_config.txt ! nvinfer config-file-path=./dstest2_sgie3_config.txt ! nvvideoconvert ! ‘video/x-raw(memory:NVMM),format=RGBA’ ! nvdsosd ! nvvideoconvert ! nvegltransform ! nveglglessink

Hi. Thanks for your swift reply. The log is :

(ANPR:45648): GStreamer-WARNING **: 10:45:28.807: Trying to link elements queue8 and nvvideo-renderer that don't share a common ancestor: nvvideo-renderer hasn't been added to a bin or pipeline, and queue8 is in anpr-pipeline
Elements could not be linked. Exiting.

This is the only message in the log.

as the log shown, queue8 linking nvvideo-renderer failed. it is because nvvideo-renderer hasn’t been added to a bin or pipeline.

But I’m adding it to the pipeline here’s the code:

sink = gst_element_factory_make("fakesink", "nvvideo-renderer");
gst_bin_add_many(GST_BIN(pipeline), queue1, pgie, queue2, tracker, queue3, sgie1, queue4, sgie2, queue5, nvdslogger,
                         queue6, nvvidconv, queue7, nvosd, queue8, sink, NULL);
     
if (!gst_element_link_many(streammux, queue1, pgie, queue2, tracker, queue3, sgie1, queue4, sgie2, queue5, nvdslogger,
                         queue6, nvvidconv, queue7, nvosd, queue8, sink, NULL));
        {
            g_printerr("Elements could not be linked. Exiting.\n");
            return -1;
        }

please refer to deepstream-test2 because the code is similar to test2. did you rebuild the code? test2 run well after adding that queue8. or can you simplify the code to narrow down this issue? or can you provide the whole code to review?

Yes I rebuilt the code. It’s a mixture of ANPR(deepstream_lpr_app/deepstream-lpr-app at master · NVIDIA-AI-IOT/deepstream_lpr_app · GitHub) and test3. Also mqtt is in the probe function. Here’s the full code:

int main(int argc, char *argv[])
{
    GMainLoop *loop = NULL;
    GstElement *pipeline = NULL, *streammux = NULL, *sink = NULL, *pgie = NULL,
               *sgie1 = NULL, *sgie2 = NULL, *tracker = NULL,
               *queue1, *queue2, *queue3, *queue4, *queue5, *queue6, *queue7, *queue8, *nvvidconv = NULL,
               *nvosd = NULL, *tiler = NULL, *nvdslogger = NULL;
    GstElement *transform = NULL;
    GstBus *bus = NULL;
    guint bus_watch_id;
    GstPad *osd_sink_pad = NULL;
    guint i = 0, num_sources = 0;
    guint tiler_rows, tiler_columns;
    guint pgie_batch_size;
    perf_measure perf_measure;
    // PERF_MODE = g_getenv("NVDS_TEST3_PERF_MODE") &&
    //             !g_strcmp0(g_getenv("NVDS_TEST3_PERF_MODE"), "1");

    int current_device = -1;
    cudaGetDevice(&current_device);
    struct cudaDeviceProp prop;
    cudaGetDeviceProperties(&prop, current_device);

    /* Check input arguments */
    if (argc < 2)
    {
        g_printerr("Usage: %s <yml file>\n", argv[0]);
        g_printerr("OR: %s <uri1> [uri2] ... [uriN] \n", argv[0]);
        return -1;
    }

    /*Read Json File*/
    json configfilejson;
    const char *jsonFileName = argv[2];
    ifstream cfgfile(jsonFileName);
    if (!cfgfile.is_open()) {
        std::cerr << "Error opening file: " << jsonFileName << std::endl;
        return 1;
    }
    cfgfile >> configfilejson;
    display_text = configfilejson["save_img"].get<int>();
    address = configfilejson["address"].get<string>();
    clientID = configfilejson["client_id"].get<string>();
    topic = configfilejson["topic"].get<string>();
    uname = configfilejson["uname"].get<string>();
    pass = configfilejson["password"].get<string>();

    /* Paho MQTT Initialize*/
    MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;
    conn_opts.username = USERNAME;
    conn_opts.password = PASSWORD;

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(-1);
    }

    /* Standard GStreamer initialization */
    gst_init(&argc, &argv);
    loop = g_main_loop_new(NULL, FALSE);

    /* Create gstreamer elements */
    /* Create Pipeline element that will form a connection of other elements */
    pipeline = gst_pipeline_new("anpr-pipeline");

    /* Create nvstreammux instance to form batches from one or more sources. */
    streammux = gst_element_factory_make("nvstreammux", "stream-muxer");

    if (!pipeline || !streammux)
    {
        g_printerr("One element could not be created. Exiting.\n");
        return -1;
    }
    gst_bin_add(GST_BIN(pipeline), streammux);

    GList *src_list = NULL;

    if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
    {

        nvds_parse_source_list(&src_list, argv[1], "source-list");

        GList *temp = src_list;
        while (temp)
        {
            num_sources++;
            temp = temp->next;
        }
        g_list_free(temp);
    }
    else
    {
        num_sources = argc - 1;
    }

    for (i = 0; i < num_sources; i++)
    {
        GstPad *sinkpad, *srcpad;
        gchar pad_name[16] = {};

        GstElement *source_bin = NULL;
        if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
        {
            g_print("Now playing : %s\n", (char *)(src_list)->data);
            source_bin = create_source_bin(i, (char *)(src_list)->data);
        }
        else
        {
            source_bin = create_source_bin(i, argv[i + 1]);
        }
        if (!source_bin)
        {
            g_printerr("Failed to create source bin. Exiting.\n");
            return -1;
        }

        cout << i << endl;

        gst_bin_add(GST_BIN(pipeline), source_bin);

        g_snprintf(pad_name, 15, "sink_%u", i);
        sinkpad = gst_element_get_request_pad(streammux, pad_name);
        if (!sinkpad)
        {
            g_printerr("Streammux request sink pad failed. Exiting.\n");
            return -1;
        }

        srcpad = gst_element_get_static_pad(source_bin, "src");
        if (!srcpad)
        {
            g_printerr("Failed to get src pad of source bin. Exiting.\n");
            return -1;
        }

        if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK)
        {
            g_printerr("Failed to link source bin to stream muxer. Exiting.\n");
            return -1;
        }

        gst_object_unref(srcpad);
        gst_object_unref(sinkpad);

        if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
        {
            src_list = src_list->next;
            cout << "src_list: "<<src_list << endl;
        }
    }

    if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
    {
        g_list_free(src_list);
    }

    /* Use nvinfer to infer on batched frame. */
    pgie  = gst_element_factory_make("nvinfer", "primary-nvinference-engine");
    sgie1 = gst_element_factory_make("nvinfer","secondary-infer-engine1");
    sgie2 = gst_element_factory_make("nvinfer","secondary-infer-engine2");
    tracker = gst_element_factory_make("nvtracker", "nvtracker");

    /* Add queue elements between every two elements */
    queue1 = gst_element_factory_make("queue", "queue1");
    queue2 = gst_element_factory_make("queue", "queue2");
    queue3 = gst_element_factory_make("queue", "queue3");
    queue4 = gst_element_factory_make("queue", "queue4");
    queue5 = gst_element_factory_make("queue", "queue5");
    queue6 = gst_element_factory_make("queue", "queue6");
    queue7 = gst_element_factory_make("queue", "queue7");
    queue8 = gst_element_factory_make("queue", "queue8");

    /* Use nvdslogger for perf measurement. */
    nvdslogger = gst_element_factory_make("nvdslogger", "nvdslogger");

    /* Use nvtiler to composite the batched frames into a 2D tiled array based
     * on the source of the frames. */
    // tiler = gst_element_factory_make("nvmultistreamtiler", "nvtiler");

    /* Use convertor to convert from NV12 to RGBA as required by nvosd */
    nvvidconv = gst_element_factory_make("nvvideoconvert", "nvvideo-converter");

    /* Create OSD to draw on the converted RGBA buffer */
    nvosd = gst_element_factory_make("nvdsosd", "nv-onscreendisplay");

    sink = gst_element_factory_make("fakesink", "nvvideo-renderer");

    if (!pgie || !sgie1 || !tracker || !sgie2 || !nvdslogger || !nvvidconv || !nvosd || !sink)
    {
        g_printerr("One element could not be created. Exiting.\n");
        return -1;
    }

    if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
    {

        nvds_parse_streammux(streammux, argv[1], "streammux");

        nvds_parse_tracker(tracker, argv[1], "tracker");

        // g_object_set(G_OBJECT(pgie),
        //              "config-file-path", "./models/door_pgie_config.yml", NULL);

        // g_object_get(G_OBJECT(pgie), "batch-size", &pgie_batch_size, NULL);
        nvds_parse_gie(pgie,  argv[1],  "primary-gie");
        nvds_parse_gie(sgie1, argv[1], "secondary-gie-0");
        nvds_parse_gie(sgie2, argv[1], "secondary-gie-1");

        if (pgie_batch_size != num_sources)
        {
            g_printerr("WARNING: Overriding infer-config batch-size (%d) with number of sources (%d)\n",
                       pgie_batch_size, num_sources);
            g_object_set(G_OBJECT(pgie), "batch-size", num_sources, NULL);
        }

        nvds_parse_osd(nvosd, argv[1], "osd");

        // tiler_rows = (guint)sqrt(num_sources);
        // tiler_columns = (guint)ceil(1.0 * num_sources / tiler_rows);
        // g_object_set(G_OBJECT(tiler), "rows", tiler_rows, "columns", tiler_columns, NULL);

        // nvds_parse_tiler(tiler, argv[1], "tiler");
        // nvds_parse_egl_sink(sink, argv[1], "sink");
    }
    else
    {

        g_object_set(G_OBJECT(streammux), "batch-size", num_sources, NULL);

        g_object_set(G_OBJECT(streammux), "width", MUXER_OUTPUT_WIDTH, "height",
                     MUXER_OUTPUT_HEIGHT,
                     "batched-push-timeout", MUXER_BATCH_TIMEOUT_USEC, NULL);

        /* Configure the nvinfer element using the nvinfer config file. */
        g_object_set(G_OBJECT(pgie),
                     "config-file-path", "./models/door_pgie_config.txt", NULL);

        /* Override the batch-size set in the config file with the number of sources. */
        g_object_get(G_OBJECT(pgie), "batch-size", &pgie_batch_size, NULL);
        if (pgie_batch_size != num_sources)
        {
            g_printerr("WARNING: Overriding infer-config batch-size (%d) with number of sources (%d)\n",
                       pgie_batch_size, num_sources);
            g_object_set(G_OBJECT(pgie), "batch-size", num_sources, NULL);
        }

        // tiler_rows = (guint)sqrt(num_sources);
        // tiler_columns = (guint)ceil(1.0 * num_sources / tiler_rows);
        // /* we set the tiler properties here */
        // g_object_set(G_OBJECT(tiler), "rows", tiler_rows, "columns", tiler_columns,
        //              "width", TILED_OUTPUT_WIDTH, "height", TILED_OUTPUT_HEIGHT, NULL);

        // g_object_set(G_OBJECT(nvosd), "process-mode", OSD_PROCESS_MODE,
        //              "display-text", OSD_DISPLAY_TEXT, NULL);

        g_object_set(G_OBJECT(sink), "qos", 0, NULL);
    }

    /* we add a message handler */
    bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
    bus_watch_id = gst_bus_add_watch(bus, bus_call, loop);
    gst_object_unref(bus);

    /* Set up the pipeline */
    /* we add all elements into the pipeline */
    if (transform)
    {
        // gst_bin_add_many(GST_BIN(pipeline), queue1, pgie, queue2, nvdslogger, tiler,
        //                  queue3, nvvidconv, queue4, nvosd, queue5, transform, sink, NULL);
        gst_bin_add_many(GST_BIN(pipeline), queue1, pgie, queue2, tracker, queue3, sgie1, queue4, sgie2, queue5, nvdslogger,
                         queue6, nvvidconv, queue7, nvosd, queue8, transform, sink, NULL);
        /* we link the elements together
         * nvstreammux -> nvinfer -> nvdslogger -> nvtiler -> nvvidconv -> nvosd
         * -> video-renderer */
        // if (!gst_element_link_many(streammux, queue1, pgie, queue2, nvdslogger, tiler,
        //                            queue3, nvvidconv, queue4, nvosd, queue5, transform, sink, NULL))
        if (!gst_element_link_many(streammux, queue1, pgie, queue2, tracker, queue3, sgie1, queue4, sgie2, queue5, nvdslogger,
                         queue6, nvvidconv, queue7, nvosd, queue8, transform, sink, NULL));
        {
            g_printerr("Elements could not be linked. Exiting.\n");
            return -1;
        }
    }
    else
    {
        // gst_bin_add_many(GST_BIN(pipeline), queue1, pgie, queue2, nvdslogger, tiler,
        //                  queue3, nvvidconv, queue4, nvosd, queue5, sink, NULL);
        // /* we link the elements together
        //  * nvstreammux -> nvinfer -> nvdslogger -> nvtiler -> nvvidconv -> nvosd
        //  * -> video-renderer */
        // if (!gst_element_link_many(streammux, queue1, pgie, queue2, nvdslogger, tiler,
        //                            queue3, nvvidconv, queue4, nvosd, queue5, sink, NULL))
        gst_bin_add_many(GST_BIN(pipeline), queue1, pgie, queue2, tracker, queue3, sgie1, queue4, sgie2, queue5, nvdslogger,
                         queue6, nvvidconv, queue7, nvosd, queue8, sink, NULL);
        /* we link the elements together
         * nvstreammux -> nvinfer -> nvdslogger -> nvtiler -> nvvidconv -> nvosd
         * -> video-renderer */
        if (!gst_element_link_many(streammux, queue1, pgie, queue2, tracker, queue3, sgie1, queue4, sgie2, queue5, nvdslogger,
                         queue6, nvvidconv, queue7, nvosd, queue8, sink, NULL));
        {
            g_printerr("Elements could not be linked. Exiting.\n");
            return -1;
        }
    }

    // /* Lets add probe to get informed of the meta data generated, we add probe to
    //  * the sink pad of the osd element, since by that time, the buffer would have
    //  * had got all the metadata. */
    // tiler_src_pad = gst_element_get_static_pad(pgie, "src");
    // if (!tiler_src_pad)
    //     g_print("Unable to get src pad\n");
    // else
    //     gst_pad_add_probe(tiler_src_pad, GST_PAD_PROBE_TYPE_BUFFER,
    //                       tiler_src_pad_buffer_probe, NULL, NULL);
    // gst_object_unref(tiler_src_pad);

    /*Create Context for Object Encoding */
    // NvDsObjEncCtxHandle obj_ctx_handle = nvds_obj_enc_create_context ();
    // if (!obj_ctx_handle)
    // {
    //     g_print("Unable to create context\n");
    //     return -1;
    // }

    /* Lets add probe to get informed of the meta data generated, we add probe to
     * the sink pad of the osd element, since by that time, the buffer would have
     * had got all the metadata. */
    osd_sink_pad = gst_element_get_static_pad(nvosd, "sink");
    if (!osd_sink_pad)
        g_print("Unable to get sink pad\n");
    else
        gst_pad_add_probe(osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
                          osd_sink_pad_buffer_probe, NULL, NULL);
    gst_object_unref(osd_sink_pad);

    // osd_sink_pad = gst_element_get_static_pad(nvdsanalytics, "src");
    // if (!osd_sink_pad)
    //     g_print("Unable to get src pad\n");
    // else
    //     gst_pad_add_probe(osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
    //                       nvdsanalytics_src_pad_buffer_probe, NULL, NULL);
    // gst_object_unref(osd_sink_pad);

    /* Set the pipeline to "playing" state */
    if (g_str_has_suffix(argv[1], ".yml") || g_str_has_suffix(argv[1], ".yaml"))
    {
        g_print("Using file: %s\n", argv[1]);
    }
    else
    {
        g_print("Now playing:");
        for (i = 0; i < num_sources; i++)
        {
            g_print(" %s,", argv[i + 1]);
        }
        g_print("\n");
    }
    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    /* Wait till pipeline encounters an error or EOS */
    g_print("Running...\n");
    g_main_loop_run(loop);

    /* Out of the main loop, clean up nicely */
    g_print("Returned, stopping playback\n");
    gst_element_set_state(pipeline, GST_STATE_NULL);
    g_print("Deleting pipeline\n");
    gst_object_unref(GST_OBJECT(pipeline));
    g_source_remove(bus_watch_id);
    g_main_loop_unref(loop);

    /** Paho MQTT*/
    g_print("Disconnecting MQTT Client\n");
    if ((rc = MQTTClient_disconnect(client, 10000)) != MQTTCLIENT_SUCCESS)
        printf("Failed to disconnect, return code %d\n", rc);
    MQTTClient_destroy(&client);
    g_print("Destroying MQTT Client\n");
    return 0;
}

The above is the main(). Below is the few functions that are defined in the main:

static gboolean
bus_call(GstBus *bus, GstMessage *msg, gpointer data)
{
    GMainLoop *loop = (GMainLoop *)data;
    switch (GST_MESSAGE_TYPE(msg))
    {
    case GST_MESSAGE_EOS:
        g_print("End of stream\n");
        g_main_loop_quit(loop);
        break;
    case GST_MESSAGE_WARNING:
    {
        gchar *debug;
        GError *error;
        gst_message_parse_warning(msg, &error, &debug);
        g_printerr("WARNING from element %s: %s\n",
                   GST_OBJECT_NAME(msg->src), error->message);
        g_free(debug);
        g_printerr("Warning: %s\n", error->message);
        g_error_free(error);
        break;
    }
    case GST_MESSAGE_ERROR:
    {
        gchar *debug;
        GError *error;
        gst_message_parse_error(msg, &error, &debug);
        g_printerr("ERROR from element %s: %s\n",
                   GST_OBJECT_NAME(msg->src), error->message);
        if (debug)
            g_printerr("Error details: %s\n", debug);
        g_free(debug);
        g_error_free(error);
        g_main_loop_quit(loop);
        break;
    }
    case GST_MESSAGE_ELEMENT:
    {
        if (gst_nvmessage_is_stream_eos(msg))
        {
            guint stream_id;
            if (gst_nvmessage_parse_stream_eos(msg, &stream_id))
            {
                g_print("Got EOS from stream %d\n", stream_id);
            }
        }
        break;
    }
    default:
        break;
    }
    return TRUE;
}

static void
cb_newpad(GstElement *decodebin, GstPad *decoder_src_pad, gpointer data)
{
    GstCaps *caps = gst_pad_get_current_caps(decoder_src_pad);
    if (!caps)
    {
        caps = gst_pad_query_caps(decoder_src_pad, NULL);
    }
    const GstStructure *str = gst_caps_get_structure(caps, 0);
    const gchar *name = gst_structure_get_name(str);
    GstElement *source_bin = (GstElement *)data;
    GstCapsFeatures *features = gst_caps_get_features(caps, 0);

    /* Need to check if the pad created by the decodebin is for video and not
     * audio. */
    if (!strncmp(name, "video", 5))
    {
        /* Link the decodebin pad only if decodebin has picked nvidia
         * decoder plugin nvdec_*. We do this by checking if the pad caps contain
         * NVMM memory features. */
        if (gst_caps_features_contains(features, GST_CAPS_FEATURES_NVMM))
        {
            /* Get the source bin ghost pad */
            GstPad *bin_ghost_pad = gst_element_get_static_pad(source_bin, "src");
            if (!gst_ghost_pad_set_target(GST_GHOST_PAD(bin_ghost_pad),
                                          decoder_src_pad))
            {
                g_printerr("Failed to link decoder src pad to source bin ghost pad\n");
            }
            gst_object_unref(bin_ghost_pad);
        }
        else
        {
            g_printerr("Error: Decodebin did not pick nvidia decoder plugin.\n");
        }
    }
}

static void
decodebin_child_added(GstChildProxy *child_proxy, GObject *object,
                      gchar *name, gpointer user_data)
{
    g_print("Decodebin child added: %s\n", name);
    if (g_strrstr(name, "decodebin") == name)
    {
        g_signal_connect(G_OBJECT(object), "child-added",
                         G_CALLBACK(decodebin_child_added), user_data);
    }
}

static GstElement *
create_source_bin(guint index, gchar *uri)
{
    GstElement *bin = NULL, *uri_decode_bin = NULL;
    gchar bin_name[16] = {};

    g_snprintf(bin_name, 15, "source-bin-%02d", index);
    /* Create a source GstBin to abstract this bin's content from the rest of the
     * pipeline */
    bin = gst_bin_new(bin_name);

    /* Source element for reading from the uri.
     * We will use decodebin and let it figure out the container format of the
     * stream and the codec and plug the appropriate demux and decode plugins. */
    if (PERF_MODE)
    {
        uri_decode_bin = gst_element_factory_make("nvurisrcbin", "uri-decode-bin");
        g_object_set(G_OBJECT(uri_decode_bin), "file-loop", TRUE, NULL);
    }
    else
    {
        uri_decode_bin = gst_element_factory_make("uridecodebin", "uri-decode-bin");
    }

    if (!bin || !uri_decode_bin)
    {
        g_printerr("One element in source bin could not be created.\n");
        return NULL;
    }

    /* We set the input uri to the source element */
    g_object_set(G_OBJECT(uri_decode_bin), "uri", uri, NULL);

    /* Connect to the "pad-added" signal of the decodebin which generates a
     * callback once a new pad for raw data has beed created by the decodebin */
    g_signal_connect(G_OBJECT(uri_decode_bin), "pad-added",
                     G_CALLBACK(cb_newpad), bin);
    g_signal_connect(G_OBJECT(uri_decode_bin), "child-added",
                     G_CALLBACK(decodebin_child_added), bin);

    gst_bin_add(GST_BIN(bin), uri_decode_bin);

    /* We need to create a ghost pad for the source bin which will act as a proxy
     * for the video decoder src pad. The ghost pad will not have a target right
     * now. Once the decode bin creates the video decoder and generates the
     * cb_newpad callback, we will set the ghost pad target to the video decoder
     * src pad. */
    if (!gst_element_add_pad(bin, gst_ghost_pad_new_no_target("src",
                                                              GST_PAD_SRC)))
    {
        g_printerr("Failed to add ghost pad in source bin\n");
        return NULL;
    }

    return bin;
}

thanks for the sharing! from the code, sink is created and added to pipeline. noticing it is a combination of lpr , mqtt and test3. can you simplify the code to narrow down this issue? for example,

  1. run test3 to check if the app run fine.
  2. add the code from lpr to test3 block by block, then check if the app run fine. if no, please find which code will cause the error.

Thanks for your reply. I have already deployed test3. Now using the concept of test3 i’m trying out anpr. The pipeline works fine with test3 and mqtt for a different scenario here is the code:

gst_bin_add_many(GST_BIN(pipeline), queue1, pgie, queue2, nvdslogger,
                         nvvidconv, queue4, nvosd, queue5, sink, NULL);
        /* we link the elements together
         * nvstreammux -> nvinfer -> nvdslogger -> nvtiler -> nvvidconv -> nvosd
         * -> video-renderer */
if (!gst_element_link_many(streammux, queue1, pgie, queue2, nvdslogger,
                                   nvvidconv, queue4, nvosd, queue5, sink, NULL))
        {
            g_printerr("Elements could not be linked. Exiting.\n");
            return -1;
        }

However, when I add sgie1 and sgie2 it’s throwing error. Here’s the log

5b7043c4b80, time 99:99:99.999999999, seq-num 51, element 'sink', GstMessageStructureChange, type=(GstStructureChangeType)GST_STRUCTURE_CHANGE_TYPE_PAD_LINK, owner=(GstElement)"\(GstQueue\)\ queue8", busy=(boolean)false;
0:00:00.497302859 48088 0x55b703a4b600 DEBUG                    bin gstbin.c:3718:gst_bin_handle_message_func:<anpr-pipeline> [msg 0x55b7043c4b80] handling child sink message of type structure-change
0:00:00.497313474 48088 0x55b703a4b600 DEBUG                    bin gstbin.c:956:bin_remove_messages:<nvvideo-renderer:sink> deleting message 0x55b7043c4c00 of type structure-change (types 0x00001000)
0:00:00.497324369 48088 0x55b703a4b600 DEBUG                GST_BUS gstbus.c:379:gst_bus_post:<bus0> [msg 0x55b7043c4b80] dropped
0:00:00.497334775 48088 0x55b703a4b600 DEBUG       GST_ELEMENT_PADS gstutils.c:1903:gst_element_link_pads_full: linked pad queue8:src to pad nvvideo-renderer:sink
Elements could not be linked. Exiting.

do you mean only adding sgie0 and sgie1 to test3 will cause error? please continue to narrow down this issue because test2 runs well with three GIEs.

Thank You

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