Getting user_meta through pyds

I need to pass two values calculated in a custom-plugin I’ve made and fetch them with a sink pad buffer probe.

Currently I’m modifying the gst-dsdirection plugin and saving a user_meta to frame_meta. The output is the same DsDirectionOutput as in the gst-dsdirection example.

static void
attach_metadata_frame (GstDsDirection * dsdirection, NvDsFrameMeta * frame_meta,
    DsDirectionOutput * output)
{

  NvDsBatchMeta *batch_meta = frame_meta->base_meta.batch_meta;

  // Attach - DsDirection MetaData
  NvDsUserMeta *user_meta = nvds_acquire_user_meta_from_pool (batch_meta);
  NvDsMetaType user_meta_type = NVDS_DIRECTION_USER_META;

  user_meta->user_meta_data = output;
  user_meta->base_meta.meta_type = user_meta_type;
  user_meta->base_meta.copy_func = copy_ds_direction_meta;
  user_meta->base_meta.release_func = release_ds_direction_meta;

  nvds_add_user_meta_to_frame (frame_meta, user_meta);

}

In the python application I’m fetching it like this:

batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(gst_buffer))
l_frame = batch_meta.frame_meta_list
while l_frame is not None:
    try:
        # Note that l_frame.data needs a cast to pyds.NvDsFrameMeta
        # The casting is done by pyds.glist_get_nvds_frame_meta()
        # The casting also keeps ownership of the underlying memory
        # in the C code, so the Python garbage collector will leave
        # it alone.
        #frame_meta = pyds.glist_get_nvds_frame_meta(l_frame.data)
        frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data)
    except StopIteration:
        break

    l_user = frame_meta.frame_user_meta_list
    print(l_user)
    user_meta = pyds.NvDsUserMeta.cast(l_user.data)

    print('user_meta:', user_meta)
    print('user_meta.user_meta_data:', user_meta.user_meta_data)
    print('user_meta.base_meta:', user_meta.base_meta)

The output from this is:

...
<pyds.GList object at 0x7f2d8fc10030>
user_meta: <pyds.NvDsUserMeta object at 0x7f2d8fc10ab0>
user_meta.user_meta_data: <capsule object NULL at 0x7f2d8fc6a300>
user_meta.base_meta: <pyds.NvDsBaseMeta object at 0x7f2d8fc100a0>
...

Any idea how to properly add it to the frame_meta and/or fetch the values with the python bindings? Should I maybe save this as a different object structure?

Thanks

Hey, so you are trying to add user meta data to the frame_meta using python app, right?

I’m saving this

typedef struct
{
  float flowx;
  float flowy;
  char direction[MAX_LABEL_SIZE];
} DsDirectionObject;

structure to the frame_meta via

nvds_add_user_meta_to_frame (frame_meta, user_meta);

But the main thing is that I’m having trouble fetching the values with a python app (probe).

I’m wondering what is the best way to do this?
I just need to save two floats in my custom plug-in to each frame, and then be able to fetch it in my python app.

Got it, you need to add your own python bindings to access your own c data structure. You can refer https://github.com/mrtj/pyds_tracker_meta for how to add your own binding

Great, thanks!

Still having trouble with this.
I’m saving this structure

typedef struct
{
  float flowx;
  float flowy;
} DsDirectionObject2;

with this function

static void
attach_metadata_frame (GstDsDirection * dsdirection, NvDsFrameMeta * frame_meta,
    DsDirectionObject2 * output, NvDsBatchMeta * batch_meta)
{

  // Attach - DsDirection MetaData
  NvDsUserMeta *user_meta = nvds_acquire_user_meta_from_pool (batch_meta);
  NvDsMetaType user_meta_type = NVDS_DIRECTION_USER_META;

  //output_object  = output->object;

  std::cout << "meanx :  " << output->flowx << std::endl;
  std::cout << "meany :  " << output->flowy << std::endl;
  std::cout << "user_meta_type :  " << user_meta_type << std::endl;

  user_meta->user_meta_data = output;
  user_meta->base_meta.meta_type = user_meta_type;
  user_meta->base_meta.copy_func = copy_ds_direction_meta;
  user_meta->base_meta.release_func = release_ds_direction_meta;

  nvds_add_user_meta_to_frame (frame_meta, user_meta);

}

which prints, e.g.:

meanx :  30.3153
meany :  -8.39673
user_meta_type :  10773

However I’m not able to cast it successfully to python with this (added in pyds_tracker_meta.cpp)

m.def("DsDirectionObject2_cast",
    [](void *obj) { return (DsDirectionObject2*)(obj); },
    "Cast given object/data to DsDirectionObject2",
    py::arg("obj"),
    py::return_value_policy::reference);

I always get the same error when I try to print the type and cast it to python

    while user_meta_list is not None:
        user_meta = pyds.NvDsUserMeta.cast(user_meta_list.data)
    
        try:
            print('user_meta: ', user_meta.base_meta.meta_type)
            if str(user_meta.base_meta.meta_type) != 'NvDsMetaType.NVDS_OPTICAL_FLOW_META':
                dsdir = pyds_tracker_meta.DsDirectionObject2_cast(user_meta.user_meta_data)
                print('dsdir: ', dsdir)
        except Exception as e:
            print(e)

        user_meta_list = user_meta_list.next

Then the output is:

user_meta:  NvDsMetaType.NVDS_OPTICAL_FLOW_META
user_meta:  NvDsMetaType.???
Unable to convert function return value to a Python type! The signature was
	(obj: capsule) -> DsDirectionObject2

I hope you can me with this
All the best,

There is no update from you for a period, assuming this is not an issue any more.
Hence we are closing this topic. If need further support, please open a new one.
Thanks

Oh, seems you also need to add binding function for your user meta type, it’s NVDS_DIRECTION_USER_META you defined, right?