#include "nv_message_converter.hpp" NvMessageConverter::NvMessageConverter() { const auto &config = ConfigManager::get_instance().get_config(); msgconv_config_file = config["msgconv"]["msgconv_config_file"]; frame_interval = config["msgconv"]["msgconv_frame_interval"]; payload_generation_library = config["msgconv"]["payload_generation_library"]; } bool NvMessageConverter::create_message_converter() { msgconv = gst_element_factory_make("nvmsgconv", "nvmsg-converter"); g_object_set(G_OBJECT(msgconv), "msg2p-lib", payload_generation_library.c_str(), NULL); g_object_set(G_OBJECT(msgconv), "config", msgconv_config_file.c_str(), NULL); g_object_set(G_OBJECT(msgconv), "payload-type", 0, NULL); // 0 = DeepStream schema, 1 = minimal schema g_object_set(G_OBJECT(msgconv), "msg2p-newapi", 0, NULL); // use new API; If you want to send images, please set // the "payload-type: 1" and "msg2p-newapi: 1" // msg2p-newapi: TRUE for DeepStream 6.x+ (recommended). g_object_set(G_OBJECT(msgconv), "frame-interval", frame_interval, NULL); // g_object_set(G_OBJECT(msgconv), // "config", "dstest5_msgconv.cfg", // message schema config // file "payload-type", 0, "msg2p-newapi", TRUE, // // use new API NULL); // g_object_set (G_OBJECT (msgconv), "config", "dstest4_msgconv_config.yml", // NULL); RETURN_ON_PARSER_ERROR(nvds_parse_msgconv (msgconv, argv[1], // "msgconv")); msg2p_meta = ds_test4_parse_meta_type(argv[1], "msgconv"); // g_print("msg2p_meta = %d\n", msg2p_meta); if (!msgconv) { g_printerr("Unable to create msgconv.Exiting."); return false; } return true; } const char *metaTypeToString(NvDsMetaType type) { switch (type) { case NVDS_INVALID_META: return "NVDS_INVALID_META"; case NVDS_BATCH_META: return "NVDS_BATCH_META"; case NVDS_FRAME_META: return "NVDS_FRAME_META"; case NVDS_OBJ_META: return "NVDS_OBJ_META"; case NVDS_DISPLAY_META: return "NVDS_DISPLAY_META"; case NVDS_CLASSIFIER_META: return "NVDS_CLASSIFIER_META"; case NVDS_LABEL_INFO_META: return "NVDS_LABEL_INFO_META"; case NVDS_USER_META: return "NVDS_USER_META"; case NVDS_PAYLOAD_META: return "NVDS_PAYLOAD_META"; case NVDS_EVENT_MSG_META: return "NVDS_EVENT_MSG_META"; case NVDS_OPTICAL_FLOW_META: return "NVDS_OPTICAL_FLOW_META"; case NVDS_LATENCY_MEASUREMENT_META: return "NVDS_LATENCY_MEASUREMENT_META"; case NVDSINFER_TENSOR_OUTPUT_META: return "NVDSINFER_TENSOR_OUTPUT_META"; case NVDSINFER_SEGMENTATION_META: return "NVDSINFER_SEGMENTATION_META"; case NVDS_CROP_IMAGE_META: return "NVDS_CROP_IMAGE_META"; case NVDS_TRACKER_PAST_FRAME_META: return "NVDS_TRACKER_PAST_FRAME_META"; case NVDS_TRACKER_BATCH_REID_META: return "NVDS_TRACKER_BATCH_REID_META"; case NVDS_TRACKER_OBJ_REID_META: return "NVDS_TRACKER_OBJ_REID_META"; case NVDS_TRACKER_TERMINATED_LIST_META: return "NVDS_TRACKER_TERMINATED_LIST_META"; case NVDS_TRACKER_SHADOW_LIST_META: return "NVDS_TRACKER_SHADOW_LIST_META"; case NVDS_OBJ_VISIBILITY: return "NVDS_OBJ_VISIBILITY"; case NVDS_OBJ_IMAGE_FOOT_LOCATION: return "NVDS_OBJ_IMAGE_FOOT_LOCATION"; case NVDS_OBJ_WORLD_FOOT_LOCATION: return "NVDS_OBJ_WORLD_FOOT_LOCATION"; case NVDS_OBJ_IMAGE_CONVEX_HULL: return "NVDS_OBJ_IMAGE_CONVEX_HULL"; case NVDS_AUDIO_BATCH_META: return "NVDS_AUDIO_BATCH_META"; case NVDS_AUDIO_FRAME_META: return "NVDS_AUDIO_FRAME_META"; case NVDS_PREPROCESS_FRAME_META: return "NVDS_PREPROCESS_FRAME_META"; case NVDS_PREPROCESS_BATCH_META: return "NVDS_PREPROCESS_BATCH_META"; case NVDS_CUSTOM_MSG_BLOB: return "NVDS_CUSTOM_MSG_BLOB"; case NVDS_ROI_META: return "NVDS_ROI_META"; case NVDS_RESERVED_META: return "NVDS_RESERVED_META"; default: return "UNKNOWN_META_TYPE"; } } static bool safe_string_print(const char *s, size_t maxlen = 512) { if (!s) return false; // Try to be conservative: check bytes up to maxlen for a terminating NUL for (size_t i = 0; i < maxlen; ++i) { // read each byte carefully; this still risks UB if pointer invalid, // but we only call this if pointer seems reasonable (non-NULL). if (s[i] == '\0') return true; } return false; // no NUL found in first maxlen bytes -> suspicious } void NvMessageConverter::attach_probe_to_sink_msgconv() { GstPad *sink_pad = gst_element_get_static_pad(msgconv, "sink"); if (!sink_pad) { std::cerr << "Unable to get sink_pad sink pad\n"; return; } gst_pad_add_probe(sink_pad, GST_PAD_PROBE_TYPE_BUFFER, nvmsgconv_probe_cb, NULL, NULL); gst_object_unref(sink_pad); } GstPadProbeReturn NvMessageConverter::nvmsgconv_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { (void)pad; (void)user_data; GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER(info); if (!buf) return GST_PAD_PROBE_OK; // make a writable copy (or just use the buffer if not modifying) // buf = gst_buffer_make_writable(buf); // get batch meta NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf); if (!batch_meta) { // g_print("[nvmsgconv probe] no batch meta\n"); return GST_PAD_PROBE_OK; } // loop over user meta to find event msg meta for (NvDsMetaList *l = batch_meta->batch_user_meta_list; l != NULL; l = l->next) { NvDsUserMeta *user_meta = (NvDsUserMeta *)l->data; // g_print("[nvmsgconv probe] batch user meta type=%s, ptr=%p\n", // metaTypeToString(user_meta->base_meta.meta_type), // (void*)user_meta->user_meta_data); if (user_meta && user_meta->base_meta.meta_type == NVDS_EVENT_MSG_META) { NvDsEventMsgMeta *msg_meta = (NvDsEventMsgMeta *)user_meta->user_meta_data; if (!msg_meta) { g_print(" NVDS_EVENT_MSG_META but user_meta_data==NULL\n"); continue; } if (msg_meta) { g_print("=== nvmsgconv probe: received event message ===\n"); if (msg_meta->ts) g_print("timestamp: %s\n", msg_meta->ts); if (msg_meta->objType == NVDS_OBJECT_TYPE_PERSON) g_print("object type: person\n"); if (msg_meta->extMsg) { // extMsg is type-specific, e.g., NvDsVehicleObject / // NvDsPersonObject g_print("extMsg present\n"); } std::quick_exit(0); } if (msg_meta) { g_print("nvmsgconv probe: got event msg meta\n"); if (msg_meta->ts) g_print(" ts: %s\n", msg_meta->ts); g_print(" objType: %d\n", msg_meta->objType); std::quick_exit(0); } // Print numeric fields and pointer addresses only (safe) g_print( " event msg ptr=%p frameId=%" G_GINT64_FORMAT " objType=%d\n", (void *)msg_meta, (gint64)msg_meta->frameId, msg_meta->objType); g_print(" bbox: top=%f left=%f w=%f h=%f\n", msg_meta->bbox.top, msg_meta->bbox.left, msg_meta->bbox.width, msg_meta->bbox.height); // Print timestamp pointer (safe) and length check before deref g_print(" ts_ptr=%p\n", (void *)msg_meta->ts); if (msg_meta->ts && safe_string_print(msg_meta->ts, 256)) { g_print(" ts: %s\n", msg_meta->ts); } else if (msg_meta->ts) { g_print( " ts appears suspicious (no NUL within 256 bytes) - not " "printing\n"); } else { g_print(" ts=NULL\n"); } // If images present, show pointer/size // if (msg_meta->image_meta.data && msg_meta->image_meta.size > 0) { // g_print(" image_meta: data_ptr=%p size=%u w=%d h=%d // type=%d\n", // (void*)msg_meta->image_meta.data, // msg_meta->image_meta.size, // msg_meta->image_meta.width, // msg_meta->image_meta.height, // msg_meta->image_meta.image_type); // } } } // Also inspect per-frame metas (some code attaches to frame_user_meta_list) for (NvDsMetaList *lf = batch_meta->frame_meta_list; lf; lf = lf->next) { NvDsFrameMeta *fmeta = (NvDsFrameMeta *)lf->data; if (!fmeta) continue; for (NvDsMetaList *l = fmeta->frame_user_meta_list; l; l = l->next) { NvDsUserMeta *um = (NvDsUserMeta *)l->data; if (!um) continue; // g_print("[nvmsgconv probe] frame %d user meta type=%s ptr=%p\n", // fmeta->frame_num, // metaTypeToString(um->base_meta.meta_type), // (void*)um->user_meta_data); if (um->base_meta.meta_type == NVDS_EVENT_MSG_META) { NvDsEventMsgMeta *m = (NvDsEventMsgMeta *)um->user_meta_data; if (!m) continue; g_print("frame-level event msg ptr=%p frameId=%" G_GINT64_FORMAT "\n", (void *)m, (gint64)m->frameId); g_print("ts_ptr=%p\n", (void *)m->ts); if (m->ts && safe_string_print(m->ts, 256)) { g_print("ts: %s\n", m->ts); } else if (m->ts) { g_print("ts suspicious - not printing\n"); } else { g_print("ts=NULL\n"); } } } } return GST_PAD_PROBE_OK; }