35.How to add custom metadata in a GStreamer native plugin and access it in Python.
Here is an example based on deepstream-test1.py and dsexample.
35.1. Add custom metadata in the dsexample plugin.
diff --git a/sources/gst-plugins/gst-dsexample/gstdsexample.cpp b/sources/gst-plugins/gst-dsexample/gstdsexample.cpp
index d5399c7..764ec0a 100644
--- a/sources/gst-plugins/gst-dsexample/gstdsexample.cpp
+++ b/sources/gst-plugins/gst-dsexample/gstdsexample.cpp
@@ -318,6 +318,76 @@ gst_dsexample_get_property (GObject * object, guint prop_id,
}
}
+#define NVDS_GST_META_DSEXAMPLE (nvds_get_user_meta_type((char *)"NVIDIA.NVDS_GST_META_DSEXAMPLE"))
+
+typedef struct _DsExampleMeta
+{
+ gchar *timestamp;
+} DsExampleMeta;
+
+/* gst meta copy function set by user */
+static gpointer dsexample_meta_copy_func(gpointer data, gpointer user_data)
+{
+ NvDsUserMeta *user_meta = (NvDsUserMeta *) data;
+ DsExampleMeta *src_meta = (DsExampleMeta *)user_meta->user_meta_data;
+ DsExampleMeta *dst_meta = (DsExampleMeta*)g_malloc0(sizeof(DsExampleMeta));
+ if (src_meta->timestamp == NULL)
+ {
+ g_print("no buffer abort !!!! \n");
+ abort();
+ }
+ dst_meta->timestamp = g_strdup(src_meta->timestamp);
+ memcpy(dst_meta, src_meta, sizeof(DsExampleMeta));
+ return (gpointer)dst_meta;
+}
+
+/* gst meta release function set by user */
+static void dsexample_meta_release_func(gpointer data, gpointer user_data)
+{
+ NvDsUserMeta *user_meta = (NvDsUserMeta *) data;
+ DsExampleMeta *meta = (DsExampleMeta *)user_meta->user_meta_data;
+ if (meta) {
+ if (meta->timestamp) {
+ g_free(meta->timestamp);
+ meta->timestamp = NULL;
+ }
+ g_free(meta);
+ meta = NULL;
+ }
+ user_meta->user_meta_data = NULL;
+}
+
+void attach_frame_custom_metadata (NvDsBatchMeta *batch_meta, NvDsFrameMeta *frame_meta)
+{
+ DsExampleMeta *meta = (DsExampleMeta *)g_malloc0(sizeof(DsExampleMeta));
+ if (meta == NULL)
+ {
+ g_print("no buffer abort !!!! \n");
+ abort();
+ }
+ struct timeval time;
+ gettimeofday(&time, NULL);
+ double cur = (time.tv_sec) * 1000.0;
+ cur += (time.tv_usec) / 1000.0;
+ /* Add dummy metadata */
+ meta->timestamp = (gchar *)g_malloc0(128);
+ snprintf(meta->timestamp, 128, "cur %.3f ms", cur);
+
+ NvDsUserMeta *user_meta =
+ nvds_acquire_user_meta_from_pool (batch_meta);
+ if (user_meta) {
+ user_meta->user_meta_data = (void *) meta;
+ user_meta->base_meta.meta_type = NVDS_GST_META_DSEXAMPLE;
+ user_meta->base_meta.copy_func =
+ (NvDsMetaCopyFunc) dsexample_meta_copy_func;
+ user_meta->base_meta.release_func =
+ (NvDsMetaReleaseFunc) dsexample_meta_release_func;
+ nvds_add_user_meta_to_frame (frame_meta, user_meta);
+ }
+
+ g_print("Attached DsExampleMeta from native ==> %s\n", meta->timestamp);
+}
+
/**
* Initialize all resources and start the output thread
*/
@@ -759,6 +829,7 @@ gst_dsexample_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf)
#endif
/* Attach the metadata for the full frame */
attach_metadata_full_frame (dsexample, frame_meta, scale_ratio, output, i);
+ attach_frame_custom_metadata(batch_meta, frame_meta);
i++;
free (output);
}
35.2. Modify the corresponding Python bindings.
diff --git a/bindings/src/bindnvdsmeta.cpp b/bindings/src/bindnvdsmeta.cpp
index 95b0585..2aec39f 100644
--- a/bindings/src/bindnvdsmeta.cpp
+++ b/bindings/src/bindnvdsmeta.cpp
@@ -22,6 +22,13 @@
namespace py = pybind11;
+#define NVDS_GST_META_DSEXAMPLE (nvds_get_user_meta_type((char *)"NVIDIA.NVDS_GST_META_DSEXAMPLE"))
+
+typedef struct _DsExampleMeta
+{
+ gchar *timestamp;
+} DsExampleMeta;
+
namespace pydeepstream {
void bindnvdsmeta(py::module &m) {
@@ -77,8 +84,25 @@ namespace pydeepstream {
pydsdoc::nvmeta::MetaTypeDoc::NVDS_START_USER_META)
.value("NVDS_FORCE32_META", NVDS_FORCE32_META,
pydsdoc::nvmeta::MetaTypeDoc::NVDS_FORCE32_META)
+ .value("NVDS_GST_META_DSEXAMPLE", NVDS_GST_META_DSEXAMPLE)
.export_values();
+ py::class_<DsExampleMeta>(m, "DsExampleMeta")
+ .def(py::init<>())
+ .def_property("timestamp",
+ STRING_PROPERTY(DsExampleMeta,
+ timestamp))
+ .def("cast",
+ [](void *data) {
+ return (DsExampleMeta *) data;
+ },
+ py::return_value_policy::reference)
+
+ .def("cast",
+ [](size_t data) {
+ return (DsExampleMeta *) data;
+ },
+ py::return_value_policy::reference);
py::class_<NvDsComp_BboxInfo>(m, "NvDsComp_BboxInfo",
pydsdoc::nvmeta::NvDsComp_BboxInfoDoc::descr)
35.3.Access the custom metadata in Python code.
diff --git a/apps/deepstream-test1/deepstream_test_1.py b/apps/deepstream-test1/deepstream_test_1.py
index 861cefc..a3e2809 100755
--- a/apps/deepstream-test1/deepstream_test_1.py
+++ b/apps/deepstream-test1/deepstream_test_1.py
@@ -47,6 +47,7 @@ def osd_sink_pad_buffer_probe(pad,info,u_data):
# Note that pyds.gst_buffer_get_nvds_batch_meta() expects the
# C address of gst_buffer as input, which is obtained with hash(gst_buffer)
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:
@@ -82,6 +83,19 @@ def osd_sink_pad_buffer_probe(pad,info,u_data):
except StopIteration:
break
+ l_user=frame_meta.frame_user_meta_list
+ while l_user is not None:
+ try:
+ user_meta = pyds.NvDsUserMeta.cast(l_user.data)
+ if (user_meta and user_meta.base_meta.meta_type == pyds.NvDsMetaType.NVDS_GST_META_DSEXAMPLE):
+ dsexample_meta = pyds.DsExampleMeta.cast(user_meta.user_meta_data)
+ print(f"access dsmeta from python {pyds.get_string(dsexample_meta.timestamp)}")
+ except StopIteration:
+ break
+ try:
+ l_user=l_user.next
+ except StopIteration:
+ break
# Acquiring a display meta object. The memory ownership remains in
# the C code so downstream plugins can still access it. Otherwise
# the garbage collector will claim it when this probe function exits.
@@ -167,6 +181,10 @@ def main(args):
if not pgie:
sys.stderr.write(" Unable to create pgie \n")
+ dsexample = Gst.ElementFactory.make("dsexample", "dsexample")
+ if not dsexample:
+ sys.stderr.write(" Unable to create dsexample \n")
+
# Use convertor to convert from NV12 to RGBA as required by nvosd
nvvidconv = Gst.ElementFactory.make("nvvideoconvert", "convertor")
if not nvvidconv:
@@ -186,7 +204,8 @@ def main(args):
sys.stderr.write(" Unable to create nv3dsink \n")
else:
print("Creating EGLSink \n")
- sink = Gst.ElementFactory.make("nveglglessink", "nvvideo-renderer")
+ # sink = Gst.ElementFactory.make("nveglglessink", "nvvideo-renderer")
+ sink = Gst.ElementFactory.make("fakesink", "nvvideo-renderer")
if not sink:
sys.stderr.write(" Unable to create egl sink \n")
@@ -206,6 +225,7 @@ def main(args):
pipeline.add(decoder)
pipeline.add(streammux)
pipeline.add(pgie)
+ pipeline.add(dsexample)
pipeline.add(nvvidconv)
pipeline.add(nvosd)
pipeline.add(sink)
@@ -225,7 +245,8 @@ def main(args):
sys.stderr.write(" Unable to get source pad of decoder \n")
srcpad.link(sinkpad)
streammux.link(pgie)
- pgie.link(nvvidconv)
+ pgie.link(dsexample)
+ dsexample.link(nvvidconv)
nvvidconv.link(nvosd)
nvosd.link(sink)
35.4.Recompile and install dsexample and pyds, and then run deepstream_test1.py. You will see the following log in the output
Attached DsExampleMeta from native ==> cur 1712056757649.727 ms
access dsmeta from python cur 1712056757649.727 ms
Frame Number=303 Number of Objects=31 Vehicle_count=26 Person_count=5
Attached DsExampleMeta from native ==> cur 1712056757651.504 ms
access dsmeta from python cur 1712056757651.504 ms
Frame Number=304 Number of Objects=27 Vehicle_count=22 Person_count=5
Attached DsExampleMeta from native ==> cur 1712056757653.223 ms
access dsmeta from python cur 1712056757653.223 ms
Frame Number=305 Number of Objects=29 Vehicle_count=23 Person_count=6
Attached DsExampleMeta from native ==> cur 1712056757654.953 ms
access dsmeta from python cur 1712056757654.953 ms
Frame Number=306 Number of Objects=29 Vehicle_count=24 Person_count=5
Attached DsExampleMeta from native ==> cur 1712056757656.722 ms
access dsmeta from python cur 1712056757656.722 ms
Frame Number=307 Number of Objects=29 Vehicle_count=25 Person_count=4
Attached DsExampleMeta from native ==> cur 1712056757658.446 ms
access dsmeta from python cur 1712056757658.446 ms