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

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()