You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
8.3 KiB
267 lines
8.3 KiB
import asyncio
|
|
import re
|
|
import time
|
|
from threading import Thread
|
|
|
|
# import cv2
|
|
import numpy as np
|
|
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, pyqtSlot, QThread, pyqtProperty
|
|
# from PyQt5.QtGui import QImage
|
|
# from PyQt5 import QtGui
|
|
|
|
from . import vision_service
|
|
|
|
|
|
class VideoStreamer(QObject):
|
|
newImage = pyqtSignal(object, int, int)
|
|
newRawImage = pyqtSignal(object)
|
|
reconnectInitiated = pyqtSignal()
|
|
reconnect = pyqtSignal()
|
|
camChangeStart = pyqtSignal()
|
|
camChangeEnd = pyqtSignal(int)
|
|
isCamChangingChanged = pyqtSignal(bool)
|
|
camReconnected = pyqtSignal(int)
|
|
beginOpenVideoCamera = pyqtSignal(str)
|
|
|
|
def __init__(self, parent: QObject = None):
|
|
super(QObject, self).__init__(parent)
|
|
self.__is_changing_camera = False
|
|
self.__stopped = False
|
|
self.__grabbed = False
|
|
self.__is_reconnecting = False
|
|
|
|
self.__frame = np.array([])
|
|
self.__cap = None
|
|
self.__tmp_cap = None
|
|
self.__rtsp_link = ''
|
|
self.__tmp_rtsp_link = ''
|
|
self.ip = ''
|
|
|
|
self.tUpdate = None
|
|
self.reconnectTimer = None
|
|
self.t = None
|
|
|
|
|
|
|
|
@pyqtProperty(bool, notify=isCamChangingChanged)
|
|
def isChangingCamera(self):
|
|
return self.__is_changing_camera
|
|
|
|
@pyqtSlot()
|
|
def beginReconnect(self):
|
|
print('RECONNECTING')
|
|
self.stopVideoCamera()
|
|
self.__is_reconnecting = True
|
|
# QTimer.singleShot(5000, self.reconnectVideo)
|
|
t = Thread(target=self.reconnectVideo, args=())
|
|
t.daemon = True
|
|
t.start()
|
|
|
|
# @pyqtSlot()
|
|
def reconnectVideo(self):
|
|
rtsp_link = self.__tmp_rtsp_link
|
|
print(f'reconnecting to {rtsp_link}')
|
|
self.stopVideoCamera()
|
|
while True:
|
|
self.reconnect.emit()
|
|
cap = vision_service.vision_service(rtsp_link)
|
|
cap.start_framing()
|
|
time.sleep(5)
|
|
if cap.get_is_framing():
|
|
print('cam is online')
|
|
self.camChangeEnd.emit(True)
|
|
|
|
time.sleep(0.1)
|
|
|
|
self.__cap = None
|
|
|
|
fps = cap.get_fps()
|
|
if fps == 0:
|
|
if not cap.get_is_framing():
|
|
return False
|
|
else:
|
|
fps = 60
|
|
|
|
self.__stopped = True
|
|
self.tUpdate.stop()
|
|
self.reconnectTimer.stop()
|
|
|
|
self.__cap = cap
|
|
self.__rtsp_link = rtsp_link
|
|
|
|
self.t = Thread(target=self.update, args=())
|
|
self.t.daemon = True
|
|
self.camReconnected.emit(int(1000 // fps))
|
|
self.__stopped = False
|
|
|
|
if not self.t.is_alive():
|
|
self.t.start()
|
|
|
|
self.__is_reconnecting = False
|
|
return True
|
|
|
|
def update(self):
|
|
while True:
|
|
if self.__stopped is True:
|
|
print('self.__stopped is True:')
|
|
self.__frame = None
|
|
break
|
|
|
|
if not self.__cap:
|
|
print('not self.__cap')
|
|
time.sleep(0.1)
|
|
continue
|
|
|
|
if self.__cap.get_is_framing():
|
|
self.__frame = self.__cap.get_frame()
|
|
time.sleep(0.066)
|
|
else:
|
|
time.sleep(0.1)
|
|
if not self.__is_reconnecting:
|
|
print('not self.__is_reconnecting')
|
|
self.__is_reconnecting = True
|
|
self.reconnectInitiated.emit() # TODO send error to client
|
|
# if self.__frame is False:
|
|
# print('[Exiting] No more frames to read')
|
|
# self.__stopped = True
|
|
# break
|
|
# self.__cap.release()
|
|
|
|
@pyqtSlot()
|
|
def run(self) -> None:
|
|
print('starting QThread')
|
|
self.tUpdate = QTimer(self)
|
|
self.reconnectTimer = QTimer(self)
|
|
# self.tUpdate.moveToThread(self)
|
|
# self.reconnectTimer.moveToThread(self)
|
|
self.t = Thread(target=self.update, args=())
|
|
self.t.daemon = True # daemon threads run in background
|
|
|
|
self.tUpdate.timeout.connect(self.streamVideo)
|
|
self.reconnectTimer.timeout.connect(self.reconnectVideo)
|
|
self.reconnectInitiated.connect(self.beginReconnect)
|
|
self.camReconnected.connect(self.tUpdate.start)
|
|
self.beginOpenVideoCamera.connect(self.openVideoCamera)
|
|
# self.exec_()
|
|
|
|
@pyqtSlot()
|
|
def streamVideo(self):
|
|
pass
|
|
# if (self.__frame is not None) and self.__frame.size != 0:
|
|
# height, width, channel = self.__frame.shape
|
|
# bytesPerLine = 3 * width
|
|
# qImg = QImage(self.__frame.data, width, height, bytesPerLine, QImage.Format_BGR888)
|
|
# self.newRawImage.emit(self.__frame)
|
|
# self.newImage.emit(qImg, width, height)
|
|
|
|
def get_frame(self):
|
|
return self.__frame
|
|
|
|
@pyqtSlot(result=bool)
|
|
def connectCam(self):
|
|
print('CONNECTING CAM')
|
|
fps = self.__tmp_cap.get_fps()
|
|
print('NEW CAP FPS:', fps)
|
|
if fps == 0:
|
|
if not self.__tmp_cap.get_is_framing():
|
|
return False
|
|
else:
|
|
fps = 60
|
|
self.__stopped = True
|
|
self.tUpdate.stop()
|
|
self.reconnectTimer.stop()
|
|
|
|
self.__rtsp_link = self.__tmp_rtsp_link
|
|
self.__cap = self.__tmp_cap
|
|
self.ip = re.findall("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", self.__rtsp_link)[0]
|
|
|
|
self.t = Thread(target=self.update, args=())
|
|
self.t.daemon = True
|
|
self.tUpdate.start(int(1000 // fps))
|
|
self.__stopped = False
|
|
if not self.t.is_alive():
|
|
self.t.start()
|
|
self.__is_changing_camera = False
|
|
self.isCamChangingChanged.emit(self.__is_changing_camera)
|
|
return True
|
|
|
|
@pyqtSlot(result=bool)
|
|
def checkCam(self):
|
|
print('CHECKING CAMERA')
|
|
if self.__tmp_cap.get_is_framing():
|
|
print('camera is framing')
|
|
self.stopVideoCamera()
|
|
self.camChangeEnd.emit(True)
|
|
QTimer.singleShot(100, self.connectCam)
|
|
return True
|
|
else:
|
|
print('camera is not framing')
|
|
self.camChangeEnd.emit(False)
|
|
self.__is_changing_camera = False
|
|
self.isCamChangingChanged.emit(self.__is_changing_camera)
|
|
return False
|
|
|
|
@pyqtSlot(str, result=bool)
|
|
def changeCamera(self, rtsp_link):
|
|
self.__is_changing_camera = True
|
|
self.isCamChangingChanged.emit(self.__is_changing_camera)
|
|
self.__tmp_rtsp_link = rtsp_link
|
|
self.__tmp_cap = vision_service.vision_service(rtsp_link)
|
|
self.__tmp_cap.start_framing()
|
|
QTimer.singleShot(5000, self.checkCam)
|
|
self.camChangeStart.emit()
|
|
return True
|
|
# except:
|
|
# print('cannot stop framing')
|
|
# return False
|
|
|
|
@pyqtProperty(str)
|
|
def rtspLink(self):
|
|
return self.__rtsp_link
|
|
|
|
@pyqtSlot(result=bool)
|
|
@pyqtSlot(str, result=bool)
|
|
def openVideoCamera(self, rtsp_link: str = None):
|
|
if self.__cap is None:
|
|
if rtsp_link is not None:
|
|
self.__tmp_rtsp_link = rtsp_link
|
|
print('rtsp_link:', self.__tmp_rtsp_link)
|
|
self.__tmp_cap = vision_service.vision_service(self.__tmp_rtsp_link)
|
|
self.__tmp_cap.start_framing()
|
|
QTimer.singleShot(5000, self.checkCam)
|
|
self.camChangeStart.emit()
|
|
return True
|
|
return False
|
|
|
|
@pyqtSlot()
|
|
def clearVideoCamera(self):
|
|
self.__cap = None
|
|
self.__rtsp_link = ''
|
|
print('clearVideoCamera finished')
|
|
|
|
@pyqtSlot(result=bool)
|
|
def stopVideoCamera(self):
|
|
self.__stopped = True
|
|
self.t = Thread(target=self.update, args=())
|
|
self.t.daemon = True
|
|
print('stopping video camera')
|
|
self.tUpdate.stop()
|
|
self.reconnectTimer.stop()
|
|
if not self.__is_reconnecting:
|
|
QTimer.singleShot(100, self.clearVideoCamera)
|
|
try:
|
|
if self.__cap:
|
|
self.__cap.stop_framing()
|
|
return True
|
|
except Exception as e:
|
|
print('cannot stop framing', e)
|
|
return False
|
|
|
|
def __del__(self):
|
|
# self.__cap.release()
|
|
try:
|
|
self.__cap.stop_framing()
|
|
except:
|
|
print('cannot stop framing')
|
|
self.tUpdate.stop()
|
|
self.__stopped = True
|