Try to send custom nvdsanalytics result to kafka, but message meta copy func compile failed

Hi everyone, I’m trying to combine deepstream-nvdsanalytics-app and deepstream-test4-app, to send custom nvdsanalytics result to kafka, for example, I want to send the number of rois to kafka, to notify us how many people in the area.

When I compile the app, error raised:

g++ -c -o deepstream_line_crossing_msgconv.o -DPLATFORM_TEGRA -I../../../includes `pkg-config --cflags gstreamer-1.0` deepstream_line_crossing_msgconv.cpp
deepstream_line_crossing_msgconv.cpp: In function ‘void* meta_copy_func(gpointer, gpointer)’:
deepstream_line_crossing_msgconv.cpp:130:22: error: invalid conversion from ‘gpointer {aka void*}’ to ‘NvDsEventMsgMeta*’ [-fpermissive]
   dstMeta = g_memdup (srcMeta, sizeof(NvDsEventMsgMeta));
             ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
deepstream_line_crossing_msgconv.cpp:139:48: error: invalid conversion from ‘gpointer {aka void*}’ to ‘gdouble* {aka double*}’ [-fpermissive]
     dstMeta->objSignature.signature = g_memdup (srcMeta->objSignature.signature,
                                       ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                 srcMeta->objSignature.size);
                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
Makefile:56: recipe for target 'deepstream_line_crossing_msgconv.o' failed
make: *** [deepstream_line_crossing_msgconv.o] Error 1

What I’ve done:

  • Modify the official deepstream_nvdsanalytics_app.cpp, adding the msgconv and msgbroker plugin from deepstream_test4_app.c
  • Create a new NvDsPersonInROIObject in nvdsmeta_schema.h, something like:
/**
 * Holds parameters that a person in roi area.
 */
typedef struct NvDsPersonInROIObject {
  gint *num_roi;    /**< Holds a pointer to the number of person in roi area. */
} NvDsPersonInROIObject;
  • Modify nvds_msg2p_generate in nvmsgconv.cpp:
NvDsPayload*
nvds_msg2p_generate (NvDsMsg2pCtx *ctx, NvDsEvent *events, guint size)
{
  gchar *message = NULL;
  gint len = 0;
  NvDsPayload *payload = (NvDsPayload *) g_malloc0 (sizeof (NvDsPayload));
  if (ctx->payloadType == NVDS_PAYLOAD_DEEPSTREAM) {
    message = generate_schema_message (ctx, events->metadata);
    if (message) {
      len = strlen (message);
      // Remove '\0' character at the end of string and just copy the content.
      payload->payload = g_memdup (message, len);
      payload->payloadSize = len;
      g_free (message);
    }
  } else if (ctx->payloadType == NVDS_PAYLOAD_DEEPSTREAM_MINIMAL) {
    message = generate_deepstream_message_minimal (ctx, events, size);
    if (message) {
      len = strlen (message);
      // Remove '\0' character at the end of string and just copy the content.
      payload->payload = g_memdup (message, len);
      payload->payloadSize = len;
      g_free (message);
    }
  } else if (ctx->payloadType == NVDS_PAYLOAD_CUSTOM) {
    // payload->payload = (gpointer) g_strdup ("CUSTOM Schema");
    // payload->payloadSize = strlen ((char *)payload->payload) + 1;
    message = generate_deepstream_message_minimal (ctx, events, size);    /*My custom parsing method here.*/
    if (message) {
      len = strlen (message);
      // Remove '\0' character at the end of string and just copy the content.
      payload->payload = g_memdup (message, len);
      payload->payloadSize = len;
      g_free (message);
    }
  } else
    payload->payload = NULL;

  return payload;
}
  • Copy the message meta copy func and meta release func from deepstream_test4_app.c to deepstream_nvdsanalytics_app.cpp:
static gpointer meta_copy_func (gpointer data, gpointer user_data)
{
  NvDsUserMeta *user_meta = (NvDsUserMeta *) data;
  NvDsEventMsgMeta *srcMeta = (NvDsEventMsgMeta *) user_meta->user_meta_data;
  NvDsEventMsgMeta *dstMeta = NULL;

  dstMeta = g_memdup (srcMeta, sizeof(NvDsEventMsgMeta));

  if (srcMeta->ts)
    dstMeta->ts = g_strdup (srcMeta->ts);

  if (srcMeta->sensorStr)
    dstMeta->sensorStr = g_strdup (srcMeta->sensorStr);

  if (srcMeta->objSignature.size > 0) {
    dstMeta->objSignature.signature = g_memdup (srcMeta->objSignature.signature,
                                                srcMeta->objSignature.size);
    dstMeta->objSignature.size = srcMeta->objSignature.size;
  }

  if(srcMeta->objectId) {
    dstMeta->objectId = g_strdup (srcMeta->objectId);
  }

  if (srcMeta->extMsgSize > 0) {
    if (srcMeta->objType == NVDS_OBJECT_TYPE_VEHICLE) {
      NvDsVehicleObject *srcObj = (NvDsVehicleObject *) srcMeta->extMsg;
      NvDsVehicleObject *obj = (NvDsVehicleObject *) g_malloc0 (sizeof (NvDsVehicleObject));
      if (srcObj->type)
        obj->type = g_strdup (srcObj->type);
      if (srcObj->make)
        obj->make = g_strdup (srcObj->make);
      if (srcObj->model)
        obj->model = g_strdup (srcObj->model);
      if (srcObj->color)
        obj->color = g_strdup (srcObj->color);
      if (srcObj->license)
        obj->license = g_strdup (srcObj->license);
      if (srcObj->region)
        obj->region = g_strdup (srcObj->region);

      dstMeta->extMsg = obj;
      dstMeta->extMsgSize = sizeof (NvDsVehicleObject);
    } else if (srcMeta->objType == NVDS_OBJECT_TYPE_PERSON) {
      NvDsPersonObject *srcObj = (NvDsPersonObject *) srcMeta->extMsg;
      NvDsPersonObject *obj = (NvDsPersonObject *) g_malloc0 (sizeof (NvDsPersonObject));

      obj->age = srcObj->age;

      if (srcObj->gender)
        obj->gender = g_strdup (srcObj->gender);
      if (srcObj->cap)
        obj->cap = g_strdup (srcObj->cap);
      if (srcObj->hair)
        obj->hair = g_strdup (srcObj->hair);
      if (srcObj->apparel)
        obj->apparel = g_strdup (srcObj->apparel);
      dstMeta->extMsg = obj;
      dstMeta->extMsgSize = sizeof (NvDsPersonObject);
    } else if (srcMeta->objType == NVDS_OBJECT_TYPE_CUSTOM) {
      NvDsPersonInROIObject *srcObj = (NvDsPersonInROIObject *) srcMeta->extMsg;
      NvDsPersonInROIObject *obj = (NvDsPersonInROIObject *) g_malloc0 (sizeof (NvDsPersonInROIObject));
      
      if (srcObj->num_roi)
        obj->num_roi = srcObj->num_roi;
      dstMeta->extMsg = obj;
      dstMeta->extMsgSize = sizeof (NvDsPersonInROIObject);
    }
  }

  return dstMeta;
}

static void meta_free_func (gpointer data, gpointer user_data)
{
  NvDsUserMeta *user_meta = (NvDsUserMeta *) data;
  NvDsEventMsgMeta *srcMeta = (NvDsEventMsgMeta *) user_meta->user_meta_data;

  g_free (srcMeta->ts);
  g_free (srcMeta->sensorStr);

  if (srcMeta->objSignature.size > 0) {
    g_free (srcMeta->objSignature.signature);
    srcMeta->objSignature.size = 0;
  }

  if(srcMeta->objectId) {
    g_free (srcMeta->objectId);
  }

  if (srcMeta->extMsgSize > 0) {
    if (srcMeta->objType == NVDS_OBJECT_TYPE_VEHICLE) {
      NvDsVehicleObject *obj = (NvDsVehicleObject *) srcMeta->extMsg;
      if (obj->type)
        g_free (obj->type);
      if (obj->color)
        g_free (obj->color);
      if (obj->make)
        g_free (obj->make);
      if (obj->model)
        g_free (obj->model);
      if (obj->license)
        g_free (obj->license);
      if (obj->region)
        g_free (obj->region);
    } else if (srcMeta->objType == NVDS_OBJECT_TYPE_PERSON) {
      NvDsPersonObject *obj = (NvDsPersonObject *) srcMeta->extMsg;

      if (obj->gender)
        g_free (obj->gender);
      if (obj->cap)
        g_free (obj->cap);
      if (obj->hair)
        g_free (obj->hair);
      if (obj->apparel)
        g_free (obj->apparel);
    } else if (srcMeta->objType == NVDS_OBJECT_TYPE_CUSTOM) {
      NvDsPersonInROIObject *obj = (NvDsPersonInROIObject *) srcMeta->extMsg;

      if (obj->num_roi)
      g_free (obj->num_roi);
    }
    g_free (srcMeta->extMsg);
    srcMeta->extMsgSize = 0;
  }
  g_free (user_meta->user_meta_data);
  user_meta->user_meta_data = NULL;
}

most of the code haven’t changed, just add a case to handle NVDS_OBJECT_TYPE_CUSTOM.

  • Makefile:
APP:= deepstream-line-crossing-msgconv

TARGET_DEVICE = $(shell gcc -dumpmachine | cut -f1 -d -)

NVDS_VERSION:=5.0

LIB_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/
APP_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/bin/

ifeq ($(TARGET_DEVICE),aarch64)
  CFLAGS:= -DPLATFORM_TEGRA
endif

SRCS:= $(wildcard *.cpp)

INCS:= $(wildcard *.h)

PKGS:= gstreamer-1.0

OBJS:= $(SRCS:.cpp=.o)

CFLAGS+= -I../../../includes

CFLAGS+= `pkg-config --cflags $(PKGS)`

LIBS:= `pkg-config --libs $(PKGS)`

LIBS+= -L$(LIB_INSTALL_DIR) -lnvdsgst_meta -lnvds_meta -lnvdsgst_helper -lm -lrt \
       -Wl,-rpath,$(LIB_INSTALL_DIR)

all: $(APP)

%.o: %.cpp $(INCS) Makefile
	$(CXX) -c -o $@ $(CFLAGS) $<

$(APP): $(OBJS) Makefile
	$(CXX) -o $(APP) $(OBJS) $(LIBS)

install: $(APP)
	cp -rv $(APP) $(APP_INSTALL_DIR)

clean:
	rm -rf $(OBJS) $(APP)



Is it the C++ code cannot be compiled like C code? Because the deepsteram-texst4-app and deepsteram-texst5-app can be compiled correctly, and the message meta copy/release function are almost the same.

Please provide complete information as applicable to your setup.

• Hardware Platform (Jetson / GPU) Jetson AGX Xavier
• DeepStream Version 5.0
• JetPack Version (valid for Jetson only) 4.4 DP
• TensorRT Version 7.0
• NVIDIA GPU Driver Version (valid for GPU only)

HI,
Sorry for a late reply.
Have you solved the issue? Can you add -fPIC to CFLAGS and try again.

hi, I solved that problem by converting the data type once again:

static gpointer meta_copy_func (gpointer data, gpointer user_data)
{
  ......
  dstMeta = (NvDsEventMsgMeta *)  g_memdup (srcMeta, sizeof(NvDsEventMsgMeta));  /*There's no (NvDsEventMsgMeta *) before.*/

  ......
  if (srcMeta->objSignature.size > 0) {
    dstMeta->objSignature.signature = (gdouble *) g_memdup (srcMeta->objSignature.signature,
                                                srcMeta->objSignature.size);  /*There's no (gdouble *) before.*/

Actually I want to send custom nvdsanalytics result to kafka, but msgconv examples (deepstream-test4 and test5) are written in C, if I add nvdsanalytics element in deepstream-test4, the compilation will failed. Is nvdsanalytics only work in C++?

BTW, what’s the -fPIC CFLAG for?

@Amycao here’s my make fail message:

cc -c -o deepstream_test4_app.o -I../../../includes `pkg-config --cflags gstreamer-1.0` deepstream_test4_app.c
In file included from deepstream_test4_app.c:40:0:
../../../includes/nvds_analytics_meta.h:28:3: error: expected specifier-qualifier-list before ‘std’
   std::vector <std::string> roiStatus;
   ^~~
../../../includes/nvds_analytics_meta.h:39:3: error: expected specifier-qualifier-list before ‘std’
   std::unordered_map<std::string, bool> ocStatus;
   ^~~
deepstream_test4_app.c: In function ‘nvdsanalytics_src_pad_buffer_probe’:
deepstream_test4_app.c:332:39: error: ‘NvDsAnalyticsObjInfo {aka struct <anonymous>}’ has no member named ‘dirStatus’
                     if (user_meta_data->dirStatus.length()){
                                       ^~
deepstream_test4_app.c:333:98: error: ‘NvDsAnalyticsObjInfo {aka struct <anonymous>}’ has no member named ‘dirStatus’
                         g_print ("object %lu moving in %s\n", obj_meta->object_id, user_meta_data->dirStatus.c_str());
                                                                                                  ^~
deepstream_test4_app.c:354:29: error: ‘NvDsAnalyticsFrameMeta {aka struct <anonymous>}’ has no member named ‘objInROIcnt’
             roi_count = meta->objInROIcnt["RF"];
                             ^~
deepstream_test4_app.c:355:28: error: ‘NvDsAnalyticsFrameMeta {aka struct <anonymous>}’ has no member named ‘objLCCumCnt’
             lc_count = meta->objLCCumCnt["Exit"];
                            ^~
deepstream_test4_app.c: In function ‘main’:
deepstream_test4_app.c:754:24: warning: implicit declaration of function ‘sqrt’ [-Wimplicit-function-declaration]
   tiler_rows = (guint) sqrt (num_sources);
                        ^~~~
deepstream_test4_app.c:754:24: warning: incompatible implicit declaration of built-in function ‘sqrt’
deepstream_test4_app.c:754:24: note: include ‘<math.h>’ or provide a declaration of ‘sqrt’
deepstream_test4_app.c:755:27: warning: implicit declaration of function ‘ceil’ [-Wimplicit-function-declaration]
   tiler_columns = (guint) ceil (1.0 * num_sources / tiler_rows);
                           ^~~~
deepstream_test4_app.c:755:27: warning: incompatible implicit declaration of built-in function ‘ceil’
deepstream_test4_app.c:755:27: note: include ‘<math.h>’ or provide a declaration of ‘ceil’
Makefile:56: recipe for target 'deepstream_test4_app.o' failed
make: *** [deepstream_test4_app.o] Error 1

I added the nvdsanalytics element in deepstream-test4-app, written in C rather than CPP.

Check the nvds_analytics_meta.h:

#ifndef _NVDS_ANALYTICS_META_H_
#define _NVDS_ANALYTICS_META_H_

#include <gst/gst.h>

#ifdef __cplusplus
extern "C"
{
#endif

#define NVDS_USER_FRAME_META_NVDSANALYTICS (nvds_get_user_meta_type((gchar*)"NVIDIA.DSANALYTICSFRAME.USER_META"))
#define NVDS_USER_OBJ_META_NVDSANALYTICS (nvds_get_user_meta_type((gchar*)"NVIDIA.DSANALYTICSOBJ.USER_META"))

/**
 */
typedef struct
{
  std::vector <std::string> roiStatus;
  std::vector <std::string> ocStatus;
  std::vector <std::string> lcStatus;
  std::string dirStatus;
  guint unique_id;
} NvDsAnalyticsObjInfo;

/**
 */
typedef struct
{
  std::unordered_map<std::string, bool> ocStatus;
  std::unordered_map<std::string, uint32_t> objInROIcnt;
  std::unordered_map<std::string, uint64_t> objLCCurrCnt;
  std::unordered_map<std::string, uint64_t> objLCCumCnt;
  guint unique_id;

} NvDsAnalyticsFrameMeta;

#ifdef __cplusplus
}
#endif

#endif 

Seems it cannot import the NvDsAnalytics* cpp object, how to modify it?

is it possible to share a change based on one sample and the compile command to reproduce this compile failure?

Thanks!

hi @mchi , here’s main c file and make file:

just run make and you’ll see the error info.

note: please place these two files in a folder and move it to the same root dir as deepstream-test4, eg: /opt/nvidia/deepstream/deepstream-5.0/sources/apps/sample_apps/deepstream-test4-nvdsanalytics

I’m trying to do a similar thing and use nvdsanalytics with a messaging but running into the same problems. Is there a reason you switched back to building a C version instead of CPP @CoderJustin

I’d like to know also if nvdsanalytics only works in a CPP build.

I’ve tried before, but it says something like: nvdsanalytics xxx object didn’t have some attributes for memory copy, I can change to cpp build again and post the result later.

@mchi @Amycao Hello, any update here? I’m stucked in it, looking for your guidence.

Hi
Can you paste CPP version?

@Amycao @dgyrobbie Hi, I figure it out, when I change to C plus plus version again, it can be built without error. I found out that the problem I mentioned in #8, is exactly the data type convert problem in #3, but you have to be careful about c plus plus syntax, such as “false”, “true”. Thanks everyone.

Hi,
I am having difficulties with the similar issue. I generated a people counting app and I would like to send the “Entry” and “Exit” results to Kafka. I used deepstream-test4 and nvdsanalytics-test apps as a base.

For this purpose, I created,

typedef struct{

guint32 lcc_cnt_exit;
guint32 lcc_cnt_entry;

} MyUserMeta;

Then, in nvdsanalytics_src_pad_buffer_probe function, I modified the code as below:

 MyUserMeta *user_data = (MyUserMeta *) g_malloc0(sizeof(MyUserMeta));

    for (NvDsMetaList * l_user = frame_meta->frame_user_meta_list;
                l_user != NULL; l_user = l_user->next) {
       NvDsUserMeta *user_meta = (NvDsUserMeta *) l_user->data;
          if (user_meta->base_meta.meta_type != NVDS_USER_FRAME_META_NVDSANALYTICS)
               continue;
           
            NvDsAnalyticsFrameMeta *meta = (NvDsAnalyticsFrameMeta *) user_meta->user_meta_data;

           user_data->lcc_cnt_entry = meta->objLCCumCnt["Entry"];
           user_data->lcc_cnt_exit = meta->objLCCumCnt["Exit"];

And, in generate_event_msg_meta function, I modified the code like this:

generate_event_msg_meta (gpointer data, gint class_id, NvDsObjectMeta * obj_params, MyUserMeta * obj_data)
{
NvDsEventMsgMeta *meta = (NvDsEventMsgMeta *) data;
meta->lccum_cnt_entry = obj_data->lcc_cnt_entry;
meta->lccum_cnt_exit = obj_data->lcc_cnt_exit ; 

Also I added these lines to nvdsmeta_schema:

typedef struct NvDsEventMsgMeta {
guint lccum_cnt_entry;
guint lccum_cnt_exit;
}

I modified nvmsgconv.cpp:

struct NvDsAnalyticsObject {
  string id;
  string desc;
  string source;
  string version;
  guint occupancy;
  guint lccum_cnt_entry;
  guint lccum_cnt_exit;
  
};

generate_analytics_module_object(){
json_object_set_double_member (analyticsObj, "Entry", meta->lccum_cnt_entry);
json_object_set_double_member (analyticsObj, "Exit", meta->lccum_cnt_exit);
}

So I am expecting to see “Entry” and “Exit” parts in the analyticsModule when I read the topic via Kafka. However, I didn’t manage. Do you have any idea to solve this?

Thank you.

Hi ovguozdemir,

Please help to open new topic for your issue. Thanks