Segmentation fault when using NvDsUserMeta+NvDsEventMsgMeta in Python app

Hello, I’m trying to use NvDsUserMeta to pass some data to downstream elements. Following example app 4 from deepstream_python_apps I allocate NvDsEventMsgMeta in a pad probe on nvstreammux sink pad and put a string in one of its gchar* fields, otherAttrs to be specific. In another pad downstream (fakesink’s src pad) I read this data. This works fine with pipeline filesrc -> h264parse -> nvv4l2decoder -> nvstreammux -> fakesink. Environment is nvidia’s deepstream:4.0.2-19.12-devel container.

However, as I add elements to this pipeline I start getting segfaults. For example, here’s my code with queue added (filesrc -> h264parse -> nvv4l2decoder -> nvstreammux -> queue -> fakesink):

import sys
import os
import gi

gi.require_version('Gst', '1.0')
gi.require_version('GstBase', '1.0')
from gi.repository import Gst, GObject, GstBase

syspath = os.getenv('PYDSBIDS_PATH', '.')
sys.path.append(os.path.join(syspath, 'x86_64'))
import pyds


def bus_call(bus, message, loop):
    t = message.type
    if t == Gst.MessageType.EOS:
        Gst.info("End-of-stream")
        loop.quit()
    elif t == Gst.MessageType.WARNING:
        err, debug = message.parse_warning()
        Gst.warning("Warning: %s: %s" % (err, debug))
    elif t == Gst.MessageType.ERROR:
        err, debug = message.parse_error()
        Gst.error("Error: %s: %s" % (err, debug))
        loop.quit()
    return True


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_callback)
    pyds.set_user_releasefunc(meta, meta_free_callback)


def meta_copy_callback(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)

    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_callback(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)


def streammux_src_pad_buffer_probe(pad, info, u_data):
    gst_buffer = info.get_buffer()
    if not gst_buffer:
        Gst.warning("Unable to get GstBuffer ")
        return

    batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(gst_buffer))
    if not batch_meta:
        return Gst.PadProbeReturn.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:
            continue

        user_meta = pyds.nvds_acquire_user_meta_from_pool(batch_meta)

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

        try:
            l_frame = l_frame.next
        except StopIteration:
            break

    pyds.nvds_release_meta_lock(batch_meta)
    return Gst.PadProbeReturn.OK


def fakesink_sink_pad_buffer_probe(pad, info, u_data):
    gst_buffer = info.get_buffer()
    if not gst_buffer:
        Gst.warning("Unable to get GstBuffer ")
        return
    batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(gst_buffer))

    if not batch_meta:
        return Gst.PadProbeReturn.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:
            continue

        l_usr = frame_meta.frame_user_meta_list
        while l_usr is not None:
            try:
                user_meta = pyds.glist_get_nvds_user_meta(l_usr.data)
            except StopIteration:
                continue

            if user_meta.base_meta.meta_type == pyds.NVDS_EVENT_MSG_META:
                event_msg_meta = pyds.glist_get_nvds_event_msg_meta(user_meta.user_meta_data)
                Gst.info(f'event msg meta, otherAttrs = {pyds.get_string(event_msg_meta.otherAttrs)}')

            try:
                l_usr = l_usr.next
            except StopIteration:
                break

        try:
            l_frame = l_frame.next
        except StopIteration:
            break

    pyds.nvds_release_meta_lock(batch_meta)
    return Gst.PadProbeReturn.OK


def main():
    GObject.threads_init()
    Gst.init(None)

    pipeline = Gst.Pipeline()
    if not pipeline:
        Gst.error(" Unable to create Pipeline")

    source = Gst.ElementFactory.make("filesrc", "file-source")
    if not source:
        Gst.error(" Unable to create Source")

    h264parser = Gst.ElementFactory.make("h264parse", "h264-parser")
    if not h264parser:
        Gst.error(" Unable to create h264 parser")

    decoder = Gst.ElementFactory.make("nvv4l2decoder", "nvv4l2-decoder")
    if not decoder:
        Gst.error(" Unable to create Nvv4l2 Decoder")

    streammux = Gst.ElementFactory.make("nvstreammux", "Stream-muxer")
    if not streammux:
        Gst.error(" Unable to create NvStreamMux")

    queue = Gst.ElementFactory.make("queue", "queue")
    if not queue:
        Gst.error(" Unable to create queue")

    sink = Gst.ElementFactory.make("fakesink", "fakesink")
    if not sink:
        Gst.error(" Unable to create fakesink")

    input_loc = '/root/deepstream_sdk/samples/streams/sample_720p.h264'
    Gst.info("Playing file %s " % input_loc)
    source.set_property('location', input_loc)

    streammux.set_property('width', 1280)
    streammux.set_property('height', 720)
    streammux.set_property('batch-size', 1)

    Gst.info("Adding elements to Pipeline")
    pipeline.add(source)
    pipeline.add(h264parser)
    pipeline.add(decoder)
    pipeline.add(streammux)
    pipeline.add(queue)
    pipeline.add(sink)

    Gst.info("Linking elements in the Pipeline")
    source.link(h264parser)
    h264parser.link(decoder)

    sinkpad = streammux.get_request_pad("sink_0")
    if not sinkpad:
        Gst.error(" Unable to get the sink pad of streammux")

    srcpad = decoder.get_static_pad("src")
    if not srcpad:
        Gst.error(" Unable to get source pad of decoder(source)")
    srcpad.link(sinkpad)

    streammux.link(queue)
    queue.link(sink)

    loop = GObject.MainLoop()
    bus = pipeline.get_bus()
    bus.add_signal_watch()
    bus.connect("message", bus_call, loop)

    streammux_src_pad = streammux.get_static_pad('src')
    if not streammux_src_pad:
        Gst.error(" Unable to get sink pad of sink")
    streammux_src_pad.add_probe(Gst.PadProbeType.BUFFER, streammux_src_pad_buffer_probe, 0)

    fakesink_sink_pad = sink.get_static_pad('sink')
    if not fakesink_sink_pad:
        Gst.error(" Unable to get sink pad of sink")
    fakesink_sink_pad.add_probe(Gst.PadProbeType.BUFFER, fakesink_sink_pad_buffer_probe, 0)

    Gst.debug_bin_to_dot_file(pipeline, Gst.DebugGraphDetails.ALL, 'graph')
    Gst.info("Starting pipeline")

    pipeline.set_state(Gst.State.PLAYING)
    try:
        loop.run()
    except:
        pass
    # cleanup
    pyds.unset_callback_funcs()
    pipeline.set_state(Gst.State.NULL)


if __name__ == '__main__':
    main()

This app gives following output:

root@WS066:/data# GST_DEBUG=python:4 python test_app.py
0:00:00.035147220   508      0x26d4190 INFO                  python test_app.py:171:main: Playing file /root/deepstream_sdk/samples/streams/sample_720p.h264 
0:00:00.035220747   508      0x26d4190 INFO                  python test_app.py:178:main: Adding elements to Pipeline
0:00:00.035285339   508      0x26d4190 INFO                  python test_app.py:186:main: Linking elements in the Pipeline
0:00:00.036042708   508      0x26d4190 INFO                  python test_app.py:218:main: Starting pipeline
0:00:00.216177997   508      0x23cfcf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.217436469   508      0x23cf400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.217970188   508      0x23cfcf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.219190741   508      0x23cf400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.220552197   508      0x23cfcf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.221502660   508      0x23cf400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.222127604   508      0x23cfcf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.222816112   508      0x23cfcf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.223647844   508      0x23cf400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.224177818   508      0x23cfcf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
Segmentation fault (core dumped)

Or, randomly:

root@WS066:/data# GST_DEBUG=python:4 python test_app.py
0:00:00.032427120   518      0x262e190 INFO                  python test_app.py:171:main: Playing file /root/deepstream_sdk/samples/streams/sample_720p.h264 
0:00:00.032499476   518      0x262e190 INFO                  python test_app.py:178:main: Adding elements to Pipeline
0:00:00.032564069   518      0x262e190 INFO                  python test_app.py:186:main: Linking elements in the Pipeline
0:00:00.033343305   518      0x262e190 INFO                  python test_app.py:218:main: Starting pipeline
0:00:00.199216978   518      0x2329cf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.200024770   518      0x2329cf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.201412275   518      0x2329400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.202080490   518      0x2329cf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.203387152   518      0x2329400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.204006595   518      0x2329cf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.205162689   518      0x2329400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.205830197   518      0x2329cf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.206770506   518      0x2329400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.207630312   518      0x2329cf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.208503194   518      0x2329400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.209196667   518      0x2329cf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
0:00:00.210111048   518      0x2329400 INFO                  python test_app.py:122:fakesink_sink_pad_buffer_probe: event msg meta, otherAttrs = test message
0:00:00.210710040   518      0x2329cf0 INFO                  python test_app.py:79:streammux_src_pad_buffer_probe: adding user meta
terminate called after throwing an instance of 'pybind11::error_already_set'
  what():  TypeError: '' object is not callable
Aborted (core dumped)

As soon as I comment out adding NvDsEventMsgMeta to NvDsUserMeta:

...
# fill_user_meta(user_meta, 'test message')
...

app correctly reaches end of stream. I think there might be some problem with memory management of deepstream meta data. Perhaps my copy/release callback are incorrect, though as far as I can see they are similar to example.

Any advice?

Hi abramov_ov, we have duplicated the segfault and will investigate.

1 Like