#include #include #include #include #include #include using std::string; // The URI for the 4k camera string uri{"rtsp://10.19.225.116/media/video1"}; /* This function is called when an error message is posted on the bus */ static void error_cb (GstBus *bus, GstMessage *msg, gpointer *data) { GError *err; gchar *debug_info; auto *loop = (GMainLoop *) data; /* Print error details on the screen */ gst_message_parse_error (msg, &err, &debug_info); g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error (&err); g_free (debug_info); g_main_loop_quit (loop); } void uri_decodebin_pad_added_handler (GstElement */*decodebin*/, GstPad *decoder_src_pad, gpointer source_bin) { GstCaps * new_pad_caps{gst_pad_get_current_caps(decoder_src_pad)}; GstStructure *new_pad_struct = gst_caps_get_structure(new_pad_caps, 0); const gchar * new_pad_type = gst_structure_get_name(new_pad_struct); GstCapsFeatures * features = gst_caps_get_features(new_pad_caps, 0); if (g_str_has_prefix(new_pad_type, "video")) { if (gst_caps_features_contains (features, "memory:NVMM")) { // Get the source bin ghost pad GstPad * bin_ghost_pad{gst_element_get_static_pad(static_cast(source_bin), "src")}; gst_ghost_pad_set_target(GST_GHOST_PAD_CAST(bin_ghost_pad), decoder_src_pad); } } gst_caps_unref(new_pad_caps); } bool add_or_remove =false; GstElement * pipeline; GstElement * tee2; GstElement * dynamic_fakesink; GstElement * dynamic_identity; std::atomic ctr; GstPad * tee2_src; static GstPadProbeReturn eos_callback_handler(GstPad */*pad*/, GstPadProbeInfo *info, gpointer /*user_data*/) { GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info); g_printerr("Got event: %s\n", GST_EVENT_TYPE_NAME (event)); if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) { if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { ctr.store(0); } } return GST_PAD_PROBE_OK; } static GstPadProbeReturn remove_dynamic_element_blocking_probe_callback_handler(GstPad */*pad*/, GstPadProbeInfo */*info*/, gpointer user_data) { GstPad * dynamic_fakesink_sink = gst_element_get_static_pad (dynamic_fakesink, "sink"); gulong id = gst_pad_add_probe(dynamic_fakesink_sink, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, &eos_callback_handler, nullptr, nullptr); g_printerr("Probe id: %lu\n", id); gst_object_unref (dynamic_fakesink_sink); GstPad* target_pad = gst_pad_get_peer(tee2_src); ctr.store(1); gst_pad_send_event(target_pad, gst_event_new_eos()); gst_object_unref (target_pad); g_printerr("EOS sent to dynamic elements\n"); //Wait till all the sinks receive the eos event while (ctr.load()!=0) g_usleep(200000); gst_element_set_state (dynamic_identity, GST_STATE_NULL); gst_element_set_state (dynamic_fakesink, GST_STATE_NULL); gst_bin_remove_many(GST_BIN(pipeline), dynamic_fakesink, dynamic_identity, NULL); gst_element_release_request_pad(tee2, tee2_src); gst_object_unref (tee2_src); GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline_removed"); g_printerr("Dynamic elements removed\n"); return GstPadProbeReturn::GST_PAD_PROBE_REMOVE; } static GstPadProbeReturn add_dynamic_element_blocking_probe_callback_handler(GstPad */*tee2_src*/, GstPadProbeInfo */*info*/, gpointer user_data) { dynamic_fakesink = gst_element_factory_make ("fakesink", "dynamic_fakesink"); dynamic_identity = gst_element_factory_make ("identity", "dynamic_identity"); gst_bin_add_many(GST_BIN (pipeline), dynamic_fakesink, dynamic_identity, NULL); gst_element_link(dynamic_identity, dynamic_fakesink); GstPad * dynamic_identity_sink = gst_element_get_static_pad (dynamic_identity, "sink"); gst_pad_link (tee2_src, dynamic_identity_sink); gst_object_unref (dynamic_identity_sink); gst_element_set_state (dynamic_fakesink, GST_STATE_PLAYING); gst_element_set_state (dynamic_identity, GST_STATE_PLAYING); GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline_add"); g_printerr("Dynamic elements added\n"); return GstPadProbeReturn::GST_PAD_PROBE_REMOVE; } static gboolean editpipeline(gpointer userdata){ if (!add_or_remove){ //add tee2_src = gst_element_get_request_pad (tee2, "src_%u"); gst_pad_add_probe(tee2_src, GST_PAD_PROBE_TYPE_IDLE, &add_dynamic_element_blocking_probe_callback_handler, nullptr, nullptr); } else { //remove gst_pad_add_probe(tee2_src, GST_PAD_PROBE_TYPE_IDLE, &remove_dynamic_element_blocking_probe_callback_handler, nullptr, nullptr); } add_or_remove=!add_or_remove; return true; } GstPadProbeReturn probe_callback_handler(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { GstBuffer* gst_buffer = gst_pad_probe_info_get_buffer(info); NvDsBatchMeta* batch_meta = gst_buffer_get_nvds_batch_meta(gst_buffer); for (NvDsMetaList * current_frame = batch_meta->frame_meta_list; current_frame != nullptr; current_frame = current_frame->next) { NvDsDisplayMeta *display_meta{nullptr}; auto* frame_meta = static_cast(current_frame->data); display_meta = nvds_acquire_display_meta_from_pool(frame_meta->base_meta.batch_meta); nvds_add_display_meta_to_frame(frame_meta, display_meta); ++display_meta->num_labels; NvOSD_TextParams *txt_params = &display_meta->text_params[0]; const size_t MAX_DISPLAY_LEN{64}; if(txt_params->display_text) { g_print("***free the text data\n"); g_free(txt_params->display_text); txt_params->display_text=NULL; } txt_params->display_text = (char *)g_malloc0(MAX_DISPLAY_LEN); snprintf(txt_params->display_text, MAX_DISPLAY_LEN, "Hello Memleak!"); txt_params->x_offset = 10; txt_params->y_offset = 12; txt_params->font_params.font_name = const_cast("Mono"); 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; 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; } return GstPadProbeReturn::GST_PAD_PROBE_OK; } int main(int argc, char *argv[]) { GstPad *tee2_sink, *tee2_src0; GstPad *fakesink_sink; GstBus *bus; GstElement * sourcebin; GMainLoop *main_loop; /* Initialize GStreamer */ gst_init (&argc, &argv); GstElement *src, *q1, *q2, *q3, *mux, *demux, *cf1, *cf2, *cf3, *nvvc1, *nvvc2, *osd, *fakesink; /* Create the elements */ sourcebin = gst_bin_new ("sourcebin"); src = gst_element_factory_make ("uridecodebin", "uridecodebin"); g_signal_connect (src, "pad-added", G_CALLBACK (uri_decodebin_pad_added_handler), sourcebin); g_object_set (G_OBJECT (src), "uri", uri.c_str(), nullptr); gst_bin_add (GST_BIN (sourcebin), src); gst_element_add_pad (sourcebin, gst_ghost_pad_new_no_target ("src",GstPadDirection::GST_PAD_SRC)); tee2 = gst_element_factory_make ("tee", "tee2"); osd = gst_element_factory_make ("nvdsosd", "osd"); g_object_set(osd, "hw-blend-color-attr", "0,0.0,0.0,0.0,0", nullptr); mux = gst_element_factory_make ("nvstreammux", "nvstreammux"); g_object_set(mux, "live-source", 1, nullptr); g_object_set(mux, "width", 3840, "height", 2160, "batch-size", 1, "batched-push-timeout", 40000, nullptr); demux = gst_element_factory_make ("nvstreamdemux", "nvstreamdemux"); cf1 = gst_element_factory_make ("capsfilter", "capsfilter1"); GstCaps* caps{gst_caps_from_string("video/x-raw(memory:NVMM), format=NV12")}; g_object_set(cf1, "caps", caps, nullptr); gst_caps_unref(caps); cf2 = gst_element_factory_make ("capsfilter", "capsfilter2"); caps =gst_caps_from_string("video/x-raw(memory:NVMM), format=RGBA"); g_object_set(cf2, "caps", caps, nullptr); gst_caps_unref(caps); cf3 = gst_element_factory_make ("capsfilter", "capsfilter3"); caps =gst_caps_from_string("video/x-raw, format=RGBA"); g_object_set(cf3, "caps", caps, nullptr); gst_caps_unref(caps); nvvc1 = gst_element_factory_make ("nvvideoconvert", "nvvideoconvert1"); nvvc2 = gst_element_factory_make ("nvvideoconvert", "nvvideoconvert2"); q1 = gst_element_factory_make ("queue", "q1"); q2 = gst_element_factory_make ("queue", "q2"); q3 = gst_element_factory_make ("queue", "q3"); fakesink = gst_element_factory_make ("fakesink", "fakesink"); pipeline = gst_pipeline_new ("test-pipeline"); //********************* Add and link gst_bin_add_many (GST_BIN (pipeline), sourcebin, q1, q2, q3, tee2, mux, demux, cf1, cf2, cf3, nvvc1, nvvc2, osd, fakesink, NULL); gst_element_link_many (sourcebin, q1, NULL); gst_element_link_many (mux, demux, NULL); gst_element_link_many (cf1, nvvc1, cf2, osd, q2, nvvc2, cf3, q3, tee2, NULL); tee2_src0 = gst_element_get_request_pad (tee2, "src_%u"); fakesink_sink = gst_element_get_static_pad (fakesink, "sink"); gst_pad_link (tee2_src0, fakesink_sink); GstPad* sinkpad{gst_element_get_request_pad(mux, "sink_0")}; GstPad *srcpad{gst_element_get_static_pad(q1, "src")}; gst_pad_link(srcpad, sinkpad); gst_object_unref(sinkpad); gst_object_unref(srcpad); GstPad * demux_src_pad{gst_element_get_request_pad(demux, "src_0")}; GstPad * cf_sink{gst_element_get_static_pad(cf1, "sink")}; gst_pad_link(demux_src_pad, cf_sink); gst_object_unref(demux_src_pad); gst_object_unref(cf_sink); //********************* Probe callback handler GstPad * osd_sink_pad = gst_element_get_static_pad(osd, "sink"); gst_pad_add_probe(osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER, &probe_callback_handler, nullptr, nullptr); gst_object_unref(osd_sink_pad); //********************* Play bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, &main_loop); gst_object_unref (bus); g_timeout_add(2000, editpipeline, nullptr); /* Start playing the pipeline */ gst_element_set_state (pipeline, GST_STATE_PLAYING); GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline"); /* Create a GLib Main Loop and set it to run */ main_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (main_loop); //********************* Free /* Release the request pads from the Tee, and unref them */ gst_element_release_request_pad (tee2, tee2_src0); gst_object_unref (tee2_src0); gst_object_unref (fakesink_sink); /* Free resources */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); return 0; }