Attaching NvDsUserMeta to frame meta in python gst plugin

Hello. I’m having some trouble adding custom info to DeepStream meta data in a python Gstreamer plugin.

I wrote minimal gst plugin based on GstBase.BaseTransform basically only implementing 2 functions

 def do_transform_ip(self, buffer: Gst.Buffer):

    batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(buffer))

    if not batch_meta:
        return Gst.FlowReturn.OK

    pyds.nvds_acquire_meta_lock(batch_meta) 

    l_frame = batch_meta.frame_meta_list
    while l_frame is not None:
        try:
            frame_meta = pyds.glist_get_nvds_frame_meta(l_frame.data)
        except StopIteration:
            break

        user_meta = pyds.nvds_acquire_user_meta_from_pool(batch_meta)
        if user_meta:
            message = 'test'
            fill_user_meta(user_meta, message)
            pyds.nvds_add_user_meta_to_frame(frame_meta, user_meta)
        else:
            Gst.info('failed to acquire user meta')

        try:
            l_frame = l_frame.next
        except StopIteration:
            break

    pyds.nvds_release_meta_lock(batch_meta)

    return Gst.FlowReturn.OK

def do_stop(self) -> bool: 
    pyds.unset_callback_funcs()
    return True

The idea is to pass some string message in a NvDsUserMeta using NvDsEventMsgMeta structure. This is how I alloc and fill the structure

def fill_user_meta(meta: pyds.NvDsUserMeta, msg: str):
    data = pyds.alloc_nvds_event_msg_meta()
    data.otherAttrs = msg

    meta.user_meta_data = data
    meta.base_meta.meta_type = pyds.NvDsMetaType.NVDS_EVENT_MSG_META

    pyds.set_user_copyfunc(meta, meta_copy_func)
    pyds.set_user_releasefunc(meta, meta_free_func)

def meta_copy_func(data, user_data) -> pyds.NvDsEventMsgMeta:
    user_meta = pyds.glist_get_nvds_user_meta(data)
    src_meta = pyds.glist_get_nvds_event_msg_meta(user_meta.user_meta_data)
    dst_meta_ptr = pyds.memdup(pyds.get_ptr(src_meta), sys.getsizeof(pyds.NvDsEventMsgMeta))
    dst_meta = pyds.glist_get_nvds_event_msg_meta(dst_meta_ptr)
    dst_meta.otherAttrs = pyds.get_string(dst_meta.otherAttrs)
    return dst_meta

def meta_free_func(data, user_data):
    user_meta = pyds.glist_get_nvds_user_meta(data)
    src_meta = pyds.glist_get_nvds_event_msg_meta(user_meta.user_meta_data)
    pyds.free_buffer(src_meta.otherAttrs)

However, my test pipeline doesn’t finish cleanly. When I run the following command in a Docker container based on nvcr.io/nvida/deepstream:4.0.2-19.12-devel with Python DS bindings

GST_DEBUG=python:4 \
gst-launch-1.0 uridecodebin uri=file:///<path to 1080p sample.mp4> \
! m.sink_0 nvstreammux name=m batch-size=1 width=1920 height=1080 \
! nvinfer config-file-path=<path to config_infer_primary.txt> \
! my_plugin \
! fakesink sync=false

At the end of processing I get

Got EOS from element "pipeline0".
Execution ended after 0:00:02.036809166
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
terminate called after throwing an instance of 'pybind11::error_already_set'
  what():  SystemError: <built-in method glist_get_nvds_user_meta of PyCapsule object at 0x7f90ceedcae0> returned a result with an error set

At:
  /opt/app/perception/event_msg_meta_helper.py(44): meta_free_func

What am I doing wrong? Any advice will be much appreciated.

It turned out that this issue is not related to Deepstream. Python gst plugin doesn’t like underscore in property names.