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.
121 lines
5.0 KiB
121 lines
5.0 KiB
8 months ago
|
import math
|
||
|
import queue
|
||
|
import cv2
|
||
|
import threading
|
||
|
import time
|
||
|
from myutils.ConfigManager import myCongif
|
||
|
import subprocess as sp
|
||
|
|
||
|
class VideoCaptureWithFPS:
|
||
|
'''视频捕获的封装类,是一个通道一个'''
|
||
|
def __init__(self, source):
|
||
|
self.source = source
|
||
|
self.width = None
|
||
|
self.height = None
|
||
|
# GStreamer --- 内存占用太高,且工作环境的部署也不简单
|
||
|
# self.pipeline = (
|
||
|
# "rtspsrc location=rtsp://192.168.3.102/live1 protocols=udp latency=100 ! "
|
||
|
# "rtph264depay !"
|
||
|
# " h264parse !"
|
||
|
# " avdec_h264 !"
|
||
|
# " videoconvert !"
|
||
|
# " appsink"
|
||
|
# )
|
||
|
#self.cap = cv2.VideoCapture(self.pipeline, cv2.CAP_GSTREAMER)
|
||
|
|
||
|
#FFmpeg --更加定制化的使用--但要明确宽高。。。
|
||
|
# self.ffmpeg_cmd = [
|
||
|
# 'ffmpeg',
|
||
|
# '-rtsp_transport', 'udp',
|
||
|
# '-i', 'rtsp://192.168.3.102/live1',
|
||
|
# '-f', 'image2pipe',
|
||
|
# '-pix_fmt', 'bgr24',
|
||
|
# '-vcodec', 'rawvideo', '-'
|
||
|
# ]
|
||
|
# self.pipe = sp.Popen(self.ffmpeg_cmd, stdout=sp.PIPE, bufsize=10 ** 8)
|
||
|
|
||
|
# opencv -- 后端默认使用的就是FFmpeg -- 不支持UDP
|
||
|
self.cap = cv2.VideoCapture(self.source)
|
||
|
if self.cap.isOpened(): #若没有打开成功,在读取画面的时候,已有判断和处理 -- 这里也要检查下内存的释放情况
|
||
|
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
||
|
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
||
|
print(self.width,self.height)
|
||
|
#self.fps = fps # 线程保持最大帧率的刷新画面---过高的帧率会影响CPU性能,但过地的帧率会造成帧积压
|
||
|
self.fps = math.ceil(self.cap.get(cv2.CAP_PROP_FPS)/float(myCongif.get_data("verify_rate")))-1 #向上取整。
|
||
|
#print(self.fps)
|
||
|
self.running = True
|
||
|
self.frame_queue = queue.Queue(maxsize=1)
|
||
|
#self.frame = None
|
||
|
#self.read_lock = threading.Lock()
|
||
|
self.thread = threading.Thread(target=self.update)
|
||
|
self.thread.start()
|
||
|
|
||
|
def update(self):
|
||
|
icount = 0
|
||
|
while self.running:
|
||
|
ret, frame = self.cap.read()
|
||
|
if not ret:
|
||
|
icount += 1
|
||
|
if icount > 5: #重连
|
||
|
self.cap.release()
|
||
|
self.cap = cv2.VideoCapture(self.source)
|
||
|
#self.cap = cv2.VideoCapture(self.pipeline, cv2.CAP_GSTREAMER)
|
||
|
if self.cap.isOpened():
|
||
|
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
||
|
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
||
|
print(self.width,self.height)
|
||
|
# self.fps = fps # 线程保持最大帧率的刷新画面---过高的帧率会影响CPU性能,但过地的帧率会造成帧积压
|
||
|
self.fps = math.ceil(
|
||
|
self.cap.get(cv2.CAP_PROP_FPS) / float(myCongif.get_data("verify_rate"))) -1 # 向上取整。
|
||
|
icount = 0
|
||
|
else:
|
||
|
#self.frame = None
|
||
|
sleep_time = myCongif.get_data("cap_sleep_time")
|
||
|
print(f"{self.source}视频流,将于{sleep_time}秒后重连!")
|
||
|
time.sleep(sleep_time)
|
||
|
continue
|
||
|
#resized_frame = cv2.resize(frame, (int(self.width / 2), int(self.height / 2)))
|
||
|
# with self.read_lock:
|
||
|
# self.frame = frame
|
||
|
if self.frame_queue.full():
|
||
|
try:
|
||
|
#print("采集线程丢帧")
|
||
|
self.frame_queue.get(timeout=0.01) #这里不get的好处是,模型线程不会有None
|
||
|
except queue.Empty: #为空不处理
|
||
|
pass
|
||
|
self.frame_queue.put(frame)
|
||
|
|
||
|
# 跳过指定数量的帧以避免积压
|
||
|
for _ in range(self.fps):
|
||
|
self.cap.grab()
|
||
|
# time.sleep(self.fps) #按照视频源的帧率进行休眠
|
||
|
#print("Frame updated at:",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
|
||
|
|
||
|
def read(self):
|
||
|
'''
|
||
|
直接读视频原画面
|
||
|
:param type: 0-大多数情况读取,1-绘制区域时读取一帧,但当前帧不丢,还是回队列
|
||
|
:return:
|
||
|
'''
|
||
|
# with self.read_lock:
|
||
|
# frame = self.frame.copy() if self.frame is not None else None
|
||
|
# if frame is not None:
|
||
|
# return True, frame
|
||
|
# else:
|
||
|
# return False, None
|
||
|
|
||
|
if not self.frame_queue.empty():
|
||
|
try:
|
||
|
frame = self.frame_queue.get(timeout=0.05)
|
||
|
except queue.Empty:
|
||
|
#print("cap-frame None")
|
||
|
return False, None
|
||
|
else:
|
||
|
#print("cap-frame None")
|
||
|
return False, None
|
||
|
return True, frame
|
||
|
|
||
|
def release(self):
|
||
|
self.running = False
|
||
|
self.thread.join()
|
||
|
self.cap.release()
|