3

I have a question about gstreamer. I made a streaming server using gst-rtsp-server.

  • IP cameras were connected to server with opencv videocapture function.
class VideoCapture:
    def __init__(self, rtsp_url):
        self.rtsp_url = rtsp_url
        self.cap = cv2.VideoCapture(self.rtsp_url)
        self.q = queue.Queue()
        self.ret = False
        t1 = threading.Thread(target=self._reader)
        t1.daemon = True
        t1.start()

  # read frames as soon as they are available, keeping only most recent one
    def _reader(self):
        while True:
          ret, frame = self.cap.read()
          self.ret = ret
          if not ret:
            self.cap.release()
            self.cap = cv2.VideoCapture(self.rtsp_url)
            print("Reconnect...")
            self.ret = ret
          if not self.q.empty():
            try:
              self.q.get_nowait()   # discard previous (unprocessed) frame
            except queue.Empty:
              pass
          self.q.put(frame)

    def read(self):
        return self.ret, self.q.get() 

class ConnectVideo(Cfg):
    def __init__(self, rtsp_url, model, ch_id, shm, arr, sem):
        super(ConnectVideo, self).__init__(ch_id)
        self.video = VideoCapture(rtsp_url)
        time.sleep(1)
        self.chsch = self.check_week()
        self.ch_id = ch_id
        self.model = model
        self.analysis = Analysis(self.model, self.ch_id)

        t_svr = threading.Thread(target = self.svr_check)
        t_svr.daemon = True
        t_svr.start()       

        t_gst = threading.Thread(target = self.get_frame)  # create thread to detect about changed channel info
        t_gst.daemon = True
        t_gst.start()

        t_chreset = threading.Thread(target = self.chreset, args = (shm, arr, sem))  # create thread to detect about changed channel info
        t_chreset.daemon = True
        t_chreset.start()

        GstServer(self.ch_id)
        loop.run()
  • The server is analyzing captured frame and return frames.
def get_frame(self):
    while True:
        self.current_time = time.time() # current time
        self.time_per_frame = self.current_time - self.prev_time  # processing time for one frame
        self.prev_time = time.time()  # initialize time with current time
        self.fps_queue.append(1/self.time_per_frame)  # append the fps for one frame

        if len(self.fps_queue) == 30: # average fps queue values
          Cfg.fps = (sum(self.fps_queue, 0.0)/len(self.fps_queue))
          self.fps_queue.pop()

        ret, frame = self.video.read()  # read the video frame by using thread

        if ret: # if the frame return value is True, execute the run method of analysis module
        ori_frame = frame.copy()
        if self.chsel[0][4] == True:
          CRUD.updateDB(self, schema='public', table='channel_status', column='cctv_status', value=0, condition=f"where ch_id = '{self.ch_id}'")
        if Cfg.on_schedule:  # if current time isn't included in non-schedule time, analyze the frame
            frame, _ = self.analysis.run(frame, Cfg.fps, self.objsel, self.settime[0][4])  
            self.pre_frame = frame
        else:
            self.pre_frame = frame
  • An returned frame is attempted to stream via Gstreamer-rtsp-server with "appsrc".
import re
import gi

from config import Cfg
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GObject, GstRtspServer
GObject.threads_init()
Gst.init(None)

class SensorFactory(GstRtspServer.RTSPMediaFactory):
    def __init__(self, **properties):
        super(SensorFactory, self).__init__(**properties)
        self.launch_string = 'appsrc name=source is-live=true block=true format=GST_FORMAT_TIME ' \
                            'caps=video/x-raw,format=BGR,width='+str(Cfg.width)+',height='+str(Cfg.height)+',framerate={}/1 ' \
                            '! videoconvert ! video/x-raw,format=I420 ' \
                            '! x264enc speed-preset=ultrafast tune=zerolatency ' \
                            '! rtph264pay config-interval=1 name=pay0 pt=96'.format(30)

    def on_need_data(self, src, length):
        frame = Cfg.frame
        data = frame.tobytes()
        buf = Gst.Buffer.new_allocate(None, len(data), None)
        buf.fill(0, data)
        duration = 1 / 30 * Gst.SECOND  # duration of a frame in nanoseconds
        buf.duration = duration

        timestamp = Cfg.number_frames * duration
        
        buf.pts = int(timestamp)
        buf.dts = int(timestamp)
        buf.offset = timestamp

        Cfg.number_frames += 1
        push_buffer_response = src.emit('push-buffer', buf)

        if push_buffer_response != Gst.FlowReturn.OK:
            print(push_buffer_response)

        Cfg.current_on += 1

    def do_create_element(self, rtsp_url):
        return Gst.parse_launch(self.launch_string)

    def do_configure(self, rtsp_media):
        Cfg.number_frames = 0
        appsrc = rtsp_media.get_element().get_child_by_name('source')
        appsrc.connect('need-data', self.on_need_data)

class GstServer(GstRtspServer.RTSPServer):
    def __init__(self, ch_id, **properties):
        super(GstServer, self).__init__(**properties)
        self.cam_number = int(*re.findall('\d+', ch_id)) - 1
        self.port = 8550 + self.cam_number
        self.rtspServer = GstRtspServer.RTSPServer()
        self.rtspServer.set_service(str(self.port))
        factory = SensorFactory()
        factory.set_shared(True)
        mountPoints = self.rtspServer.get_mount_points()
        mountPoints.add_factory(f'/stream{self.cam_number}', factory)

        self.rtspServer.attach(None)
        print('rtsp-server started and ready to accept connections')

One client works well... But I am getting errors like "Assertion fctx->async_lock failed at libavcodec/pthread_frame.c:155" when trying to use multiple clients.

What should I do for this? Any help any kind of help is well appreciated !

mars
  • 31
  • 2

0 Answers0