#include #include #include #include #include #include #include "math.h" #include #include #include "nvbufsurface.h" #include "nvbufsurftransform.h" #include "demo_app.h" #include "gst-nvmessage.h" #include #include GMainLoop *loop = NULL; guint bus_watch_id; GstElement *pipeline = NULL, *src = NULL, *streammux=NULL; gchar *cfg_path; GstBus *bus = NULL; #define MAX_NUM_SOURCES 2 gint g_num_sources = 0; GMutex eos_lock; 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; char* SOURCE = NULL; #define CUDAVER 10.0 #define NVDS_APP_VERSION_MAJOR 1 #define NVDS_APP_VERSION_MINOR 2 #define SIZE_OF_DATETIME 20 static gchar **cfg_files = NULL; static gchar **input_files = NULL; static gboolean print_version = FALSE; static guint num_instances=0; static guint num_input_files; #define MAX_INSTANCES 128 AppCtx *appCtx[MAX_INSTANCES]; char strTime[SIZE_OF_DATETIME+1]; FILE *fp = NULL; static gboolean save_txt_flag=FALSE; GOptionEntry entries[] = { {"version", 'v', 0, G_OPTION_ARG_NONE, &print_version, "Print Demo version", NULL} , {"cfg-file", 'c', 0, G_OPTION_ARG_FILENAME_ARRAY, &cfg_files, "Set the config file", NULL} , // {"input-file", 'i', 0, G_OPTION_ARG_FILENAME_ARRAY, &input_files, // "Set the input file", NULL} // , {NULL} , }; static GstPadProbeReturn queue_test_src_buffer_probe_tmp(GstPad * pad, GstPadProbeInfo * info, gpointer u_data) { g_print("Frame No:%d\n", frame_No); GstBuffer *buf = (GstBuffer*)info->data; NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf); for (NvDsMetaList * l_frame = batch_meta->frame_meta_list; l_frame != NULL; l_frame = l_frame->next){ NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)l_frame->data; //g_print("Frame No:%d\n", frame_meta->frame_num); if (frame_meta->frame_num == 0){ GstElement * eleTmp = gst_bin_get_by_name(GST_BIN(pipeline), "queue_custom"); GstClockTime time = gst_element_get_start_time(eleTmp); g_print("%ld\n", time); //gst_element_set_start_time(eleTmp, 0); GstState state, pending; gst_element_get_state(eleTmp, &state, &pending, GST_CLOCK_TIME_NONE); g_print("state=%d\n", state); g_print("pending=%d\n", pending); } } frame_No++; return GST_PAD_PROBE_OK; } static gboolean bus_call (GstBus * bus, GstMessage * msg, gpointer data) { GMainLoop *loop = (GMainLoop *) data; g_print("msg=%d\n", GST_MESSAGE_TYPE(msg)); switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: g_print ("End of stream\n"); g_main_loop_quit (loop); g_print("end!\n"); 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); } } break; } case GST_MESSAGE_DEVICE_ADDED: { g_print("GST_MESSAGE_DEVICE_ADDED\n"); } case GST_MESSAGE_DEVICE_REMOVED: { g_print("GST_MESSAGE_DEVICE_REMOVED\n"); } default: //g_print("msg=%d\n", GST_MESSAGE_TYPE(msg)); break; } return TRUE; } static gboolean main_init(int argc, char* argv[]){ GOptionContext *ctx = NULL; GOptionGroup *group = NULL; cfg_path = "/home/yl/Product/KeyVIRdemo/demo_config.txt"; for (guint i = 0; i < 1; i++){ appCtx[i] = g_malloc0(sizeof(AppCtx)); //memset(appCtx[i], 0, sizeof(AppCtx)); if (!parse_config_file(&appCtx[i]->config, cfg_path)){ g_print("Failed to parse config file \n"); return -1; } } gst_init(NULL, NULL); g_mutex_init(&eos_lock); pipeline = gst_pipeline_new("demo-pipeline"); } static gboolean main_uninit(){ 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_mutex_clear(&eos_lock); } GstElement* create_src_bin(char *uri, guint index) { GstElement* src_bin = NULL, *src = NULL, *h264parse = NULL, *nvv4l2decoder = NULL; g_print("create src bin for [%d][%s]\n", index, uri); gchar tmp_name[16]; g_snprintf(tmp_name, 15, "src_bin_%02d", index); src_bin = gst_bin_new(tmp_name); g_snprintf(tmp_name, 15, "src_elem_%02d", index); src = gst_element_factory_make("filesrc", tmp_name); //g_object_set(G_OBJECT(src), "location", appCtx[0]->config.multi_source_config[0].uri, NULL); g_object_set(G_OBJECT(src), "location", uri, NULL); g_snprintf(tmp_name, 15, "h264parse_%02d", index); h264parse = gst_element_factory_make("h264parse", tmp_name); g_snprintf(tmp_name, 15, "nvv4l2decoder_%02d", index); nvv4l2decoder = gst_element_factory_make("nvv4l2decoder", tmp_name); gst_bin_add_many(GST_BIN(src_bin), src, h264parse, nvv4l2decoder, NULL); gst_element_link_many(src, h264parse, nvv4l2decoder, NULL); NVGSTDS_BIN_ADD_GHOST_PAD(src_bin, nvv4l2decoder, "src"); gst_bin_add(GST_BIN(pipeline), src_bin); GstPad *sinkpad, *srcpad; srcpad = gst_element_get_static_pad(src_bin, "src"); if (!srcpad) { g_printerr("Failed to get sink pad of sink bin. Exiting.\n"); return NULL; } gchar pad_name[16]; g_snprintf(pad_name, 16, "sink_%u", index); sinkpad = gst_element_get_request_pad(streammux, pad_name); if (!sinkpad) { g_printerr("Streamdemux request source pad failed. Exiting.\n"); return NULL; } if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) { g_printerr("Failed to link source bin to stream demuxer. Exiting.\n"); return NULL; } gst_object_unref(srcpad); gst_object_unref(sinkpad); g_source_enabled[index] = TRUE; g_eos_list[index] = FALSE; done: return src_bin; } static void stop_release_source(gint source_id) { GstStateChangeReturn state_return; gchar pad_name[16]; GstPad *sinkpad = NULL; 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--; g_print("release done!\n"); 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_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]); 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; } } static gboolean delete_sources() { gint source_id; g_mutex_lock(&eos_lock); for (source_id = 0; source_id < MAX_NUM_SOURCES; source_id++) { g_print("g_eos_list[source_id]=%d\n", g_eos_list[source_id]); g_print("g_source_enabled[source_id]=%d\n", g_source_enabled[source_id]); if (g_eos_list[source_id] == TRUE && g_source_enabled[source_id] == TRUE) { g_print("Calling Stop %d\n", source_id); g_source_enabled[source_id] = FALSE; stop_release_source(source_id); } } g_mutex_unlock(&eos_lock); if (g_num_sources == 0) { //g_main_loop_quit(loop); g_print("All sources Stopped quitting 1\n"); return TRUE; } do { source_id = rand() % MAX_NUM_SOURCES; } while (!g_source_enabled[source_id]); g_source_enabled[source_id] = FALSE; g_print("Calling Stop %d \n", source_id); stop_release_source(source_id); if (g_num_sources == 0) { //g_main_loop_quit(loop); g_print("All sources Stopped quitting 2\n"); return TRUE; } g_print("delete done\n"); return TRUE; } static gboolean add_sources(gpointer data) { gint source_id = g_num_sources; GstElement *src_bin; GstStateChangeReturn state_return; g_print("\ng_source_enabled = %d\n", g_source_enabled[0]); do{ source_id = rand() % MAX_NUM_SOURCES; } while (g_source_enabled[source_id]); g_source_enabled[source_id] = TRUE; g_print("Calling Start %d \n", source_id); src_bin = create_src_bin(data, source_id); if (!src_bin){ g_printerr("Failed to create src_bin[%d]\n", 0); return -1; } g_source_bin_list[source_id] = src_bin; g_num_sources++; return TRUE; } static int main_func(int argc, char* argv[]) { ///////////////////////////////////////////////////////////////////////////// GstElement *pgie = NULL, *nvtracker = NULL, *sgie = NULL, *nvvidconv = NULL, *nvosd = NULL, *sink = NULL, *nvvideoconvert = NULL, *nvv4l2h264enc = NULL, *matroskamux = NULL, *h264parse2 = NULL, *queue_custom = NULL; GstElement *tee = NULL, *queue1 = NULL, *queue2 = NULL, *nvvidconv_2 = NULL, *caps_filter_2 = NULL, *nvjpegenc_2 = NULL, *sink_2 = NULL; GstCaps *caps_2 = NULL; GstPad *srcpad_0 = NULL, *sinkpad_0 = NULL, *srcpad_1 = NULL, *sinkpad_1 = NULL, *queue_pad = NULL, *srcpad_2 = NULL, *sinkpad_2 = NULL; streammux = gst_element_factory_make("nvstreammux", "stream-muxer"); if (!set_streammux_properties(&appCtx[0]->config.streammux_config, streammux)){ g_printerr("Failed to set streammux properties. Exiting\n"); return -1; } gst_bin_add(GST_BIN(pipeline), streammux); g_source_bin_list = g_malloc0(sizeof(GstElement *)* MAX_NUM_SOURCES); // for (int i = 0; i < 1; i++){ // add_sources("./data/test-1.h264"); // } pgie = gst_element_factory_make("nvinfer", "primary-nvinference-engine"); queue_custom = gst_element_factory_make("queue", "queue_custom"); nvtracker = gst_element_factory_make("nvtracker", "tracker"); sgie = gst_element_factory_make("nvinfer", "secondary1-nvinference-engine"); NvDsOSDBin* NvOsdBin; NvOsdBin = g_malloc0(sizeof(NvDsOSDBin)); //memset(NvOsdBin, 0, sizeof(NvDsOSDBin)); create_osd_bin(&appCtx[0]->config.osd_config, NvOsdBin); if (!NvOsdBin){ g_print("failed to create NvOsdBin!\n"); return -1; } tee = gst_element_factory_make("tee", "tee"); queue1 = gst_element_factory_make("queue", "queue1"); nvvideoconvert = gst_element_factory_make("nvvideoconvert", "nvvideoconvert"); nvv4l2h264enc = gst_element_factory_make("nvv4l2h264enc", "nvv4l2h264enc"); g_object_set(G_OBJECT(nvv4l2h264enc), "bitrate", 8000000, NULL); h264parse2 = gst_element_factory_make("h264parse", "h264parse-2"); matroskamux = gst_element_factory_make("matroskamux", "matroskamux"); //sink = gst_element_factory_make("filesink", "sink"); //g_object_set(G_OBJECT(sink), "location", "./res/res.mp4", "sync", FALSE, "qos", FALSE, NULL); sink = gst_element_factory_make("fakesink", "sink"); g_object_set(G_OBJECT(sink), "sync", FALSE, "qos", FALSE, NULL); if (!queue1 || !streammux || !pgie || !queue_custom || !nvtracker || !nvvideoconvert || !sink){ g_print("error create element 1!\n"); return -1; } queue2 = gst_element_factory_make("queue", "queue2"); nvvidconv_2 = gst_element_factory_make("nvvideoconvert", "nvvideoconvert-3"); caps_filter_2 = gst_element_factory_make(NVDS_ELEM_CAPS_FILTER, "caps_filter3"); caps_2 = gst_caps_from_string("video/x-raw, format=I420"); g_object_set(G_OBJECT(caps_filter_2), "caps", caps_2, NULL); gst_caps_unref(caps_2); nvjpegenc_2 = gst_element_factory_make("nvjpegenc", "nvjpegenc-3"); sink_2 = gst_element_factory_make("fakesink", "sink-3"); // multifilesink //g_object_set(G_OBJECT(sink_2), "location", "./res/img_%04d.jpg", NULL); if (!queue2 || !nvvidconv_2 || !caps_filter_2 || !nvjpegenc_2 || !sink_2){ g_print("error create element 2!\n"); return -1; } if (!set_pgie_properties(&appCtx[0]->config.primary_gie_config, pgie)){ g_printerr("Failed to set pgie properties. Exiting\n"); return -1; } if (!set_tracker_properties(nvtracker, cfg_path)) { g_printerr("Failed to set tracker properties. Exiting5.\n"); return -1; } gst_bin_add_many(GST_BIN(pipeline), //pgie, nvtracker, queue_custom, NvOsdBin->bin, tee, NULL); ///////////////////////////////////////////////// if (!gst_element_link_many(streammux, queue_custom, // pgie, nvtracker, NvOsdBin->bin, tee, NULL)){ g_printerr("Elements could not be linked. Exiting2.\n"); return -1; } gboolean queue1_enable = TRUE; if (queue1_enable){ gst_bin_add_many(GST_BIN(pipeline), queue1, nvvideoconvert, nvv4l2h264enc, h264parse2, matroskamux, sink, NULL); srcpad_1 = gst_element_get_request_pad(tee, "src_1"); if (!srcpad_1){ g_printerr("tee_queue1 Error!\n"); return -1; } sinkpad_1 = gst_element_get_static_pad(queue1, "sink"); if (!sinkpad_1){ g_printerr("sinkpad1 Error!\n"); return -1; } if (gst_pad_link(srcpad_1, sinkpad_1) != GST_PAD_LINK_OK){ g_printerr("Elements could not be linked: 1. Exiting7.\n"); } gst_object_unref(srcpad_1); gst_object_unref(sinkpad_1); if (!gst_element_link_many(queue1, nvvideoconvert, nvv4l2h264enc, h264parse2, matroskamux, sink, NULL)){ g_printerr("Elements could not be linked. Exiting2.\n"); return -1; } } queue_pad = gst_element_get_static_pad(queue_custom, "src"); if (!queue_pad) g_print("Unable to get sink2 pad\n"); else gst_pad_add_probe(queue_pad, GST_PAD_PROBE_TYPE_BUFFER, queue_test_src_buffer_probe_tmp, NULL, NULL); g_print("pause pipeline!\n"); gst_element_set_state(pipeline, GST_STATE_READY); return 0; } int main(int argc, char* argv[]){ g_print("init pipeline!\n"); main_init(argc, argv); main_func(argc, argv); loop = g_main_loop_new(NULL, FALSE); char* source_uri[10] = { "./data/test-1.h264", "./data/ch00.h264", "./data/testNvDCF.h264"}; guint times = 3; for (int i = 0; i < times; i++){ g_print("-----------------uri %d----------------------\n", i+1); g_print("check g_num_sources=%d\n", g_num_sources); if (g_num_sources == MAX_NUM_SOURCES){ g_print("start delete source!\n"); delete_sources(); } add_sources(source_uri[i]); bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); bus_watch_id = gst_bus_add_watch(bus, bus_call, loop); gst_object_unref(bus); g_print("play pipeline!\n"); if (gst_element_set_state(pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { g_printerr("Failed to set pipeline to playing. Exiting 1.\n"); return -1; } g_main_loop_run(loop); gst_element_set_state(pipeline, GST_STATE_PAUSED); } g_print("uninit pipeline!\n"); main_uninit(); return 0; }