/* * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include "gstnvdsmeta.h" #include "gst-nvmessage.h" #include "nvdsmeta.h" #define MAX_DISPLAY_LEN 64 #define MEASURE_ENABLE 1 #define PGIE_CLASS_ID_VEHICLE 0 #define PGIE_CLASS_ID_PERSON 2 #define SGIE_CLASS_ID_LPD 0 /* 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 /* Muxer batch formation timeout, for e.g. 40 millisec. Should ideally be set * based on the fastest source's framerate. */ #define MUXER_BATCH_TIMEOUT_USEC 4000000 #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" #define CONFIG_GPU_ID "gpu-id" #define GST_CAPS_FEATURES_NVMM "memory:NVMM" gint frame_number = 0; gint total_plate_number = 0; gchar pgie_classes_str[4][32] = { "Vehicle", "TwoWheeler", "Person", "Roadsign" }; typedef struct _DsSourceBin { GstElement *source_bin; GstElement *uri_decode_bin; GstElement *vidconv; GstElement *nvvidconv; GstElement *capsfilt; gint index; bool is_imagedec; }DsSourceBinStruct; extern "C" void parse_nvdsanalytics_meta_data (NvDsBatchMeta *batch_meta); #define PRIMARY_DETECTOR_UID 1 #define SECONDARY_DETECTOR_UID 2 #define SECONDARY_CLASSIFIER_UID 3 typedef struct _perf_measure{ GstClockTime pre_time; GstClockTime total_time; guint count; }perf_measure; 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; } /* osd_sink_pad_buffer_probe will extract metadata received on OSD sink pad * and update params for drawing rectangle, object information etc. */ static GstPadProbeReturn osd_sink_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer u_data) { GstBuffer *buf = (GstBuffer *) info->data; NvDsObjectMeta *obj_meta = NULL; guint vehicle_count = 0; guint person_count = 0; guint lp_count = 0; guint label_i = 0; NvDsMetaList * l_frame = NULL; NvDsMetaList * l_obj = NULL; NvDsMetaList * l_class = NULL; NvDsMetaList * l_label = NULL; NvDsDisplayMeta *display_meta = NULL; NvDsClassifierMeta * class_meta = NULL; NvDsLabelInfo * label_info = NULL; GstClockTime now; perf_measure * perf = (perf_measure *)(u_data); NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf); now = g_get_monotonic_time(); if (perf->pre_time == GST_CLOCK_TIME_NONE) { perf->pre_time = now; perf->total_time = GST_CLOCK_TIME_NONE; } else { if (perf->total_time == GST_CLOCK_TIME_NONE) { perf->total_time = (now - perf->pre_time); } else { perf->total_time += (now - perf->pre_time); } perf->pre_time = now; perf->count++; } for (l_frame = batch_meta->frame_meta_list; l_frame != NULL; l_frame = l_frame->next) { NvDsFrameMeta *frame_meta = (NvDsFrameMeta *) (l_frame->data); int offset = 0; if (!frame_meta) continue; for (l_obj = frame_meta->obj_meta_list; l_obj != NULL; l_obj = l_obj->next) { obj_meta = (NvDsObjectMeta *) (l_obj->data); if (!obj_meta) continue; /* Check that the object has been detected by the primary detector * and that the class id is that of vehicles/persons. */ if (obj_meta->unique_component_id == PRIMARY_DETECTOR_UID) { if (obj_meta->class_id == PGIE_CLASS_ID_VEHICLE) vehicle_count++; if (obj_meta->class_id == PGIE_CLASS_ID_PERSON) person_count++; } if (obj_meta->unique_component_id == SECONDARY_DETECTOR_UID) { if (obj_meta->class_id == SGIE_CLASS_ID_LPD) { lp_count++; /* Print this info only when operating in secondary model. */ if (obj_meta->parent) g_print ("License plate found for parent object %p (type=%s)\n", obj_meta->parent, pgie_classes_str[obj_meta->parent->class_id]); obj_meta->text_params.set_bg_clr = 1; obj_meta->text_params.text_bg_clr.red = 0.0; obj_meta->text_params.text_bg_clr.green = 0.0; obj_meta->text_params.text_bg_clr.blue = 0.0; obj_meta->text_params.text_bg_clr.alpha = 0.0; obj_meta->text_params.font_params.font_color.red = 1.0; obj_meta->text_params.font_params.font_color.green = 1.0; obj_meta->text_params.font_params.font_color.blue = 0.0; obj_meta->text_params.font_params.font_color.alpha = 1.0; obj_meta->text_params.font_params.font_size = 12; } } for (l_class = obj_meta->classifier_meta_list; l_class != NULL; l_class = l_class->next) { class_meta = (NvDsClassifierMeta *)(l_class->data); if (!class_meta) continue; if (class_meta->unique_component_id == SECONDARY_CLASSIFIER_UID) { for ( label_i = 0, l_label = class_meta->label_info_list; label_i < class_meta->num_labels && l_label; label_i++, l_label = l_label->next) { label_info = (NvDsLabelInfo *)(l_label->data); if (label_info) { if (label_info->label_id == 0 && label_info->result_class_id == 1) { g_print ("Plate License %s\n",label_info->result_label); } } } } } } display_meta = nvds_acquire_display_meta_from_pool(batch_meta); NvOSD_TextParams *txt_params = &display_meta->text_params[0]; display_meta->num_labels = 1; txt_params->display_text = (char*) g_malloc0 (MAX_DISPLAY_LEN); offset = snprintf(txt_params->display_text, MAX_DISPLAY_LEN, "Person = %d ", person_count); offset += snprintf(txt_params->display_text + offset , MAX_DISPLAY_LEN, "Vehicle = %d ", vehicle_count); /* Now set the offsets where the string should appear */ txt_params->x_offset = 10; txt_params->y_offset = 12; /* Font , font-color and font-size */ char font_n[6]; snprintf(font_n, 6, "Serif"); txt_params->font_params.font_name = font_n; 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; nvds_add_display_meta_to_frame(frame_meta, display_meta); } g_print ("Frame Number = %d Vehicle Count = %d Person Count = %d" " License Plate Count = %d\n", frame_number, vehicle_count, person_count, lp_count); frame_number++; total_plate_number += lp_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_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; } default: break; } return TRUE; } static void cb_newpad (GstElement * decodebin, GstPad * decoder_src_pad, gpointer data) { g_print ("In cb_newpad\n"); GstCaps *caps = gst_pad_get_current_caps (decoder_src_pad); const GstStructure *str = gst_caps_get_structure (caps, 0); const gchar *name = gst_structure_get_name (str); DsSourceBinStruct *bin_struct = (DsSourceBinStruct *) 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 to videoconvert if no hardware decoder is used */ if (bin_struct->vidconv) { GstPad *conv_sink_pad = gst_element_get_static_pad (bin_struct->vidconv, "sink"); if (gst_pad_link (decoder_src_pad, conv_sink_pad)) { g_printerr ("Failed to link decoderbin src pad to converter sink pad\n"); } g_object_unref(conv_sink_pad); if (!gst_element_link (bin_struct->vidconv, bin_struct->nvvidconv)) { g_printerr ("Failed to link videoconvert to nvvideoconvert\n"); } } else { GstPad *conv_sink_pad = gst_element_get_static_pad (bin_struct->nvvidconv, "sink"); if (gst_pad_link (decoder_src_pad, conv_sink_pad)) { g_printerr ("Failed to link decoderbin src pad to converter sink pad\n"); } g_object_unref(conv_sink_pad); } if (gst_caps_features_contains (features, GST_CAPS_FEATURES_NVMM)) { g_print ("###Decodebin pick nvidia decoder plugin.\n"); } else { /* Get the source bin ghost pad */ g_print ("###Decodebin did not pick nvidia decoder plugin.\n"); } } } static void decodebin_child_added (GstChildProxy * child_proxy, GObject * object, gchar * name, gpointer user_data) { DsSourceBinStruct *bin_struct = (DsSourceBinStruct *) 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); } if (g_strstr_len (name, -1, "pngdec") == name) { bin_struct->vidconv = gst_element_factory_make ("videoconvert", "source_vidconv"); gst_bin_add (GST_BIN (bin_struct->source_bin), bin_struct->vidconv); bin_struct->is_imagedec=true; } else { bin_struct->vidconv = NULL; bin_struct->is_imagedec=false; } } static bool create_source_bin (DsSourceBinStruct *ds_source_struct, gchar * uri) { gchar bin_name[16] = { }; GstCaps *caps = NULL; GstCapsFeatures *feature = NULL; ds_source_struct->nvvidconv = NULL; ds_source_struct->capsfilt = NULL; ds_source_struct->source_bin = NULL; ds_source_struct->uri_decode_bin = NULL; g_snprintf (bin_name, 15, "source-bin-%02d", ds_source_struct->index); /* Create a source GstBin to abstract this bin's content from the rest of the * pipeline */ ds_source_struct->source_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. */ ds_source_struct->uri_decode_bin = gst_element_factory_make ("uridecodebin", "uri-decode-bin"); ds_source_struct->nvvidconv = gst_element_factory_make ("nvvideoconvert", "source_nvvidconv"); ds_source_struct->capsfilt = gst_element_factory_make ("capsfilter", "source_capset"); if (!ds_source_struct->source_bin || !ds_source_struct->uri_decode_bin || !ds_source_struct->nvvidconv || !ds_source_struct->capsfilt) { g_printerr ("One element in source bin could not be created.\n"); return false; } /* We set the input uri to the source element */ g_object_set (G_OBJECT (ds_source_struct->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 (ds_source_struct->uri_decode_bin), "pad-added", G_CALLBACK (cb_newpad), ds_source_struct); g_signal_connect (G_OBJECT (ds_source_struct->uri_decode_bin), "child-added", G_CALLBACK (decodebin_child_added), ds_source_struct); caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "NV12", NULL); feature = gst_caps_features_new ("memory:NVMM", NULL); gst_caps_set_features (caps, 0, feature); g_object_set (G_OBJECT (ds_source_struct->capsfilt), "caps", caps, NULL); #ifndef PLATFORM_TEGRA g_object_set (G_OBJECT (ds_source_struct->nvvidconv), "nvbuf-memory-type", 3, NULL); #endif gst_bin_add_many (GST_BIN (ds_source_struct->source_bin), ds_source_struct->uri_decode_bin, ds_source_struct->nvvidconv, ds_source_struct->capsfilt, NULL); if (!gst_element_link (ds_source_struct->nvvidconv, ds_source_struct->capsfilt)) { g_printerr ("Could not link vidconv and capsfilter\n"); return false; } /* 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. */ GstPad *gstpad = gst_element_get_static_pad (ds_source_struct->capsfilt, "src"); if (!gstpad) { g_printerr ("Could not find srcpad in '%s'", GST_ELEMENT_NAME(ds_source_struct->capsfilt)); return false; } if(!gst_element_add_pad (ds_source_struct->source_bin, gst_ghost_pad_new("src", gstpad))) { g_printerr ("Could not add ghost pad in '%s'", GST_ELEMENT_NAME(ds_source_struct->capsfilt)); } gst_object_unref (gstpad); 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, char * config_file_name) { 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, config_file_name, 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 (config_file_name, 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 (config_file_name, 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; } /* nvdsanalytics_src_pad_buffer_probe will extract metadata received on * nvdsanalytics src pad and extract nvanalytics metadata etc. */ static GstPadProbeReturn nvdsanalytics_src_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); parse_nvdsanalytics_meta_data (batch_meta); return GST_PAD_PROBE_OK; } int main (int argc, char *argv[]) { GMainLoop *loop = NULL; GstElement *pipeline = NULL,*streammux = NULL, *sink = NULL, *primary_detector = NULL, *secondary_detector = NULL, *nvvidconv = NULL, *nvosd = NULL, *nvvidconv1 = NULL, *nvh264enc = NULL, *capfilt = NULL, *secondary_classifier = NULL, *nvtile=NULL; GstElement *tracker = NULL, *nvdsanalytics = NULL; GstElement *queue1 = NULL, *queue2 = NULL, *queue3 = NULL, *queue4 = NULL, *queue5 = NULL, *queue6 = NULL, *queue7 = NULL, *queue8 = NULL, *queue9 = NULL, *queue10 = NULL; DsSourceBinStruct source_struct[128]; #ifdef PLATFORM_TEGRA GstElement *transform = NULL; #endif GstBus *bus = NULL; guint bus_watch_id; GstPad *osd_sink_pad = NULL; GstCaps *caps = NULL; GstCapsFeatures *feature = NULL; //int i; static guint src_cnt = 0; guint tiler_rows, tiler_columns; perf_measure perf_measure; GstPad *sinkpad, *srcpad; gchar pad_name_sink[16] = "sink_0"; gchar pad_name_src[16] = "src"; /* Check input arguments */ if (argc < 6 || argc > 133 || (atoi(argv[1]) != 1 && atoi(argv[1]) != 2) || (atoi(argv[2]) != 1 && atoi(argv[2]) != 2 && atoi(argv[2]) != 3) || (atoi(argv[3]) != 1 && atoi(argv[3]) != 0) ) { g_printerr ("Usage: %s [1:us model|2: ch_model] [1:file sink|2:fakesink|" "3:display sink] [0:ROI disable|0:ROI enable] ... " "\n", argv[0]); return -1; } //For Chinese language supporting setlocale(LC_CTYPE, ""); /* Standard GStreamer initialization */ gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); perf_measure.pre_time = GST_CLOCK_TIME_NONE; perf_measure.total_time = GST_CLOCK_TIME_NONE; perf_measure.count = 0; /* Create gstreamer elements */ /* Create Pipeline element that will form a connection of other elements */ pipeline = gst_pipeline_new ("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); /* Multiple source files */ for (src_cnt=0; src_cnt<(guint)argc-5; src_cnt++) { /* Source element for reading from the file */ source_struct[src_cnt].index = src_cnt; if (!create_source_bin (&(source_struct[src_cnt]), argv[src_cnt + 4])) { g_printerr ("Source bin could not be created. Exiting.\n"); return -1; } gst_bin_add (GST_BIN (pipeline), source_struct[src_cnt].source_bin); g_snprintf (pad_name_sink, 64, "sink_%d", src_cnt); sinkpad = gst_element_get_request_pad (streammux, pad_name_sink); g_print("Request %s pad from streammux\n",pad_name_sink); if (!sinkpad) { g_printerr ("Streammux request sink pad failed. Exiting.\n"); return -1; } srcpad = gst_element_get_static_pad (source_struct[src_cnt].source_bin, pad_name_src); if (!srcpad) { g_printerr ("Decoder request src pad failed. Exiting.\n"); return -1; } if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK) { g_printerr ("Failed to link decoder to stream muxer. Exiting.\n"); return -1; } gst_object_unref (sinkpad); gst_object_unref (srcpad); } /* Create three nvinfer instances for two detectors and one classifier*/ primary_detector = gst_element_factory_make ("nvinfer", "primary-infer-engine1"); secondary_detector = gst_element_factory_make ("nvinfer", "secondary-infer-engine1"); secondary_classifier = gst_element_factory_make ("nvinfer", "secondary-infer-engine2"); /* Use convertor to convert from NV12 to RGBA as required by nvosd */ nvvidconv = gst_element_factory_make ("nvvideoconvert", "nvvid-converter"); /* Create OSD to draw on the converted RGBA buffer */ nvosd = gst_element_factory_make ("nvdsosd", "nv-onscreendisplay"); nvvidconv1 = gst_element_factory_make ("nvvideoconvert", "nvvid-converter1"); nvh264enc = gst_element_factory_make ("nvv4l2h264enc" ,"nvvideo-h264enc"); capfilt = gst_element_factory_make ("capsfilter", "nvvideo-caps"); nvtile = gst_element_factory_make ("nvmultistreamtiler", "nvtiler"); tracker = gst_element_factory_make ("nvtracker", "nvtracker"); /* Use nvdsanalytics to perform analytics on object */ nvdsanalytics = gst_element_factory_make ("nvdsanalytics", "nvdsanalytics"); 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"); queue9 = gst_element_factory_make ("queue", "queue9"); queue10 = gst_element_factory_make ("queue", "queue10"); if (atoi(argv[2]) == 1) sink = gst_element_factory_make ("filesink", "nvvideo-renderer"); else if (atoi(argv[2]) == 2) sink = gst_element_factory_make ("fakesink", "fake-renderer"); else if (atoi(argv[2]) == 3) { #ifdef PLATFORM_TEGRA transform = gst_element_factory_make ("nvegltransform", "nvegltransform"); if(!transform) { g_printerr ("nvegltransform element could not be created. Exiting.\n"); return -1; } #endif sink = gst_element_factory_make ("nveglglessink", "nvvideo-renderer"); } if (!primary_detector || !secondary_detector || !nvvidconv || !nvosd || !sink || !capfilt || !nvh264enc) { 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, "batch-size", src_cnt, "batched-push-timeout", MUXER_BATCH_TIMEOUT_USEC, NULL); tiler_rows = (guint) sqrt (src_cnt); tiler_columns = (guint) ceil (1.0 * src_cnt / tiler_rows); g_object_set (G_OBJECT (nvtile), "rows", tiler_rows, "columns", tiler_columns, "width", 1280, "height", 720, NULL); g_object_set (G_OBJECT (nvdsanalytics), "config-file", "config_nvdsanalytics.txt", NULL); /* Set the config files for the two detectors and one classifier. The PGIE * detects the cars. The first SGIE detects car plates from the cars and the * second SGIE classifies the caracters in the car plate to identify the car * plate string. */ g_object_set (G_OBJECT (primary_detector), "config-file-path", "trafficamnet_config.txt", "unique-id", PRIMARY_DETECTOR_UID, NULL); if (atoi(argv[1]) == 1) { g_object_set (G_OBJECT (secondary_detector), "config-file-path", "lpd_us_config.txt", "unique-id", SECONDARY_DETECTOR_UID, "process-mode", 2, NULL); g_object_set (G_OBJECT (secondary_classifier), "config-file-path", "lpr_config_sgie_us.txt", "unique-id", SECONDARY_CLASSIFIER_UID, "process-mode", 2, NULL); } else if (atoi(argv[1]) == 2) { g_object_set (G_OBJECT (secondary_detector), "config-file-path", "lpd_ccpd_config.txt", "unique-id", SECONDARY_DETECTOR_UID, "process-mode", 2, NULL); g_object_set (G_OBJECT (secondary_classifier), "config-file-path", "lpr_config_sgie_ch.txt", "unique-id", SECONDARY_CLASSIFIER_UID, "process-mode", 2, NULL); } char name[300]; snprintf(name, 300, "lpr_sample_tracker_config.txt"); if (!set_tracker_properties(tracker, name)) { g_printerr ("Failed to set tracker1 properties. Exiting.\n"); return -1; } caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "I420", NULL); feature = gst_caps_features_new ("memory:NVMM", NULL); gst_caps_set_features (caps, 0, feature); g_object_set (G_OBJECT (capfilt), "caps", caps, NULL); /* we add a bus 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), primary_detector, secondary_detector, tracker, nvdsanalytics, queue1, queue2, queue3, queue4, queue5, queue6, queue7, queue8, secondary_classifier, nvvidconv, nvosd, nvtile, sink, NULL); if (atoi(argv[3]) == 0) { if (!gst_element_link_many (streammux, queue1, primary_detector, queue2, tracker, queue3, secondary_detector, queue5, secondary_classifier, queue6, nvtile, queue7, nvvidconv, queue8, nvosd, NULL)) { g_printerr ("Inferring and tracking elements link failure.\n"); return -1; } } else { if (!gst_element_link_many (streammux, queue1, primary_detector, queue2, tracker, queue3, nvdsanalytics, queue4, secondary_detector, queue5, secondary_classifier, queue6, nvtile, queue7, nvvidconv, queue8, nvosd, NULL)) { g_printerr ("Inferring and tracking elements link failure.\n"); return -1; } } if (atoi(argv[2]) == 1) { g_object_set (G_OBJECT (sink), "location", argv[argc-1],NULL); gst_bin_add_many (GST_BIN (pipeline), nvvidconv1, nvh264enc, capfilt, queue9, queue10, NULL); if (!gst_element_link_many (nvosd, queue9, nvvidconv1, capfilt, queue10, nvh264enc, sink, NULL)) { g_printerr ("OSD and sink elements link failure.\n"); return -1; } } else if (atoi(argv[2]) == 2) { g_object_set (G_OBJECT (sink), "sync", 0, "async", false,NULL); if (!gst_element_link (nvosd, sink)) { g_printerr ("OSD and sink elements link failure.\n"); return -1; } } else if (atoi(argv[2]) == 3) { #ifdef PLATFORM_TEGRA gst_bin_add_many (GST_BIN (pipeline), transform, queue9, NULL); if (!gst_element_link_many (nvosd, queue9, transform, sink, NULL)) { g_printerr ("OSD and sink elements link failure.\n"); return -1; } #else gst_bin_add (GST_BIN (pipeline), queue9); if (!gst_element_link_many (nvosd, queue9, sink, NULL)) { g_printerr ("OSD and sink elements link failure.\n"); return -1; } #endif } /* 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, &perf_measure, 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 */ g_print ("Now playing: %s\n", argv[1]); 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 ("Average fps %f\n", ((perf_measure.count-1)*src_cnt*1000000.0)/perf_measure.total_time); g_print ("Totally %d plates are inferred\n",total_plate_number); g_print ("Deleting pipeline\n"); gst_object_unref (GST_OBJECT (pipeline)); g_source_remove (bus_watch_id); g_main_loop_unref (loop); return 0; }