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.
 
 
 
 

171 lines
6.3 KiB

import threading
from collections import deque
import numpy as np
import time
import copy
import queue
import cv2
import asyncio
class ChannelData:
def __init__(self, str_url, int_type, bool_run, deque_length,icount_max):
self.cap = None #该通道视频采集对象
self.work_th = None #该通道工作线程句柄
self.b_model = False #是否有运行模型线程
self.bool_run = bool_run # 线程运行标识
self.str_url = str_url #视频源地址
self.int_type = int_type #视频源类型,0-usb,1-rtsp,2-hksdk
self.icount_max = icount_max # 帧序列号上限
self.lock = threading.RLock() # 用于保证线程安全
self.deque_frame = deque(maxlen=deque_length) #视频缓冲区用于保存录像
self.last_frame = None # 保存图片数据
self.frame_queue = queue.Queue(maxsize=1)
self.counter = 0 #帧序列号--保存报警录像使用
#添加一帧图片
def add_deque(self, value):
self.deque_frame.append(value) #deque 满了以后会把前面的数据移除
#拷贝一份数据
def copy_deque(self):
return copy.deepcopy(self.deque_frame)
#获取最后一帧图片
def get_last_frame(self):
if self.b_model:
# with self.lock:
# frame = self.last_frame
# return frame
#if not self.frame_queue.empty():
try:
frame = self.frame_queue.get(timeout=0.3) #web传输没有做帧率控制了,可以超时时间长一点
except queue.Empty:
print("channel--frame None")
return None
# else:
# return None
return frame
else: #如果没有运行,直接从cap获取画面
if self.cap:
ret, frame = self.cap.read() # 除了第一帧,其它应该都是有画面的
if not ret:
print("channel--frame None")
return None
ret, frame_bgr_webp = cv2.imencode('.jpg', frame)
if not ret:
buffer_bgr_webp = None
else:
buffer_bgr_webp = frame_bgr_webp.tobytes()
return buffer_bgr_webp
return None
def update_last_frame(self,buffer):
if buffer:
# with self.lock:
# self.last_frame = None
# self.last_frame = buffer
# if self.frame_queue.full():
# try:
# print("channel--丢帧")
# self.frame_queue.get(timeout=0.01)
# except queue.Empty: #为空不处理
# pass
# self.frame_queue.put(buffer)
try:
self.frame_queue.put(buffer,timeout=0.05)
except queue.Full:
#print("channel--未插入")
pass
#帧序列号自增 一个线程中处理,不用加锁
def increment_counter(self):
self.counter += 1
if self.counter > self.icount_max:
self.counter = 0
def get_counter(self):
return self.counter
#清空数据,停止工作线程(若有 ,并删除deque 和 last_frame)
def clear(self):
start_time = time.time()
with self.lock:
if self.b_model: #b_model为true,说明开启了工作线程
self.bool_run = False
self.work_th.join() #等待通道对应的子线程,停止工作。
#time.sleep(1)
self.deque_frame.clear()
self.last_frame = None #二选一
self.frame_queue = queue.Queue(maxsize=1) #二选一
self.counter = 0
end_time = time.time()
execution_time = end_time - start_time
print(f"停止一个通道线程,花费了: {execution_time} seconds")
def stop_run(self):
self.bool_run = False
class ChannelManager:
def __init__(self):
self.channels = {}
self.cm_lock = threading.RLock() # 用于保证字典操作的线程安全
#增加节点
def add_channel(self, channel_id, str_url, int_type, bool_run, deque_length=10,icount_max=100000):
with self.cm_lock:
if channel_id in self.channels: #若已经有数据,先删除后再增加
self.channels[channel_id].clear() # 手动清理资源
del self.channels[channel_id]
ch_data = ChannelData(str_url, int_type, bool_run, deque_length, icount_max)
self.channels[channel_id] = ch_data
return ch_data
#删除节点
def delete_channel(self, channel_id): #需要验证资源的释放清空
with self.cm_lock:
if channel_id in self.channels:
self.channels[channel_id].clear() # 手动清理资源
self.channels[channel_id].cap.release()
del self.channels[channel_id]
#获取节点
def get_channel(self, channel_id):
with self.cm_lock:
return self.channels.get(channel_id)
#停止工作线程---要把视频采集线程停止掉
def stop_channel(self,channel_id):
with self.cm_lock:
if channel_id == 0:
# for clannel_id,clannel_data in self.channels.items():
# clannel_data.clear()
for clannel_data in self.channels:
clannel_data.clear() #停止工作线程,并清空业务数据
clannel_data.cap.release() #停止视频采集线程,并是否采集资源
self.channels.clear() #清空整个字典
else:
if channel_id in self.channels:
self.channels[channel_id].clear() # 手动清理资源
self.channels[channel_id].cap.release()
del self.channels[channel_id]
if __name__ == "__main__":
# 示例使用
manager = ChannelManager()
manager.add_channel('channel_1', 'test', 123, True, deque_length=5)
# 更新和读取操作
manager.update_channel_deque('channel_1', 'data1')
manager.update_channel_buffer('channel_1', np.array([[1, 2], [3, 4]]))
manager.increment_channel_counter('channel_1')
channel_data = manager.get_channel_data('channel_1')
print(channel_data)