|
@@ -5,6 +5,7 @@
|
|
|
#include "ThreadPool/ThreadPool.h"
|
|
|
#include "GlobalInfo/GlobalVariable.h"
|
|
|
#include "GlobalInfo/GlobalConfig.h"
|
|
|
+#include "UniversalFunc.h"
|
|
|
|
|
|
#include <QApplication>
|
|
|
#include <QVector>
|
|
@@ -21,12 +22,12 @@ SPAServer::SPAServer()
|
|
|
|
|
|
/* 读取全局的配置文件 */
|
|
|
QString strConfigFile = QApplication::applicationDirPath() + "/config.ini";
|
|
|
- if(!g_config.readConfig(strConfigFile))
|
|
|
+ if(!GConfig.readConfig(strConfigFile))
|
|
|
{
|
|
|
/* 读取配置文件失败,直接退出程序 */
|
|
|
return;
|
|
|
}
|
|
|
- g_config.printValue();
|
|
|
+ GConfig.printValue();
|
|
|
|
|
|
|
|
|
m_threadRunning = true;
|
|
@@ -63,11 +64,12 @@ void SPAServer::startServer()
|
|
|
|
|
|
/**
|
|
|
* @brief 从基础平台获取算法信息和设备信息的线程函数
|
|
|
+ * 从基础平台获取算法信息和设备信息,然后更新到EQM数据库所对应的表中
|
|
|
*
|
|
|
*/
|
|
|
void SPAServer::threadFromSuperBrain()
|
|
|
{
|
|
|
- SPDLOG_LOGGER_INFO(m_logger, "开启 fromSuperBrainThread 线程");
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "开启 fromSuperBrainThread 线程, 获取算法和设备信息");
|
|
|
/* 创建变量 */
|
|
|
std::vector<AlgorithmInfo> vecAlgNewInfo;
|
|
|
std::vector<DeviceInfo> vecDevNewInfo;
|
|
@@ -81,6 +83,7 @@ void SPAServer::threadFromSuperBrain()
|
|
|
m_toEQMDataBase.getAlgorithmInfo(m_vecEqmAlgInfo);
|
|
|
m_toEQMDataBase.getDeviceInfo(m_vecEqmDevInfo);
|
|
|
m_toEQMDataBase.getDeviceAlgorithmInfo(m_vecEqmDevInfo, m_listDevIDDelete);
|
|
|
+
|
|
|
/* 从超脑获取基础信息 */
|
|
|
m_fromSuperBrain.getTaskTypeList(vecAlgNewInfo);
|
|
|
m_fromSuperBrain.getDeviceList(vecDevNewInfo);
|
|
@@ -92,12 +95,16 @@ void SPAServer::threadFromSuperBrain()
|
|
|
|
|
|
vecAlgNewInfo.clear();
|
|
|
vecDevNewInfo.clear();
|
|
|
+
|
|
|
/* 更新算法详细信息 */
|
|
|
m_mutexActionInfo.lock();
|
|
|
m_toEQMDataBase.getActionInfo(m_listActionInfo);
|
|
|
m_mutexActionInfo.unlock();
|
|
|
+
|
|
|
+ /* 10秒更新一次 */
|
|
|
std::this_thread::sleep_for(std::chrono::seconds(10));
|
|
|
}
|
|
|
+ SPDLOG_LOGGER_INFO(m_logger, "退出 fromSuperBrainThread 线程");
|
|
|
}
|
|
|
|
|
|
/* 处理算法信息,返回值为true,说明有改变,需要重新读取 */
|
|
@@ -431,287 +438,6 @@ void SPAServer::threadFromRedis(const CameraThreadInfo& info)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
-// /* 解析Redis基础数据 */
|
|
|
-// void SPAServer::parseRedisData(const std::string& strData, AlarmInfo& alarmInfo)
|
|
|
-// {
|
|
|
-// try
|
|
|
-// {
|
|
|
-// nJson json0;
|
|
|
-// json0 = nJson::parse(strData);
|
|
|
-// alarmInfo.AlarmID = json0["alarmId"].get<int>();
|
|
|
-// alarmInfo.ChannelID = json0["channel"].get<int>();
|
|
|
-// alarmInfo.PicUrl = json0["picUrl"].get<std::string>();
|
|
|
-// alarmInfo.ImageInfo = json0["imageInfo"].get<std::string>();
|
|
|
-
|
|
|
-// /* 解析时间,需要将时间中的“T”换成空格 */
|
|
|
-// alarmInfo.StartTime = json0["beginTime"].get<std::string>();
|
|
|
-// std::replace(alarmInfo.StartTime.begin(), alarmInfo.StartTime.end(), 'T', ' ');
|
|
|
-// alarmInfo.EndTime = json0["endTime"].get<std::string>();
|
|
|
-// std::replace(alarmInfo.EndTime.begin(), alarmInfo.EndTime.end(), 'T', ' ');
|
|
|
-// alarmInfo.EventTime = json0["eventTime"].get<std::string>();
|
|
|
-// std::replace(alarmInfo.EventTime.begin(), alarmInfo.EventTime.end(), 'T', ' ');
|
|
|
-// /* 判断bBoxes有无数据,有数据就解析,没数据就直接返回了 */
|
|
|
-// nJson json1 = json0["bBoxes"];
|
|
|
-
|
|
|
-// std::string labelList; /* 记录违禁品 */
|
|
|
-// std::string bboxList; /* 记录bbox */
|
|
|
-// if(!json1.empty())
|
|
|
-// {
|
|
|
-// for(auto& it0 : json1)
|
|
|
-// {
|
|
|
-// /* 如果status是true,就不是报警,直接跳过 */
|
|
|
-// bool status = it0["status"].get<bool>();
|
|
|
-// if(status)
|
|
|
-// {
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// /* 这一条Box数据报警了将其内容存储起来 */
|
|
|
-// alarmInfo.Is_Alarm = true;
|
|
|
-// /* 解析label,违禁品关键字,先判断这个是不是违禁品检测的算法ID */
|
|
|
-// if(alarmInfo.ActionID == g_actionList.ActContraband)
|
|
|
-// {
|
|
|
-// /* 解析报警,取出报警类型 */
|
|
|
-// nJson label = it0["label"];
|
|
|
-// for(auto& it1 : label)
|
|
|
-// {
|
|
|
-// std::string strLabel = it1.get<std::string>();
|
|
|
-// /* 检测是否已经加入到字符串中了 */
|
|
|
-// strLabel += "|";
|
|
|
-// if(labelList.find(strLabel) != std::string::npos)
|
|
|
-// {
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// labelList += strLabel;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// /* 解析bbox,貌似是在图像中的位置 */
|
|
|
-// nJson bbox = it0["bbox"];
|
|
|
-// std::string strBbox;
|
|
|
-// for(auto& it1 : bbox)
|
|
|
-// {
|
|
|
-// strBbox += std::to_string(it1.get<int>()) + ",";
|
|
|
-// }
|
|
|
-// /* 去掉最后一个“,” */
|
|
|
-// if(!strBbox.empty())
|
|
|
-// {
|
|
|
-// strBbox.pop_back();
|
|
|
-// }
|
|
|
-// bboxList += strBbox + "|";
|
|
|
-// }
|
|
|
-// /* 去掉最后一个“|” */
|
|
|
-// if(!labelList.empty())
|
|
|
-// {
|
|
|
-// labelList.pop_back();
|
|
|
-// }
|
|
|
-// if(!bboxList.empty())
|
|
|
-// {
|
|
|
-// bboxList.pop_back();
|
|
|
-// }
|
|
|
-// SPDLOG_LOGGER_DEBUG(m_logger, "违禁品列表:{}", labelList);
|
|
|
-// SPDLOG_LOGGER_DEBUG(m_logger, "bbox列表:{}", bboxList);
|
|
|
-// }
|
|
|
-
|
|
|
-// /* 如果有报警的Box */
|
|
|
-// if(alarmInfo.Is_Alarm)
|
|
|
-// {
|
|
|
-// /* 添加报警信息的提示信息 */
|
|
|
-// alarmInfo.BboxList = bboxList;
|
|
|
-// if( (alarmInfo.ActionID == g_actionList.ActContraband) && !labelList.empty() )
|
|
|
-// {
|
|
|
-// alarmInfo.ActionDes = fmt::format("出现违禁品[{}]告警", labelList);
|
|
|
-// SPDLOG_LOGGER_INFO(m_logger, "{}", alarmInfo.ActionDes);
|
|
|
-// }else {
|
|
|
-// alarmInfo.ActionDes = json0["actionDes"].get<std::string>();
|
|
|
-// }
|
|
|
-// /* 判断有没有报警数据 */
|
|
|
-// if(alarmInfo.ImageInfo.empty())
|
|
|
-// {
|
|
|
-// SPDLOG_LOGGER_ERROR(m_logger, "有报警区域,但是没有图片信息");
|
|
|
-// return;
|
|
|
-// }
|
|
|
-// /* 如果是人员报警,就存储人员报警信息 */
|
|
|
-// if(alarmInfo.ActionID == g_actionList.ActFace)
|
|
|
-// {
|
|
|
-// nJson jsonArray = json0["personList"];
|
|
|
-// for(auto& it : jsonArray)
|
|
|
-// {
|
|
|
-// PersonInfo personInfo;
|
|
|
-// personInfo.PersonID = it["personId"].get<std::string>();
|
|
|
-// personInfo.PersonName = it["personName"].get<std::string>();
|
|
|
-// alarmInfo.vecPersonInfo.push_back(personInfo);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-// }
|
|
|
-// catch (const nJson::parse_error& e)
|
|
|
-// {
|
|
|
-// SPDLOG_LOGGER_ERROR(m_logger, "解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
|
|
|
-// return;
|
|
|
-// }
|
|
|
-// catch (const nJson::type_error& e)
|
|
|
-// {
|
|
|
-// SPDLOG_LOGGER_ERROR(m_logger, "解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
|
|
|
-// return;
|
|
|
-// }
|
|
|
-
|
|
|
-// }
|
|
|
-
|
|
|
-/**
|
|
|
- * @brief 解析Redis的基础通用数据,不包含bBoxes数组数据
|
|
|
- *
|
|
|
- * @param strData Redis返回的源数据,JSON格式
|
|
|
- * @param alarmInfo 解析出来的数据
|
|
|
- */
|
|
|
-void SPAServer::parseRedisBaseData(const std::string& strData, AlarmInfo& alarmInfo)
|
|
|
-{
|
|
|
- try
|
|
|
- {
|
|
|
- nJson json0;
|
|
|
- json0 = nJson::parse(strData);
|
|
|
- alarmInfo.AlarmID = json0["alarmId"].get<int>();
|
|
|
- alarmInfo.ChannelID = json0["channel"].get<int>();
|
|
|
- alarmInfo.PicUrl = json0["picUrl"].get<std::string>();
|
|
|
- alarmInfo.ImageInfo = json0["imageInfo"].get<std::string>();
|
|
|
-
|
|
|
- /* 解析时间,需要将时间中的“T”换成空格 */
|
|
|
- alarmInfo.StartTime = json0["beginTime"].get<std::string>();
|
|
|
- std::replace(alarmInfo.StartTime.begin(), alarmInfo.StartTime.end(), 'T', ' ');
|
|
|
- alarmInfo.EndTime = json0["endTime"].get<std::string>();
|
|
|
- std::replace(alarmInfo.EndTime.begin(), alarmInfo.EndTime.end(), 'T', ' ');
|
|
|
- alarmInfo.EventTime = json0["eventTime"].get<std::string>();
|
|
|
- std::replace(alarmInfo.EventTime.begin(), alarmInfo.EventTime.end(), 'T', ' ');
|
|
|
-
|
|
|
- }
|
|
|
- catch (const nJson::parse_error& e)
|
|
|
- {
|
|
|
- SPDLOG_LOGGER_ERROR(m_logger, "解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
|
|
|
- return;
|
|
|
- }
|
|
|
- catch (const nJson::type_error& e)
|
|
|
- {
|
|
|
- SPDLOG_LOGGER_ERROR(m_logger, "解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
|
|
|
- return;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @brief 解析Redis的bBoxes数据,这个内容可能根据算法ID不同,内容不同
|
|
|
- *
|
|
|
- * @param strData
|
|
|
- * @param alarmInfo
|
|
|
- */
|
|
|
-void SPAServer::parseRedisBBoxesData(const std::string& strData, AlarmInfo& alarmInfo)
|
|
|
-{
|
|
|
- try
|
|
|
- {
|
|
|
- nJson json0;
|
|
|
- json0 = nJson::parse(strData);
|
|
|
- /* 判断bBoxes有无数据,有数据就解析,没数据就直接返回了 */
|
|
|
- nJson json1 = json0["bBoxes"];
|
|
|
-
|
|
|
- std::string labelList; /* 记录违禁品 */
|
|
|
- std::list<std::string> listBbox; /* 记录bbox */
|
|
|
- if(!json1.empty())
|
|
|
- {
|
|
|
- for(auto& it0 : json1)
|
|
|
- {
|
|
|
- /* 如果status是true,就不是报警,直接跳过 */
|
|
|
- bool status = it0["status"].get<bool>();
|
|
|
- if(status)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- /* 这一条Box数据报警了将其内容存储起来 */
|
|
|
- alarmInfo.Is_Alarm = true;
|
|
|
- /* 解析label,违禁品关键字,先判断这个是不是违禁品检测的算法ID */
|
|
|
- if(alarmInfo.ActionID == g_actionList.ActContraband)
|
|
|
- {
|
|
|
- /* 解析报警,取出报警类型 */
|
|
|
- nJson label = it0["label"];
|
|
|
- for(auto& it1 : label)
|
|
|
- {
|
|
|
- std::string strLabel = it1.get<std::string>();
|
|
|
- /* 检测是否已经加入到字符串中了 */
|
|
|
- strLabel += "|";
|
|
|
- if(labelList.find(strLabel) != std::string::npos)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- labelList += strLabel;
|
|
|
- }
|
|
|
- }
|
|
|
- /* 解析bbox,貌似是在图像中的位置 */
|
|
|
- nJson bbox = it0["bbox"];
|
|
|
- std::string strBbox;
|
|
|
- for(auto& it1 : bbox)
|
|
|
- {
|
|
|
- strBbox += std::to_string(it1.get<int>()) + ",";
|
|
|
- }
|
|
|
- /* 去掉最后一个“,” */
|
|
|
- if(!strBbox.empty())
|
|
|
- {
|
|
|
- strBbox.pop_back();
|
|
|
- }
|
|
|
- listBbox.push_back(strBbox);
|
|
|
- }
|
|
|
- /* 去掉最后一个“|” */
|
|
|
- if(!labelList.empty())
|
|
|
- {
|
|
|
- labelList.pop_back();
|
|
|
- }
|
|
|
- SPDLOG_LOGGER_DEBUG(m_logger, "违禁品列表:{}", labelList);
|
|
|
-
|
|
|
- }
|
|
|
- /* 如果有报警的Box,解析出报警的说明 */
|
|
|
- if(alarmInfo.Is_Alarm)
|
|
|
- {
|
|
|
- /* 添加报警信息的提示信息 */
|
|
|
- alarmInfo.listBbox = listBbox;
|
|
|
- /* 违禁品报警信息,违禁品列表不是空的,就添加补充的文字 */
|
|
|
- if( (alarmInfo.ActionID == g_actionList.ActContraband) && !labelList.empty() )
|
|
|
- {
|
|
|
- alarmInfo.ActionDes = fmt::format("出现违禁品[{}]告警", labelList);
|
|
|
- SPDLOG_LOGGER_INFO(m_logger, "{}", alarmInfo.ActionDes);
|
|
|
- }else {
|
|
|
- /* 其他报警信息,直接获取 */
|
|
|
- alarmInfo.ActionDes = json0["actionDes"].get<std::string>();
|
|
|
- }
|
|
|
- /* 判断有没有报警数据 */
|
|
|
- if(alarmInfo.ImageInfo.empty())
|
|
|
- {
|
|
|
- SPDLOG_LOGGER_WARN(m_logger, "有报警区域,但是没有图片信息");
|
|
|
- return;
|
|
|
- }
|
|
|
- /* 如果是人员报警,就存储人员报警信息 */
|
|
|
- if(alarmInfo.ActionID == g_actionList.ActFace)
|
|
|
- {
|
|
|
- nJson jsonArray = json0["personList"];
|
|
|
- for(auto& it : jsonArray)
|
|
|
- {
|
|
|
- PersonInfo personInfo;
|
|
|
- personInfo.PersonID = it["personId"].get<std::string>();
|
|
|
- personInfo.PersonName = it["personName"].get<std::string>();
|
|
|
- alarmInfo.vecPersonInfo.push_back(personInfo);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- catch (const nJson::parse_error& e)
|
|
|
- {
|
|
|
- SPDLOG_LOGGER_ERROR(m_logger, "解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
|
|
|
- return;
|
|
|
- }
|
|
|
- catch (const nJson::type_error& e)
|
|
|
- {
|
|
|
- SPDLOG_LOGGER_ERROR(m_logger, "解析Redis数据失败:{}, 错误ID:{}", e.what(), e.id);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -765,39 +491,34 @@ void SPAServer::threadRoomCamera()
|
|
|
|
|
|
while (m_threadRunning)
|
|
|
{
|
|
|
- m_mutexRunFAI.lock();
|
|
|
+ GThreadInfo.lockRunFAI();
|
|
|
/* 先清理已经退出的线程所用到的Action或者RoomAction */
|
|
|
- m_runListFuncActInfo.clearNoneFuncActionInfo();
|
|
|
+ GThreadInfo.clearNoneFuncActionInfo();
|
|
|
|
|
|
/* 创建应用信息,根据从EQM数据库读取到的配置的应用信息创建 */
|
|
|
toEQMDataBase->getAlarmAppInfo(listAppAndTime);
|
|
|
for(const auto& it : listAppAndTime)
|
|
|
{
|
|
|
/* 创建应用信息,如果已有该应用,就更新时间 */
|
|
|
- m_runListFuncActInfo.addFuncActionInfo(it);
|
|
|
+ GThreadInfo.addFuncActionInfo(it);
|
|
|
}
|
|
|
|
|
|
/* 先获取EQM数据库信息,取出房间和摄像机关联信息 */
|
|
|
m_mutexActionInfo.lock();
|
|
|
toEQMDataBase->getActionInfo(m_listActionInfo);
|
|
|
/* 将算法信息加入到不同的列表中 */
|
|
|
- m_runListFuncActInfo.clearActionList();
|
|
|
+ GThreadInfo.clearActionList();
|
|
|
for(const auto& it : m_listActionInfo.getData())
|
|
|
{
|
|
|
- m_runListFuncActInfo.addActionInfo(*it);
|
|
|
+ GThreadInfo.addActionInfo(*it);
|
|
|
}
|
|
|
|
|
|
/* 检查算法信息的状态,频率里的应用没有配置摄像机就设置为线程运行状态为停止,退出该线程 */
|
|
|
- for(const auto& it : m_runListFuncActInfo.getData())
|
|
|
- {
|
|
|
- if(it->listRoomCamActInfo.size() == 0)
|
|
|
- {
|
|
|
- it->RunState = RunTimeState::RUN_STATE_STOP;
|
|
|
- }
|
|
|
- }
|
|
|
+ GThreadInfo.setNoneCameraFuncStop();
|
|
|
m_mutexActionInfo.unlock();
|
|
|
+
|
|
|
/* 开启线程 */
|
|
|
- for(const auto& it0 : m_runListFuncActInfo.getData())
|
|
|
+ for(const auto& it0 : GThreadInfo.getList())
|
|
|
{
|
|
|
/* 人员在岗识别 */
|
|
|
|
|
@@ -808,20 +529,20 @@ void SPAServer::threadRoomCamera()
|
|
|
/* 违禁品识别 */
|
|
|
|
|
|
/* 普通任务线程,一个任务对应一个摄像机和一个算法ID,无需联动 */
|
|
|
- if(it0->appFunction == AppFunction::APP_ALLDOWN)
|
|
|
+ if(it0->appFunction == AppFunction::APP_AllDown)
|
|
|
{
|
|
|
if(it0->RunState == RunTimeState::RUN_STATE_INIT)
|
|
|
{
|
|
|
- CPPTP.add_task(&SPAServer::threadActNormal, this, it0);
|
|
|
+ // CPPTP.add_task(&SPAServer::threadActNormal, this, it0);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
- m_mutexRunFAI.unlock();
|
|
|
+ GThreadInfo.unlockRunFAI();
|
|
|
|
|
|
/* 休眠n秒,默认应该是300秒 */
|
|
|
- std::this_thread::sleep_for(std::chrono::seconds(g_config.CheckSet));
|
|
|
+ std::this_thread::sleep_for(std::chrono::seconds(GConfig.CheckSet));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -855,7 +576,7 @@ void SPAServer::threadActPersonWork(FuncActionInfo* RFAInfo)
|
|
|
while (m_threadRunning)
|
|
|
{
|
|
|
/* 更新线程信息 */
|
|
|
- updateFuncInfo(pRFAInfo);
|
|
|
+ GThreadInfo.updateFuncInfo(pRFAInfo.get());
|
|
|
if(pRFAInfo->appFunction == AppFunction::APP_NONE)
|
|
|
{
|
|
|
break;
|
|
@@ -909,7 +630,7 @@ void SPAServer::threadActPersonWork(FuncActionInfo* RFAInfo)
|
|
|
it->MinNum = it->listPersonInfo.size();
|
|
|
}
|
|
|
/* 判断是否需要写入数据库,超过设置的时间就写入,默认是600秒 */
|
|
|
- if(now.toSecsSinceEpoch() - it->StartTime.toSecsSinceEpoch() > g_config.AppUpdateOnWorkTimeInterval)
|
|
|
+ if(now.toSecsSinceEpoch() - it->StartTime.toSecsSinceEpoch() > GConfig.AppUpdateOnWorkTimeInterval)
|
|
|
{
|
|
|
/* 写入数据库 */
|
|
|
if(toEQMDataBase->insertOnWorkInfo(*it))
|
|
@@ -922,9 +643,9 @@ void SPAServer::threadActPersonWork(FuncActionInfo* RFAInfo)
|
|
|
}
|
|
|
++it;
|
|
|
}
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(g_config.ThreadSleepMS));
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
|
|
|
}
|
|
|
- setThreadState(pRFAInfo, RunTimeState::RUN_STATE_STOP);
|
|
|
+ GThreadInfo.setThreadState(pRFAInfo.get(), RunTimeState::RUN_STATE_STOP);
|
|
|
SPDLOG_LOGGER_INFO(m_logger, "关闭 {} 线程,ChannelID:{}", pRFAInfo->strFunctionName, pRFAInfo->ChannelID);
|
|
|
}
|
|
|
|
|
@@ -976,7 +697,7 @@ void SPAServer::threadActIllegalInvasion(FuncActionInfo* RFAInfo)
|
|
|
while (m_threadRunning)
|
|
|
{
|
|
|
/* 更新线程信息 */
|
|
|
- updateFuncInfo(pRFAInfo);
|
|
|
+ GThreadInfo.updateFuncInfo(pRFAInfo.get());
|
|
|
if(pRFAInfo->appFunction == AppFunction::APP_NONE)
|
|
|
{
|
|
|
break;
|
|
@@ -1113,7 +834,7 @@ void SPAServer::threadActIllegalInvasion(FuncActionInfo* RFAInfo)
|
|
|
/* 没有报警,检查是否是报警结束了,是否符合写入数据库的条件 */
|
|
|
QDateTime currTime = QDateTime::currentDateTime();
|
|
|
int secs = currTime.toSecsSinceEpoch() - pIll->FirstTime.toSecsSinceEpoch();
|
|
|
- if(secs >= g_config.AppBadMan)
|
|
|
+ if(secs >= GConfig.AppBadMan)
|
|
|
{
|
|
|
if(!pIll->strImageInfo.empty())
|
|
|
{
|
|
@@ -1142,9 +863,9 @@ void SPAServer::threadActIllegalInvasion(FuncActionInfo* RFAInfo)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(g_config.ThreadSleepMS));
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
|
|
|
}
|
|
|
- setThreadState(pRFAInfo, RunTimeState::RUN_STATE_STOP);
|
|
|
+ GThreadInfo.setThreadState(pRFAInfo.get(), RunTimeState::RUN_STATE_STOP);
|
|
|
SPDLOG_LOGGER_INFO(m_logger, "关闭 {} 线程,ChannelID:{}", pRFAInfo->strFunctionName, pRFAInfo->ChannelID);
|
|
|
}
|
|
|
|
|
@@ -1181,9 +902,9 @@ void SPAServer::threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo)
|
|
|
|
|
|
while (m_threadRunning)
|
|
|
{
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(g_config.ThreadSleepMS));
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(GConfig.ThreadSleepMS));
|
|
|
/************ 更新线程信息 ************/
|
|
|
- updateFuncInfo(pRFAInfo);
|
|
|
+ GThreadInfo.updateFuncInfo(pRFAInfo.get());
|
|
|
if(pRFAInfo->appFunction == AppFunction::APP_NONE)
|
|
|
{
|
|
|
break;
|
|
@@ -1286,146 +1007,10 @@ void SPAServer::threadActRegionalPersonnelDetection(FuncActionInfo* RFAInfo)
|
|
|
/************ 检测频率直播间 + 导播间房间的人数 ************/
|
|
|
|
|
|
}
|
|
|
- setThreadState(pRFAInfo, RunTimeState::RUN_STATE_STOP);
|
|
|
+ GThreadInfo.setThreadState(pRFAInfo.get(), RunTimeState::RUN_STATE_STOP);
|
|
|
SPDLOG_LOGGER_INFO(m_logger, "关闭 {} 线程,ChannelID:{}", pRFAInfo->strFunctionName, pRFAInfo->ChannelID);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * @brief 普通任务识别,一个算法只需要一个摄像机,包括 违禁品识别、玩手机检测、老鼠等
|
|
|
- 1、报警判断条件:机房内出现摄像头的违禁物品识别算法输出结果包含指定违规内容时,记为报警行为,直接
|
|
|
- 展示报警结果
|
|
|
- 2、这里应该是不区分违禁物品是什么,只要有违禁物品就报警。如果一个违禁物品消失之前又出现了第二个违禁物品,
|
|
|
- 两个违禁物品都消失后,这次报警才会结束。
|
|
|
- 3、一有报警信息就写入到EQM数据库的tAlarmInfo表中,报警开始时间是EventTime
|
|
|
- 4、如果报警结束时间小于设置的最小间隔,就删除这条数据,超过这个时间,就更新结束时间
|
|
|
- 5、报警信息要有图片,如果当前没有图片,就使用上一张图片
|
|
|
- *
|
|
|
- * @param info 线程信息
|
|
|
- */
|
|
|
-void SPAServer::threadActNormal(FuncActionInfo* info)
|
|
|
-{
|
|
|
- SPDLOG_LOGGER_INFO(m_logger, "开启 {} 线程, ChannelID:{} ,App:{}",info->strFunctionName, info->ChannelID, info->strFunctionName);
|
|
|
- /* 创建读取Redis的实例 */
|
|
|
- std::shared_ptr<FromRedis> fromRedis = std::make_shared<FromRedis>();
|
|
|
- /* 创建写入EQM数据库实例 */
|
|
|
- std::shared_ptr<ToEQMDataBase> toEQMDataBase = std::make_shared<ToEQMDataBase>();
|
|
|
- /* 局部变量,保存这个线程的信息 */
|
|
|
- std::shared_ptr<FuncActionInfo> pFuncAct = std::make_shared<FuncActionInfo>();
|
|
|
- *pFuncAct = *info;
|
|
|
- /* 保存报警数据 */
|
|
|
- std::shared_ptr<ListAlarmInfo> listAlarmInfo = std::make_shared<ListAlarmInfo>();
|
|
|
-
|
|
|
- while (m_threadRunning)
|
|
|
- {
|
|
|
- /* 更新算法关联的摄像机ID */
|
|
|
- updateFuncInfo(pFuncAct);
|
|
|
- /* 如果线程的运行状态为 */
|
|
|
- if(pFuncAct->RunState == RunTimeState::RUN_STATE_STOP)
|
|
|
- {
|
|
|
- pFuncAct->appFunction = AppFunction::APP_NONE;
|
|
|
- break;
|
|
|
- }
|
|
|
- /* 读取Redis信息,处理数据 */
|
|
|
- for(const auto& roomInfo : pFuncAct->listRoomCamActInfo)
|
|
|
- {
|
|
|
- for(const auto& it : roomInfo.mapCameraAction)
|
|
|
- {
|
|
|
- /* 读取Redis数据 */
|
|
|
- std::string strKey = std::to_string(it.first) + ":" + it.second;
|
|
|
- std::string strRetValue;
|
|
|
- if(!fromRedis->getRedisString(strKey, strRetValue))
|
|
|
- {
|
|
|
- SPDLOG_LOGGER_ERROR(m_logger, "读取Redis数据失败, Key:{}", strKey);
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
- continue;
|
|
|
- }
|
|
|
- /* 解析数据 */
|
|
|
- AlarmInfo alarmInfo;
|
|
|
- parseRedisBaseData(strRetValue, alarmInfo);
|
|
|
- parseRedisBBoxesData(strRetValue, alarmInfo);
|
|
|
- /* 判断事件的时效性,超过多少秒不更新就可能是超脑挂了 */
|
|
|
- if(isEventTimeVaild(alarmInfo.EventTime))
|
|
|
- {
|
|
|
- SPDLOG_LOGGER_WARN(m_logger, "Redis Key:{} 数据长时间没有更新,EventTime:{}",strKey, alarmInfo.EventTime);
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
- continue;
|
|
|
- }
|
|
|
- /* 找出数组中与当前报警ID相同的的报警信息 */
|
|
|
- auto pAlarmInfo = listAlarmInfo->findAlarmInfo(alarmInfo);
|
|
|
- if(pAlarmInfo == nullptr)
|
|
|
- {
|
|
|
- /* 没有找到报警记录,就新建一个 */
|
|
|
- AlarmInfo newAlarmInfo = alarmInfo;
|
|
|
- listAlarmInfo->addAlarmInfo(newAlarmInfo);
|
|
|
- /* 重新查找该报警信息 */
|
|
|
- pAlarmInfo = listAlarmInfo->findAlarmInfo(alarmInfo);
|
|
|
- if(pAlarmInfo == nullptr)
|
|
|
- {
|
|
|
- SPDLOG_LOGGER_ERROR(m_logger, "查找报警信息失败, Key:{}", strKey);
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- /* 判断有无报警记录,新的报警就写入到EQM的tAlarmInfo表中,正在报警的记录就判断和更新,
|
|
|
- * 结束报警就更新tAlarmInfo的报警数据的结束时间,并清空pAlarmInfo */
|
|
|
- if(pAlarmInfo->Is_Alarm)
|
|
|
- {
|
|
|
- /* 正在报警中,检查是否报警结束 */
|
|
|
- if(alarmInfo.Is_Alarm)
|
|
|
- {
|
|
|
- /* 更新图片信息 */
|
|
|
- if(!alarmInfo.ImageInfo.empty())
|
|
|
- {
|
|
|
- pAlarmInfo->ImageInfo = alarmInfo.ImageInfo;
|
|
|
- }
|
|
|
- } else {
|
|
|
- /* 报警结束,判断时长,更新数据库结束时间,结束时间是此时电脑时间 */
|
|
|
- if(timeDiffWithNow(pAlarmInfo->EventTime) > g_config.Contraband)
|
|
|
- {
|
|
|
- pAlarmInfo->EndTime = chronoToStrTime(std::chrono::system_clock::now());
|
|
|
- toEQMDataBase->updateAlarmEndTime(*pAlarmInfo);
|
|
|
- }else {
|
|
|
- /* 不够报警时间,目前不做任何处理,不删除EQM报警记录 */
|
|
|
- }
|
|
|
-
|
|
|
- /* 清空报警信息 */
|
|
|
- pAlarmInfo->reInit();
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* 是新的报警 */
|
|
|
- if(alarmInfo.Is_Alarm)
|
|
|
- {
|
|
|
- /* 图片不能是空,如果是空的,就不写入数据库 */
|
|
|
- if(!alarmInfo.ImageInfo.empty())
|
|
|
- {
|
|
|
- /* 违禁品检测,开始时间是事件时间 */
|
|
|
- alarmInfo.StartTime = alarmInfo.EventTime;
|
|
|
- alarmInfo.EndTime = "";
|
|
|
- if(toEQMDataBase->insertAlarmInfo(alarmInfo))
|
|
|
- {
|
|
|
- /* 保存新的报警记录 */
|
|
|
- *pAlarmInfo = alarmInfo;
|
|
|
- }else {
|
|
|
- SPDLOG_LOGGER_ERROR(m_logger, "写入tAlarmInfo报警数据失败, Key: {}", strKey);
|
|
|
- }
|
|
|
- }else {
|
|
|
- SPDLOG_LOGGER_ERROR(m_logger, "频道:{}, 房间:{}, 摄像机:{}, 算法:{}, 有报警区域, 但是没有图片信息", pFuncAct->ChannelID, roomInfo.RoomID, it.first, it.second);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* 休眠设置的时间 */
|
|
|
- std::this_thread::sleep_for(std::chrono::seconds(g_config.ThreadSleepMS));
|
|
|
- }
|
|
|
- /* 设置线程退出的状态 */
|
|
|
- setThreadState(pFuncAct, RunTimeState::RUN_STATE_STOP);
|
|
|
- SPDLOG_LOGGER_INFO(m_logger, "{} 线程退出,Channel:{}",pFuncAct->strFunctionName, pFuncAct->ChannelID);
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
|
|
|
/* 将该算法对应的摄像机放入摄像机列表 */
|
|
@@ -1454,71 +1039,3 @@ bool SPAServer::insertCameraToAction(RoomActionInfo* pRAInfo, std::list<RoomCame
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * @brief 功能线程更新功能信息,这里是从内存中的数组里获取
|
|
|
- *
|
|
|
- * @param pInfo
|
|
|
- * @return true
|
|
|
- * @return false
|
|
|
- */
|
|
|
- bool SPAServer::updateFuncInfo(std::shared_ptr<FuncActionInfo> pInfo)
|
|
|
-{
|
|
|
- pInfo->clearActionList();
|
|
|
- std::lock_guard<std::mutex> look(m_mutexRunFAI);
|
|
|
- auto fa = m_runListFuncActInfo.findAppFunction(*pInfo);
|
|
|
- if(fa == nullptr)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- *pInfo = *fa;
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-/* 设置线程状态 */
|
|
|
-void SPAServer::setThreadState(std::shared_ptr<FuncActionInfo> pInfo, RunTimeState state)
|
|
|
-{
|
|
|
- std::lock_guard<std::mutex> look(m_mutexRunFAI);
|
|
|
- auto p = m_runListFuncActInfo.findAppFunction(*pInfo);
|
|
|
- if(p != nullptr)
|
|
|
- {
|
|
|
- p->RunState = state;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-/* 计算与当前时间的时间差,返回秒 */
|
|
|
-int SPAServer::timeDiffWithNow(const std::string& strTime)
|
|
|
-{
|
|
|
- auto now = std::chrono::system_clock::now();
|
|
|
-
|
|
|
- auto eventTime = strTimeToChrono(strTime);
|
|
|
- std::chrono::duration<double> diff = now - eventTime;
|
|
|
-
|
|
|
- return diff.count();
|
|
|
-}
|
|
|
-
|
|
|
-/* 字符串时间转换成std::chrono时间点 */
|
|
|
-std::chrono::system_clock::time_point SPAServer::strTimeToChrono(const std::string& strTime)
|
|
|
-{
|
|
|
- std::istringstream iss(strTime);
|
|
|
- std::tm tmEvent = {};
|
|
|
- iss >> std::get_time(&tmEvent, "%Y-%m-%d %H:%M:%S");
|
|
|
-
|
|
|
- return std::chrono::system_clock::from_time_t(std::mktime(&tmEvent));
|
|
|
-}
|
|
|
-
|
|
|
-/* 时间点转换成字符串 */
|
|
|
-std::string SPAServer::chronoToStrTime(const std::chrono::system_clock::time_point& timePoint)
|
|
|
-{
|
|
|
- std::time_t time = std::chrono::system_clock::to_time_t(timePoint);
|
|
|
- std::tm tmEvent = *std::localtime(&time);
|
|
|
- char buf[64] = {0};
|
|
|
- std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tmEvent);
|
|
|
-
|
|
|
- return std::string(buf);
|
|
|
-}
|
|
|
-
|