inference.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. #include "inference.h"
  2. #define MAX_DISPLAY_LEN 64
  3. #define PGIE_CLASS_ID_VEHICLE 0
  4. #define PGIE_CLASS_ID_PERSON 2
  5. /* By default, OSD process-mode is set to CPU_MODE. To change mode, set as:
  6. * 1: GPU mode (for Tesla only)
  7. * 2: HW mode (For Jetson only)
  8. */
  9. #define OSD_PROCESS_MODE 0
  10. /* By default, OSD will not display text. To display text, change this to 1 */
  11. #define OSD_DISPLAY_TEXT 1
  12. /* The muxer output resolution must be set if the input streams will be of
  13. * different resolution. The muxer will scale all the input frames to this
  14. * resolution. */
  15. #define MUXER_OUTPUT_WIDTH 1920
  16. #define MUXER_OUTPUT_HEIGHT 1080
  17. /* Muxer batch formation timeout, for e.g. 40 millisec. Should ideally be set
  18. * based on the fastest source's framerate. */
  19. #define MUXER_BATCH_TIMEOUT_USEC 500
  20. #define TILED_OUTPUT_WIDTH 1920
  21. #define TILED_OUTPUT_HEIGHT 1080
  22. /* NVIDIA Decoder source pad memory feature. This feature signifies that source
  23. * pads having this capability will push GstBuffers containing cuda buffers. */
  24. #define GST_CAPS_FEATURES_NVMM "memory:NVMM"
  25. gint frame_number = 0;
  26. namespace MIVA{
  27. std::shared_ptr<Inference> infer = NULL;
  28. std::shared_ptr<Inference> Inference::CreateNew()
  29. {
  30. if(infer == NULL) infer = std::make_shared<Inference>();
  31. return infer;
  32. }
  33. Inference::Inference()
  34. {
  35. }
  36. Inference::~Inference()
  37. {
  38. Destory();
  39. }
  40. // Init 初始化
  41. int32_t Inference::Init(vector<DataSource> DataList)
  42. {
  43. // init
  44. this->loop = g_main_loop_new (NULL, FALSE);
  45. // 创建管道
  46. this->pipeline = gst_pipeline_new("dstest3-pipeline");
  47. // 创建批处理器
  48. this->streammux = gst_element_factory_make ("nvstreammux", "stream-muxer");
  49. if(this->pipeline == NULL || this->streammux == NULL){
  50. ErrorL << "One element could not be created. Exiting.";
  51. return ERR;
  52. }
  53. gst_bin_add (GST_BIN (this->pipeline), this->streammux);
  54. // 创建数据源
  55. std::vector<DataSource>::iterator iter;
  56. int i = 0;
  57. for(iter = DataList.begin(); iter != DataList.end(); iter++){
  58. GstPad *sinkpad, *srcpad;
  59. gchar pad_name[16] = { };
  60. GstElement *source_bin = create_source_bin ((*iter).Id, (gchar*)((*iter).uri).c_str());
  61. if (!source_bin) {
  62. ErrorL << "Failed to create source bin. Exiting.";
  63. return ERR;
  64. }
  65. gst_bin_add(GST_BIN (this->pipeline), source_bin);
  66. g_snprintf (pad_name, 15, "sink_%u", i);
  67. sinkpad = gst_element_get_request_pad (this->streammux, pad_name);
  68. if(!sinkpad){
  69. ErrorL << "Streammux request sink pad failed. Exiting.";
  70. return ERR;
  71. }
  72. srcpad = gst_element_get_static_pad(source_bin, "src");
  73. if(!srcpad){
  74. ErrorL << "Failed to get src pad of source bin. Exiting.";
  75. return ERR;
  76. }
  77. if(gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK){
  78. ErrorL << "Failed to link source bin to stream muxer. Exiting.";
  79. return ERR;
  80. }
  81. gst_object_unref (srcpad);
  82. gst_object_unref (sinkpad);
  83. i++;
  84. }
  85. /* Use nvinfer to infer on batched frame. */
  86. this->pgie = gst_element_factory_make("nvinfer", "primary-nvinference-engine");
  87. /* Add queue elements between every two elements */
  88. this->queue1 = gst_element_factory_make ("queue", "queue1");
  89. this->queue2 = gst_element_factory_make ("queue", "queue2");
  90. this->queue3 = gst_element_factory_make ("queue", "queue3");
  91. this->queue4 = gst_element_factory_make ("queue", "queue4");
  92. this->queue5 = gst_element_factory_make ("queue", "queue5");
  93. /* Use nvtiler to composite the batched frames into a 2D tiled array based
  94. * on the source of the frames. */
  95. this->tiler = gst_element_factory_make ("nvmultistreamtiler", "nvtiler");
  96. /* Use convertor to convert from NV12 to RGBA as required by nvosd */
  97. this->nvvidconv = gst_element_factory_make ("nvvideoconvert", "nvvideo-converter");
  98. this->nvosd = gst_element_factory_make ("nvdsosd", "nv-onscreendisplay");
  99. #ifdef PLATFORM_TEGRA
  100. this->transform = gst_element_factory_make ("nvegltransform", "nvegl-transform");
  101. #endif
  102. this->sink = gst_element_factory_make ("nveglglessink", "nvvideo-renderer");
  103. if (!this->pgie || !this->tiler || !this->nvvidconv || !this->nvosd || !this->sink) {
  104. ErrorL << "One element could not be created. Exiting.";
  105. return -1;
  106. }
  107. #ifdef PLATFORM_TEGRA
  108. if(!this->transform) {
  109. ErrorL << "One tegra element could not be created. Exiting.";
  110. return -1;
  111. }
  112. #endif
  113. g_object_set(G_OBJECT(this->streammux), "batch-size", i, NULL);
  114. g_object_set (G_OBJECT (this->streammux), "width", MUXER_OUTPUT_WIDTH, "height",MUXER_OUTPUT_HEIGHT,
  115. "batched-push-timeout", MUXER_BATCH_TIMEOUT_USEC, NULL);
  116. /* Configure the nvinfer element using the nvinfer config file. */
  117. g_object_set (G_OBJECT (this->pgie),
  118. "config-file-path", "config_infer_primary_yoloV5.txt", NULL);
  119. /* Override the batch-size set in the config file with the number of sources. */
  120. g_object_get (G_OBJECT (this->pgie), "batch-size", &(this->pgie_batch_size), NULL);
  121. if (this->pgie_batch_size != i) {
  122. WarnL << "WARNING: Overriding infer-config batch-size:" << this->pgie_batch_size << "with number of sources ("<< i << ")";
  123. g_object_set (G_OBJECT (this->pgie), "batch-size", i, NULL);
  124. }
  125. this->tiler_rows = (guint) sqrt (i);
  126. this->tiler_columns = (guint) ceil (1.0 * i / this->tiler_rows);
  127. /* we set the tiler properties here */
  128. g_object_set (G_OBJECT (this->tiler), "rows", this->tiler_rows, "columns", this->tiler_columns,
  129. "width", TILED_OUTPUT_WIDTH, "height", TILED_OUTPUT_HEIGHT, NULL);
  130. g_object_set (G_OBJECT (this->nvosd), "process-mode", OSD_PROCESS_MODE,
  131. "display-text", OSD_DISPLAY_TEXT, NULL);
  132. g_object_set (G_OBJECT (this->sink), "qos", 0, NULL);
  133. this->bus = gst_pipeline_get_bus (GST_PIPELINE (this->pipeline));
  134. this->bus_watch_id = gst_bus_add_watch (this->bus, bus_call, this->loop);
  135. gst_object_unref (this->bus);
  136. gst_bin_add_many (GST_BIN (this->pipeline), this->queue1, this->pgie, this->queue2, this->tiler, this->queue3,
  137. this->nvvidconv, this->queue4, this->nvosd, this->queue5, this->transform, this->sink, NULL);
  138. // gst_bin_add_many (GST_BIN (this->pipeline), this->queue2, this->tiler, this->queue3,
  139. // this->nvvidconv, this->queue4, this->nvosd, this->queue5, this->transform, this->sink, NULL);
  140. // /* we link the elements together
  141. // * nvstreammux -> nvinfer -> nvtiler -> nvvidconv -> nvosd -> video-renderer */
  142. // if (!gst_element_link_many (this->streammux, this->queue2, this->tiler, this->queue3,
  143. // this->nvvidconv, this->queue4, this->nvosd, this->queue5, this->transform, this->sink, NULL)) {
  144. // ErrorL << "Elements could not be linked. Exiting.";
  145. // return -1;
  146. // }
  147. if (!gst_element_link_many (this->streammux, this->queue1, this->pgie, this->queue2, this->tiler, this->queue3,
  148. this->nvvidconv, this->queue4, this->nvosd, this->queue5, this->transform, this->sink, NULL)) {
  149. ErrorL << "Elements could not be linked. Exiting.";
  150. return -1;
  151. }
  152. this->tiler_src_pad = gst_element_get_static_pad(this->pgie, "src");
  153. if (!this->tiler_src_pad)
  154. InfoL << "Unable to get src pad";
  155. else
  156. gst_pad_add_probe (this->tiler_src_pad, GST_PAD_PROBE_TYPE_BUFFER,
  157. tiler_src_pad_buffer_probe, NULL, NULL);
  158. gst_object_unref (this->tiler_src_pad);
  159. return OK;
  160. }
  161. void Inference::ReadyTask()
  162. {
  163. InfoL << "Now ReadyTask";
  164. gst_element_set_state(this->pipeline, GST_STATE_READY);
  165. g_main_loop_run(this->loop);
  166. }
  167. // 启动任务
  168. void Inference::StartTask()
  169. {
  170. InfoL << "Now palying";
  171. gst_element_set_state(this->pipeline, GST_STATE_PLAYING);
  172. }
  173. // 暂停任务
  174. void Inference::PauseTask()
  175. {
  176. InfoL << "Now Pause";
  177. gst_element_set_state(this->pipeline, GST_STATE_PAUSED);
  178. }
  179. // 销毁对象
  180. void Inference::Destory()
  181. {
  182. InfoL << "Returned, stopping playback";
  183. gst_element_set_state(this->pipeline, GST_STATE_NULL);
  184. InfoL << "Deleting pipeline";
  185. gst_object_unref(GST_OBJECT(this->pipeline));
  186. g_source_remove(this->bus_watch_id);
  187. g_main_loop_unref(this->loop);
  188. infer = NULL;
  189. }
  190. GstPadProbeReturn
  191. Inference::tiler_src_pad_buffer_probe(GstPad * pad, GstPadProbeInfo * info, gpointer u_data)
  192. {
  193. //获取从管道中获取推理结果
  194. GstBuffer *buf = (GstBuffer *) info->data;
  195. NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);
  196. //初始化要使用的数据结构
  197. NvDsObjectMeta *obj_meta = NULL; //目标检测元数据类型变量
  198. NvDsMetaList * l_frame = NULL;
  199. NvDsMetaList * l_obj = NULL;
  200. NvDsDisplayMeta *display_meta = NULL;
  201. for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;l_frame = l_frame->next) //从批量中获取某一帧图
  202. {
  203. NvDsFrameMeta *frame_meta = (NvDsFrameMeta *) (l_frame->data);
  204. int num = 0;
  205. for (l_obj = frame_meta->obj_meta_list; l_obj != NULL;l_obj = l_obj->next)
  206. {
  207. obj_meta = (NvDsObjectMeta *) (l_obj->data);
  208. if (obj_meta->class_id == 0) // Person
  209. {
  210. num++;
  211. }
  212. }
  213. //画左上角的统计信息
  214. display_meta = nvds_acquire_display_meta_from_pool(batch_meta);
  215. NvOSD_TextParams *txt_params = &display_meta->text_params[0];
  216. display_meta->num_labels = 1;
  217. txt_params->display_text = (char *)g_malloc0 (MAX_DISPLAY_LEN);
  218. snprintf(txt_params->display_text, MAX_DISPLAY_LEN, "Number of people: %d \n", num);
  219. // 推理广播
  220. NoticeCenter::Instance().emitEvent(NOTICE_INFER,frame_meta->source_id, num);
  221. txt_params->x_offset = 30;
  222. txt_params->y_offset = 30;
  223. /* Font , font-color and font-size */
  224. txt_params->font_params.font_name = (char *)"Serif";
  225. txt_params->font_params.font_size = 10;
  226. txt_params->font_params.font_color.red = 1.0;
  227. txt_params->font_params.font_color.green = 1.0;
  228. txt_params->font_params.font_color.blue = 1.0;
  229. txt_params->font_params.font_color.alpha = 1.0;
  230. /* Text background color */
  231. txt_params->set_bg_clr = 1;
  232. txt_params->text_bg_clr.red = 0.0;
  233. txt_params->text_bg_clr.green = 0.0;
  234. txt_params->text_bg_clr.blue = 0.0;
  235. txt_params->text_bg_clr.alpha = 1.0;
  236. // nvds_add_display_meta_to_frame(frame_meta, display_meta);
  237. }
  238. return GST_PAD_PROBE_OK;
  239. }
  240. gboolean Inference::bus_call (GstBus * bus, GstMessage * msg, gpointer data)
  241. {
  242. GMainLoop *loop = (GMainLoop *) data;
  243. switch (GST_MESSAGE_TYPE (msg)) {
  244. case GST_MESSAGE_EOS:
  245. InfoL << "End of stream";
  246. g_main_loop_quit (loop);
  247. break;
  248. case GST_MESSAGE_WARNING:
  249. {
  250. gchar *debug;
  251. GError *error;
  252. gst_message_parse_warning (msg, &error, &debug);
  253. WarnL << "WARNING from element " << GST_OBJECT_NAME (msg->src) << ": " << error->message;
  254. g_free (debug);
  255. ErrorL << "Warning: " << error->message;
  256. g_error_free (error);
  257. break;
  258. }
  259. case GST_MESSAGE_ERROR:
  260. {
  261. gchar *debug;
  262. GError *error;
  263. gst_message_parse_error (msg, &error, &debug);
  264. ErrorL << "ERROR from element" << GST_OBJECT_NAME (msg->src) << ":" << error->message;
  265. if (debug)
  266. ErrorL << "Error details:" << debug;
  267. g_free (debug);
  268. g_error_free (error);
  269. g_main_loop_quit (loop);
  270. break;
  271. }
  272. #ifndef PLATFORM_TEGRA
  273. case GST_MESSAGE_ELEMENT:
  274. {
  275. if (gst_nvmessage_is_stream_eos (msg)) {
  276. guint stream_id;
  277. if (gst_nvmessage_parse_stream_eos (msg, &stream_id)) {
  278. InfoL << "Got EOS from stream " << stream_id;
  279. }
  280. }
  281. break;
  282. }
  283. #endif
  284. default:
  285. break;
  286. }
  287. return TRUE;
  288. }
  289. void Inference::cb_newpad (GstElement * decodebin, GstPad * decoder_src_pad, gpointer data)
  290. {
  291. InfoL << "In cb_newpad";
  292. GstCaps *caps = gst_pad_get_current_caps (decoder_src_pad);
  293. const GstStructure *str = gst_caps_get_structure (caps, 0);
  294. const gchar *name = gst_structure_get_name (str);
  295. GstElement *source_bin = (GstElement *) data;
  296. GstCapsFeatures *features = gst_caps_get_features (caps, 0);
  297. /* Need to check if the pad created by the decodebin is for video and not
  298. * audio. */
  299. if (!strncmp (name, "video", 5)) {
  300. /* Link the decodebin pad only if decodebin has picked nvidia
  301. * decoder plugin nvdec_*. We do this by checking if the pad caps contain
  302. * NVMM memory features. */
  303. if (gst_caps_features_contains (features, GST_CAPS_FEATURES_NVMM)) {
  304. /* Get the source bin ghost pad */
  305. GstPad *bin_ghost_pad = gst_element_get_static_pad (source_bin, "src");
  306. if (!gst_ghost_pad_set_target (GST_GHOST_PAD (bin_ghost_pad),
  307. decoder_src_pad)) {
  308. ErrorL << "Failed to link decoder src pad to source bin ghost pad";
  309. }
  310. gst_object_unref (bin_ghost_pad);
  311. } else {
  312. ErrorL << "Error: Decodebin did not pick nvidia decoder plugin.";
  313. }
  314. }
  315. }
  316. void Inference::decodebin_child_added (GstChildProxy * child_proxy, GObject * object,
  317. gchar * name, gpointer user_data)
  318. {
  319. InfoL << "Decodebin child added: " << name;
  320. if (g_strrstr (name, "decodebin") == name) {
  321. g_signal_connect (G_OBJECT (object), "child-added",
  322. G_CALLBACK (decodebin_child_added), user_data);
  323. }
  324. }
  325. GstElement* Inference::create_source_bin(guint index, gchar * uri)
  326. {
  327. GstElement *bin = NULL, *uri_decode_bin = NULL;
  328. gchar bin_name[16] = { };
  329. g_snprintf (bin_name, 15, "source-bin-%02d", index);
  330. /* Create a source GstBin to abstract this bin's content from the rest of the
  331. * pipeline */
  332. bin = gst_bin_new (bin_name);
  333. /* Source element for reading from the uri.
  334. * We will use decodebin and let it figure out the container format of the
  335. * stream and the codec and plug the appropriate demux and decode plugins. */
  336. uri_decode_bin = gst_element_factory_make ("uridecodebin", "uri-decode-bin");
  337. if (!bin || !uri_decode_bin) {
  338. ErrorL << "One element in source bin could not be created.";
  339. return NULL;
  340. }
  341. /* We set the input uri to the source element */
  342. g_object_set (G_OBJECT (uri_decode_bin), "uri", uri, NULL);
  343. /* Connect to the "pad-added" signal of the decodebin which generates a
  344. * callback once a new pad for raw data has beed created by the decodebin */
  345. g_signal_connect (G_OBJECT (uri_decode_bin), "pad-added",
  346. G_CALLBACK (cb_newpad), bin);
  347. g_signal_connect (G_OBJECT (uri_decode_bin), "child-added",
  348. G_CALLBACK (decodebin_child_added), bin);
  349. gst_bin_add (GST_BIN (bin), uri_decode_bin);
  350. /* We need to create a ghost pad for the source bin which will act as a proxy
  351. * for the video decoder src pad. The ghost pad will not have a target right
  352. * now. Once the decode bin creates the video decoder and generates the
  353. * cb_newpad callback, we will set the ghost pad target to the video decoder
  354. * src pad. */
  355. if (!gst_element_add_pad (bin, gst_ghost_pad_new_no_target ("src",
  356. GST_PAD_SRC))) {
  357. ErrorL << "Failed to add ghost pad in source bin";
  358. return NULL;
  359. }
  360. return bin;
  361. }
  362. }