Apply this patch,then rebuild and reinstall the pyds*.whl
.
diff --git a/bindings/src/bindfunctions.cpp b/bindings/src/bindfunctions.cpp
index eade8d5..7a4b459 100644
--- a/bindings/src/bindfunctions.cpp
+++ b/bindings/src/bindfunctions.cpp
@@ -586,7 +586,7 @@ namespace pydeepstream {
std::function<utils::RELEASEFUNC_SIG> const &func) {
utils::set_freefunc(meta, func);
},
- py::call_guard<py::gil_scoped_release>(),
+ py::call_guard<py::gil_scoped_release>(),
"meta"_a,
"func"_a,
pydsdoc::methodsDoc::user_releasefunc);
@@ -601,10 +601,9 @@ namespace pydeepstream {
// Required for backward compatibility
m.def("unset_callback_funcs",
[]() {
- utils::release_all_func();
- },
- py::call_guard<py::gil_scoped_release>()
- );
+ utils::release_all_func();
+ },
+ py::call_guard<py::gil_scoped_release>());
m.def("alloc_char_buffer",
[](size_t size) {
@@ -650,6 +649,14 @@ namespace pydeepstream {
py::return_value_policy::reference,
pydsdoc::methodsDoc::get_ptr);
+ m.def("get_native_ptr",
+ [](size_t ptr) {
+ return (gpointer) ptr;
+ },
+ "ptr"_a,
+ py::return_value_policy::reference,
+ pydsdoc::methodsDoc::get_ptr);
+
m.def("strdup",
[](size_t ptr) -> size_t {
char *str = (char *) ptr;
diff --git a/bindings/src/utils.cpp b/bindings/src/utils.cpp
index 9f97794..009314a 100644
--- a/bindings/src/utils.cpp
+++ b/bindings/src/utils.cpp
@@ -28,6 +28,7 @@
#include "nvdsmeta_schema.h"
#include "utils.hpp"
#include "nvds_obj_encode.h"
+#include "gst-nvdssr.h"
#include "bind_string_property_definitions.h"
#include "../../docstrings/utilsdoc.h"
@@ -103,6 +104,48 @@ namespace pydeepstream {
},
py::return_value_policy::reference,
pydsdoc::utilsdoc::NvDsObjEncUsrArgsDoc::cast);
+
+ py::enum_<NvDsSRContainerType>(m, "NvDsSRContainerType")
+ .value("NVDSSR_CONTAINER_MP4", NVDSSR_CONTAINER_MP4)
+ .value("NVDSSR_CONTAINER_MKV", NVDSSR_CONTAINER_MKV)
+ .export_values();
+
+ py::class_<NvDsSRRecordingInfo>(m, "NvDsSRRecordingInfo")
+ .def(py::init<>())
+ .def_property("filename", STRING_CHAR_ARRAY(NvDsSRRecordingInfo, filename))
+ .def_property("dirpath", STRING_CHAR_ARRAY(NvDsSRRecordingInfo, dirpath))
+ .def_readwrite("duration", &NvDsSRRecordingInfo::duration)
+ .def_readwrite("containerType", &NvDsSRRecordingInfo::containerType)
+ .def_readwrite("width", &NvDsSRRecordingInfo::width)
+ .def_readwrite("height", &NvDsSRRecordingInfo::height)
+ .def_readwrite("containsVideo", &NvDsSRRecordingInfo::containsVideo)
+ .def_readwrite("channels", &NvDsSRRecordingInfo::channels)
+ .def_readwrite("samplingRate", &NvDsSRRecordingInfo::samplingRate)
+ .def_readwrite("containsAudio", &NvDsSRRecordingInfo::containsAudio)
+ .def("cast", [](size_t data) {
+ return (NvDsSRRecordingInfo *) data;
+ },
+ py::return_value_policy::reference)
+ .def("cast", [](void* data) {
+ return (NvDsSRRecordingInfo *) data;
+ },
+ py::return_value_policy::reference);
+ struct SRUserContext {
+ int sessionid;
+ char name[32];
+ };
+ py::class_<SRUserContext>(m, "SRUserContext")
+ .def(py::init<>())
+ .def_readwrite("sessionid", &SRUserContext::sessionid)
+ .def_property("name", STRING_CHAR_ARRAY(SRUserContext, name))
+ .def("cast", [](size_t data) {
+ return (SRUserContext *) data;
+ },
+ py::return_value_policy::reference)
+ .def("cast", [](void* data) {
+ return (SRUserContext *) data;
+ },
+ py::return_value_policy::reference);
}
}
Sample code modify from deepstream_test_1.py
diff --git a/apps/deepstream-test1/deepstream_test_1.py b/apps/deepstream-test1/deepstream_test_1.py
index 1367fb4..6070649 100755
--- a/apps/deepstream-test1/deepstream_test_1.py
+++ b/apps/deepstream-test1/deepstream_test_1.py
@@ -23,8 +23,10 @@ import os
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GLib, Gst
+from gi.repository import GObject
from common.platform_info import PlatformInfo
from common.bus_call import bus_call
+import ctypes
import pyds
@@ -116,9 +118,56 @@ def osd_sink_pad_buffer_probe(pad,info,u_data):
l_frame=l_frame.next
except StopIteration:
break
-
+
return Gst.PadProbeReturn.OK
+nvurisrcbin = None
+
+def stop_record_callback():
+ global nvurisrcbin
+ nvurisrcbin.emit('stop-sr', 0)
+
+# keep same as native for get size of native struct
+class SRUserContext(ctypes.Structure):
+ _fields_ = [
+ ("sessionid", ctypes.c_int),
+ ("name", ctypes.c_char * 32)
+ ]
+
+# GstElement * src, NvDsSRRecordingInfo* recordingInfo, void* data, void* user_data
+def record_done(nvurisrcbin, recordingInfo, user_ctx, user_data):
+ print(f"record_done nvurisrcbin {nvurisrcbin} recordingInfo {recordingInfo} \
+ user_ctx {user_ctx} user_data {user_data}")
+ info = pyds.NvDsSRRecordingInfo.cast(hash(recordingInfo))
+ sr = pyds.SRUserContext.cast(hash(user_ctx))
+ print(f"filename {info.filename} -- dir {info.dirpath} {info.width} x {info.height}")
+ print(f"session id {sr.sessionid} -- name {sr.name}")
+
+
+def cb_newpad(decodebin, decoder_src_pad, data):
+ print("In cb_newpad\n")
+ caps=decoder_src_pad.get_current_caps()
+ if not caps:
+ caps = decoder_src_pad.query_caps()
+ gststruct=caps.get_structure(0)
+ gstname=gststruct.get_name()
+ source_bin=data
+ features=caps.get_features(0)
+
+ # Need to check if the pad created by the decodebin is for video and not
+ # audio.
+ print("gstname=",gstname)
+ if(gstname.find("video")!=-1):
+ # Link the decodebin pad only if decodebin has picked nvidia
+ # decoder plugin nvdec_*. We do this by checking if the pad caps contain
+ # NVMM memory features.
+ print("features=",features)
+ if features.contains("memory:NVMM"):
+ # Get the source bin ghost pad
+ sink_pad=source_bin.request_pad_simple("sink_0")
+ ret = decoder_src_pad.link(sink_pad)
+ else:
+ sys.stderr.write(" Error: Decodebin did not pick nvidia decoder plugin.\n")
def main(args):
# Check input arguments
@@ -130,6 +179,7 @@ def main(args):
# Standard GStreamer initialization
Gst.init(None)
+ uri = args[1]
# Create gstreamer elements
# Create Pipeline element that will form a connection of other elements
print("Creating Pipeline \n ")
@@ -138,30 +188,25 @@ def main(args):
if not pipeline:
sys.stderr.write(" Unable to create Pipeline \n")
- # Source element for reading from the file
- print("Creating Source \n ")
- source = Gst.ElementFactory.make("filesrc", "file-source")
- if not source:
- sys.stderr.write(" Unable to create Source \n")
-
- # Since the data format in the input file is elementary h264 stream,
- # we need a h264parser
- print("Creating H264Parser \n")
- h264parser = Gst.ElementFactory.make("h264parse", "h264-parser")
- if not h264parser:
- sys.stderr.write(" Unable to create h264 parser \n")
-
- # Use nvdec_h264 for hardware accelerated decode on GPU
- print("Creating Decoder \n")
- decoder = Gst.ElementFactory.make("nvv4l2decoder", "nvv4l2-decoder")
- if not decoder:
- sys.stderr.write(" Unable to create Nvv4l2 Decoder \n")
+ global nvurisrcbin
+ nvurisrcbin = Gst.ElementFactory.make("nvurisrcbin", "uri-decode-bin")
+ if not nvurisrcbin:
+ sys.stderr.write(" Unable to create nvurisrcbin \n")
+
+ nvurisrcbin.set_property("smart-record", 2) # enable smart record.
+ nvurisrcbin.set_property("smart-rec-dir-path", ".") # set record path.
# Create nvstreammux instance to form batches from one or more sources.
streammux = Gst.ElementFactory.make("nvstreammux", "Stream-muxer")
if not streammux:
sys.stderr.write(" Unable to create NvStreamMux \n")
+ nvurisrcbin.set_property("uri", uri)
+ # Connect to the "pad-added" signal of the decodebin which generates a
+ # callback once a new pad for raw data has beed created by the decodebin
+ nvurisrcbin.connect("pad-added", cb_newpad, streammux)
+ nvurisrcbin.connect("sr-done", record_done, pipeline)
+
# Use nvinfer to run inferencing on decoder's output,
# behaviour of inferencing is set through config file
pgie = Gst.ElementFactory.make("nvinfer", "primary-inference")
@@ -196,7 +241,6 @@ def main(args):
sys.stderr.write(" Unable to create egl sink \n")
print("Playing file %s " %args[1])
- source.set_property('location', args[1])
if os.environ.get('USE_NEW_NVSTREAMMUX') != 'yes': # Only set these properties if not using new gst-nvstreammux
streammux.set_property('width', 1920)
streammux.set_property('height', 1080)
@@ -206,9 +250,7 @@ def main(args):
pgie.set_property('config-file-path', "dstest1_pgie_config.txt")
print("Adding elements to Pipeline \n")
- pipeline.add(source)
- pipeline.add(h264parser)
- pipeline.add(decoder)
+ pipeline.add(nvurisrcbin)
pipeline.add(streammux)
pipeline.add(pgie)
pipeline.add(nvvidconv)
@@ -219,16 +261,6 @@ def main(args):
# file-source -> h264-parser -> nvh264-decoder ->
# nvinfer -> nvvidconv -> nvosd -> video-renderer
print("Linking elements in the Pipeline \n")
- source.link(h264parser)
- h264parser.link(decoder)
-
- sinkpad = streammux.request_pad_simple("sink_0")
- if not sinkpad:
- sys.stderr.write(" Unable to get the sink pad of streammux \n")
- srcpad = decoder.get_static_pad("src")
- if not srcpad:
- sys.stderr.write(" Unable to get source pad of decoder \n")
- srcpad.link(sinkpad)
streammux.link(pgie)
pgie.link(nvvidconv)
nvvidconv.link(nvosd)
@@ -252,12 +284,30 @@ def main(args):
# start play back and listen to events
print("Starting pipeline \n")
pipeline.set_state(Gst.State.PLAYING)
+
+ sessionid = pyds.get_native_ptr(pyds.alloc_buffer(4))
+ print(f"sessionid {sessionid}")
+
+ sr_user_context_size = ctypes.sizeof(SRUserContext)
+ sr_user_context_buf = pyds.get_native_ptr(pyds.alloc_buffer(sr_user_context_size))
+ sr_user_context = pyds.SRUserContext.cast(sr_user_context_buf)
+ sr_user_context.sessionid = 42
+ sr_user_context.name = "sr-demo"
+ print(f"sr_user_context_buf {sr_user_context_buf}")
+
+ # signal_info = GObject.signal_query('start-sr', nvurisrcbin)
+ # print(f"signal_info {signal_info.param_types}")
+ nvurisrcbin.emit('start-sr', sessionid, 2, 7, sr_user_context_buf)
+ GLib.timeout_add(5000, stop_record_callback)
+
try:
loop.run()
except:
pass
# cleanup
pipeline.set_state(Gst.State.NULL)
+ pyds.free_gbuffer(sessionid)
+ pyds.free_gbuffer(sr_user_context_buf)
if __name__ == '__main__':
sys.exit(main(sys.argv))