Multiple streams for deepstream-yolo-app

I want to be able to add and delete video streams on the fly in the deepstream-yolo-app. Are there any tried and tested ways of doing so? Thanks in advance.

here is the example of changing the source.
https://devtalk.nvidia.com/default/topic/1037582/deepstream-for-tesla/restarting-pipeline-on-deepstream2-0/post/5276883/#5276883

The objective was not switching between streams but adding or deleting new ones while running existing ones. Thanks for the answer but that’s not exactly what I was looking for. I did try to implement the solution based on the answer but didn’t seem to work. Here’s the link to a more specific question

https://devtalk.nvidia.com/default/topic/1051509/deepstream-for-tesla/using-nvyolo-plugin-with-the-deepstream-app-/post/5337026/#5337026

Please refer to add/del source part.

/*
 * Copyright (c) 2018 NVIDIA Corporation.  All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA Corporation is strictly prohibited.
 *
 */

#include <gst/gst.h>
#include <glib.h>
#include <math.h>
#include <gmodule.h>
#include <string.h>
#include <sys/time.h>
#include "gstnvdsmeta.h"
#include "gstnvstreammeta.h"
#include "gst-nvmessage.h"

#define MAX_DISPLAY_LEN 64

#define PGIE_CLASS_ID_VEHICLE 0
#define PGIE_CLASS_ID_PERSON 2
#define SET_GPU_ID(object, gpu_id) g_object_set (G_OBJECT (object), "gpu-id", gpu_id, NULL);
#define SET_MEMORY(object, mem_id) g_object_set (G_OBJECT (object), "nvbuf-memory-type", mem_id, NULL);
#define SINK_ELEMENT "nveglglessink"

GMainLoop *loop = NULL;
/* The muxer output resolution must be set if the input streams will be of
 * different resolution. The muxer will scale all the input frames to this
 * resolution. */
#define MUXER_OUTPUT_WIDTH 1280
#define MUXER_OUTPUT_HEIGHT 720

#define TILED_OUTPUT_WIDTH 1280
#define TILED_OUTPUT_HEIGHT 720
#define GPU_ID 1
#define MEM_CUDA 1
#define MEM_UNIFIED 2


gint frame_number = 0;
gint g_num_sources = 0;
gint source_id_list[200];
GstElement **g_source_bin_list = NULL;
gchar pgie_classes_str[4][32] = { "Vehicle", "TwoWheeler", "Person",
  "Roadsign"
};

GstElement *pipeline = NULL, *streammux = NULL, *sink = NULL, *pgie = NULL,
           *nvvidconv = NULL, *nvosd = NULL, *tiler = NULL , *tracker = NULL;

gchar *uri = NULL;

static gboolean add_sources(gpointer data);

static void
decodebin_child_added (GstChildProxy *child_proxy, GObject *object,
                       gchar *name, gpointer user_data)
{
  if (g_strrstr (name, "decodebin") == name) {
    g_signal_connect (G_OBJECT (object), "child-added",
        G_CALLBACK (decodebin_child_added), user_data);
  }
  if (g_strrstr (name, "nvcuvid") == name) {
    g_object_set (object, "gpu-id", GPU_ID, NULL);
    //SET_MEMORY (object, MEM_UNIFIED);
    g_print ("Set decoder gpu-id\n");
  }
}

static void
cb_newpad (GstElement *decodebin, GstPad *pad, gpointer data)
{
  GstCaps *caps = gst_pad_query_caps (pad, NULL);
  const GstStructure *str = gst_caps_get_structure (caps, 0);
  const gchar *name = gst_structure_get_name (str);

  if (!strncmp (name, "video", 5)) {
    gint source_id = (*(gint*)data);
    gchar pad_name[16]={0};
    GstPad *sinkpad = NULL;
    g_snprintf (pad_name, 15, "sink_%u", source_id);
    sinkpad = gst_element_get_request_pad (streammux, pad_name);
    //GstPad *sinkpad = gst_element_get_static_pad (bin, "sink");
    if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK) {
      g_print ("Failed to link decodebin to pipeline\n");
    } else {
      g_print("Decodebin linked to pipeline\n");// %d %p\n", source_id, sinkpad);
    }
    gst_object_unref (sinkpad);
  }
}

static GstElement *
create_uridecode_bin (guint index, gchar *filename) {
  GstElement *bin = NULL;
  gchar bin_name[16] = { };

  source_id_list[index] = index;
  g_snprintf (bin_name, 15, "source-bin-%02d", index);
  bin = gst_element_factory_make ("uridecodebin", bin_name);
  g_object_set (G_OBJECT (bin), "uri", filename, NULL);
  g_signal_connect (G_OBJECT (bin), "pad-added",
      G_CALLBACK (cb_newpad), &source_id_list[index]);
  g_signal_connect (G_OBJECT (bin), "child-added",
                    G_CALLBACK (decodebin_child_added), &source_id_list[index]);


  return bin;
}

static gboolean delete_sources(gpointer data)
{
  static gboolean stop = TRUE;
  gint source_id = g_num_sources-1;
  GstElement *source_bin;
  GstStateChangeReturn state_return;
  gchar pad_name[16];
  GstPad *sinkpad = NULL;

  g_print ("Calling Stop %d \n", source_id);
  state_return = gst_element_set_state(g_source_bin_list[source_id], GST_STATE_NULL);
  switch (state_return) {
    case GST_STATE_CHANGE_SUCCESS:
      g_print ("STATE CHANGE SUCCESS\n\n");
       g_snprintf (pad_name, 15, "sink_%u", source_id);
       sinkpad = gst_element_get_static_pad (streammux, pad_name);
       gst_element_release_request_pad (streammux, sinkpad);
       g_print ("STATE CHANGE SUCCESS %p\n\n",sinkpad);
      gst_object_unref(sinkpad);
      gst_bin_remove (GST_BIN (pipeline), g_source_bin_list[source_id]);
//      gst_object_unref(g_source_bin_list[source_id]);
      source_id--;
      g_num_sources--;
      break;
    case GST_STATE_CHANGE_FAILURE:
      g_print ("STATE CHANGE FAILURE\n\n");
      break;
    case GST_STATE_CHANGE_ASYNC:
      g_print ("STATE CHANGE ASYNC\n\n");
      state_return = gst_element_get_state (g_source_bin_list[source_id], NULL, NULL, GST_CLOCK_TIME_NONE);
      g_snprintf (pad_name, 15, "sink_%u", source_id);
      sinkpad = gst_element_get_static_pad (streammux, pad_name);
      gst_element_release_request_pad (streammux, sinkpad);
      g_print ("STATE CHANGE ASYNC %p\n\n",sinkpad);
      gst_object_unref(sinkpad);
      gst_bin_remove (GST_BIN (pipeline), g_source_bin_list[source_id]);
      gst_object_unref(g_source_bin_list[source_id]);
      source_id--;
      g_num_sources--;
      break;
    case GST_STATE_CHANGE_NO_PREROLL:
      g_print ("STATE CHANGE NO PREROLL\n\n");
      break;
    default:
      break;
  }

  if (source_id == 0){

    g_timeout_add_seconds (2, add_sources, (gpointer)g_source_bin_list);
    return FALSE;
  }

  return TRUE;
}

static gboolean add_sources(gpointer data)
{
  static gboolean stop = TRUE;
  gint source_id = g_num_sources;
  GstElement *source_bin;
  GstStateChangeReturn state_return;

  g_print ("Calling Start %d \n", source_id);
  source_bin = create_uridecode_bin(source_id, uri);
  if (!source_bin) {
    g_printerr ("Failed to create source bin. Exiting.\n");
    return -1;
  }
  g_source_bin_list[source_id] = source_bin;
  gst_bin_add (GST_BIN (pipeline), source_bin);
  state_return = gst_element_set_state(g_source_bin_list[source_id], GST_STATE_PLAYING);
  switch (state_return) {
    case GST_STATE_CHANGE_SUCCESS:
      g_print ("STATE CHANGE SUCCESS\n\n");
      source_id++;
      break;
    case GST_STATE_CHANGE_FAILURE:
      g_print ("STATE CHANGE FAILURE\n\n");
      break;
    case GST_STATE_CHANGE_ASYNC:
      g_print ("STATE CHANGE ASYNC\n\n");
      state_return = gst_element_get_state (g_source_bin_list[source_id], NULL, NULL, GST_CLOCK_TIME_NONE);
      source_id++;
      break;
    case GST_STATE_CHANGE_NO_PREROLL:
      g_print ("STATE CHANGE NO PREROLL\n\n");
      break;
    default:
      break;
  }
  g_num_sources = source_id;
  if (source_id == 20){

    g_timeout_add_seconds (5, delete_sources, (gpointer)g_source_bin_list);

    return FALSE;
  }

  return TRUE;
}
static gboolean
start_stop_func (gpointer data)
{
  static gboolean stop = TRUE;
  static gint source_id = 0;
  static GRand *grnd_gen = NULL;
  GstStateChangeReturn state_return;
  GstPad *sinkpad = NULL;
  gchar pad_name[16];
  if (!grnd_gen) {
    grnd_gen = g_rand_new ();
  }

  if (stop) {
   source_id =  g_rand_int_range (grnd_gen, 0, g_num_sources);
   g_print ("Calling Stop %d \n", source_id);
   state_return = gst_element_set_state(g_source_bin_list[source_id], GST_STATE_NULL);


   switch (state_return) {
     case GST_STATE_CHANGE_SUCCESS:
       stop = FALSE;
       g_snprintf (pad_name, 15, "sink_%u", source_id);
       sinkpad = gst_element_get_static_pad (streammux, pad_name);
       gst_element_release_request_pad (streammux, sinkpad);
       g_print ("STATE CHANGE SUCCESS %p\n\n",sinkpad);
       gst_object_unref(sinkpad);
       break;
     case GST_STATE_CHANGE_FAILURE:
       g_print ("STATE CHANGE FAILURE\n\n");
       break;
     case GST_STATE_CHANGE_ASYNC:
       g_snprintf (pad_name, 15, "sink_%u", source_id);
       sinkpad = gst_element_get_static_pad (streammux, pad_name);
       gst_element_release_request_pad (streammux, sinkpad);
       g_print ("STATE CHANGE ASYNC %p\n\n",sinkpad);
       gst_object_unref(sinkpad);
       stop = FALSE;
       state_return = gst_element_get_state (g_source_bin_list[source_id], NULL, NULL, GST_CLOCK_TIME_NONE);
       break;
     case GST_STATE_CHANGE_NO_PREROLL:
       g_print ("STATE CHANGE NO PREROLL\n\n");
       break;
     default:
       break;
   }

  }else {
   g_print ("Calling Start %d \n", source_id);
   state_return = gst_element_set_state(g_source_bin_list[source_id], GST_STATE_PLAYING);
   switch (state_return) {
     case GST_STATE_CHANGE_SUCCESS:
       g_print ("STATE CHANGE SUCCESS\n\n");
       stop = TRUE;
       break;
     case GST_STATE_CHANGE_FAILURE:
       g_print ("STATE CHANGE FAILURE\n\n");
       break;
     case GST_STATE_CHANGE_ASYNC:
       g_print ("STATE CHANGE ASYNC\n\n");
       stop = TRUE;
       state_return = gst_element_get_state (g_source_bin_list[source_id], NULL, NULL, GST_CLOCK_TIME_NONE);
       break;
     case GST_STATE_CHANGE_NO_PREROLL:
       g_print ("STATE CHANGE NO PREROLL\n\n");
       break;
     default:
       break;
   }
  }


  return TRUE;
}

/* tiler_sink_pad_buffer_probe  will extract metadata received on OSD sink pad
 * and update params for drawing rectangle, object information etc. */

static GstPadProbeReturn
tiler_src_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer u_data)
{

  GstMeta *gst_meta = NULL;
  NvDsMeta *nvdsmeta = NULL;
  gpointer state = NULL;
  static GQuark _nvdsmeta_quark = 0;
  GstBuffer *buf = (GstBuffer *) info->data;
  NvDsFrameMeta *frame_meta = NULL;
  guint num_rects = 0, rect_index = 0, l_index = 0;
  NvDsObjectParams *obj_meta = NULL;
  guint i = 0;
  NvOSD_TextParams *txt_params = NULL;
  GstNvStreamMeta *streammeta = NULL;

  if (!_nvdsmeta_quark)
    _nvdsmeta_quark = g_quark_from_static_string (NVDS_META_STRING);

  streammeta = gst_buffer_get_nvstream_meta (buf);

  while ((gst_meta = gst_buffer_iterate_meta (buf, &state))) {
    if (gst_meta_api_type_has_tag (gst_meta->info->api, _nvdsmeta_quark)) {

      nvdsmeta = (NvDsMeta *) gst_meta;

      /* We are interested only in intercepting Meta of type
       * "NVDS_META_FRAME_INFO" as they are from our infer elements. */
      if (nvdsmeta->meta_type == NVDS_META_FRAME_INFO) {
        guint vehicle_count = 0;
        guint person_count = 0;

        frame_meta = (NvDsFrameMeta *) nvdsmeta->meta_data;
        if (frame_meta == NULL) {
          g_print ("NvDS Meta contained NULL meta \n");
          return GST_PAD_PROBE_OK;
        }

        /* We reset the num_strings here as we plan to iterate through the
         *  the detected objects and form our own strings.
         *  The pipeline generated strings shall be discarded.
         */
        frame_meta->num_strings = 0;

        num_rects = frame_meta->num_rects;

        /* This means we have num_rects in frame_meta->obj_params,
         * now lets iterate through them */

        for (rect_index = 0; rect_index < num_rects; rect_index++) {
          /* Now using above information we need to form a text that should
           * be displayed on top of the bounding box, so lets form it here. */

          obj_meta = (NvDsObjectParams *) & frame_meta->obj_params[rect_index];

          txt_params = &(obj_meta->text_params);
          if (txt_params->display_text)
            g_free (txt_params->display_text);

          txt_params->display_text = g_malloc0 (MAX_DISPLAY_LEN);

          g_snprintf (txt_params->display_text, MAX_DISPLAY_LEN, "%s %d ",
              pgie_classes_str[obj_meta->class_id], obj_meta->tracking_id);

          if (obj_meta->class_id == PGIE_CLASS_ID_VEHICLE)
            vehicle_count++;
          if (obj_meta->class_id == PGIE_CLASS_ID_PERSON)
            person_count++;

          /* Now set the offsets where the string should appear */
          txt_params->x_offset = obj_meta->rect_params.left;
          txt_params->y_offset = obj_meta->rect_params.top - 25;

          /* Font , font-color and font-size */
          txt_params->font_params.font_name = "Arial";
          txt_params->font_params.font_size = 10;
          txt_params->font_params.font_color.red = 1.0;
          txt_params->font_params.font_color.green = 1.0;
          txt_params->font_params.font_color.blue = 1.0;
          txt_params->font_params.font_color.alpha = 1.0;

          /* Text background color */
          txt_params->set_bg_clr = 1;
          txt_params->text_bg_clr.red = 0.0;
          txt_params->text_bg_clr.green = 0.0;
          txt_params->text_bg_clr.blue = 0.0;
          txt_params->text_bg_clr.alpha = 1.0;

          frame_meta->num_strings++;
        }
  /*      g_print ("Source %d Frame Number = %lu Number of objects = %d "
            "Vehicle Count = %d Person Count = %d\n", frame_meta->stream_id,
            streammeta->stream_frame_num[frame_meta->batch_id],
            num_rects, vehicle_count, person_count);*/
      }
    }
  }
  return GST_PAD_PROBE_OK;
}

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 GstElement *
create_source_bin (guint index, gchar *filename, GstElement **ele_source)
{
  GstElement *bin = NULL, *source = NULL, *h264parser = NULL, *decoder = NULL,
             *videoconvert = NULL, *nvvidconv=NULL, *convertfilter=NULL;
  gchar bin_name[16] = { };
  GstCaps *caps;

  g_snprintf (bin_name, 15, "source-bin-%02d", index);
  /* Source element for reading from the file */
  bin = gst_bin_new (bin_name);

  /* Source element for reading from the file */
  source = gst_element_factory_make ("filesrc", "file-source");

  /* Since the data format in the input file is elementary h264 stream,
   * we need a h264parser */
  h264parser = gst_element_factory_make ("h264parse", "h264-parser");

  /* Use nvdec_h264 for hardware accelerated decode on GPU */
  decoder = gst_element_factory_make ("nvdec_h264", "nvh264-decoder");

  videoconvert = gst_element_factory_make ("videoconvert", "videoconvert1");

  nvvidconv = gst_element_factory_make ("nvvidconv", "nvvideoconvert1");
  convertfilter = gst_element_factory_make ("capsfilter", "src_cap_filter");
  caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "NV12", NULL);

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

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

  g_object_set (G_OBJECT (convertfilter), "caps", caps, NULL);
  gst_bin_add_many (GST_BIN (bin), source, h264parser, decoder,  NULL);

  if (!gst_element_link_many (source, h264parser, decoder, nvvidconv, NULL)) {
    g_printerr ("Failed to link source_bin elements\n");
    return NULL;
  }

  /* We need to create a ghost pad for the source bin which acts as a proxy for
   * the decoder src pad */
  GstPad *gstpad = gst_element_get_static_pad (decoder, "src");
  if (!gstpad) {
    g_printerr ("Could not find src in '%s'\n", GST_ELEMENT_NAME(decoder));
    return NULL;
  }
  if (!gst_element_add_pad (bin, gst_ghost_pad_new ("src", gstpad))) {
    g_printerr ("Failed to add ghost pad in source bin\n");
    return NULL;
  }
  gst_object_unref (gstpad);

  *ele_source = source;
  return bin;
}

int
main (int argc, char *argv[])
{
  GstBus *bus = NULL;
  guint bus_watch_id;
  gulong tiler_probe_id = 0;
  GstPad *tiler_src_pad = NULL;
  guint i, num_sources;
  guint tiler_rows, tiler_columns;
  guint pgie_batch_size;

  /* Check input arguments */
  if (argc != 2 ) {
    g_printerr ("Usage: %s <uri1> \n", argv[0]);
    return -1;
  }
  num_sources = argc - 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 ("dstest-pipeline");

  /* Use nvinfer to run inferencing on decoder's output,
   * behaviour of inferencing is set through config file */
  streammux = gst_element_factory_make ("nvstreammux", "stream-muxer");
  g_object_set(G_OBJECT(streammux), "batched-push-timeout",
      25000, NULL);
  g_object_set(G_OBJECT(streammux), "batch-size",
      30, NULL);
  SET_GPU_ID (streammux, GPU_ID);
  //SET_MEMORY (streammux, MEM_UNIFIED);

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

  g_source_bin_list = g_malloc0 (sizeof (GstElement*)*num_sources*200);
  uri = g_strdup (argv[1]);
  for (i = 0; i < /*num_sources*/1; i++) {
    GstPad *sinkpad, *srcpad;
    gchar pad_name[16] = { };
    GstElement *source_bin = create_uridecode_bin(i, argv[i+1]);
    if (!source_bin) {
      g_printerr ("Failed to create source bin. Exiting.\n");
      return -1;
    }
    g_source_bin_list[i] = source_bin;
    gst_bin_add (GST_BIN (pipeline), source_bin);
  }

  g_num_sources = num_sources;

  /* Use nvinfer to run inferencing on decoder's output,
   * behaviour of inferencing is set through config file */
  pgie = gst_element_factory_make ("nvinfer", "primary-nvinference-engine");

  /* Use nvinfer to run inferencing on decoder's output,
   * behaviour of inferencing is set through config file */
  tiler = gst_element_factory_make ("nvmultistreamtiler", "nvtiler");

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

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

  tracker = gst_element_factory_make ("nvtracker", "nv-tracker");

  /* Finally render the osd output */
  sink = gst_element_factory_make (SINK_ELEMENT, "nvvideo-renderer");

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

  g_object_set (G_OBJECT (streammux), "width", MUXER_OUTPUT_WIDTH, "height",
      MUXER_OUTPUT_HEIGHT, NULL);
  g_object_set (G_OBJECT (tracker), "tracker-width", 640, "tracker-height",
      368, NULL);
  SET_GPU_ID (tracker, GPU_ID);
  SET_GPU_ID (nvvidconv, GPU_ID);
  //SET_MEMORY (nvvidconv, MEM_UNIFIED);

  /* Set all the necessary properties of the nvinfer element,
   * the necessary ones are : */
  g_object_set (G_OBJECT (pgie),
      "config-file-path", "dstest_pgie_config.txt", NULL);
  SET_GPU_ID (pgie, GPU_ID);

  /* Set all the necessary properties of the nvinfer element,
   * the necessary ones are : */
  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);
  }
  g_object_set (G_OBJECT (pgie), "batch-size", 30, NULL);

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

  /* we set the osd properties here */
  g_object_set (G_OBJECT (nvosd), "font-size", 15, NULL);
  SET_GPU_ID (nvosd, GPU_ID);
  SET_GPU_ID (sink, GPU_ID);

  /* 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 */
  gst_bin_add_many (GST_BIN (pipeline), pgie, tracker, tiler, nvvidconv,  nvosd, sink, NULL);

  /* we link the elements together */
  /* file-source -> h264-parser -> nvh264-decoder ->
   * nvinfer -> nvvidconv -> nvosd -> video-renderer */
  if (!gst_element_link_many (streammux, pgie, tracker,
        tiler, nvvidconv, nvosd, sink,
        NULL)) {
    g_printerr ("Elements could not be linked. Exiting.\n");
    return -1;
  }

  g_object_set(G_OBJECT(sink), "sync", FALSE, NULL);
  /* 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
    tiler_probe_id = gst_pad_add_probe (tiler_src_pad, GST_PAD_PROBE_TYPE_BUFFER,
        tiler_src_pad_buffer_probe, NULL, NULL);

  gst_element_set_state (pipeline, GST_STATE_PAUSED);
  /* Set the pipeline to "playing" state */
  //g_usleep(100000);
  g_print ("Now playing: %s\n", argv[1]);
  if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
    g_printerr ("Failed to set pipeline to playing. Exiting.\n");
    return -1;
  }
 //GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "ds-app-playing");

  /* Wait till pipeline encounters an error or EOS */
  g_print ("Running...\n");
  g_timeout_add_seconds (2, add_sources, (gpointer)g_source_bin_list);
  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);
  g_free (g_source_bin_list);
  g_free (uri);
  return 0;
}

Thanks for the help. I tried running the code with minor changes as there were some errors initially. After the changes this is the terminal printout I get when I try make:

/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp: In function ‘gboolean delete_sources(gpointer)’:
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:118:23: warning: unused variable ‘stop’ [-Wunused-variable]
static gboolean stop = TRUE;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:120:19: warning: unused variable ‘source_bin’ [-Wunused-variable]
GstElement source_bin;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp: In function ‘gboolean add_sources(gpointer)’:
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:174:23: warning: unused variable ‘stop’ [-Wunused-variable]
static gboolean stop = TRUE;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp: In function ‘GstPadProbeReturn tiler_src_pad_buffer_probe(GstPad
, GstPadProbeInfo*, gpointer)’:
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:306:44: warning: unused variable ‘l_index’ [-Wunused-variable]
guint num_rects = 0, rect_index = 0, l_index = 0;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:308:13: warning: unused variable ‘i’ [-Wunused-variable]
guint i = 0;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:310:24: warning: variable ‘streammeta’ set but not used [-Wunused-but-set-variable]
GstNvStreamMeta streammeta = NULL;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp: In function ‘GstElement
create_source_bin(guint, gchar*, GstElement**)’:
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:452:19: warning: variable ‘videoconvert’ set but not used [-Wunused-but-set-variable]
*videoconvert = NULL, nvvidconv=NULL, convertfilter=NULL;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp: In function ‘int main(int, char
)’:
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:557:17: warning: unused variable ‘sinkpad’ [-Wunused-variable]
GstPad sinkpad, srcpad;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:557:27: warning: unused variable ‘srcpad’ [-Wunused-variable]
GstPad sinkpad, srcpad;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:558:15: warning: unused variable ‘pad_name’ [-Wunused-variable]
gchar pad_name[16] = { };
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:514:14: warning: variable ‘tiler_probe_id’ set but not used [-Wunused-but-set-variable]
gulong tiler_probe_id = 0;
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp: At global scope:
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:218:5: warning: ‘gboolean start_stop_func(gpointer)’ defined but not used [-Wunused-function]
start_stop_func (gpointer data)
^
/home/test/Documents/deepstream/deepstream_reference_apps/yolo/apps/deepstream-yolo/deepstream-yolo-app.cpp:449:5: warning: ‘GstElement
create_source_bin(guint, gchar
, GstElement
)’ defined but not used [-Wunused-function]
create_source_bin (guint index, gchar *filename, GstElement **ele_source)
^
[100%] Linking CXX executable deepstream-yolo-app
CMakeFiles/deepstream-yolo-app.dir/deepstream-yolo-app.cpp.o: In function tiler_src_pad_buffer_probe(_GstPad*, _GstPadProbeInfo*, void*)': deepstream-yolo-app.cpp:(.text+0x26a): undefined reference to gst_buffer_get_nvstream_meta’
CMakeFiles/deepstream-yolo-app.dir/deepstream-yolo-app.cpp.o: In function bus_call(_GstBus*, _GstMessage*, void*)': deepstream-yolo-app.cpp:(.text+0x452): undefined reference to gst_nvmessage_is_stream_eos’
deepstream-yolo-app.cpp:(.text+0x463): undefined reference to `gst_nvmessage_parse_stream_eos’
collect2: error: ld returned 1 exit status
CMakeFiles/deepstream-yolo-app.dir/build.make:94: recipe for target ‘deepstream-yolo-app’ failed
make[2]: *** [deepstream-yolo-app] Error 1
CMakeFiles/Makefile2:67: recipe for target ‘CMakeFiles/deepstream-yolo-app.dir/all’ failed
make[1]: *** [CMakeFiles/deepstream-yolo-app.dir/all] Error 2
Makefile:127: recipe for target ‘all’ failed
make: *** [all] Error 2

If you could clarianksfy why there are so many unused variables and elaborate on the Error I’m getting that would be great. Thanks again for helping.

The anomaly detection app has this feature implemented. Please have a look at

Removing a source

https://github.com/NVIDIA-AI-IOT/deepstream_reference_apps/blob/master/anomaly/apps/deepstream-anomaly-detection/deepstream-anomaly-app.c#L446

Adding a source

https://github.com/NVIDIA-AI-IOT/deepstream_reference_apps/blob/master/anomaly/apps/deepstream-anomaly-detection/deepstream-anomaly-app.c#L420

The main issue we’re trying to solve is sharing 1 yolo instance with multiple sources, if it’s possible. The anomaly app doesn’t use yolo so that problem doesn’t occur there. Still, thanks for your answer!

The problem is not in the yolo plugin. The source add/delete feature is implemented in the app layer. You’ll need to implement a similar logic in the yolo app as well.