deepstream-no-osd-queue.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. # Import required libraries
  2. import argparse
  3. import sys
  4. import os
  5. sys.path.append('../')
  6. sys.path.append('../source_code')
  7. import gi
  8. import configparser
  9. gi.require_version('Gst', '1.0')
  10. from gi.repository import GObject, Gst
  11. from gi.repository import GLib
  12. from ctypes import *
  13. import time
  14. import sys
  15. import math
  16. import platform
  17. from common.bus_call import bus_call
  18. from common.FPS import GETFPS
  19. import pyds
  20. PGIE_CLASS_ID_VEHICLE = 0
  21. PGIE_CLASS_ID_BICYCLE = 1
  22. PGIE_CLASS_ID_PERSON = 2
  23. PGIE_CLASS_ID_ROADSIGN = 3
  24. g_args=None
  25. # Define variables to be used later
  26. fps_streams_new={}
  27. pgie_classes_str= ["Vehicle", "TwoWheeler", "Person","RoadSign"]
  28. ################ Three Stream Pipeline ###########
  29. # Define Input and output Stream information
  30. INPUT_VIDEO = 'file:///opt/nvidia/deepstream/deepstream-5.0/samples/streams/sample_720p.h264'
  31. def parse_args():
  32. parser = argparse.ArgumentParser()
  33. parser.add_argument("--num-sources", type=int, default=1, help="Number of sources, it replicates inputs if its is greater than length of inputs")
  34. parser.add_argument("--prof", type=bool, default=False, help="Profiling Mode , Profiles with a shorter video clip.")
  35. args = parser.parse_args()
  36. return args
  37. def cb_newpad(decodebin, decoder_src_pad,data):
  38. print("In cb_newpad\n")
  39. caps=decoder_src_pad.get_current_caps()
  40. gststruct=caps.get_structure(0)
  41. gstname=gststruct.get_name()
  42. source_bin=data
  43. features=caps.get_features(0)
  44. # Need to check if the pad created by the decodebin is for video and not
  45. # audio.
  46. print("gstname=",gstname)
  47. if(gstname.find("video")!=-1):
  48. # Link the decodebin pad only if decodebin has picked nvidia
  49. # decoder plugin nvdec_*. We do this by checking if the pad caps contain
  50. # NVMM memory features.
  51. print("features=",features)
  52. if features.contains("memory:NVMM"):
  53. # Get the source bin ghost pad
  54. bin_ghost_pad=source_bin.get_static_pad("src")
  55. if not bin_ghost_pad.set_target(decoder_src_pad):
  56. sys.stderr.write("Failed to link decoder src pad to source bin ghost pad\n")
  57. else:
  58. sys.stderr.write(" Error: Decodebin did not pick nvidia decoder plugin.\n")
  59. def decodebin_child_added(child_proxy,Object,name,user_data):
  60. print("Decodebin child added:", name, "\n")
  61. if(name.find("decodebin") != -1):
  62. Object.connect("child-added",decodebin_child_added,user_data)
  63. def create_source_bin(args, index,uri):
  64. print("Creating source bin")
  65. # Create a source GstBin to abstract this bin's content from the rest of the
  66. # pipeline
  67. bin_name="source-bin-%02d" %index
  68. print(bin_name)
  69. nbin=Gst.Bin.new(bin_name)
  70. if not nbin:
  71. sys.stderr.write(" Unable to create source bin \n")
  72. # Source element for reading from the uri.
  73. # We will use decodebin and let it figure out the container format of the
  74. # stream and the codec and plug the appropriate demux and decode plugins.
  75. uri_decode_bin=Gst.ElementFactory.make("uridecodebin", "uri-decode-bin")
  76. if not uri_decode_bin:
  77. sys.stderr.write(" Unable to create uri decode bin \n")
  78. # We set the input uri to the source element
  79. uri_decode_bin.set_property("uri",uri)
  80. # Connect to the "pad-added" signal of the decodebin which generates a
  81. # callback once a new pad for raw data has beed created by the decodebin
  82. uri_decode_bin.connect("pad-added",cb_newpad,nbin)
  83. uri_decode_bin.connect("child-added",decodebin_child_added,nbin)
  84. # We need to create a ghost pad for the source bin which will act as a proxy
  85. # for the video decoder src pad. The ghost pad will not have a target right
  86. # now. Once the decode bin creates the video decoder and generates the
  87. # cb_newpad callback, we will set the ghost pad target to the video decoder
  88. # src pad.
  89. Gst.Bin.add(nbin,uri_decode_bin)
  90. bin_pad=nbin.add_pad(Gst.GhostPad.new_no_target("src",Gst.PadDirection.SRC))
  91. if not bin_pad:
  92. sys.stderr.write(" Failed to add ghost pad in source bin \n")
  93. return None
  94. return nbin
  95. ## Make Element or Print Error and any other detail
  96. def make_elm_or_print_err(factoryname, name, printedname, detail=""):
  97. print("Creating", printedname)
  98. elm = Gst.ElementFactory.make(factoryname, name)
  99. if not elm:
  100. sys.stderr.write("Unable to create " + printedname + " \n")
  101. if detail:
  102. sys.stderr.write(detail)
  103. return elm
  104. # src_pad_buffer_probe
  105. def src_pad_buffer_probe(pad,info,u_data):
  106. #Intiallizing object counter with 0.
  107. obj_counter = {
  108. PGIE_CLASS_ID_VEHICLE:0,
  109. PGIE_CLASS_ID_PERSON:0,
  110. PGIE_CLASS_ID_BICYCLE:0,
  111. PGIE_CLASS_ID_ROADSIGN:0
  112. }
  113. # Set frame_number & rectangles to draw as 0
  114. frame_number=0
  115. num_rects=0
  116. gst_buffer = info.get_buffer()
  117. if not gst_buffer:
  118. print("Unable to get GstBuffer ")
  119. return
  120. # Retrieve batch metadata from the gst_buffer
  121. # Note that pyds.gst_buffer_get_nvds_batch_meta() expects the
  122. # C address of gst_buffer as input, which is obtained with hash(gst_buffer)
  123. batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(gst_buffer))
  124. l_frame = batch_meta.frame_meta_list
  125. while l_frame is not None:
  126. try:
  127. # Note that l_frame.data needs a cast to pyds.NvDsFrameMeta
  128. frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data)
  129. except StopIteration:
  130. break
  131. # Get frame number , number of rectables to draw and object metadata
  132. frame_number=frame_meta.frame_num
  133. num_rects = frame_meta.num_obj_meta
  134. l_obj=frame_meta.obj_meta_list
  135. while l_obj is not None:
  136. try:
  137. # Casting l_obj.data to pyds.NvDsObjectMeta
  138. obj_meta=pyds.NvDsObjectMeta.cast(l_obj.data)
  139. except StopIteration:
  140. break
  141. # Increment Object class by 1
  142. obj_counter[obj_meta.class_id] += 1
  143. try:
  144. l_obj=l_obj.next
  145. except StopIteration:
  146. break
  147. print("Frame Number={} Number of Objects={} Vehicle_count={} Person_count={}".format(frame_number, num_rects, obj_counter[PGIE_CLASS_ID_VEHICLE], obj_counter[PGIE_CLASS_ID_PERSON]))
  148. # FPS Probe
  149. fps_streams_new["stream{0}".format(frame_meta.pad_index)].get_fps()
  150. try:
  151. l_frame=l_frame.next
  152. except StopIteration:
  153. break
  154. return Gst.PadProbeReturn.OK
  155. def main():
  156. args = parse_args()
  157. global g_args
  158. g_args = args
  159. num_sources = args.num_sources
  160. path = os.path.abspath(os.getcwd())
  161. if (args.prof):
  162. INPUT_VIDEO = 'file://' + path +'/../source_code/dataset/sample_720p_prof.mp4'
  163. else :
  164. INPUT_VIDEO = 'file:///opt/nvidia/deepstream/deepstream-5.0/samples/streams/sample_720p.h264'
  165. print("Creating pipeline with "+str(num_sources)+" streams")
  166. # Initialise FPS
  167. for i in range(0,num_sources):
  168. fps_streams_new["stream{0}".format(i)]=GETFPS(i)
  169. # Standard GStreamer initialization
  170. Gst.init(None)
  171. # Create gstreamer elements */
  172. # Create Pipeline element that will form a connection of other elements
  173. print("Creating Pipeline \n ")
  174. pipeline = Gst.Pipeline()
  175. if not pipeline:
  176. sys.stderr.write(" Unable to create Pipeline \n")
  177. ########### Create Elements required for the Pipeline ###########
  178. # Create nvstreammux instance to form batches from one or more sources.
  179. streammux = make_elm_or_print_err("nvstreammux", "Stream-muxer","Stream-muxer")
  180. pipeline.add(streammux)
  181. for i in range(num_sources):
  182. print("Creating source_bin ",i," \n ")
  183. uri_name=INPUT_VIDEO
  184. if uri_name.find("rtsp://") == 0 :
  185. is_live = True
  186. source_bin=create_source_bin(args, i, uri_name)
  187. if not source_bin:
  188. sys.stderr.write("Unable to create source bin \n")
  189. pipeline.add(source_bin)
  190. padname="sink_%u" %i
  191. sinkpad = streammux.get_request_pad(padname)
  192. if not sinkpad:
  193. sys.stderr.write("Unable to create sink pad bin \n")
  194. srcpad = source_bin.get_static_pad("src")
  195. if not srcpad:
  196. sys.stderr.write("Unable to create src pad bin \n")
  197. srcpad.link(sinkpad)
  198. # Use nvinfer to run inferencing on decoder's output, behaviour of inferencing is set through config file
  199. pgie = make_elm_or_print_err("nvinfer", "primary-inference" ,"pgie")
  200. # Use nvtracker to give objects unique-ids
  201. tracker = make_elm_or_print_err("nvtracker", "tracker",'tracker')
  202. # Seconday inference for Finding Car Color
  203. sgie1 = make_elm_or_print_err("nvinfer", "secondary1-nvinference-engine",'sgie1')
  204. # Seconday inference for Finding Car Make
  205. sgie2 = make_elm_or_print_err("nvinfer", "secondary2-nvinference-engine",'sgie2')
  206. # # Seconday inference for Finding Car Type
  207. sgie3 = make_elm_or_print_err("nvinfer", "secondary3-nvinference-engine",'sgie3')
  208. # Create Sink for storing the output
  209. fakesink = make_elm_or_print_err("fakesink", "fakesink", "Sink")
  210. # Queues to enable buffering
  211. queue1=make_elm_or_print_err("queue","queue1","queue1")
  212. queue2=make_elm_or_print_err("queue","queue2","queue2")
  213. queue3=make_elm_or_print_err("queue","queue3","queue3")
  214. queue4=make_elm_or_print_err("queue","queue4","queue4")
  215. queue5=make_elm_or_print_err("queue","queue5","queue5")
  216. queue6=make_elm_or_print_err("queue","queue6","queue6")
  217. ############ Set properties for the Elements ############
  218. # Set Input Width , Height and Batch Size
  219. streammux.set_property('width', 1920)
  220. streammux.set_property('height', 1080)
  221. streammux.set_property('batch-size', 1)
  222. # Timeout in microseconds to wait after the first buffer is available
  223. # to push the batch even if a complete batch is not formed.
  224. streammux.set_property('batched-push-timeout', 4000000)
  225. # Set configuration file for nvinfer
  226. # Set Congifuration file for nvinfer
  227. pgie.set_property('config-file-path', "../source_code/N1/dstest4_pgie_config.txt")
  228. sgie1.set_property('config-file-path', "../source_code/N1/dstest4_sgie1_config.txt")
  229. sgie2.set_property('config-file-path', "../source_code/N1/dstest4_sgie2_config.txt")
  230. sgie3.set_property('config-file-path', "../source_code/N1/dstest4_sgie3_config.txt")
  231. #Set properties of tracker from tracker_config
  232. config = configparser.ConfigParser()
  233. config.read('../source_code/N1/dstest4_tracker_config.txt')
  234. config.sections()
  235. for key in config['tracker']:
  236. if key == 'tracker-width' :
  237. tracker_width = config.getint('tracker', key)
  238. tracker.set_property('tracker-width', tracker_width)
  239. if key == 'tracker-height' :
  240. tracker_height = config.getint('tracker', key)
  241. tracker.set_property('tracker-height', tracker_height)
  242. if key == 'gpu-id' :
  243. tracker_gpu_id = config.getint('tracker', key)
  244. tracker.set_property('gpu_id', tracker_gpu_id)
  245. if key == 'll-lib-file' :
  246. tracker_ll_lib_file = config.get('tracker', key)
  247. tracker.set_property('ll-lib-file', tracker_ll_lib_file)
  248. if key == 'll-config-file' :
  249. tracker_ll_config_file = config.get('tracker', key)
  250. tracker.set_property('ll-config-file', tracker_ll_config_file)
  251. if key == 'enable-batch-process' :
  252. tracker_enable_batch_process = config.getint('tracker', key)
  253. tracker.set_property('enable_batch_process', tracker_enable_batch_process)
  254. # Fake sink properties
  255. fakesink.set_property("sync", 0)
  256. fakesink.set_property("async", 0)
  257. ########## Add and Link ELements in the Pipeline ##########
  258. print("Adding elements to Pipeline \n")
  259. pipeline.add(queue1)
  260. pipeline.add(pgie)
  261. pipeline.add(queue2)
  262. pipeline.add(tracker)
  263. pipeline.add(queue3)
  264. pipeline.add(sgie1)
  265. pipeline.add(queue4)
  266. pipeline.add(sgie2)
  267. pipeline.add(queue5)
  268. pipeline.add(sgie3)
  269. pipeline.add(queue6)
  270. pipeline.add(fakesink)
  271. print("Linking elements in the Pipeline \n")
  272. streammux.link(queue1)
  273. queue1.link(pgie)
  274. pgie.link(queue2)
  275. queue2.link(tracker)
  276. tracker.link(queue3)
  277. queue3.link(sgie1)
  278. sgie1.link(queue4)
  279. queue4.link(sgie2)
  280. sgie2.link(queue5)
  281. queue5.link(sgie3)
  282. sgie3.link(fakesink)
  283. # create an event loop and feed gstreamer bus mesages to it
  284. loop = GLib.MainLoop()
  285. bus = pipeline.get_bus()
  286. bus.add_signal_watch()
  287. bus.connect ("message", bus_call, loop)
  288. print("Added and Linked elements to pipeline")
  289. src_pad=sgie3.get_static_pad("src")
  290. if not src_pad:
  291. sys.stderr.write(" Unable to get src pad \n")
  292. else:
  293. src_pad.add_probe(Gst.PadProbeType.BUFFER, src_pad_buffer_probe, 0)
  294. # List the sources
  295. print("Now playing...")
  296. print("Starting pipeline \n")
  297. # start play back and listed to events
  298. pipeline.set_state(Gst.State.PLAYING)
  299. start_time = time.time()
  300. try:
  301. loop.run()
  302. except:
  303. pass
  304. # cleanup
  305. print("Exiting app\n")
  306. pipeline.set_state(Gst.State.NULL)
  307. print("--- %s seconds ---" % (time.time() - start_time))
  308. if __name__ == '__main__':
  309. sys.exit(main())