import cv2 import threading import base64 from myutils.ConfigManager import myCongif from myutils.MyLogger_logger import LogHandler #独立模型线程 from core.ModelNodeManager import ModelNodeManger #from core.ModelNode import ModelNode from core.ChannelData import ChannelData #其实ChannelNode会更加贴切一些 ''' 通道对象管理类,只针对通道节点的维护,和工作线程的开启和停止, ChannelData的操作必须维护在ChannelManager里面!不能输出ChannelData对象! ''' class ChannelManager: def __init__(self): self._channels = {} #channel_id ChannelData(C_Node) self.cm_lock = threading.RLock() # 用于保证字典操作的线程安全 self.logger = LogHandler().get_logger("ChannelManager") # 独立Model_th相关参数 --- modelNode 用一个类封装下model线程和其相关参数 self.model_list = {} # model_id -- modelNode self.workType = int(myCongif.get_data("workType")) self.device_id = myCongif.get_data("device_id") #增加节点 def add_channel(self, channel_id,deque_length,icount_max,warnM): ret = False with self.cm_lock: if channel_id in self._channels: #若已经有数据,先删除后再增加 self._channels[channel_id].stop_work(0) # 停止工作 del self._channels[channel_id] if self.workType == 2: # 若有model线程停止了,则删除该model节点 self.delModelNode() #channel_id,deque_length,icount_max,warnM ch_data = ChannelData(channel_id, deque_length, icount_max,warnM) self._channels[channel_id] = ch_data ret = True return ret #删除节点 def delete_channel(self, channel_id): #需要验证资源的释放清空 '''删除节点,包含了停止该节点工作线程''' ret = True with self.cm_lock: if channel_id == 0: for clannel_data in self._channels: clannel_data.stop_work(0) self._channels.clear() #清空节点 else: if channel_id in self._channels: self._channels[channel_id].stop_work(0) #停止工作 del self._channels[channel_id] if self.workType == 2: #若有model线程停止了,则删除该model节点 self.delModelNode() return ret #开始工作线程 def start_channel(self,channel_id,cap_data,model_data,schedule,type): ''' 启动通道的工作线程 -- 启动应该没有一下子启动所有 :param channel_id: 启动通道的ID channel_id == 0的情况已经在上一层处理了,这里不会有0 :param cap_data: [source,type] :param model_data: 跟该通道关联的模型数据 :param schedule :param type: 0-启动所有工作线程,1-启动CAP采集线程,2-启动model工资线程 :return: ''' ret = False with self.cm_lock: if channel_id in self._channels: c_node = self._channels[channel_id] model_nodeM = None if self.workType == 2 and type !=1: #需要确保当type!=1时,model_data必须有数据 -- 调用时已经有判断 model_nodeM = self.CreateModelNode(model_data[0], model_data[5], channel_id) ret = c_node.start_work(cap_data,model_data,schedule,type,model_nodeM) return ret #停止工作线程---要把视频采集线程停止掉 def stop_channel(self,channel_id,type): #9-10截止目前就重启模型线程时用到该函数(channel_id,2) ''' 停止通道的工作线程 :param channel_id: 0-停止所有通道的工作线程,其他值为具体停止哪个工作线程 :param type: 0-停止所有工作线程,1-停止CAP采集线程,2-停止model工资线程 :return: ''' with self.cm_lock: ret = False if channel_id == 0: # for clannel_id,clannel_data in self.channels.items(): for clannel_data in self._channels: clannel_data.stop_work(type) ret = True else: if channel_id in self._channels: self._channels[channel_id].stop_work(type) ret =True if self.workType == 2: #若有model线程停止了,则删除该model节点 self.delModelNode() return ret def get_channel_data(self,channel_id): cdata = None if channel_id in self._channels: cdata = self._channels[channel_id] return cdata def cm_get_last_frame(self,channel_id): #这里如果加锁的话,阻塞会比较厉害,但具体程度也需要验证。 frame = None if channel_id in self._channels: try: frame = self._channels[channel_id].get_last_frame() except Exception as e: print(e) return frame def cm_get_cap_frame(self,channel_id): img_base64 = None if channel_id in self._channels: channel_data = self._channels[channel_id] if channel_data.cap: try: for i in range(5): ret, frame = channel_data.cap.read() if ret: ret, frame_bgr_webp = cv2.imencode('.jpg', frame) if ret: # 将图像数据编码为Base64 img_base64 = base64.b64encode(frame_bgr_webp).decode('utf-8') break except Exception as e: print(e) return img_base64 '''模型独立线程修改2024-9-9,要求是双模式兼容''' '''2024-10-13修改独立线程为独立进程---acl初始化需要在子进程中初始化 -- 该方案无法兼容旧版本''' '''2025-10-24修改动态通道数量,cm --> mn_m -->model_nodel''' def CreateModelNode(self, model_id, model_path, channel_id): if model_id in self.model_list: modelNM = self.model_list[model_id] else: modelNM = ModelNodeManger(self.device_id,model_id,model_path) self.model_list[model_id] = modelNM #modelN = ModelNode(self.device_id, model_path,channel_id) return modelNM def delModelNode(self): #关于modelnodel :1.考虑modelnode是否可以不删除,清空inmq即可,2.mdel_list是否需要加锁。#? #return for model_id, modelNodeM in self.model_list.items(): if modelNodeM.ch_count == 0: del self.model_list[model_id] if __name__ == "__main__": # 示例使用 pass