text: #!/usr/bin/env python3
  
  ################################################################################
  # SPDX-FileCopyrightText: Copyright (c) 2020-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  # SPDX-License-Identifier: Apache-2.0
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  # http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  ################################################################################
  
  import sys
  sys.path.append('../')
  import gi
  import configparser
  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
  
  import pyds
  import mmap
  
  fps_streams = {}
  frame_count = {}
  saved_count = {}
  dict_label = {}
  bounding_bboxes =[]
  past_tracking_meta=[0]
  MIN_CONFIDENCE = 0.3
  MAX_CONFIDENCE = 0.99
  
  
  def load_labels(filename):
      labels=[]
      with open(filename,"r") as f:
          labels=f.read().split('\n')
      return labels
  
  class_names=load_labels("labels.txt")
  for i in range(len(class_names)):
      dict_label[class_names[i]]=0
  
  # tiler_sink_pad_buffer_probe  will extract metadata received on OSD sink pad
  # and update params for drawing rectangle, object information etc.
  def osd_sink_pad_buffer_probe(pad,info,u_data):
      frame_number = 0
      
      for i in range(len(class_names)):
          dict_label[class_names[i]]=0
  
      num_rects = 0
      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))
      l_frame = batch_meta.frame_meta_list
      while l_frame is not None: #--------对一帧图片进行所有目标的遍历
          try: 
              frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data)
          except StopIteration:
              break
  
          frame_number = frame_meta.frame_num
          num_rects = frame_meta.num_obj_meta #--------储存每帧目标的总个数
          l_obj = frame_meta.obj_meta_list
          bounding_bboxes =[]
          while l_obj  is not None:  #--------对同个目标类型不同个体进行遍历 
              try:
                  obj_meta = pyds.NvDsObjectMeta.cast(l_obj.data)
              except StopIteration:
                  break
              dict_label[class_names[obj_meta.class_id]]  += 1
  
              class_id = obj_meta.class_id
              top = obj_meta.tracker_bbox_info.org_bbox_coords.top
              left = obj_meta.tracker_bbox_info.org_bbox_coords.left
              width = obj_meta.tracker_bbox_info.org_bbox_coords.width
              height = obj_meta.tracker_bbox_info.org_bbox_coords.height
              object_id = obj_meta.object_id
              #print(int(class_id), "   ",int(top), "   ",int(left), "   ",int(width), "   ",int(height),"   ", int(object_id))
  
              bounding_bboxes.append(int(class_id))
              bounding_bboxes.append(int(top))
              bounding_bboxes.append(int(left))
              bounding_bboxes.append(int(width)) 
              bounding_bboxes.append(int(height))
              bounding_bboxes.append(int(object_id)) 
              obj_meta.rect_params.border_color.set(0.0, 1.0, 0.0, 0.0) #--------red ,green, blue, black
              try:
                  l_obj = l_obj.next
                  
              except StopIteration:
                  break
          print("bounding_bboxes:",bounding_bboxes)
          bounding_bboxes_len =  len(str(bounding_bboxes))
          real_len = bounding_bboxes_len
          print("bounding_bboxes_len:", bounding_bboxes_len)
  
          #--------mmap向internal_memory.txt所指向的内存中写入数据--------#
          with open('internal_memory.txt', 'r+') as f:
              # mmap基本上接收两个参数,(文件描述符,读取长度),size 为0表示读取整个文件
              mm = mmap.mmap(f.fileno(), 0)
              mm.seek(0)  # 定位到文件头
              if len(str(bounding_bboxes_len)) != 5:  # 获取有效信息的长度数字取值
                  for ii in range(5 - len(str(bounding_bboxes_len))):  # 循环添加“_”至满5位
                      bounding_bboxes_len = str(bounding_bboxes_len) + str("-")
              print("bounding_bboxes_len_str = ", bounding_bboxes_len)
              mm.write(bytes(str(bounding_bboxes_len), 'utf-8'))
              # 切片读取方式
              # mm.write(bytes(det_str, 'utf-8'))
              mm.seek(6)
              mm.write(bytes(str(bounding_bboxes), 'utf-8'))
              # 标准读取方式
              print(mm[:real_len + 6])  # prints "Hello Python!"
              # 像处理文件一样关闭mmap映射
              mm.close()
  
  
  
          bounding_bboxes =[]
          
          #--------创建左上角长条形数据显示串--------#
          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]
  
          #左上角显示text串
          py_nvosd_text_params.display_text = "Frame Number = {}  Number of Objects = {}  Vechile_count = {} person_count = {}".format(frame_number, num_rects, dict_label["car"], dict_label["person"])
          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,  1,  0.0,  0.0)
          print(pyds.get_string(py_nvosd_text_params.display_text))
  
          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(args):
      # Check input arguments
      if len(args) != 2:
          sys.stderr.write("usage: %s <v4l2-device-path>\n" % args[0])
          sys.exit(1)
  
      # Standard GStreamer initialization
      GObject.threads_init()
      Gst.init(None)
  
      # Create gstreamer elements
      # Create Pipeline element that will form a connection of other elements
      print("Creating Pipeline \n ")
      pipeline = Gst.Pipeline()
  
      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("v4l2src", "usb-cam-source")
      if not source:
          sys.stderr.write(" Unable to create Source \n")
  
      caps_v4l2src = Gst.ElementFactory.make("capsfilter", "v4l2src_caps")
      if not caps_v4l2src:
          sys.stderr.write(" Unable to create v4l2src capsfilter \n")
  
  
      print("Creating Video Converter \n")
  
      # Adding videoconvert -> nvvideoconvert as not all
      # raw formats are supported by nvvideoconvert;
      # Say YUYV is unsupported - which is the common
      # raw format for many logi usb cams
      # In case we have a camera with raw format supported in
      # nvvideoconvert, GStreamer plugins' capability negotiation
      # shall be intelligent enough to reduce compute by
      # videoconvert doing passthrough (TODO we need to confirm this)
  
  
      # videoconvert to make sure a superset of raw formats are supported
      vidconvsrc = Gst.ElementFactory.make("videoconvert", "convertor_src1")
      if not vidconvsrc:
          sys.stderr.write(" Unable to create videoconvert \n")
  
      # nvvideoconvert to convert incoming raw buffers to NVMM Mem (NvBufSurface API)
      nvvidconvsrc = Gst.ElementFactory.make("nvvideoconvert", "convertor_src2")
      if not nvvidconvsrc:
          sys.stderr.write(" Unable to create Nvvideoconvert \n")
  
      caps_vidconvsrc = Gst.ElementFactory.make("capsfilter", "nvmm_caps")
      if not caps_vidconvsrc:
          sys.stderr.write(" Unable to create capsfilter \n")
  
      # 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")
  
      # Use nvinfer to run inferencing on camera's output,
      # behaviour of inferencing is set through config file
      pgie = Gst.ElementFactory.make("nvinfer", "primary-inference")
      if not pgie:
          sys.stderr.write(" Unable to create pgie \n")
  
      # Use convertor to convert from NV12 to RGBA as required by nvosd
      nvvidconv = Gst.ElementFactory.make("nvvideoconvert", "convertor")
      if not nvvidconv:
          sys.stderr.write(" Unable to create nvvidconv \n")
  
      # Create OSD to draw on the converted RGBA buffer
      nvosd = Gst.ElementFactory.make("nvdsosd", "onscreendisplay")
  
      if not nvosd:
          sys.stderr.write(" Unable to create nvosd \n")
  
  
      tracker = Gst.ElementFactory.make("nvtracker", "tracker")
      if not tracker:
         sys.stderr.write(" Unable to create tracker \n")
  
      # Finally render the osd output
      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 " %args[1])
      caps_v4l2src.set_property('caps', Gst.Caps.from_string("video/x-raw, framerate=30/1"))
      caps_vidconvsrc.set_property('caps', Gst.Caps.from_string("video/x-raw(memory:NVMM)"))
      source.set_property('device', args[1])
      streammux.set_property('width', 1080)
      streammux.set_property('height', 720)
      streammux.set_property('batch-size', 1)
      streammux.set_property('batched-push-timeout', 4000000)
      pgie.set_property('config-file-path', "config_infer_primary.txt")
      # Set sync = false to avoid late frame drops at the display-sink
      sink.set_property('sync', False)
  
      config = configparser.ConfigParser()
      config.read('dstest_x_tracker_config.txt')
      config.sections()
  
      for key in config['tracker']:
          if key == 'tracker-width':
              tracker_width = config.getint('tracker', key)
              tracker.set_property('tracker-width', tracker_width)
          if key == 'tracker-height':
              tracker_height = config.getint('tracker', key)
              tracker.set_property('tracker-height', tracker_height)
          if key == 'gpu-id':
              tracker_gpu_id = config.getint('tracker', key)
              tracker.set_property('gpu_id', tracker_gpu_id)
          if key == 'll-lib-file':
              tracker_ll_lib_file = config.get('tracker', key)
              tracker.set_property('ll-lib-file', tracker_ll_lib_file)
          if key == 'll-config-file':
              tracker_ll_config_file = config.get('tracker', key)
              tracker.set_property('ll-config-file', tracker_ll_config_file)
          if key == 'enable-batch-process':
              tracker_enable_batch_process = config.getint('tracker', key)
              tracker.set_property('enable_batch_process', tracker_enable_batch_process)
  
      print("Adding elements to Pipeline \n")
      pipeline.add(source)
      pipeline.add(caps_v4l2src)
      pipeline.add(vidconvsrc)
      pipeline.add(nvvidconvsrc)
      pipeline.add(caps_vidconvsrc)
      pipeline.add(streammux)
      pipeline.add(pgie)
      pipeline.add(tracker)
      pipeline.add(nvvidconv)
      pipeline.add(nvosd)
      pipeline.add(sink)
      if is_aarch64():
          pipeline.add(transform)
  
      # we link the elements together
      # v4l2src -> nvvideoconvert -> mux -> 
      # nvinfer -> nvvideoconvert -> nvosd -> video-renderer
      print("Linking elements in the Pipeline \n")
      source.link(caps_v4l2src)
      caps_v4l2src.link(vidconvsrc)
      vidconvsrc.link(nvvidconvsrc)
      nvvidconvsrc.link(caps_vidconvsrc)
  
      sinkpad = streammux.get_request_pad("sink_0")
      if not sinkpad:
          sys.stderr.write(" Unable to get the sink pad of streammux \n")
      srcpad = caps_vidconvsrc.get_static_pad("src")
      if not srcpad:
          sys.stderr.write(" Unable to get source pad of caps_vidconvsrc \n")
      srcpad.link(sinkpad)
      streammux.link(pgie)
      pgie.link(tracker)
      tracker.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)
  
      # Lets add probe to get informed of the meta data generated, we add probe to
      # the sink pad of the osd element, since by that time, the buffer would have
      # had got all the metadata.
      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__':
      sys.exit(main(sys.argv))
  
  