About nvstreammux's stream eos event

Please provide complete information as applicable to your setup.

**• Hardware Platform (Jetson / GPU)**1060
**• DeepStream Version 6.0
**• ubuntu1804
**• TensorRT Version 8.0
**• NVIDIA GPU Driver Version (valid for GPU only) 510

I write a custom service with deepstream sdk, which recieve the http request to start or stop the request uri’s(may be rtsp rtmp and file:///) anlysis.

and when I request thp http to start one uri stream to be analysising, and after a while, I then request the http to stop the uri stream’s analysis, and then request the http to start and stop the stream uri again and again, it has no problem and work well(note for simple test, all the start and stop requests are on same input stream uri,
and same nvstreammux’s sink pad index , which is every time request and release nvstreammux’s sink_1 pad)

but when I request the http to start the stream’s analysising and not stop it from the http request,
and when the file:///path/to/video reach the end, In the bus callback, I handle the nvstreammux’s stream eos event and in this event I remove this source(and release the nvstreammux’s sink pad sink_1 with the same way as the http stop used.
and then I again to request the http to start analysing the stream uri with nvstreammux’s pad sink_1,the pipline bus callback will recieve the stream eos event as soon as the stream is linked to reqested nvstreammux’s sink_1 pad, and so it could not be anlysising.

I don’t know why and how to resolve this problem.
need your help, thank you!

Maybe the EOS state haven’t been reset when you process the EOS even in the bus callback.

hi @kesong:
Thank you for your reply, could you tell me how to reset the streammux pligin’s eos state in the bus callback?

Try set the pipe to Gst.State.NULL then reset it to Gst.State.PLAYING?

@neoragex2002 Thank you, but I think this is not a good idea, because set the pipline to NULL then to PLAYTING state will affect other streams analysising!

How to reproduce the issue?

@kesong
you could edit from the runtime_source_add_del sample, like below, input one source and when the buscallback recieve the nvstreammux eos event, delete the source and add the source to the pipline again(pad_index 0).
because the nvstreammux is not open source, I don’t know why after the nvstreammux eos event from stream_id (eg. stream_id =0), we again to add a source to the pipline use the nvstreammux’s pad_index=0, it will triggle the eos event as soon as the source is add sccuess to the pipline.

#include <stdlib.h>
#include <gst/gst.h>
#include <glib.h>
#include <math.h>
#include <gmodule.h>
#include <string.h>
#include <sys/time.h>
#include “gstnvdsmeta.h”
#include “gst-nvmessage.h”
#include “nvdsmeta.h”
#include <cuda_runtime_api.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 1920
    #define MUXER_OUTPUT_HEIGHT 1080

#define TILED_OUTPUT_WIDTH 1280
#define TILED_OUTPUT_HEIGHT 720
#define GPU_ID 0
#define MAX_NUM_SOURCES 4
#define PGIE_CONFIG_FILE “dstest_pgie_config.txt”
#define TRACKER_CONFIG_FILE “dstest_tracker_config.txt”
#define SGIE1_CONFIG_FILE “dstest_sgie1_config.txt”
#define SGIE2_CONFIG_FILE “dstest_sgie2_config.txt”
#define SGIE3_CONFIG_FILE “dstest_sgie3_config.txt”

#define CONFIG_GPU_ID “gpu-id”
#define CONFIG_GROUP_TRACKER “tracker”
#define CONFIG_GROUP_TRACKER_WIDTH “tracker-width”
#define CONFIG_GROUP_TRACKER_HEIGHT “tracker-height”
#define CONFIG_GROUP_TRACKER_LL_CONFIG_FILE “ll-config-file”
#define CONFIG_GROUP_TRACKER_LL_LIB_FILE “ll-lib-file”
#define CONFIG_GROUP_TRACKER_ENABLE_BATCH_PROCESS “enable-batch-process”

gint g_num_sources = 0;
gint g_source_id_list[MAX_NUM_SOURCES];
gboolean g_eos_list[MAX_NUM_SOURCES];
gboolean g_source_enabled[MAX_NUM_SOURCES];
GstElement **g_source_bin_list = NULL;
GMutex eos_lock;

/* Assuming Resnet 10 model packaged in DS SDK */
gchar pgie_classes_str[4][32] = { “Vehicle”, “TwoWheeler”, “Person”,
“Roadsign”
};

GstElement *pipeline = NULL, *streammux = NULL, *sink = NULL, *pgie = NULL,
*sgie1 = NULL, *sgie2 = NULL, *sgie3 = NULL,
*nvvideoconvert = NULL, *nvosd = NULL, *tiler = NULL, *tracker = NULL;

gchar *uri = NULL;

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);
}
int current_device = -1;
cudaGetDevice(&current_device);
struct cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, current_device);

if (g_strrstr (name, “nvv4l2decoder”) == name) {
if(prop.integrated) {
g_object_set (object, “enable-max-performance”, TRUE, NULL);
g_object_set (object, “bufapi-version”, TRUE, NULL);
g_object_set (object, “drop-frame-interval”, 0, NULL);
g_object_set (object, “num-extra-surfaces”, 0, NULL);
} else {
g_object_set (object, “gpu-id”, GPU_ID, NULL);
}
}
}

static gchar *
get_absolute_file_path (gchar *cfg_file_path, gchar *file_path)
{
gchar abs_cfg_path[PATH_MAX + 1];
gchar *abs_file_path;
gchar *delim;

if (file_path && file_path[0] == ‘/’) {
return file_path;
}

if (!realpath (cfg_file_path, abs_cfg_path)) {
g_free (file_path);
return NULL;
}

/* Return absolute path of config file if file_path is NULL. */
if (!file_path) {
abs_file_path = g_strdup (abs_cfg_path);
return abs_file_path;
}

delim = g_strrstr (abs_cfg_path, “/”);
*(delim + 1) = ‘\0’;

abs_file_path = g_strconcat (abs_cfg_path, file_path, NULL);
g_free (file_path);

return abs_file_path;
}

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);

g_print (“decodebin new pad %s\n”, name);
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);
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”);
}
gst_object_unref (sinkpad);
}
}

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

g_print (“creating uridecodebin for [%s]\n”, filename);
g_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), &g_source_id_list[index]);
g_signal_connect (G_OBJECT (bin), “child-added”,
G_CALLBACK (decodebin_child_added), &g_source_id_list[index]);
g_source_enabled[index] = TRUE;

return bin;
}

static void
stop_release_source (gint source_id)
{
GstStateChangeReturn state_return;
gchar pad_name[16];
GstPad *sinkpad = NULL;
g_print(“stop release source id %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_pad_send_event (sinkpad, gst_event_new_flush_stop (FALSE));
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]);
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”);
g_snprintf (pad_name, 15, “sink_%u”, source_id + 1);
sinkpad = gst_element_get_static_pad (streammux, pad_name);
gst_pad_send_event (sinkpad, gst_event_new_flush_stop (FALSE));
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]);
source_id–;
g_num_sources–;
break;
case GST_STATE_CHANGE_NO_PREROLL:
g_print (“STATE CHANGE NO PREROLL\n\n”);
break;
default:
break;
}

}

static gboolean
delete_sources (int source_id)
{
stop_release_source (source_id);
return TRUE;
}
static gboolean
add_source(int index){
g_print(“add_source id %d\n”, index);
gint source_id = index;
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;
}
return TRUE;
}

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);
// g_mutex_lock (&eos_lock);
// g_eos_list[stream_id] = TRUE;
// g_mutex_unlock (&eos_lock);
stop_release_source(stream_id);
add_source(stream_id);
// add_sources()
}
}
break;
}
default:
break;
}
return TRUE;
}

/* Tracker config parsing */

#define CHECK_ERROR(error)
if (error) {
g_printerr (“Error while parsing config file: %s\n”, error->message);
goto done;
}

static gboolean
set_tracker_properties (GstElement *nvtracker)
{
gboolean ret = FALSE;
GError *error = NULL;
gchar **keys = NULL;
gchar **key = NULL;
GKeyFile *key_file = g_key_file_new ();

if (!g_key_file_load_from_file (key_file, TRACKER_CONFIG_FILE, G_KEY_FILE_NONE,
&error)) {
g_printerr (“Failed to load config file: %s\n”, error->message);
return FALSE;
}

keys = g_key_file_get_keys (key_file, CONFIG_GROUP_TRACKER, NULL, &error);
CHECK_ERROR (error);

for (key = keys; *key; key++) {
if (!g_strcmp0 (*key, CONFIG_GROUP_TRACKER_WIDTH)) {
gint width =
g_key_file_get_integer (key_file, CONFIG_GROUP_TRACKER,
CONFIG_GROUP_TRACKER_WIDTH, &error);
CHECK_ERROR (error);
g_object_set (G_OBJECT (nvtracker), “tracker-width”, width, NULL);
} else if (!g_strcmp0 (*key, CONFIG_GROUP_TRACKER_HEIGHT)) {
gint height =
g_key_file_get_integer (key_file, CONFIG_GROUP_TRACKER,
CONFIG_GROUP_TRACKER_HEIGHT, &error);
CHECK_ERROR (error);
g_object_set (G_OBJECT (nvtracker), “tracker-height”, height, NULL);
} else if (!g_strcmp0 (*key, CONFIG_GPU_ID)) {
guint gpu_id =
g_key_file_get_integer (key_file, CONFIG_GROUP_TRACKER,
CONFIG_GPU_ID, &error);
CHECK_ERROR (error);
g_object_set (G_OBJECT (nvtracker), “gpu_id”, gpu_id, NULL);
} else if (!g_strcmp0 (key, CONFIG_GROUP_TRACKER_LL_CONFIG_FILE)) {
char
ll_config_file = get_absolute_file_path (TRACKER_CONFIG_FILE,
g_key_file_get_string (key_file,
CONFIG_GROUP_TRACKER,
CONFIG_GROUP_TRACKER_LL_CONFIG_FILE, &error));
CHECK_ERROR (error);
g_object_set (G_OBJECT (nvtracker), “ll-config-file”, ll_config_file, NULL);
} else if (!g_strcmp0 (key, CONFIG_GROUP_TRACKER_LL_LIB_FILE)) {
char
ll_lib_file = get_absolute_file_path (TRACKER_CONFIG_FILE,
g_key_file_get_string (key_file,
CONFIG_GROUP_TRACKER,
CONFIG_GROUP_TRACKER_LL_LIB_FILE, &error));
CHECK_ERROR (error);
g_object_set (G_OBJECT (nvtracker), “ll-lib-file”, ll_lib_file, NULL);
} else if (!g_strcmp0 (*key, CONFIG_GROUP_TRACKER_ENABLE_BATCH_PROCESS)) {
gboolean enable_batch_process =
g_key_file_get_integer (key_file, CONFIG_GROUP_TRACKER,
CONFIG_GROUP_TRACKER_ENABLE_BATCH_PROCESS, &error);
CHECK_ERROR (error);
g_object_set (G_OBJECT (nvtracker), “enable_batch_process”,
enable_batch_process, NULL);
} else {
g_printerr (“Unknown key ‘%s’ for group [%s]”, *key,
CONFIG_GROUP_TRACKER);
}
}

ret = TRUE;
done:
if (error) {
g_error_free (error);
}
if (keys) {
g_strfreev (keys);
}
if (!ret) {
g_printerr ("%s failed", func);
}
return ret;
}

static GstPadProbeReturn
osd_sink_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer u_data)
{
GstBuffer *buf = (GstBuffer *) info->data;
NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);
guint num_rects = 0;
NvDsObjectMeta *obj_meta = NULL;
NvDsMetaList * l_frame = NULL;
NvDsMetaList * l_obj = NULL;
NvDsMetaList * l_user_meta = NULL;
NvDsDisplayMeta *display_meta = NULL;
NvDsFrameMeta frame_meta = NULL;
NvDsUserMeta
user_meta = NULL;
for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;
l_frame = l_frame->next) {
frame_meta = (NvDsFrameMeta *) (l_frame->data);
// g_print(“pad_index %d\n”, frame_meta->pad_index);
}
// g_print(“end of the post process\n”);
return GST_PAD_PROBE_OK;
}

int
main (int argc, char *argv)
{
GstBus *bus = NULL;
guint bus_watch_id;
guint i, num_sources;
guint tiler_rows, tiler_columns;
guint pgie_batch_size;
GstElement *nvtransform;

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

/* Check input arguments */
if (argc != 2) {
g_printerr (“Usage: %s \n”, argv[0]);
return -1;
}
num_sources = argc - 1;

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

g_mutex_init (&eos_lock);
/* 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);

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 *) * MAX_NUM_SOURCES);
uri = g_strdup (argv[1]);
for (i = 0; i < num_sources; i++) {
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 nvtiler to stitch o/p from upstream components */
tiler = gst_element_factory_make (“nvmultistreamtiler”, “nvtiler”);

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

if(prop.integrated) {
nvtransform = gst_element_factory_make (“nvegltransform”, “nvegltransform”);
}

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

auto 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, (gpointer) osd_sink_pad, NULL);
gst_object_unref (osd_sink_pad);

tracker = gst_element_factory_make (“nvtracker”, “nvtracker”);

sgie1 = gst_element_factory_make (“nvinfer”, “secondary-nvinference-engine1”);
sgie2 = gst_element_factory_make (“nvinfer”, “secondary-nvinference-engine2”);
sgie3 = gst_element_factory_make (“nvinfer”, “secondary-nvinference-engine3”);

/* Finally render the osd output */
sink = gst_element_factory_make (SINK_ELEMENT, “nveglglessink”);
if(prop.integrated) {
if (!pgie || !sgie1 || !sgie2 || !sgie3 || !tiler || !nvvideoconvert || !nvosd
|| !sink || !tracker || !nvtransform) {
g_printerr (“One element could not be created. Exiting.\n”);
return -1;
}
} else {
if (!pgie || !sgie1 || !sgie2 || !sgie3 || !tiler || !nvvideoconvert || !nvosd
|| !sink || !tracker) {
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);

/* Set all the necessary properties of the nvinfer element,

  • the necessary ones are : */
    g_object_set (G_OBJECT (pgie), “config-file-path”, PGIE_CONFIG_FILE, NULL);
    g_object_set (G_OBJECT (sgie1), “config-file-path”, SGIE1_CONFIG_FILE, NULL);
    g_object_set (G_OBJECT (sgie2), “config-file-path”, SGIE2_CONFIG_FILE, NULL);
    g_object_set (G_OBJECT (sgie3), “config-file-path”, SGIE3_CONFIG_FILE, NULL);

/* Set necessary properties of the tracker element. */
if (!set_tracker_properties(tracker)) {
g_printerr (“Failed to set tracker properties. Exiting.\n”);
return -1;
}

/* 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 < MAX_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”, MAX_NUM_SOURCES, NULL);
    }

/* Set GPU ID of elements */
SET_GPU_ID (pgie, GPU_ID);
SET_GPU_ID (sgie1, GPU_ID);
SET_GPU_ID (sgie2, GPU_ID);
SET_GPU_ID (sgie3, GPU_ID);

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_GPU_ID (nvvideoconvert, GPU_ID);
SET_GPU_ID (nvosd, GPU_ID);
if(!prop.integrated) {
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, sgie1, sgie2, sgie3,
tiler, nvvideoconvert, nvosd, sink, NULL);

if(prop.integrated) {
gst_bin_add (GST_BIN (pipeline), nvtransform);
}

/* we link the elements together /
/
file-source → h264-parser → nvh264-decoder →

  • nvinfer → nvvideoconvert → nvosd → video-renderer */
    if(prop.integrated) {
    if (!gst_element_link_many (streammux, pgie, tracker, sgie1, sgie2, sgie3,
    tiler, nvvideoconvert, nvosd, nvtransform, sink, NULL)) {
    g_printerr (“Elements could not be linked. Exiting.\n”);
    return -1;
    }
    } else {
    if (!gst_element_link_many (streammux, pgie, tracker, sgie1, sgie2, sgie3,
    tiler, nvvideoconvert, nvosd, sink, NULL)) {
    g_printerr (“Elements could not be linked. Exiting.\n”);
    return -1;
    }
    }

g_object_set (G_OBJECT (sink), “sync”, FALSE, “qos”, FALSE, NULL);

gst_element_set_state (pipeline, GST_STATE_PAUSED);

/* Set the pipeline to “playing” state */
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 (10, 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);
g_mutex_clear (&eos_lock);
return 0;
}