• Jetson AGX Xavier
• Deepstream 6.0
• JetPack 4.6
• TensorRT 8.0.1
• NVIDIA GPU Driver 32.6.1
Hello, I getting videostream from rtsp cam and use it on this pipeline:
import argparse
import os
import sys
sys.path.append('../')
import dbf
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
from common.is_aarch_64 import is_aarch64
from common.bus_call import bus_call
from common.FPS import GETFPS
import configparser
import numpy as np
import cv2
import pyds
PGIE_CLASS_ID_BOTTOM = 0
PGIE_CLASS_ID_HOOK = 1
PGIE_CLASS_ID_PRESS_B = 2
COLORS = [[255, 255, 255], [0, 0, 128], [0, 128, 128], [128, 0, 0],
[128, 0, 128], [128, 128, 0], [0, 128, 0], [0, 0, 64],
[0, 0, 192], [0, 128, 64], [0, 128, 192], [128, 0, 64],
[128, 0, 192], [0, 0, 0]]
total_bottoms = 0
bottom_absence = 0
bottom_counter = 0
press_counter = 0
hook_counter = 0
all_confirms = {1: 0, 2: 0, 3: 0}
def map_mask_as_display_bgr(mask):
""" Assigning multiple colors as image output using the information
contained in mask. (BGR is opencv standard.)
"""
# getting a list of available classes
shp = mask.shape
bgr = np.zeros((shp[0], shp[1]))
bgr[mask == 0] = 255
return bgr
fps_stream=0
def cb_newpad(decodebin, decoder_src_pad,data):
print("In cb_newpad\n")
caps=decoder_src_pad.get_current_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
bin_ghost_pad=source_bin.get_static_pad("src")
if not bin_ghost_pad.set_target(decoder_src_pad):
sys.stderr.write("Failed to link decoder src pad to source bin ghost pad\n")
else:
sys.stderr.write(" Error: Decodebin did not pick nvidia decoder plugin.\n")
def decodebin_child_added(child_proxy,Object,name,user_data):
print("Decodebin child added:", name, "\n")
if(name.find("decodebin") != -1):
Object.connect("child-added",decodebin_child_added,user_data)
def create_source_bin(index,uri):
print("Creating source bin")
# Create a source GstBin to abstract this bin's content from the rest of the
# pipeline
bin_name="source-bin-%02d" %index
print(bin_name)
nbin=Gst.Bin.new(bin_name)
if not nbin:
sys.stderr.write(" Unable to create source bin \n")
# Source element for reading from the uri.
# We will use decodebin and let it figure out the container format of the
# stream and the codec and plug the appropriate demux and decode plugins.
uri_decode_bin=Gst.ElementFactory.make("uridecodebin", "uri-decode-bin")
if not uri_decode_bin:
sys.stderr.write(" Unable to create uri decode bin \n")
# We set the input uri to the source element
uri_decode_bin.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
uri_decode_bin.connect("pad-added",cb_newpad,nbin)
uri_decode_bin.connect("child-added",decodebin_child_added,nbin)
# We need to create a ghost pad for the source bin which will act as a proxy
# for the video decoder src pad. The ghost pad will not have a target right
# now. Once the decode bin creates the video decoder and generates the
# cb_newpad callback, we will set the ghost pad target to the video decoder
# src pad.
Gst.Bin.add(nbin,uri_decode_bin)
bin_pad=nbin.add_pad(Gst.GhostPad.new_no_target("src",Gst.PadDirection.SRC))
if not bin_pad:
sys.stderr.write(" Failed to add ghost pad in source bin \n")
return None
return nbin
def find_number_of_clusters(mask):
global all_confirms
start_point = (0, 0)
bottoms_counts = []
thresh = cv2.threshold(mask, 100, 255, cv2.THRESH_BINARY)[1]
erosion_kernel = np.ones((2,2),np.uint8)
erosion = cv2.erode(thresh,erosion_kernel, iterations = 1)
# Make 4 parts and check every
for half in range(8):
half_mask = erosion[:, half*64:(half+1) * 64]
# Threshhold to binar
contours = cv2.findContours(half_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
index = 1
isolated_count = 0
cluster_count = 0
for cntr in contours:
area = cv2.contourArea(cntr)
convex_hull = cv2.convexHull(cntr)
convex_hull_area = cv2.contourArea(convex_hull)
if(convex_hull_area == 0):
convex_hull_area = 1
if(area == 0):
area = 1
name = "img_num_" + str(half) + ".jpg"
cv2.imwrite(name, half_mask)
# Find a box around the area and compare to area
ratio = area / convex_hull_area
# If area less then box it is not a noize
if ratio < 0.90:
cluster_count = cluster_count + 1
# And if area close to box area it mostly noize
else:
isolated_count = isolated_count + 1
index = index + 1
# Append cluster area
bottoms_counts.append(cluster_count)
#bottoms_counts example - 1x1x1x2+2x1x1x2 - means that we got 1 bottom
#bottoms_counts exampls2 - 1x1x2+2+2x1x1x1 - meants that we got 2 bottom
#If we got more than 2 + it means we got 2 bottoms (or 3 if + connects 3s)
confirms = []
print(bottoms_counts)
for part in range(1, len(bottoms_counts) - 1):
this = bottoms_counts[part]
last = bottoms_counts[part-1]
if(this != last) and (this > 1) and (last > 1):
confirms.append(min(this, last))
if(bottoms_counts[0] > 1):
confirms.append(bottoms_counts[0])
if(bottoms_counts[7] > 1):
confirms.append(bottoms_counts[7])
if len(confirms) > 1:
if(max(confirms) % 2 == 0):
all_confirms[2] += 1
else:
all_confirms[3] += 1
else:
all_confirms[1] += 1
def osd_sink_pad_buffer_probe(pad,info,u_data):
global total_bottoms
global bottom_absence
global bottom_counter
global press_counter
global hook_counter
global all_confirms
global table
# print("Pad: " ,dir(pad))
# print("Info: ", dir(info))
obj_counter = {
PGIE_CLASS_ID_BOTTOM:0,
PGIE_CLASS_ID_HOOK:0,
PGIE_CLASS_ID_PRESS_B:0
}
num_rects=0
gst_buffer = info.get_buffer()
#print("Buffer: ", dir(gst_buffer))
if not gst_buffer:
print("Unable to get GstBuffer ")
return
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:
frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data)
# print("Base_meta: ", dir(frame_meta.base_meta))
# print("Buf_pts: ", frame_meta.buf_pts)
except StopIteration:
break
num_rects = frame_meta.num_obj_meta
l_user = frame_meta.frame_user_meta_list
l_obj=frame_meta.obj_meta_list
while l_obj is not None:
try:
obj_meta=pyds.NvDsObjectMeta.cast(l_obj.data)
except StopIteration:
break
obj_counter[obj_meta.class_id] += 1
obj_meta.rect_params.border_color.set(0.0, 0.0, 1.0, 0.0)
try:
l_obj=l_obj.next
#print(dir(batch_meta))
frame = pyds.get_nvds_buf_surface(hash(gst_buffer), frame_meta.batch_id)
except StopIteration:
break
while l_user is not None:
try:
# Note that l_user.data needs a cast to pyds.NvDsUserMeta
# The casting is done by pyds.NvDsUserMeta.cast()
# The casting also keeps ownership of the underlying memory
# in the C code, so the Python garbage collector will leave
# it alone.
seg_user_meta = pyds.NvDsUserMeta.cast(l_user.data)
except StopIteration:
break
if seg_user_meta and seg_user_meta.base_meta.meta_type == \
pyds.NVDSINFER_SEGMENTATION_META:
try:
# Note that seg_user_meta.user_meta_data needs a cast to
# pyds.NvDsInferSegmentationMeta
# The casting is done by pyds.NvDsInferSegmentationMeta.cast()
# The casting also keeps ownership of the underlying memory
# in the C code, so the Python garbage collector will leave
# it alone.
segmeta = pyds.NvDsInferSegmentationMeta.cast(seg_user_meta.user_meta_data)
except StopIteration:
break
# Retrieve mask data in the numpy format from segmeta
# Note that pyds.get_segmentation_masks() expects object of
# type NvDsInferSegmentationMeta
masks = pyds.get_segmentation_masks(segmeta)
masks = np.array(masks, copy=True, order='C')
# map the obtained masks to colors of 2 classes.
frame_image = map_mask_as_display_bgr(masks).astype(np.uint8)
# gray_image = cv2.cvtColor(frame_image, cv2.COLOR_BGR2GRAY).astype(np.uint8)
find_number_of_clusters(frame_image)
try:
l_user = l_user.next
except StopIteration:
break
print(all_confirms)
if(obj_counter[PGIE_CLASS_ID_BOTTOM] == 0):
bottom_absence += 1
else:
if(bottom_absence > 300) and (press_counter > 300):
total_bottoms += max(all_confirms, key=all_confirms.get)
table.open(mode=dbf.READ_WRITE)
table.append(dbf.Date(1979, 9,13), total_bottoms)
print ('records added:')
for record in table:
print (record)
print ('-----')
table.close
all_confirms = {1: 0, 2: 0, 3:0}
press_counter = 0
bottom_absence = 0
if bottom_counter > 100:
bottom_absence = 0
bottom_counter += 1
if(obj_counter[PGIE_CLASS_ID_PRESS_B] > 0):
press_counter += 1
display_meta=pyds.nvds_acquire_display_meta_from_pool(batch_meta)
display_meta.num_labels = 1
py_nvosd_text_params = display_meta.text_params[0]
fps = fps_stream.get_fps()
py_nvosd_text_params.display_text = "FPS={} Bottoms_at_press={} Total_Bottoms={} Press={}".format(fps, max(all_confirms, key=all_confirms.get), total_bottoms, obj_counter[PGIE_CLASS_ID_PRESS_B])
py_nvosd_text_params.x_offset = 10
py_nvosd_text_params.y_offset = 12
py_nvosd_text_params.font_params.font_name = "Serif"
py_nvosd_text_params.font_params.font_size = 10
py_nvosd_text_params.font_params.font_color.set(1.0, 1.0, 1.0, 1.0)
py_nvosd_text_params.set_bg_clr = 1
py_nvosd_text_params.text_bg_clr.set(0.0, 0.0, 0.0, 1.0)
pyds.nvds_add_display_meta_to_frame(frame_meta, display_meta)
try:
l_frame=l_frame.next
except StopIteration:
break
return Gst.PadProbeReturn.OK
def main(opt):
global fps_stream
global table
table = dbf.Table('Отчёт Hermes.dbf', 'Date D; Bottoms N(3,0);')
print('db definition created with field names:', table.field_names)
# Check input arguments
fps_stream=GETFPS(0)
# Standard GStreamer initialization
GObject.threads_init()
Gst.init(None)
# Create gstreamer elements
print("Creating Pipeline \n ")
pipeline = Gst.Pipeline()
if not pipeline:
sys.stderr.write(" Unable to create Pipeline \n")
streammux = Gst.ElementFactory.make("nvstreammux", "Stream-muxer")
if not streammux:
sys.stderr.write(" Unable to create NvStreamMux \n")
pipeline.add(streammux)
uri_name = "rtsp://" + opt.log + ":" + opt.pwd + "@" + opt.ip + ":" + opt.port + "/snl/live/main"
if uri_name.find("file://") == 0 :
is_live = True
source_bin=create_source_bin(0, uri_name)
if not source_bin:
sys.stderr.write("Unable to create source bin \n")
pipeline.add(source_bin)
padname="sink_%u" %0
sinkpad= streammux.get_request_pad(padname)
if not sinkpad:
sys.stderr.write("Unable to create sink pad bin \n")
srcpad=source_bin.get_static_pad("src")
if not srcpad:
sys.stderr.write("Unable to create src pad bin \n")
srcpad.link(sinkpad)
# Countinue init elements
pgie = Gst.ElementFactory.make("nvinfer", "primary-inference")
if not pgie:
sys.stderr.write(" Unable to create pgie \n")
dsexample = Gst.ElementFactory.make("dsexample", "cropper")
if not dsexample:
sys.stderr.write(" Unable to create dsexample \n")
sgie = Gst.ElementFactory.make("nvinfer", "secondary1-nvinference-engine")
if not sgie:
sys.stderr.write(" Unable to make sgie1 \n")
nvsegvisual = Gst.ElementFactory.make("nvsegvisual", "nvsegvisual")
if not nvsegvisual:
sys.stderr.write("Unable to create nvsegvisual\n")
nvvidconv = Gst.ElementFactory.make("nvvideoconvert", "convertor")
if not nvvidconv:
sys.stderr.write(" Unable to create nvvidconv \n")
nvvidconv2 = Gst.ElementFactory.make("nvvideoconvert", "convertor2")
if not nvvidconv2:
sys.stderr.write(" Unable to create nvvidconv2 \n")
nvosd = Gst.ElementFactory.make("nvdsosd", "onscreendisplay")
if not nvosd:
sys.stderr.write(" Unable to create nvosd \n")
if is_aarch64():
transform = Gst.ElementFactory.make("nvegltransform", "nvegl-transform")
print("Creating EGLSink \n")
sink = Gst.ElementFactory.make("nveglglessink", "nvvideo-renderer")
if not sink:
sys.stderr.write(" Unable to create egl sink \n")
print("Playing cam %s ", uri_name)
# Setting options on elements
streammux.set_property('width', 1920)
streammux.set_property('height', 1080)
streammux.set_property('batch-size', 1)
streammux.set_property('batched-push-timeout', 4000000)
nvvidconv2.set_property('nvbuf-memory-type', 0)
pgie.set_property('config-file-path', "config_yolo.txt")
dsexample.set_property('full-frame', 0)
dsexample.set_property('blur_objects', True)
sgie.set_property('config-file-path', 'config_unet.txt')
nvsegvisual.set_property('width', 512)
nvsegvisual.set_property('height', 512)
sink.set_property('sync', 0)
# Adding elements
print("Adding elements to Pipeline \n")
pipeline.add(pgie)
pipeline.add(sgie)
pipeline.add(nvvidconv2)
pipeline.add(nvsegvisual)
pipeline.add(dsexample)
pipeline.add(nvvidconv)
pipeline.add(nvosd)
pipeline.add(sink)
if is_aarch64():
pipeline.add(transform)
# Linking elements
print("Linking elements in the Pipeline \n")
streammux.link(pgie)
pgie.link(nvvidconv2)
nvvidconv2.link(dsexample)
dsexample.link(sgie)
sgie.link(nvsegvisual)
nvsegvisual.link(nvvidconv)
nvvidconv.link(nvosd)
if is_aarch64():
nvosd.link(transform)
transform.link(sink)
else:
nvosd.link(sink)
# create an event loop and feed gstreamer bus mesages to it
loop = GObject.MainLoop()
bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect ("message", bus_call, loop)
osdsinkpad = nvosd.get_static_pad("sink")
if not osdsinkpad:
sys.stderr.write(" Unable to get sink pad of nvosd \n")
osdsinkpad.add_probe(Gst.PadProbeType.BUFFER, osd_sink_pad_buffer_probe, 0)
# start play back and listen to events
print("Starting pipeline \n")
pipeline.set_state(Gst.State.PLAYING)
try:
loop.run()
except:
pass
# cleanup
pipeline.set_state(Gst.State.NULL)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--log', type = str, default = 'admin')
parser.add_argument('--pwd', type = str, default = '-')
parser.add_argument('--ip', type = str, default = '-')
parser.add_argument('--port', type = str, default = '-')
opt = parser.parse_args()
print(opt)
main(opt)
I use dsexample script to crop the detected object and push it to segmentation.
After 10000-11000 frames it executes osd_sink_pad_buffer_probe() 6 times and freezes on ±30 minutes.
I understood it because i wrote some prints in dsexample and some in osd_sink_pad_buffer_probe() and I seen that before freeze only osd_sink_pad_buffer_probe printed something out.
Before freeze jtop shows that all CPU got 0%
Where is the problem? Please give me an advice.