50.[DSx_dGPU_App] How to insert SEI in bitstream using nvdsmetainsert in pyds?
1.Add nvdsmetainsert element upstream of nvv4l2h264enc/nvv4l2h265enc and set the serialize-lib property value
nvdsmetainsert.set_property('serialize-lib', '/opt/nvidia/deepstream/deepstream/lib/libnvds_sei_serialization.so')
2.Add python bindings for NVDS_CUSTOM_PAYLOAD in pyds native code and recompile and reinstall pyds-*.whl
+typedef struct _NVDS_CUSTOM_PAYLOAD
+{
+ uint32_t payloadType;
+ uint32_t payloadSize;
+ uint8_t *payload;
+} NVDS_CUSTOM_PAYLOAD;
3.Add user meta of type NVDS_DUMMY_BBOX_META(libnvds_sei_serialization.so is open source, modify it according to your needs)
+ data.payload = pyds.alloc_buffer(len(sei_payload))
+
+ ctypes.memmove(data.payload, sei_payload, len(sei_payload))
+
+ data.payloadSize = len(sei_payload)
user_meta.user_meta_data = data
- user_meta.base_meta.meta_type = pyds.NvDsMetaType.NVDS_USER_META
+ user_meta.base_meta.meta_type = pyds.NvDsMetaType.NVDS_DUMMY_BBOX_META
The complete solution below
diff --git a/apps/deepstream-custom-binding-test/deepstream_custom_binding_test.py b/apps/deepstream-custom-binding-test/deepstream_custom_binding_test.py
index 5e41846c..c4d8b28a 100644
--- a/apps/deepstream-custom-binding-test/deepstream_custom_binding_test.py
+++ b/apps/deepstream-custom-binding-test/deepstream_custom_binding_test.py
@@ -20,6 +20,8 @@
import sys
import os
import gi
+import uuid
+import ctypes
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GLib
@@ -40,6 +42,9 @@ def bus_call(bus, message, loop):
loop.quit()
return True
+KLV_PAYLOAD_TYPE = 0x01 # Example payload type for KLV data
def streammux_src_pad_buffer_probe(pad, info, u_data):
gst_buffer = info.get_buffer()
if not gst_buffer:
@@ -64,15 +69,21 @@ def streammux_src_pad_buffer_probe(pad, info, u_data):
if user_meta:
print('adding user meta')
- test_string = 'test message ' + str(frame_number)
+ uuid_bytes = uuid.UUID("550e8400-e29b-41d4-a716-446655440000").bytes
+ klv_data_buffer = " this is a test KLV data buffer for frame " + str(frame_number)
+ sei_payload = uuid_bytes + klv_data_buffer.encode('utf-8')
+
+ print(f"type of sei_payload: {type(sei_payload)} len: {len(sei_payload)}")
data = pyds.alloc_custom_struct(user_meta)
- data.message = test_string
- data.message = pyds.get_string(data.message)
- data.structId = frame_number
- data.sampleInt = frame_number + 1
+ data.payload = pyds.alloc_buffer(len(sei_payload))
+
+ ctypes.memmove(data.payload, sei_payload, len(sei_payload))
+
+ data.payloadSize = len(sei_payload)
+ data.payloadType = KLV_PAYLOAD_TYPE
user_meta.user_meta_data = data
- user_meta.base_meta.meta_type = pyds.NvDsMetaType.NVDS_USER_META
+ user_meta.base_meta.meta_type = pyds.NvDsMetaType.NVDS_DUMMY_BBOX_META
pyds.nvds_add_user_meta_to_frame(frame_meta, user_meta)
else:
@@ -87,52 +98,6 @@ def streammux_src_pad_buffer_probe(pad, info, u_data):
return Gst.PadProbeReturn.OK
-def fakesink_sink_pad_buffer_probe(pad, info, u_data):
- gst_buffer = info.get_buffer()
- if not gst_buffer:
- print("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.NvDsFrameMeta.cast(l_frame.data)
- except StopIteration:
- continue
-
- l_usr = frame_meta.frame_user_meta_list
- while l_usr is not None:
- try:
- user_meta = pyds.NvDsUserMeta.cast(l_usr.data)
- except StopIteration:
- continue
-
- if user_meta.base_meta.meta_type == pyds.NvDsMetaType.NVDS_USER_META:
- custom_msg_meta = pyds.CustomDataStruct.cast(user_meta.user_meta_data)
- print(f'event msg meta, otherAttrs = {pyds.get_string(custom_msg_meta.message)}')
- print('custom meta structId:: ', custom_msg_meta.structId)
- print('custom meta msg:: ', pyds.get_string(custom_msg_meta.message))
- print('custom meta sampleInt:: ', custom_msg_meta.sampleInt)
- 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(args):
# Check input arguments
if len(args) != 2:
@@ -164,12 +129,22 @@ def main(args):
queue = Gst.ElementFactory.make("queue", "queue")
if not queue:
sys.stderr.write(" Unable to create queue")
+
+ nvdsmetainsert = Gst.ElementFactory.make("nvdsmetainsert", "nvds-meta-insert")
+ if not nvdsmetainsert:
+ sys.stderr.write(" Unable to create NvDsMetaInsert")
+
queue1 = Gst.ElementFactory.make("queue", "queue1")
if not queue1:
sys.stderr.write(" Unable to create queue")
- sink = Gst.ElementFactory.make("fakesink", "fakesink")
+
+ nvv4l2h264enc = Gst.ElementFactory.make("nvv4l2h264enc", "nvv4l2-h264-encoder")
+ if not nvv4l2h264enc:
+ sys.stderr.write(" Unable to create Nvv4l2 H264 Encoder")
+
+ sink = Gst.ElementFactory.make("filesink", "filesink")
if not sink:
- sys.stderr.write(" Unable to create fake sink \n")
+ sys.stderr.write(" Unable to create filesink \n")
print("reading input")
print("Playing file %s " %args[1])
source.set_property('location', args[1])
@@ -184,9 +159,16 @@ def main(args):
pipeline.add(decoder)
pipeline.add(streammux)
pipeline.add(queue)
+ pipeline.add(nvdsmetainsert)
pipeline.add(queue1)
+ pipeline.add(nvv4l2h264enc)
pipeline.add(sink)
+ print("Setting properties of elements")
+ nvdsmetainsert.set_property('serialize-lib', '/opt/nvidia/deepstream/deepstream/lib/libnvds_sei_serialization.so')
+ nvv4l2h264enc.set_property('bitrate', 4000000)
+ sink.set_property('location', 'output.h264')
+
print("Linking elements in the Pipeline")
source.link(h264parser)
h264parser.link(decoder)
@@ -201,8 +183,10 @@ def main(args):
srcpad.link(sinkpad)
streammux.link(queue)
- queue.link(queue1)
- queue1.link(sink)
+ queue.link(nvdsmetainsert)
+ nvdsmetainsert.link(queue1)
+ queue1.link(nvv4l2h264enc)
+ nvv4l2h264enc.link(sink)
loop = GLib.MainLoop()
bus = pipeline.get_bus()
@@ -214,10 +198,6 @@ def main(args):
sys.stderr.write(" Unable to get src pad of streammux")
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:
- sys.stderr.write(" Unable to get sink pad of fakesink")
- 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')
print("Starting pipeline")
diff --git a/bindings/src/bindnvdsmeta.cpp b/bindings/src/bindnvdsmeta.cpp
index a644665a..9621f940 100644
--- a/bindings/src/bindnvdsmeta.cpp
+++ b/bindings/src/bindnvdsmeta.cpp
@@ -85,6 +85,7 @@ namespace pydeepstream {
pydsdoc::nvmeta::MetaTypeDoc::NVDS_FORCE32_META)
.value("NVDS_PREPROCESS_BATCH_META", NVDS_PREPROCESS_BATCH_META,
pydsdoc::nvmeta::MetaTypeDoc::NVDS_PREPROCESS_BATCH_META)
+ .value("NVDS_DUMMY_BBOX_META", nvds_get_user_meta_type("NVIDIA.DUMMY.BBOX.META"))
.export_values();
diff --git a/bindings/src/custom_binding/bindcustom.cpp b/bindings/src/custom_binding/bindcustom.cpp
index 5e0a253b..d0665611 100644
--- a/bindings/src/custom_binding/bindcustom.cpp
+++ b/bindings/src/custom_binding/bindcustom.cpp
@@ -24,18 +24,16 @@ namespace py = pybind11;
namespace pydeepstream {
- CustomDataStruct * copy_custom_struct(void* data, void* user_data) {
+ NVDS_CUSTOM_PAYLOAD * copy_custom_struct(void* data, void* user_data) {
NvDsUserMeta * srcMeta = (NvDsUserMeta*) data;
- CustomDataStruct * srcData = (CustomDataStruct *) srcMeta->user_meta_data;
- CustomDataStruct *destData = (CustomDataStruct *) g_malloc0(
- sizeof(CustomDataStruct));
- destData->structId = srcData->structId;
- destData->sampleInt = srcData->sampleInt;
- if (srcData->message != nullptr) {
- char* srcString = (char *) srcData->message;
- int strSize = strlen(srcString);
- destData->message = (char*)calloc(strSize + 1, sizeof(char));
- strcpy(destData->message, srcData->message);
+ NVDS_CUSTOM_PAYLOAD * srcData = (NVDS_CUSTOM_PAYLOAD *) srcMeta->user_meta_data;
+ NVDS_CUSTOM_PAYLOAD *destData = (NVDS_CUSTOM_PAYLOAD *) g_malloc0(
+ sizeof(NVDS_CUSTOM_PAYLOAD));
+ destData->payloadType = srcData->payloadType;
+ destData->payloadSize = srcData->payloadSize;
+ if (srcData->payload != nullptr) {
+ destData->payload = (uint8_t*)calloc(srcData->payloadSize, sizeof(uint8_t));
+ memcpy(destData->payload, srcData->payload, srcData->payloadSize);
}
return destData;
}
@@ -43,14 +41,10 @@ namespace pydeepstream {
void release_custom_struct(void * data, void * user_data) {
NvDsUserMeta * srcMeta = (NvDsUserMeta*) data;
if (srcMeta != nullptr) {
- CustomDataStruct * srcData = (CustomDataStruct *) srcMeta->user_meta_data;
+ NVDS_CUSTOM_PAYLOAD * srcData = (NVDS_CUSTOM_PAYLOAD *) srcMeta->user_meta_data;
if (srcData != nullptr) {
- auto * message = srcData->message;
- srcData->structId = 0;
- srcData->sampleInt = 0;
- if (srcData->message != nullptr)
- {
- free(srcData->message);
+ if (srcData->payload != nullptr) {
+ free(srcData->payload);
}
g_free(srcData);
}
@@ -59,30 +53,33 @@ namespace pydeepstream {
void bindcustom(py::module &m) {
/* CustomDataStruct bindings to be used with NvDsUserMeta */
- py::class_<CustomDataStruct>(m, "CustomDataStruct",
- pydsdoc::custom::CustomDataStructDoc::descr)
+ py::class_<NVDS_CUSTOM_PAYLOAD>(m, "NVDS_CUSTOM_PAYLOAD")
.def(py::init<>())
- .def_readwrite("structId", &CustomDataStruct::structId)
- .def_property("message", STRING_FREE_EXISTING(CustomDataStruct, message))
- .def_readwrite("sampleInt", &CustomDataStruct::sampleInt)
+ .def_readwrite("payloadType", &NVDS_CUSTOM_PAYLOAD::payloadType)
+ .def_readwrite("payloadSize", &NVDS_CUSTOM_PAYLOAD::payloadSize)
+ .def_property("payload",
+ [](const NVDS_CUSTOM_PAYLOAD &self) -> size_t {
+ return (size_t)self.payload;
+ },
+ [](NVDS_CUSTOM_PAYLOAD& self, size_t ptr) {
+ self.payload = (uint8_t *) ptr;
+ }, py::return_value_policy::reference)
.def("cast",
[](void *data) {
- return (CustomDataStruct *) data;
+ return (NVDS_CUSTOM_PAYLOAD *) data;
},
- py::return_value_policy::reference,
- pydsdoc::custom::CustomDataStructDoc::cast);
+ py::return_value_policy::reference);
m.def("alloc_custom_struct",
[](NvDsUserMeta *meta) {
- auto *mem = (CustomDataStruct *) g_malloc0(
- sizeof(CustomDataStruct));
+ auto *mem = (NVDS_CUSTOM_PAYLOAD *) g_malloc0(
+ sizeof(NVDS_CUSTOM_PAYLOAD));
meta->base_meta.copy_func = (NvDsMetaCopyFunc) pydeepstream::copy_custom_struct;
meta->base_meta.release_func = (NvDsMetaReleaseFunc) pydeepstream::release_custom_struct;
return mem;
},
- py::return_value_policy::reference,
- pydsdoc::methodsDoc::alloc_custom_struct);
+ py::return_value_policy::reference);
}
diff --git a/bindings/src/custom_binding/include/custom_data.hpp b/bindings/src/custom_binding/include/custom_data.hpp
index a9abe44e..aeb271fb 100644
--- a/bindings/src/custom_binding/include/custom_data.hpp
+++ b/bindings/src/custom_binding/include/custom_data.hpp
@@ -18,8 +18,9 @@
using namespace std;
-struct CustomDataStruct {
- int structId;
- char* message;
- int sampleInt;
-};
\ No newline at end of file
+typedef struct _NVDS_CUSTOM_PAYLOAD
+{
+ uint32_t payloadType;
+ uint32_t payloadSize;
+ uint8_t *payload;
+} NVDS_CUSTOM_PAYLOAD;
\ No newline at end of file
Refer to this topic