Quellcode durchsuchen

V0.2
1、根据算法创建任务线程的线程基本完成了

Apple vor 7 Monaten
Ursprung
Commit
76cf6e2475

+ 151 - 3
SecurePlayAuxServer/GlobalInfo/GlobalInfo.cpp

@@ -1,5 +1,6 @@
 #include "GlobalInfo.h"
 
+#include <QSettings>
 
 /* ====================================================================================
  * *******************************    全局变量定义    **********************************
@@ -67,6 +68,26 @@ bool DeviceInfo::isEqualAlgorithmInfo(const std::vector<AlgorithmInfo>& other)
  * **************************    ListActionInfo成员函数    ****************************
  * ====================================================================================*/
 
+
+/* 对比除摄像机外的基础信息是否相等 */
+bool ActionInfo::isEqualBaseInfo(const ActionInfo& other)
+{
+    if(ChannelID != other.ChannelID) {
+        return false;
+    }
+    if(RoomID != other.RoomID) {
+        return false;
+    }
+    if(ActionID != other.ActionID) {
+        return false;
+    }
+    if(RoomType != other.RoomType) {
+        return false;
+    }
+    return true;
+}
+
+
 /* 添加关联信息,会自动进行重复判断,如果已有相同的信息,则跳过 */
 bool ListActionInfo::insertActionInfo(ActionInfo* info)
 {
@@ -98,6 +119,41 @@ bool ListActionInfo::deleteActionInfo(ActionInfo* info)
     return true;
 }
 
+/* 给算法添加摄像机,原有的会被替换掉 */
+bool ListActionInfo::addActionCamera(ActionInfo* pInfo)
+{
+    auto pActionInfo = findActionIDInListNoCamera(pInfo);
+    if(pActionInfo != nullptr)
+    {
+        pActionInfo->CameraID = pInfo->CameraID;
+    }
+    return true;
+}
+
+/* 清空算法中的摄像机信息 */
+void ListActionInfo::clearCameraList()
+{
+    for(auto& it0 : listActionInfo)
+    {
+        it0->CameraID = -1;
+    }
+}
+
+/* 清空设置成STOP或ERROR的Action */
+void ListActionInfo::clearStopAction()
+{
+    for(auto it0 = listActionInfo.begin(); it0 != listActionInfo.end();)
+    {
+        if(( (*it0)->RunState == RunTimeState::RUN_STATE_STOP) || ((*it0)->RunState == RunTimeState::RUN_STATE_ERROR))
+        {
+            delete *it0;
+            it0 = listActionInfo.erase(it0);
+        }else {
+            ++it0;
+        }
+    }
+}
+
 /* 查找算法ID是否已在列表中 */
 ActionInfo* ListActionInfo::findActionInList(ActionInfo* pInfo)
 {
@@ -111,6 +167,20 @@ ActionInfo* ListActionInfo::findActionInList(ActionInfo* pInfo)
     return nullptr;
 }
 
+/* 查找算法ID是否在列表中,这里查找不会对比摄像机ID */
+ActionInfo* ListActionInfo::findActionIDInListNoCamera(ActionInfo* pInfo)
+{
+    for(const auto& it0 : listActionInfo)
+    {
+        if(it0->isEqualBaseInfo(*pInfo))
+        {
+            return it0;
+        }
+    }
+    return nullptr;
+}
+
+
 /* 清空容器 */
 void ListActionInfo::clear()
 {
@@ -130,7 +200,7 @@ void ListActionInfo::clear()
 bool ListRoomActionInfo::insertRoomActionInfo(const RoomActionInfo& info)
 {
     /* 先判断是否已经在列表中了 */
-    if(findActionIDInList(info.RoomID, info.ActionID) == nullptr)
+    if(findActionIDInList(info.ChannelID, info.RoomID, info.ActionID) == nullptr)
     {
         RoomActionInfo* pRoomActionInfo = new RoomActionInfo;
         *pRoomActionInfo = info;
@@ -141,10 +211,10 @@ bool ListRoomActionInfo::insertRoomActionInfo(const RoomActionInfo& info)
 }
 
 /* 添加关联信息,会自动进行重复判断,如果已有相同的room和action关联信息,则跳过 */
-bool ListRoomActionInfo::insertRoomActionInfo(const int RoomID, const std::string& strActionID)
+bool ListRoomActionInfo::insertRoomActionInfo(const int ChannelID, const int RoomID, const std::string& strActionID)
 {
     /* 先判断是否已经在列表中了 */
-    if(findActionIDInList(RoomID, strActionID) == nullptr)
+    if(findActionIDInList(ChannelID, RoomID, strActionID) == nullptr)
     {
         RoomActionInfo* pRoomActionInfo = new RoomActionInfo;
         pRoomActionInfo->RoomID = RoomID;
@@ -154,6 +224,26 @@ bool ListRoomActionInfo::insertRoomActionInfo(const int RoomID, const std::strin
     return true;
 }
 
+/* 删除一个容器,注意,这个不能在别的for循环中删除,只能单独删除 */
+bool ListRoomActionInfo::deleteRoomActionInfo(RoomActionInfo* pInfo)
+{
+    if(pInfo == nullptr)
+    {
+        return false;
+    }
+    for(auto it0 = listRoomActionInfo.begin(); it0 != listRoomActionInfo.end(); ++it0)
+    {
+        if(*it0 == pInfo)
+        {
+            listRoomActionInfo.erase(it0);
+            delete pInfo;
+            pInfo = nullptr;
+            return true;
+        }
+    }
+    return false;
+}
+
 /* 清空容器 */
 void ListRoomActionInfo::clear()
 {
@@ -184,6 +274,30 @@ void ListRoomActionInfo::addActionInfo(const ActionInfo& info)
     }
 }
 
+/* 清空算法对应的摄像机列表 */
+void ListRoomActionInfo::clearCameraList()
+{
+    for(auto& it0 : listRoomActionInfo)
+    {
+        it0->listCameraID.clear();
+    }
+}
+
+/* 清理设置为STOP或者ERROR的RoomAction */
+void ListRoomActionInfo::clearStopRoomAction()
+{
+    for(auto it0 = listRoomActionInfo.begin(); it0 != listRoomActionInfo.end();)
+    {
+        if(( (*it0)->RunState == RunTimeState::RUN_STATE_STOP) || ((*it0)->RunState == RunTimeState::RUN_STATE_ERROR))
+        {
+            delete *it0;
+            it0 = listRoomActionInfo.erase(it0);
+        }else {
+            ++it0;
+        }
+    }
+}
+
 /* 查找算法ID是否已在列表中 */
 RoomActionInfo* ListRoomActionInfo::findActionIDInList(const int chnID, const int RoomID, const std::string& strActionID)
 {
@@ -196,3 +310,37 @@ RoomActionInfo* ListRoomActionInfo::findActionIDInList(const int chnID, const in
     }
     return nullptr;
 }
+
+
+/* ====================================================================================
+ * **************************    GlobalConfig成员函数    ******************************
+ * ====================================================================================*/
+
+GlobalConfig::GlobalConfig()
+{
+
+}
+
+/* 读取配置文件 */
+bool GlobalConfig::readConfig(const QString& strConfigFile)
+{
+    QSettings settings(strConfigFile, QSettings::IniFormat);
+    settings.setIniCodec("UTF-8");
+
+    AppPeopleOnWork = settings.value("APPPEPOLEONWORK").toString().toInt();         /* 离岗时间 */
+    AppBadthing = settings.value("APPBADTHING").toString().toInt();                 /* 违禁物品出现的时间 */
+    AppBadMan = settings.value("APPBADMAN").toString().toInt();                     /* 非法入侵 */
+    AppTired = settings.value("APPTIRED").toString().toInt();                       /* 疲劳检测时间 */
+    AppPeopleCont = settings.value("APPPEOPLECONT").toString().toInt();             /* 人员聚集时间 */
+    AppPlayPhone = settings.value("APPPLAYPHONE").toString().toInt();               /* 玩手机识别 */
+    AppMouse = settings.value("APPMOUSE").toString().toInt();                       /* 手势识别 */
+    AppMask = settings.value("APPMASK").toString().toInt();                         /* 戴口罩识别 */
+
+    CheckSet = settings.value("CHECKSET").toString().toInt();                       /* 服务端多久检测一次配置 */
+    EventTimeValid = settings.value("EVENTTIMEVALID").toString().toInt();           /* 事件时间有效期 */
+
+    Key = settings.value("Key").toString().toStdString();                           /* Key */
+    Secret = settings.value("Secret").toString().toStdString();                     /* Secret */
+
+    return true;
+}

+ 83 - 7
SecurePlayAuxServer/GlobalInfo/GlobalInfo.h

@@ -108,6 +108,7 @@ struct DeviceInfo
     }
     /* 对比是否相等 */
     bool operator==(const DeviceInfo& other);
+
     /* 对比设备关联的算法信息是否相等 */
     bool isEqualAlgorithmInfo(const std::vector<AlgorithmInfo>& other);
 };
@@ -214,6 +215,15 @@ struct RoomCameraInfo
     }
 };
 
+/* 线程运行时的状态 */
+enum class RunTimeState
+{
+    RUN_STATE_INIT = 0,         /* 初始化 */
+    RUN_STATE_RUN,              /* 运行 */
+    RUN_STATE_STOP,             /* 停止 */
+    RUN_STATE_ERROR,            /* 错误 */
+    RUN_STATE_NONE              /* 无状态 */
+};
 
 /**
  * @brief 单个算法信息,包括包含的摄像机,房间、频率信息
@@ -221,6 +231,7 @@ struct RoomCameraInfo
  */
 struct ActionInfo
 {
+    RunTimeState RunState;          /* 线程运行状态 */
     int ChannelID;                  /* 通道ID */
     int RoomID;                     /* 房间ID */
     int CameraID;                   /* 摄像机ID */
@@ -228,7 +239,15 @@ struct ActionInfo
     std::string ActionID;           /* 算法ID */
     std::string strRoomName;        /* 房间名称 */
 
-    ActionInfo() = default;
+    ActionInfo() {
+        RunState = RunTimeState::RUN_STATE_INIT;
+        ChannelID = -1;
+        RoomID = -1;
+        CameraID = -1;
+        RoomType = -1;
+        ActionID = "";
+        strRoomName = "";
+    }
     ActionInfo& operator=(const ActionInfo& other) {
         if (this != &other) {
             ChannelID = other.ChannelID;
@@ -240,7 +259,7 @@ struct ActionInfo
         }
         return *this;
     }
-    /* 对比 */
+    /* 对比是否相等,这个需要完全相等,包括算法信息和摄像机信息 */
     bool operator==(const ActionInfo& other) const {
         if(ChannelID != other.ChannelID) {
             return false;
@@ -259,11 +278,13 @@ struct ActionInfo
         }
         return true;
     }
+    /* 对比除摄像机外的基础信息是否相等 */
+    bool isEqualBaseInfo(const ActionInfo& other);
     
 };
 
 /**
- * @brief 算法信息列表
+ * @brief 算法信息列表,这个列表既可以存储房间和算法ID的关联信息,也可以用来存储运行线程的信息
  * 
  */
 class ListActionInfo
@@ -275,8 +296,17 @@ public:
     bool insertActionInfo(ActionInfo* info);
     /* 删除信息 */
     bool deleteActionInfo(ActionInfo* info);
+    /* 给算法添加摄像机,原有的会被替换掉 */
+    bool addActionCamera(ActionInfo* pInfo);
+    /* 清空算法中的摄像机信息 */
+    void clearCameraList();
+    /* 清空设置成STOP或ERROR的Action */
+    void clearStopAction();
     /* 查找算法ID是否已在列表中 */
     ActionInfo* findActionInList(ActionInfo* pInfo);
+    /* 查找算法ID是否在列表中,这里查找不会对比摄像机ID */
+    ActionInfo* findActionIDInListNoCamera(ActionInfo* pInfo);
+    
     /* 获取容器 */
     std::list<ActionInfo*>& getData() {
         return listActionInfo;
@@ -289,11 +319,12 @@ public:
 };
 
 /**
- * @brief 房间ID和算法ID关联的信息,里面也包含该算法使用了哪些摄像机
+ * @brief 算法信息,以房间分类,算法包含在这干房间内所需要的摄像机ID
  * 
  */
 struct RoomActionInfo
 {
+    RunTimeState RunState;          /* 线程运行状态 */
     int ChannelID;                  /* 通道ID */
     int RoomID;                     /* 房间ID */
     int RoomType;                   /* 房间类型 */
@@ -301,9 +332,19 @@ struct RoomActionInfo
     std::string strRoomName;        /* 房间名称 */
     std::list<int> listCameraID;    /* 摄像机ID */
 
-    RoomActionInfo() = default;
+    RoomActionInfo() {
+        RunState = RunTimeState::RUN_STATE_INIT;
+        ChannelID = -1;
+        RoomID = -1;
+        RoomType = -1;
+        ActionID = "";
+        strRoomName = "";
+        listCameraID.clear();
+    }
     RoomActionInfo(const RoomActionInfo& other)
-        : ChannelID(other.ChannelID), RoomID(other.RoomID), RoomType(other.RoomType), ActionID(other.ActionID), strRoomName(other.strRoomName), listCameraID(other.listCameraID) {}
+        : ChannelID(other.ChannelID), RoomID(other.RoomID), 
+        RoomType(other.RoomType), ActionID(other.ActionID), 
+        strRoomName(other.strRoomName), listCameraID(other.listCameraID) {}
     RoomActionInfo& operator=(const RoomActionInfo& other) {
         if (this != &other) {
             ChannelID = other.ChannelID;
@@ -328,13 +369,20 @@ public:
     /* 添加关联信息,会自动进行重复判断,如果已有相同的room和action关联信息,则跳过 */
     bool insertRoomActionInfo(const RoomActionInfo& info);
     /* 添加关联信息,会自动进行重复判断,如果已有相同的room和action关联信息,则跳过 */
-    bool insertRoomActionInfo(const int RoomID, const std::string& strActionID);
+    bool insertRoomActionInfo(const int ChannelID, const int RoomID, const std::string& strActionID);
+    /* 删除一个容器,注意,这个不能在别的for循环中删除,只能单独删除 */
+    bool deleteRoomActionInfo(RoomActionInfo* pInfo);
     /* 清空容器 */
     void clear();
     /* 添加算法信息,根据传入的算法信息,自动将其加入到对应的容器中 */
     void addActionInfo(const ActionInfo& info);
+    /* 清空算法对应的摄像机列表 */
+    void clearCameraList();
+    /* 清理设置为STOP或者ERROR的RoomAction */
+    void clearStopRoomAction();
     /* 查找算法ID是否已在列表中 */
     RoomActionInfo* findActionIDInList(const int chnID, const int RoomID, const std::string& strActionID);
+    
     /* 获取容器 */
     std::list<RoomActionInfo*>& getData() {
         return listRoomActionInfo;
@@ -345,6 +393,34 @@ public:
 };
 
 
+/**
+ * @brief 读取配置文件
+ * 
+ */
+ class GlobalConfig
+ {
+public:
+    GlobalConfig();
+    ~GlobalConfig() = default;
+
+    /* 读取配置文件 */
+    bool readConfig(const QString& strConfigFile);
+    
+    int AppPeopleOnWork;        /* 离岗时间 */
+    int AppBadthing;            /* 违禁物品出现的时间 */
+    int AppBadMan;              /* 非法入侵 */
+    int AppTired;               /* 疲劳检测时间 */
+    int AppPeopleCont;          /* 区域人员统计 */
+    int AppPlayPhone;           /* 玩手机识别 */
+    int AppMouse;               /* 老鼠识别 */
+    int AppMask;                /* 戴口罩识别 */
+
+    int CheckSet;               /* 服务端多久检测一次配置 */
+    int EventTimeValid;         /* 事件时间有效期 */
+
+    std::string Key;            /* Key */
+    std::string Secret;         /* Secret */
+ };
 
 
 

+ 215 - 56
SecurePlayAuxServer/SPAServer.cpp

@@ -82,9 +82,9 @@ void SPAServer::threadFromSuperBrain()
         vecAlgNewInfo.clear();
         vecDevNewInfo.clear();
         /* 更新算法详细信息 */
-        m_mutexCameraActionID.lock();
+        m_mutexActionInfo.lock();
         m_toEQMDataBase.getActionInfo(m_listActionInfo);
-        m_mutexCameraActionID.unlock();
+        m_mutexActionInfo.unlock();
         std::this_thread::sleep_for(std::chrono::seconds(10));
     }
 }
@@ -137,27 +137,27 @@ bool SPAServer::processDeviceInfo(std::vector<DeviceInfo> vecNewDevInfo)
     /* 如果本地缓存没有数据,那么就全部插入 */
     if(m_vecEqmDevInfo.size() > 0)
     {
-        for(const auto& it : vecNewDevInfo)
+        for(auto& DevInfo : vecNewDevInfo)
         {
             bool isExist = false;
-            for(const auto& it0 : m_vecEqmDevInfo)
+            for(auto& it0 : m_vecEqmDevInfo)
             {
-                if(it.DeviceID == it0.DeviceID)
+                if(DevInfo.DeviceID == it0.DeviceID)
                 {
                     isExist = true;
                     /* 对比其他项是否相等,不相等就更新 */
-                    if(it == it0)
+                    if(DevInfo == it0)
                     {
                         continue;
                     }else {
-                        vecDevUpdate.push_back(it);
+                        vecDevUpdate.push_back(DevInfo);
                     }
                     break;
                 }
             }
             if(!isExist)
             {
-                vecDevInsert.push_back(it);
+                vecDevInsert.push_back(DevInfo);
             }
         }
     }else {
@@ -548,22 +548,35 @@ void SPAServer::parseRedisData(const std::string& strData, AlarmInfo& alarmInfo)
 bool SPAServer::isEventTimeVaild(const std::string& strTime)
 {
     /* 获取当前时间 */
-    time_t now = time(0);
+    std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
     /* 字符串转成时间 */
-    tm tmTime;
-    strptime(strTime.c_str(), "%Y-%m-%d %H:%M:%S", &tmTime);
-    time_t eventTime = mktime(&tmTime);
+    std::istringstream iss(strTime);
+    std::tm tmEvent = {};
+    iss >> std::get_time(&tmEvent, "%Y-%m-%d %H:%M:%S");
     /* 时间差 */
-    double diff = difftime(now, eventTime);
-    SPDLOG_LOGGER_DEBUG(m_logger, "now:{} eventTime: {} 时间差:{}秒",now, eventTime, diff);
-
+    std::chrono::system_clock::time_point eventTime = std::chrono::system_clock::from_time_t(std::mktime(&tmEvent));
+    std::chrono::duration<double> diff = now - eventTime;
+    // SPDLOG_LOGGER_DEBUG(m_logger, "now:{} eventTime: {} 时间差:{}秒",now, eventTime, diff);
+    if(diff.count() > 600)
+    {
+        // SPDLOG_LOGGER_ERROR(m_logger, "Redis数据长时间没有更新,EventTime:{}", strTime);
+        return false;
+    }
     return true;
 }
 
 
 /**
  * @brief 分派任务的线程
- *        线程定时刷新房间和摄像机的管理关系,以及和算法Action的关联关系
+        1、 线程定时刷新房间和摄像机的关联关系,以及和算法Action的关联关系
+        2、 将算法信息加入到不同的列表中
+            需要多个摄像机配合的加入到m_runListRoomActionInfo列表
+            不需要多个摄像机配合的加入到m_runListActionInfo列表
+        3、 每次刷新都会清空算法的摄像机列表,但是不会动其他基本信息,如果是列表中没有对应的信息,就会创建新的ActionInfo
+            那么RunState的状态是INIT,需要开启新的线程
+            如果刷新完成后,算法对应的摄像机列表为空,那么对应的线程就会停止运行,将RunState设置为STOP,本线程的下一轮
+            循环就会删除这个ActionInfo
+
  */
 void SPAServer::threadRoomCamera()
 {
@@ -578,71 +591,82 @@ void SPAServer::threadRoomCamera()
 
         /* 取出每个房间的所有算法,int是RoomID,string是Action */
         std::multimap<int, std::string> mapCameraActionID;
-        m_mutexRoomActionInfo.lock();
-        m_mutexCameraActionID.lock();
-        /* 将算法信息根据房间分类,并找到其需要的摄像机 */
-        m_listRoomActionInfo.clear();
+        m_mutexRunRAI.lock();
+        m_mutexActionInfo.lock();
+        /* 先清理已经退出的线程所用到的Action或者RoomAction */
+        m_runListRoomActionInfo.clearStopRoomAction();
+        m_runListActionInfo.clearStopAction();
+
+        m_mutexRunActionInfo.lock();
+        /* 将算法信息加入到不同的列表中
+         * 需要多个摄像机配合的加入到m_runListRoomActionInfo列表
+         * 不需要多个摄像机配合的加入到m_runListActionInfo列表
+         * */
+        m_runListRoomActionInfo.clearCameraList();
+        m_runListActionInfo.clearCameraList();
         for(const auto& it : m_listActionInfo.getData())
         {
-            m_listRoomActionInfo.addActionInfo(*it);
+            if(it->ActionID == ActPersonWork || it->ActionID == ActPersonNumber)
+            {
+                m_runListRoomActionInfo.addActionInfo(*it);
+            }else {
+                m_runListActionInfo.addActionCamera(it);
+            }
         }
-        /* 根据每个房间的算法功能,创建线程 */
-        for(const auto& it0 : m_listRoomActionInfo.getData())
+        m_mutexActionInfo.unlock();
+        /* 这个容器只用于多个摄像机融合的算法,一个房间的一个算法是一个线程 */
+        for(const auto& it0 : m_runListRoomActionInfo.getData())
         {
-            /* 人员在岗识别,这个算法需要多个摄像机配合 */
+            /* 人员在岗识别 */
             if(it0->ActionID == ActPersonWork)
             {
                 SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 人员在岗识别", it0->RoomID);
-
+                /* 判断是否需要创建新的线程 */
+                if(it0->RunState == RunTimeState::RUN_STATE_INIT)
+                {
+                    /* 创建新的线程 */
+                    CPPTP.add_task(&SPAServer::threadActPersonWork, this, it0);
+                }
             }
-            /* 区域人员检测,这个需要融合检测 */
+            /* 区域人员检测 */
             else if (it0->ActionID == ActPersonNumber)
             {
                 SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 区域人员检测", it0->RoomID);
-
+                if(it0->RunState == RunTimeState::RUN_STATE_INIT)
+                {
+                    CPPTP.add_task(&SPAServer::threadActPersonNumber, this, it0);
+                }
             }
+        }
+        /* 这个容器用于不关联的算法信息,每个设备上的每个算法是一个线程 */
+        for(const auto& it0 : m_runListActionInfo.getData())
+        {
             /* 违禁物品识别,不需要多个摄像机融合判断,多少个报警都直接上报 */
-            else if (it0->ActionID == ActContraband)
+            if (it0->ActionID == ActContraband)
             {
                 SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 违禁品检测", it0->RoomID);
-
+                if(it0->RunState == RunTimeState::RUN_STATE_INIT)
+                {
+                    CPPTP.add_task(&SPAServer::threadActContraband, this, it0);
+                }
             }
             /* 非法入侵检测,这个也不需要摄像机融合 */
             else if (it0->ActionID == ActIllegalInvasion)
             {
                 SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 非法入侵检测", it0->RoomID);
-
             }
             /* 疲劳检测,不需要摄像机融合检测,直接上报 */
             else if (it0->ActionID == ActFatigueDetection)
             {
                 SPDLOG_LOGGER_INFO(m_logger, "RoomID:{} 疲劳检测", it0->RoomID);
-
             }
-            
         }
-        m_mutexCameraActionID.unlock();
-        m_mutexRoomActionInfo.unlock();
+        m_mutexRunRAI.unlock();
+        m_mutexRunActionInfo.unlock();
     }
 }
 
 
-/* 判断相机是否有这个算法 */
-bool SPAServer::isCameraHasAction(const int CameraID, const std::string& strActionID)
-{
-    for(const auto& it : m_mapCameraActionID)
-    {
-        if(it.first == CameraID)
-        {
-            if(it.second == strActionID)
-            {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
 /* 将该算法对应的摄像机放入摄像机列表 */
 bool SPAServer::insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCameraInfo>& listRC, std::multimap<int, std::string>& mapCameraActionID)
 {
@@ -673,8 +697,8 @@ bool SPAServer::insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCame
 /* 更新房间、算法需要的摄像机个数 */
 bool SPAServer::updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAInfo)
 {
-    std::lock_guard<std::mutex> look(m_mutexRoomActionInfo);
-    for(auto& it : m_listRoomActionInfo.getData())
+    std::lock_guard<std::mutex> look(m_mutexRunRAI);
+    for(auto& it : m_runListRoomActionInfo.getData())
     {
         if((it->RoomID == pRAInfo->RoomID) && (it->ActionID == pRAInfo->ActionID))
         {
@@ -686,6 +710,36 @@ bool SPAServer::updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAI
     return true;
 }
 
+/* 更新算法的摄像机ID */
+bool SPAServer::updateActionCameraID(std::shared_ptr<ActionInfo> pInfo)
+{
+    pInfo->CameraID = -1;
+    std::lock_guard<std::mutex> look(m_mutexRunActionInfo);
+    for(auto& it : m_runListActionInfo.getData())
+    {
+        if(it->isEqualBaseInfo(*pInfo))
+        {
+            pInfo->CameraID = it->CameraID;
+            break;
+        }
+    }
+    return true;
+}
+
+/* 设置线程状态 */
+void SPAServer::setThreadState(std::shared_ptr<ActionInfo> pInfo, RunTimeState state)
+{
+    std::lock_guard<std::mutex> look(m_mutexRunActionInfo);
+    for(auto& it : m_runListActionInfo.getData())
+    {
+        if(it->isEqualBaseInfo(*pInfo))
+        {
+            it->RunState = state;
+            break;
+        }
+    }
+}
+
 
 
 /**
@@ -711,12 +765,16 @@ void SPAServer::threadActPersonWork(RoomActionInfo* RAInfo)
     *pRAInfo = *RAInfo;
     int CameraCount = pRAInfo->listCameraID.size();
     /* 摄像机数目小于0就退出线程 */
-    while (CameraCount > 0)
+    while (m_threadRunning)
     {
         /* 更新算法关联的摄像机个数 */
         pRAInfo->listCameraID.clear();
         updateRoomActionCameraCount(pRAInfo);
         CameraCount = pRAInfo->listCameraID.size();
+        if(CameraCount == 0)
+        {
+            break;
+        }
 
         /* 读取Redis数据 */
         for(const auto& camID : pRAInfo->listCameraID)
@@ -754,14 +812,18 @@ void SPAServer::threadActPersonNumber(RoomActionInfo* RAInfo)
     /* 局部变量 */
     std::shared_ptr<RoomActionInfo> pRAInfo = std::make_shared<RoomActionInfo>();
     *pRAInfo = *RAInfo;
-    int CameraCount = pRAInfo->listCameraID.size();
-    /* 摄像机数目于0就退出线程 */
-    while (CameraCount > 0)
+    int CameraCount = 0;
+    /* 摄像机数目于0就退出线程 */
+    while (m_threadRunning)
     {
         /* 更新算法关联的摄像机个数 */
         pRAInfo->listCameraID.clear();
         updateRoomActionCameraCount(pRAInfo);
         CameraCount = pRAInfo->listCameraID.size();
+        if(CameraCount == 0)
+        {
+            break;
+        }
 
         /* 读取Redis数据 */
         for(const auto& camID : pRAInfo->listCameraID)
@@ -780,4 +842,101 @@ void SPAServer::threadActPersonNumber(RoomActionInfo* RAInfo)
     }
 }
 
+/**
+ * @brief 报警判断条件:机房内出现摄像头的违禁物品识别算法输出结果包含指定违规内容时,记为报警行为,直接
+          展示报警结果
+ * 
+ * @param info 
+ */
+void SPAServer::threadActContraband(ActionInfo* info)
+{
+    SPDLOG_LOGGER_INFO(m_logger, "开启违禁物品识别线程,RoomID:{} ,Action:{}", info->RoomID, info->ActionID);
+    /* 创建读取Redis的实例 */
+    std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
+    /* 局部变量,保存这个线程的信息 */
+    std::shared_ptr<ActionInfo> pActInfo = std::make_shared<ActionInfo>();
+    *pActInfo = *info;
+    /* 摄像机ID小于0就退出线程 */
+    while (m_threadRunning)
+    {
+        /* 更新算法关联的摄像机ID */
+        updateActionCameraID(pActInfo);
+        /* 如果摄像机ID是小于0,那么这个算法就没有对应的摄像机了,线程就退出了 */
+        if(pActInfo->CameraID < 0)
+        {
+            break;
+        }
+        /* 读取Redis数据 */
+        std::string strKey = std::to_string(pActInfo->CameraID) + ":" + pActInfo->ActionID;
+        std::string strRetValue;
+        if(!fromRedis->getRedisString(strKey, strRetValue))
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
+            continue;
+        }
+        /* 解析数据 */
+        AlarmInfo alarmInfo;
+        parseRedisData(strRetValue, alarmInfo);
+        /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
+        if(isEventTimeVaild(alarmInfo.EventTime))
+        {
+            SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
+            continue;
+        }
+        /* 判断有无报警记录,写入到EQM数据库 */
+    }
+    /* 设置线程退出的状态 */
+    setThreadState(pActInfo, RunTimeState::RUN_STATE_STOP);
+    SPDLOG_LOGGER_INFO(m_logger, "违禁物品识别线程退出,RoomID:{} ,CameraID, Action:{}", pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
+}
+
+/**
+ * @brief  1、野猫、宠物识别:报警判断条件:机房内出现摄像头的宠物识别算法输出报警结果时,记为报警行为,直接
+              展示报警结果
+           2、无权限人员识别:报警判断条件:当判断出区域非法入侵行为时,依据人脸识别结果,判断是否为人脸库人
+              员,非人脸库的人员时判断为非法入侵行为(背影需要报警需要结合区域人员检测算法判断)
+ * 
+ * @param info 
+ */
+void SPAServer::threadActIllegalInvasion(ActionInfo* info)
+{
+    SPDLOG_LOGGER_INFO(m_logger, "开启非法入侵检测线程,RoomID:{} ,Action:{}", info->RoomID, info->ActionID);
+    /* 创建读取Redis的实例 */
+    std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
+    /* 局部变量,保存这个线程的信息 */
+    std::shared_ptr<ActionInfo> pActInfo = std::make_shared<ActionInfo>();
+    *pActInfo = *info;
+    /* 摄像机ID小于0就退出线程 */
+    while (m_threadRunning)
+    {
+        /* 更新算法关联的摄像机ID */
+        updateActionCameraID(pActInfo);
+        /* 如果摄像机ID是小于0,那么这个算法就没有对应的摄像机了,线程就退出了 */
+        if(pActInfo->CameraID < 0)
+        {
+            break;
+        }
+        /* 读取Redis数据 */
+        std::string strKey = std::to_string(pActInfo->CameraID) + ":" + pActInfo->ActionID;
+        std::string strRetValue;
+        if(!fromRedis->getRedisString(strKey, strRetValue))
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
+            continue;
+        }
+        /* 解析数据 */
+        AlarmInfo alarmInfo;
+        parseRedisData(strRetValue, alarmInfo);
+        /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
+        if(isEventTimeVaild(alarmInfo.EventTime))
+        {
+            SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
+            continue;
+        }
+        /* 判断有无报警记录,写入到EQM数据库 */
+    }
+    /* 设置线程退出的状态 */
+    setThreadState(pActInfo, RunTimeState::RUN_STATE_STOP);
+    SPDLOG_LOGGER_INFO(m_logger, "非法入侵检测线程退出,RoomID:{} ,CameraID:{}, Action:{}", pActInfo->RoomID, pActInfo->CameraID, pActInfo->ActionID);
+}
 

+ 18 - 7
SecurePlayAuxServer/SPAServer.h

@@ -39,17 +39,23 @@ private:
 
     /* 分派任务的线程 */
     void threadRoomCamera();
-    /* 判断相机是否有这个算法 */
-    bool isCameraHasAction(const int CameraID, const std::string& strActionID);
     /* 将该算法对应的摄像机放入摄像机列表 */
     bool insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCameraInfo>& listRC, std::multimap<int, std::string>& mapCameraActionID);
     /* 更新房间、算法需要的摄像机个数 */
     bool updateRoomActionCameraCount(std::shared_ptr<RoomActionInfo> pRAInfo);
+    /* 更新算法的摄像机ID */
+    bool updateActionCameraID(std::shared_ptr<ActionInfo> pInfo);
+    /* 设置线程状态 */
+    void setThreadState(std::shared_ptr<ActionInfo> pInfo, RunTimeState state);
     
     /* 人员在岗识别线程,应该是人脸识别线程,这个需要房间内多个摄像机共同识别 */
     void threadActPersonWork(RoomActionInfo* RAInfo);
     /* 区域人员检测,检测这个区域内的人数,不能少于多少人,不能多余多少人 */
     void threadActPersonNumber(RoomActionInfo* RAInfo);
+    /* 违禁物品识别 */
+    void threadActContraband(ActionInfo* info);
+    /* 非法入侵检测 */
+    void threadActIllegalInvasion(ActionInfo* info);
 
 
 private:
@@ -63,6 +69,7 @@ private:
     std::string m_keyContraband;                        /* 违禁品检测的Key,这个Key后面可能随时会变动 */
     std::string m_KeyFace;                              /* 人脸检测的Key */
 
+    std::mutex m_mutexActionID;                         /* 算法ID的互斥锁 */
     std::string ActPersonWork;                          /* 人员在岗识别 */
     std::string ActPersonNumber;                        /* 区域人员检测 */
     std::string ActContraband;                          /* 违禁品检测 */
@@ -73,15 +80,19 @@ private:
     std::vector<AlgorithmInfo> m_vecEqmAlgInfo;
     /* 设备信息,这个是tActionCamer的信息 */
     std::vector<DeviceInfo> m_vecEqmDevInfo;
-    /* 摄像机ID和算法ID对应表 */
-    std::mutex m_mutexCameraActionID;
-    std::multimap<int, std::string> m_mapCameraActionID;
+    /* 算法信息列表,每个算法所在的频率、房间、摄像机 */
+    std::mutex m_mutexActionInfo;
     ListActionInfo m_listActionInfo;
     /* 设备和算法关联信息,这里存储着已经删除的设备对应的算法信息,将在这一轮循环中删除 */
     std::list<int> m_listDevIDDelete;
+
+
     /* 房间和算法关联的信息,包含所需要的摄像机ID */
-    std::mutex m_mutexRoomActionInfo;
-    ListRoomActionInfo m_listRoomActionInfo;
+    std::mutex m_mutexRunRAI;
+    ListRoomActionInfo m_runListRoomActionInfo;
+    /* 运行时的算法信息列表,这个容器存储的是不需要摄像机融合的算法 */
+    std::mutex m_mutexRunActionInfo;
+    ListActionInfo m_runListActionInfo;
 
 };