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 !