diff --git a/doc/Atlas人车物检测SDK说明_v0.0.0.pdf b/doc/Atlas人车物检测SDK说明_v0.0.0.pdf new file mode 100644 index 0000000..25899f8 --- /dev/null +++ b/doc/Atlas人车物检测SDK说明_v0.0.0.pdf diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..d721224 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,87 @@ +XX = g++ + + +PROJECT_ROOT= /home/cmhu/vpt_ascend + +DEPEND_DIR = $(PROJECT_ROOT)/bin +SRC_ROOT = $(PROJECT_ROOT)/src + +TARGET= $(PROJECT_ROOT)/bin/vpt_proj + +THIRDPARTY_ROOT = $(PROJECT_ROOT)/3rdparty +SPDLOG_ROOT = $(THIRDPARTY_ROOT)/spdlog-1.9.2/release +OPENCV_ROOT = $(THIRDPARTY_ROOT)/opencv-4.5.4/release +JSON_ROOT = $(THIRDPARTY_ROOT)/jsoncpp-1.9.5/release +FFMPEG_ROOT = $(THIRDPARTY_ROOT)/ffmpeg-4.2.2/release + +DEFS = -DENABLE_DVPP_INTERFACE + +include_dir=-I/usr/local/Ascend/ascend-toolkit/6.3.RC1/x86_64-linux/include \ + -I $(SPDLOG_ROOT)/include \ + -I $(SRC_ROOT)/common \ + -I $(OPENCV_ROOT)/include/opencv4 \ + -I $(JSON_ROOT)/include \ + -I $(FFMPEG_ROOT)/include \ + +lib_dir=-L/usr/local/Ascend/ascend-toolkit/6.3.RC1/runtime/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/latest/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/latest/runtime/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1/runtime/lib64/stub \ + +lib=-lacl_dvpp -lascendcl -lacl_dvpp_mpi -lruntime -lascendalog -lc_sec -lmsprofiler -lgert -lmmpa -lascend_hal -lexe_graph -lge_executor -lgraph -lprofapi -lascend_protobuf -lerror_manager -lopencv_dnn -lopencv_calib3d -lhybrid_executor -lregister -ldavinci_executor -lge_common -lge_common_base \ + -lplatform -lgraph_base -lqos_manager + +LIBS= -L $(SPDLOG_ROOT)/lib -l:libspdlog.a \ + -L $(DEPEND_DIR) -lvpt_det -lsycheck \ + -L $(OPENCV_ROOT)/lib -lopencv_video -lopencv_highgui -lopencv_imgproc -lopencv_core -lopencv_features2d -lopencv_flann\ + -L $(JSON_ROOT)/lib -ljsoncpp \ + -L $(JSON_ROOT)/lib -lavformat -lavcodec -lswscale -lavutil -lavfilter -lswresample -lavdevice \ + +CXXFLAGS= -g -O0 -fPIC $(include_dir) $(lib_dir) $(lib) $(LIBS) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wall -Wno-deprecated -Wdeprecated-declarations -Wl,-Bsymbolic -ldl + + + +SRCS:=$(wildcard $(SRC_ROOT)/ai_platform/*.cpp) \ + $(wildcard $(SRC_ROOT)/decoder/interface/*.cpp) \ + $(wildcard $(SRC_ROOT)/decoder/dvpp/*.cpp) \ + $(wildcard $(SRC_ROOT)/demo/*.cpp) \ + $(wildcard $(SRC_ROOT)/ai_engine_module/sort/*.cpp) \ + $(wildcard $(SRC_ROOT)/ai_engine_module/*.cpp) \ + $(wildcard $(SRC_ROOT)/util/*.cpp) \ + $(wildcard $(SRC_ROOT)/reprocessing_module/*.cpp) \ + +OBJS = $(patsubst %.cpp, %.o, $(notdir $(SRCS))) + + +$(TARGET):$(OBJS) + rm -f $(TARGET) + $(XX) -o $@ $^ $(CXXFLAGS) + rm -f *.o + +%.o:$(SRC_ROOT)/decoder/dvpp/%.cpp + $(XX) $(CXXFLAGS) -c $< + +%.o:$(SRC_ROOT)/decoder/interface/%.cpp + $(XX) $(CXXFLAGS) -c $< + +%.o:$(SRC_ROOT)/ai_platform/%.cpp + $(XX) $(CXXFLAGS) -c $< + +%.o:$(SRC_ROOT)/ai_engine_module/sort/%.cpp + $(XX) $(CXXFLAGS) -c $< + +%.o:$(SRC_ROOT)/ai_engine_module/%.cpp + $(XX) $(CXXFLAGS) -c $< + +%.o:$(SRC_ROOT)/demo/%.cpp + $(XX) $(CXXFLAGS) -c $< + +%.o:$(SRC_ROOT)/util/%.cpp + $(XX) $(CXXFLAGS) -c $< + +%.o:$(SRC_ROOT)/reprocessing_module/%.cpp + $(XX) $(CXXFLAGS) -c $< + +clean: + rm -f *.o $(TARGET) \ No newline at end of file diff --git a/src/ai_engine_module/VPTProcess.cpp b/src/ai_engine_module/VPTProcess.cpp new file mode 100644 index 0000000..63b5ed5 --- /dev/null +++ b/src/ai_engine_module/VPTProcess.cpp @@ -0,0 +1,209 @@ +#include "VPTProcess.h" +#include "../common/logger.hpp" +#include "../ai_platform/task_param_manager.h" + +#include +#include +#include + +#include "vpt.h" +#include "../ai_platform/macro_definition.h" +#include "../ai_platform/det_obj_header.h" + +#include "opencv2/opencv.hpp" + +#include "../util/vpc_util.h" + +VPTProcess::VPTProcess(){ + m_max_batchsize = 16; +} + +VPTProcess::~VPTProcess(){ + release(); +} + +/* 算法初始化 */ +int VPTProcess::init(VPTProcess_PARAM vparam){ + + LOG_INFO("vpt 版本:{}", vpt_get_version()); + + vpt_param param; + param.modelNames = "./models/vpt0715_310p.om"; + param.threshold = vparam.threshold; + param.devId = vparam.gpuid; + param.isTrk = false; + + m_devId = param.devId; + ACL_CALL(aclrtSetDevice(m_devId), ACL_ERROR_NONE, -1); + ACL_CALL(aclrtCreateContext(&m_algorthim_ctx, m_devId), ACL_ERROR_NONE, -1); + + int ret = vpt_init(&m_det_handle, param); + if(ret != 0){ + LOG_DEBUG("vpt init error."); + return -1; + } + + return 0; +} + +/* 算法计算 */ +int VPTProcess::process_gpu(sy_img * batch_img, vector& tasklist, + vector& result, vector>& deleteObjectID, vector>& unUsedResult) +{ + int batchsize = tasklist.size(); + + if (result.empty()) + result.resize(batchsize); + + /* 结果结构体初始化 */ + // vpt_result *vpt_det_result = new vpt_result[batchsize]; + // for (int b = 0; b < batchsize; b++){ + // vpt_det_result[b].obj_count_ = 0; + // vpt_det_result[b].obj_results_ = new vpt_obj_result[MAX_DET_COUNT]; + // } + + do{ + /* 路数太多时 按照最大batchsize数 拆批次运行 */ + // int cur_batch_size = m_max_batchsize; + // int cycleTimes = batchsize / cur_batch_size + (batchsize % cur_batch_size == 0 ? 0 : 1); + + // for (int c = 0; c < cycleTimes; c++){ + + // int real_batchsize = c == cycleTimes - 1 ? (batchsize - cur_batch_size*c) : cur_batch_size; + // int startbatch = c*cur_batch_size; + + // vpt_result *real_res = vpt_det_result + startbatch; + + // aclrtSetDevice(m_devId); + // int ret = aclrtSetCurrentContext(m_algorthim_ctx); + // if(ACL_ERROR_NONE != ret){ + // break; + // } + // ret = vpt_batch(m_det_handle, batch_img + startbatch, real_batchsize, &real_res); + // if(ret != 0){ + // break; + // } + // } + + + aclrtSetDevice(m_devId); + int ret = aclrtSetCurrentContext(m_algorthim_ctx); + if(ACL_ERROR_NONE != ret){ + break; + } + vpt_result *vpt_det_result; + ret = vpt_batch(m_det_handle, batch_img, batchsize, &vpt_det_result); + if(ret != 0){ + break; + } + + vector >> detectResult(batchsize); // sort + + /* 将检测的结果放进数组 转换为跟踪的输入需要(若为人脸 则检测结果可能跟多,比如需要带上ldmk点) */ + // filter by threshold. + for (int b = 0; b < batchsize; b++) + { + vpt_result cur_result = vpt_det_result[b]; + + for (int c = 0; c < cur_result.obj_count_ && c < MAX_OBJ_COUNT; c++) + { + float x1 = vpt_det_result[b].obj_results_[c].obj_rect.left_; + float y1 = vpt_det_result[b].obj_results_[c].obj_rect.top_; + float x2 = vpt_det_result[b].obj_results_[c].obj_rect.left_ + vpt_det_result[b].obj_results_[c].obj_rect.width_; + float y2 = vpt_det_result[b].obj_results_[c].obj_rect.top_ + vpt_det_result[b].obj_results_[c].obj_rect.height_; + + float class_id = vpt_det_result[b].obj_results_[c].obj_index; + float score = vpt_det_result[b].obj_results_[c].obj_score; + + if (score >= THRESHOLD) + { + vector obj; + obj.push_back(x1); + obj.push_back(y1); + obj.push_back(x2); + obj.push_back(y2); + obj.push_back(score); + obj.push_back(class_id); + detectResult[b].push_back(obj); + } + } + } + + bool isUseDet = true; + for (size_t detectIndex = 0; detectIndex < batchsize; detectIndex++) { + string task_id = tasklist[detectIndex]; + + if (! taskTrackers[task_id].tracker.GetState()) + continue; + + Sort &cur_sort = taskTrackers[task_id].tracker; + isUseDet = true; + + const float maxLen = std::sqrt(batch_img[detectIndex].w_ * batch_img[detectIndex].w_ + batch_img[detectIndex].h_ * batch_img[detectIndex].h_); //-modified by zsh 220719 + /* FusionInterval是跳帧参数,以十类人车物为例,一般跳5帧,所以第一帧检测,后续四帧纯跟踪 */ + for (int j = 0; j < taskTrackers[task_id].tracker.FusionInterval; j++) + { + /* 跟踪:第一帧 带检测框信息的跟踪,取结果返回 */ + if (j == 0) + { + int objCount = cur_sort.update_v2(isUseDet, /*save lk = */false, /*center_dist = */true, maxLen, detectResult[detectIndex], result[detectIndex].obj, deleteObjectID[detectIndex]); + result[detectIndex].obj_count = objCount; + result[detectIndex].task_id = task_id; + + vector>().swap(detectResult[detectIndex]); + detectResult[detectIndex].clear(); + isUseDet = false; + } else /* 跟踪:后四帧 纯粹跟踪 纯跟踪结果不返回 */ + { + onelevel_det_result un_result; + //un_result.obj_count = cur_sort.update(isUseDet, false, detectResult[detectIndex], un_result.obj, deleteObjectID[detectIndex]); + un_result.obj_count = cur_sort.update_v2(isUseDet, false, true, maxLen, detectResult[detectIndex], un_result.obj, deleteObjectID[detectIndex]); + } + } + } + + vector >>().swap(detectResult); // free memory. + } while (0); + + // if(vpt_det_result) + // { + // for (int b = 0; b < batchsize; b++) + // { + // delete[] vpt_det_result[b].obj_results_; + // } + // delete[] vpt_det_result; + // } + + return 0; +} + + +/* 算法句柄 资源释放 */ +void VPTProcess::release(){ + if (m_det_handle){ + vpt_release(&m_det_handle); + m_det_handle = NULL; + } + if(m_algorthim_ctx){ + aclrtDestroyContext(m_algorthim_ctx); + } +} + +// 221117byzsh +void VPTProcess::addTaskTracker(const string taskID, double rWidth, double rHeight, int skip_frame) +{ + TaskTracker t; + t.TaskID = taskID; + t.ratioWidth = rWidth; + t.ratioHeight = rHeight; + t.tracker.FusionInterval = skip_frame; + + taskTrackers[taskID] = t; +} + +/* 任务结束跟踪器 */ +bool VPTProcess::finishTaskTracker(const string taskID) +{ + taskTrackers.erase(taskID); + return true; +} \ No newline at end of file diff --git a/src/ai_engine_module/VPTProcess.h b/src/ai_engine_module/VPTProcess.h new file mode 100644 index 0000000..319b621 --- /dev/null +++ b/src/ai_engine_module/VPTProcess.h @@ -0,0 +1,93 @@ +/******************************************************************************************* +* Version: VPT_x64_V2.0.0_20170705 +* CopyRight: 中科院自动化研究所模式识别实验室图像视频组 +* UpdateDate: 20170705 +* Content: 人车物监测跟踪 +********************************************************************************************/ +#pragma once +#include +#include +#include "sort/Sort.h" +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" + +using namespace std; + +// #define THRESHOLD 0.45 +#define THRESHOLD 0.3 + +struct TaskTracker +{ + string TaskID; + double ratioWidth; + double ratioHeight; + Sort tracker; +}; + + +typedef struct VPTProcess_PARAM +{ + int gpuid; //指定显卡id + float threshold; + int max_batch; + + char* serialize_file; + char* auth_license; + VPTProcess_PARAM() : gpuid(0), threshold(0.6), max_batch(20) {}; +}VPTProcess_PARAM; + +class VPTProcess { + +public: + VPTProcess(); + ~VPTProcess(); + /************************************************************************* + * FUNCTION: VPT_Init + * PURPOSE: 初始化 + * PARAM: + [in] vparam 参数 + * RETURN: handle + * NOTES: + *************************************************************************/ + int init(VPTProcess_PARAM vparam); + + + /** + * @brief 人车物检测跟踪 + * + * @param handle [in] + * @param batch_img [in] + * @param batchsize [in] + * @param result [in] + * @param deleteObjectID [in] + * @param unUsedResult [in] + * @param class_label_count [in/out] + * @return int -1:图像错误; 其他:检测到的个数 + */ + int process_gpu(sy_img * batch_img, vector& tasklist, + vector& result, vector>& deleteObjectID, vector>& unUsedResult); + + + /************************************************************************* + * FUNCTION: VPT_Release + * PURPOSE: 资源释放 + * PARAM: + [in] handle - 处理句柄 + * RETURN: NULL + * NOTES: + *************************************************************************/ + void release(); + + + void addTaskTracker(const string taskID, double rWidth =1, double rHeight=1, int skip_frame=5); //221117byzsh + bool finishTaskTracker(const string taskID); + +private: + int m_devId; + aclrtContext m_algorthim_ctx; + + void* m_det_handle{nullptr}; + float threshold{0.6}; + int m_max_batchsize; + map taskTrackers; +}; diff --git a/src/ai_engine_module/sort/CycleQueue.h b/src/ai_engine_module/sort/CycleQueue.h new file mode 100644 index 0000000..7950168 --- /dev/null +++ b/src/ai_engine_module/sort/CycleQueue.h @@ -0,0 +1,111 @@ +#include + +using namespace std; + +#define MAX_LENGTH 100 + +typedef struct TRACK_POINT +{ + int x; + int y; +}TRACK_POINT; + +//template +class cycleQueue +{ +private: + unsigned int m_size; + int m_front; + int m_rear; + TRACK_POINT m_data[MAX_LENGTH]; + + bool firstPush; + bool full_size; + +public: + + cycleQueue() {} + + cycleQueue(unsigned size) + :m_size(size), + m_front(0), + m_rear(0) + { + //m_data = new TRACK_POINT[size]; + full_size = false; + firstPush = true; + } + + void set_param(unsigned size) + { + m_size = size; + //m_data = new TRACK_POINT[size]; + full_size = false; + firstPush = true; + m_front = 0; + m_rear = 0; + } + + ~cycleQueue() + { + //delete[] m_data; + } + + bool isEmpty() + { + return m_front == m_rear; + } + + bool isFull() + { + return m_front == (m_rear + 1) % m_size; + } + + int getFront() + { + return m_front; + } + + int getRear() + { + return m_rear; + } + + int size() + { + if (full_size) return m_size; + else if (m_rear == m_front && firstPush == false) return m_size; + else return m_rear - m_front; + } + + void push(TRACK_POINT ele)throw(bad_exception) + { + if (m_front == m_rear && firstPush==false) + { + m_front = (m_front + 1) % m_size; + full_size = true; + //cout << "full_size" << endl; + } + + m_data[m_rear] = ele; + m_rear = (m_rear + 1) % m_size; + firstPush = false; + } + + TRACK_POINT pop() throw(bad_exception) + { + if (isEmpty()) + { + throw bad_exception(); + } + TRACK_POINT tmp = m_data[m_front]; + m_front = (m_front + 1) % m_size; + return tmp; + } + + TRACK_POINT& get(int i) + { + //T tmp = m_data[i]; + return m_data[i]; + } +}; \ No newline at end of file diff --git a/src/ai_engine_module/sort/HungarianAlgorithm.cpp b/src/ai_engine_module/sort/HungarianAlgorithm.cpp new file mode 100644 index 0000000..046f9fe --- /dev/null +++ b/src/ai_engine_module/sort/HungarianAlgorithm.cpp @@ -0,0 +1,409 @@ +#include +#include +#include "HungarianAlgorithm.h" + +#include + +using namespace std; + + +// B = A( extractRows, extractCols ) +// Require: +// extractRows.size()==A.rows, extractCols.size()==A.cols +// sum(extractRows)==B.rows, sum(extractCols)==B.cols +void extractGrids(const cv::Mat &A, const vector &extractRows, const vector &extractCols, cv::Mat &B) +{ + typedef float ValueType; + ValueType *pt1 = (ValueType*)A.data, *pt2 = (ValueType*)B.data, *pt3, *pt4; + const int step1 = A.step1(), rows = A.rows, cols = A.cols, step2 = B.step1(); + vector::const_iterator it1, it2, it3 = extractRows.end(), it4 = extractCols.end(); + for (it1 = extractRows.begin(); it1 != it3; pt1 += step1){ + pt3 = pt1; + if (*(it1++)){ + pt4 = pt2; + for (it2 = extractCols.begin(); it2 != it4; pt3++) + if (*(it2++)) + *(pt4++) = *pt3; + pt2 += step2; + } + } +} + +// B = A( extract ) +// Require: +// min(A.rows,A.cols) ==1 +// if(A.rows)==1, then require: A.cols==extract.size(), B.rows==1, sum(extract)==B.cols +// if(A.cols)==1, then require: A.rows==extract.size(), B.cols==1, sum(extract)==B.rows +void extractDots(const cv::Mat &A, const vector &extract, cv::Mat &B) +{ + assert(A.rows == 1 || A.cols == 1); + typedef float ValueType; + ValueType *pt1 = (ValueType*)A.data, *pt2 = (ValueType*)B.data; + vector::const_iterator it = extract.begin(), it2 = extract.end(); + if (A.rows == 1){ + for (; it != it2; pt1++) + if (*(it++)) + *(pt2++) = *pt1; + } + else{ + int step1 = A.step1(), step2 = B.step1(); + for (; it != it2; pt1 += step1) + if (*(it++)){ + *pt2 = *pt1; + pt2 += step2; + } + } +} + + +/* Initial Matlab code comes from: +http://www.mathworks.com/matlabcentral/fileexchange/20652-hungarian-algorithm-for-linear-assignment-problems--v2-3- + +Hungarian algorithm for matrix assignment problem. +costMat: there are (rows) works and (cols) jobs. costMat(i,j) means the cost of assigning job (j) to worker (i). +The problem is to solve a holistic optimization problem of assigning each worker a job! +The algorithm allows partial assignment - if there is no proper job for worker (i) we would set assignment(i) to -1, meaning no assignment for worker (i). + +Negatives in costMat means the corresponding assignments are forbidden. +*/ +void munkres(cv::Mat &IoUMat, vector &assignment) +{ + assert(IoUMat.type() == CV_32FC1); + const int rows = IoUMat.rows, cols = IoUMat.cols; + assignment.assign(rows, -1); + // modify input port O - IoU = cost + cv::Mat O = cv::Mat::ones(rows, cols, CV_32FC1); + cv::Mat costMat(rows, cols, CV_32FC1); + absdiff(O, IoUMat, costMat); + + cv::Mat validMat(rows, cols, CV_8UC1); + compare(costMat, cv::Scalar(0), validMat, CV_CMP_GE); + + float *ptF, *ptF2; + uchar *ptU, *ptU2; + int stepGap; + int r, c, i; + unsigned j; + vector::iterator it1, it2; + vector::iterator it3, it4; + + // validCol & validRow + vector validRow(rows, false); + ptU = validMat.data; + for (r = 0; r validCol(cols, false); + ptU = validMat.data; + for (c = 0; cnCols ? nRows : nCols; + if (!n) + return; + + // sumValid & maxValid + float sumValid = 0, maxValid = -1.f; + ptF = (float*)costMat.data; + ptU = validMat.data; + stepGap = validMat.step - validMat.cols; + r = 0; while (r++maxValid) maxValid = v; + } + else ptF++; + } ptU += stepGap; + } + + // bigM & maxValid + maxValid *= 10.f; + float bigM = log10f(sumValid); + int power = (int)ceilf(bigM) + 1; + bigM = 1.f; //bigM = pow( 10, power ); + for (i = 0; i starZ(n, -1); + ptU = zP.data; + for (r = 0; r noncoverColumn(n, true); + for (it3 = starZ.begin(); it3 != starZ.end(); it3++){ + if (*it3<0) continue; + noncoverColumn[*it3] = false; + } + vector noncoverRow(n, true); + vector primeZ(n, -1); + + // minC_uncovered & minR_uncovered + int cnt1 = 0, cnt2 = 0; + it1 = noncoverColumn.begin(), it2 = noncoverRow.begin(); + i = 0; while (i++ rIdx, cIdx; // [rIdx,cIdx] = find(temp4); + ptU = temp4.data; + stepGap = temp4.step - temp4.cols; + for (r = 0; r cR, cC; + for (j = 0; j rIdx2, cIdx2; + for (it3 = rIdx.begin(), it4 = cIdx.begin(); it3 != rIdx.end(); it3++, it4++) + if (*it3 != uZr){ + rIdx2.push_back(*it3); + cIdx2.push_back(*it4); + } + rIdx = rIdx2, cIdx = cIdx2; + // cR = find(~coverRow); + cR.clear(); + for (j = 0; j(stz)); + temp1 = tmp1(cv::Rect(0, 0, 1, sz)); + extractDots(dMat.col(stz), noncoverRow, temp1); + temp4 = tmp4(cv::Rect(0, 0, 1, sz)); + compare(temp1, minR_uncovered, temp4, CV_CMP_EQ); + // rIdx = [rIdx(:);cR(z)]; + for (i = 0, ptU = temp4.data; i= 0){ + starZ[rowZ1] = -1; + uZc = primeZ[rowZ1]; + uZr = rowZ1; + for (j = 0; j rowIdx(nRows), colIdx(nCols); + it1 = validRow.begin(), it2 = validCol.begin(); + for (i = 0, it3 = rowIdx.begin(); i vIdx(nRows, false); + it1 = vIdx.begin(), it3 = starZ.begin(); + i = 0; while (i++-1){ + uchar isInvalid = validMat.at(j, job); // validMat is now "invalidMat" + if (isInvalid) + assignment[j] = -1; + } + } +} \ No newline at end of file diff --git a/src/ai_engine_module/sort/HungarianAlgorithm.h b/src/ai_engine_module/sort/HungarianAlgorithm.h new file mode 100644 index 0000000..59fb386 --- /dev/null +++ b/src/ai_engine_module/sort/HungarianAlgorithm.h @@ -0,0 +1,24 @@ +#ifndef HUNGARIANALGORITHM_H_ +#define HUNGARIANALGORITHM_H_ + +#include +#ifdef _MSC_VER + #include +#else + #include + #include + #include +#endif + +#include +#include + +using namespace std; + + + +void extractGrids(const cv::Mat &A, const vector &extractRows, const vector &extractCols, cv::Mat &B); +void extractDots(const cv::Mat &A, const vector &extract, cv::Mat &B); +void munkres(cv::Mat &IoUMat, vector &assignment); + +#endif diff --git a/src/ai_engine_module/sort/KalmanBoxTracker.cpp b/src/ai_engine_module/sort/KalmanBoxTracker.cpp new file mode 100644 index 0000000..acc9b22 --- /dev/null +++ b/src/ai_engine_module/sort/KalmanBoxTracker.cpp @@ -0,0 +1,210 @@ +#include "KalmanBoxTracker.h" +#include + +#include "../../common/logger.hpp" + +float IoU(vector &bb_test, vector &bb_gt) +{ + float xx1, yy1, xx2, yy2, w, h, wh, o; + xx1 = max(bb_test[0], bb_gt[0]); + yy1 = max(bb_test[1], bb_gt[1]); + xx2 = min(bb_test[2], bb_gt[2]); + yy2 = min(bb_test[3], bb_gt[3]); + w = max(float(0), (xx2 - xx1)); + h = max(float(0), (yy2 - yy1)); + wh = w * h; + o = wh / ((bb_test[2] - bb_test[0])*(bb_test[3] - bb_test[1]) + + (bb_gt[2] - bb_gt[0])*(bb_gt[3] - bb_gt[1]) - wh); + return o; +} + +// added by zsh 220718 +float center_distance(vector &bb_test, vector &bb_gt, float maxLength) +{ + float w1 = bb_gt[2] - bb_gt[0]; + float h1 = bb_gt[3] - bb_gt[1]; + float bbox_cx = (bb_gt[0] + bb_gt[2]) / 2; + float bbox_cy = (bb_gt[1] + bb_gt[3]) / 2; + + float w2 = bb_test[2] - bb_test[0]; + float h2 = bb_test[3] - bb_test[1]; + float cx = (bb_test[0] + bb_test[2]) / 2; + float cy = (bb_test[1] + bb_test[3]) / 2; + + float scaleW = 100; + float scaleH = 100; + if (w2 != 0 && h2 != 0) { + scaleW = w1 / w2; + if (scaleW < 1) scaleW = 1. / scaleW; + scaleH = h1 / h2; + if (scaleH < 1) scaleH = 1. / scaleH; + } + + float res = std::sqrt((cx - bbox_cx)*(cx - bbox_cx)+(cy - bbox_cy)*(cy - bbox_cy)) / maxLength * + scaleW * scaleH; + //std::cout << res << std::endl; + return res; +} + +void convert_bbox_to_z(vector &bbox, vector &z) +{ + if(bbox.size() <= 0){ + LOG_ERROR("convert_bbox_to_z - bbox.size() 小于0"); + return; + } + float w, h, x, y, s, r; + w = bbox[2] - bbox[0]; + h = bbox[3] - bbox[1]; + x = bbox[0] + w / 2; + y = bbox[1] + h / 2; + if(fabs(h) < 1e-6){ + LOG_ERROR("convert_bbox_to_z - h小于0"); + return; + } + s = w * h; //scale is just area + r = w / h; + z.push_back(x); + z.push_back(y); + z.push_back(s); + z.push_back(r); + +} + +void convert_x_to_bbox(cv::Mat &x, vector &bbox) +{ + float w, h; + w = sqrt(x.at(2) * x.at(3)); + h = x.at(2) / w; + //bbox[x1,y1,x2,y2]; + bbox.push_back(x.at(0) - w / 2); + bbox.push_back(x.at(1) - h / 2); + bbox.push_back(x.at(0) + w / 2); + bbox.push_back(x.at(1) + h / 2); +} + + + +KalmanBoxTracker::KalmanBoxTracker(vector &bbox, int trackLength) +{ + KF.init(7, 4, 0); //初始化卡尔曼滤波器对象KF + state = cv::Mat::zeros(7, 1, CV_32F); + processNoise = cv::Mat::zeros(7, 1, CV_32F); + measurement = cv::Mat::zeros(4, 1, CV_32F); //定义测量值 + + KF.transitionMatrix = (cv::Mat_(7, 7) << \ + 1, 0, 0, 0, 1, 0, 0, \ + 0, 1, 0, 0, 0, 1, 0, \ + 0, 0, 1, 0, 0, 0, 1, \ + 0, 0, 0, 1, 0, 0, 0, \ + 0, 0, 0, 0, 1, 0, 0, \ + 0, 0, 0, 0, 0, 1, 0, \ + 0, 0, 0, 0, 0, 0, 1); //状态转移矩阵A + + KF.measurementMatrix = (cv::Mat_(4, 7) << \ + 1, 0, 0, 0, 0, 0, 0, \ + 0, 1, 0, 0, 0, 0, 0, \ + 0, 0, 1, 0, 0, 0, 0, \ + 0, 0, 0, 1, 0, 0, 0); //测量矩阵H + + KF.measurementNoiseCov = (cv::Mat_(4, 4) << \ + 1, 0, 0, 0, \ + 0, 1, 0, 0, \ + 0, 0, 10, 0, \ + 0, 0, 0, 10); //测量噪声方差矩阵R + + KF.errorCovPost = (cv::Mat_(7, 7) << \ + 10, 0, 0, 0, 0, 0, 0, \ + 0, 10, 0, 0, 0, 0, 0, \ + 0, 0, 10, 0, 0, 0, 0, \ + 0, 0, 0, 10, 0, 0, 0, \ + 0, 0, 0, 0, 10000, 0, 0, \ + 0, 0, 0, 0, 0, 10000, 0, \ + 0, 0, 0, 0, 0, 0, 10000); //后验错误估计协方差矩阵P + + KF.processNoiseCov = (cv::Mat_(7, 7) << \ + 1, 0, 0, 0, 0, 0, 0, \ + 0, 1, 0, 0, 0, 0, 0, \ + 0, 0, 1, 0, 0, 0, 0, \ + 0, 0, 0, 1, 0, 0, 0, \ + 0, 0, 0, 0, 0.01, 0, 0, \ + 0, 0, 0, 0, 0, 0.01, 0, \ + 0, 0, 0, 0, 0, 0, 0.0001); //系统噪声方差矩阵Q + + vector z; + convert_bbox_to_z(bbox, z); + KF.statePost = (cv::Mat_(7, 1) << z[0], z[1], z[2], z[3], 0, 0, 0); //corrected state + state = (cv::Mat_(7, 1) << z[0], z[1], z[2], z[3], 0, 0, 0); + time_since_update = 0; + cls = bbox[5]; + //history + //hits = 0; + hit_streak = 0; + age = 0; + + m_trackLength = trackLength; + //history = new cycleQueue>(trackLength); + history.set_param(trackLength); +} + +KalmanBoxTracker::~KalmanBoxTracker() +{ + + /*int trackerSize = history.size(); + + for (int i = 0; i < trackerSize; i++) + { + history.get(i).clear(); + vector().swap(history.get(i)); + + }*/ + + /*if (history != NULL) + { + delete history; + history = NULL; + }*/ +} + +void KalmanBoxTracker::update(vector &bbox) +{ + time_since_update = 0; + //history + //hits += 1; + hit_streak += 1; + vector z; + convert_bbox_to_z(bbox, z); + measurement = (cv::Mat_(4, 1) << z[0], z[1], z[2], z[3]); + KF.correct(measurement); + frame_count++; +} + +vector KalmanBoxTracker::predict() +{ + if ((KF.statePost.at(6) + KF.statePost.at(2)) <= 0) + KF.statePost.at(6) *= 0.0; + + KF.predict(); + + age += 1; + if (time_since_update >= FusionInterval) + hit_streak = 0; + time_since_update += 1; + vector bbox; + convert_x_to_bbox(KF.statePost, bbox); + //history.push_back(bbox); + + TRACK_POINT tmp_point; + tmp_point.x = bbox[0] + (bbox[2] - bbox[0]) / 2; + tmp_point.y = bbox[1] + (bbox[3] - bbox[1]) / 2; + history.push(tmp_point); + + return bbox; +} + +vector KalmanBoxTracker::get_state() +{ + vector bbox; + convert_x_to_bbox(KF.statePost, bbox); + return bbox; +} + diff --git a/src/ai_engine_module/sort/KalmanBoxTracker.h b/src/ai_engine_module/sort/KalmanBoxTracker.h new file mode 100644 index 0000000..db808b3 --- /dev/null +++ b/src/ai_engine_module/sort/KalmanBoxTracker.h @@ -0,0 +1,59 @@ +#ifndef KALMANBOXTRACKER_H_ +#define KALMANBOXTRACKER_H_ + +#include +#include +#include +#include +#include +#include "CycleQueue.h" + +using namespace std; + +// #define FusionInterval 5 //控制算法跳帧 +class KalmanBoxTracker +{ +public: + //int count = 0; + int time_since_update = 0; + int FusionInterval = 5; //控制算法跳帧 221117 + int id = 0; + int cls = 0; + float score = 0.00; + std::vector ldmk; + //-added by zsh 220719 人脸姿态角- + float roll = 0.0; + float yaw = 0.0; + float pitch = 0.0; + //------------------------------- + + //vector< vector > history; + + cycleQueue history; //固定大小的轨迹 + //int hits; + int hit_streak = 0; + int age = 0; + int m_trackLength = 0; + + int frame_count {1}; + +public: + KalmanBoxTracker(vector &bbox, int trackLength); + ~KalmanBoxTracker(); + void update(vector &bbox); + vector predict(); + vector get_state(); +private: + cv::KalmanFilter KF; //创建卡尔曼滤波器对象KF + cv::Mat measurement; + cv::Mat state;// (7, 1, CV_32F); //state = x + cv::Mat processNoise; +}; + +float IoU(vector &bb_test, vector &bb_gt); +float center_distance(vector &bb_test, vector &bb_gt, float maxLength); // added by zsh 220718 +void convert_bbox_to_z(vector &bbox, vector &z); +void convert_x_to_bbox(cv::Mat &x, vector &bbox); + + +#endif \ No newline at end of file diff --git a/src/ai_engine_module/sort/Sort.cpp b/src/ai_engine_module/sort/Sort.cpp new file mode 100644 index 0000000..d64bc90 --- /dev/null +++ b/src/ai_engine_module/sort/Sort.cpp @@ -0,0 +1,792 @@ +#include "Sort.h" +#include +#include + +#ifdef _MSC_VER +#include +#include +#define _ACCESS _access +#define _MKDIR(a) _mkdir((a)) +#else +#include +#include +#include +#define _ACCESS access +#define _MKDIR(a) mkdir((a),0755) +#endif +#include + +const int color[11][3] = { { 255, 0, 0 }, { 255, 128, 255 }, { 255, 128, 0 }, { 255, 215, 0 }, { 154, 205, 50 }, { 0, 128, 0 }, \ +{0, 128, 255}, { 186, 85, 211 }, { 91, 46, 0 }, { 0, 0, 0 }, { 255, 255, 255 } +}; + + + +Sort::Sort() +{ + // max_age = 10; + max_age = 15; // 221103 + min_hits = 3; + frame_count = 0; + WORK = true; + //-----------------by zl---------------------// + istraffic = false; //by zl 不统计交通量 + trackcount = 0; + //-----------------by zl---------------------// + + max_track_length = MAX_LENGTH; +} + +int Sort::update(bool isUseDet, bool copy_ldmk, vector< vector > &dets, det_objinfo *result, vector &deleteObjectID) +{ + //get predicted locations from existing trackers. + vector< vector > trks; + vector pos; + int ObjCount = 0; //by zl 本帧图像中的有效前景个数 + vector bbox; + + for (int i = 0; i < trackers.size(); i++ ) + { + pos = trackers[i].predict(); // 对跟踪列表中的框进行预测(包含初始化的和匹配后update的) + pos.push_back(1); + pos.push_back(trackers[i].cls); + trks.push_back(pos); + pos.clear(); + } + + if (isUseDet == true) + { + vector< vector > matched; + vector unmatched_dets; + vector unmatched_trks; + + Sort::associate_detections_to_trackers(matched, unmatched_dets, unmatched_trks, dets, trks, 0.3); + //update matched trackers with assigned detections----匹配上的更新跟踪信息 + for (int matched_number = 0; matched_number < matched.size(); matched_number++) + { + trackers[matched[matched_number][1]].update(dets[matched[matched_number][0]]); + trackers[matched[matched_number][1]].score = dets[matched[matched_number][0]][4]; + trackers[matched[matched_number][1]].cls = dets[matched[matched_number][0]][5]; + if (copy_ldmk)//存入关键点信息 + { + for (int m = 0; m < 50; ++m) + { + trackers[matched[matched_number][1]].ldmk.push_back(dets[matched[matched_number][0]][m + 6]); + } + } + } + + //create and initialise new trackers for unmatched detections----为未匹配上的检测框分配新tracker + for (int unmatched_dets_number = 0; unmatched_dets_number < unmatched_dets.size(); unmatched_dets_number++) + { + KalmanBoxTracker tracker = KalmanBoxTracker(dets[unmatched_dets[unmatched_dets_number]], max_track_length); + tracker.id = -1; + tracker.FusionInterval = FusionInterval; //221117byzsh + trackers.push_back(tracker); + trackers[trackers.size() - 1].score = dets[unmatched_dets[unmatched_dets_number]][4];//by zl 20170525 解决第一次检测时置信度为0问题 + + if (copy_ldmk)//存入关键点信息 + { + for (int m = 0; m < 50; ++m) + { + trackers[trackers.size() - 1].ldmk.push_back(dets[unmatched_dets[unmatched_dets_number]][m + 6]); + } + } + + // cout << "trackers size: " << trackers.size() << endl; + + } + + for (int trackers_number = 0; trackers_number < trackers.size();) + { + // cout << trackers[trackers_number].id << " " < max_age) // 失配次数超过max_age,放入轨迹消失列表,从跟踪列表中删除 + { + if (trackers[trackers_number].id != -1) + { + deleteObjectID.push_back(trackers[trackers_number].id); + } + + trackcount++; + std::vector().swap(trackers[trackers_number].ldmk); + trackers.erase(trackers.begin() + trackers_number); + continue; + } + // 失配次数小于FusionInterval且满足最小匹配次数则返回 + if (ObjCount < MAX_OBJ_COUNT && (trackers[trackers_number].time_since_update < FusionInterval) && ((trackers[trackers_number].hit_streak >= min_hits) || (frame_count <= (min_hits * FusionInterval)))) + { + + if (trackers[trackers_number].id == -1) + trackers[trackers_number].id = trackcount++; + result[ObjCount].id = trackers[trackers_number].id; + + bbox = trackers[trackers_number].get_state(); + result[ObjCount].left = bbox[0]; // bbout[i][0]; + result[ObjCount].top = bbox[1]; //bbout[i][1]; + result[ObjCount].right = bbox[2]; //bbout[i][2]; + result[ObjCount].bottom = bbox[3]; //bbout[i][3]; + result[ObjCount].confidence = trackers[trackers_number].score; // bbout[i][4]; + result[ObjCount].index = trackers[trackers_number].cls; // bbout[i][5] - 1; + result[ObjCount].center_x = result[ObjCount].left + (result[ObjCount].right - result[ObjCount].left) * 0.5; // 中心点 add by 20170227 + result[ObjCount].center_y = result[ObjCount].top + (result[ObjCount].bottom - result[ObjCount].top) * 0.5; // 中心点 + if (trackers[trackers_number].age == 2 * FusionInterval) + { + result[ObjCount].snap_flag = 1; // 中心点 + } + else + { + result[ObjCount].snap_flag = 0; // 中心点 + } + + if (copy_ldmk) // 存入关键点信息 + { + for (int m = 0; m < 25; ++m) + { + result[ObjCount].landmark_point[m].x_ = trackers[trackers_number].ldmk[2 * m]; + result[ObjCount].landmark_point[m].y_ = trackers[trackers_number].ldmk[2 * m + 1]; + } + } +#if _Debug + printf("trackers_number = %d, trackers.size() = %d, update: index = %d, id = %d, (%d, %d), (%d, %d)\n", trackers_number, trackers.size(), result[ObjCount].index, result[ObjCount].id, result[ObjCount].left, result[ObjCount].top, result[ObjCount].right, result[ObjCount].bottom); +#endif + ObjCount++; + } + trackers_number++;//共多少条轨迹 + } + } + else + { + for (int trackers_number = 0; trackers_number < trackers.size() && ObjCount < MAX_OBJ_COUNT; trackers_number++) + { + if (trackers[trackers_number].id == -1) + trackers[trackers_number].id = trackcount++; + bbox = trackers[trackers_number].get_state(); + result[trackers_number].id = trackers[trackers_number].id; + result[trackers_number].left = bbox[0]; // bbout[i][0]; + result[trackers_number].top = bbox[1]; //bbout[i][1]; + result[trackers_number].right = bbox[2]; //bbout[i][2]; + result[trackers_number].bottom = bbox[3]; //bbout[i][3]; + result[trackers_number].confidence = trackers[trackers_number].score; // bbout[i][4]; + result[trackers_number].index = trackers[trackers_number].cls;//bbox[5] - 1;// trackers[trackers_number].cls - 1; // bbout[i][5] - 1; + result[trackers_number].center_x = (int)(result[trackers_number].left + (result[trackers_number].right - result[trackers_number].left) * 0.5); // 中心点 add by 20170227 + result[trackers_number].center_y = (int)(result[trackers_number].top + (result[trackers_number].bottom - result[trackers_number].top) * 0.5); // 中心点 + + if (copy_ldmk)//存入关键点信息 + { + for (int m = 0; m < 25; ++m) + { + result[trackers_number].landmark_point[m].x_ = trackers[trackers_number].ldmk[2 * m]; + result[trackers_number].landmark_point[m].y_ = trackers[trackers_number].ldmk[2 * m + 1]; + } + } + + result[ObjCount].snap_flag = 0; // 中心点 + + ObjCount++; + } + } + + //---------------------------注释掉了这步操作 用了新的绘制轨迹的函数 需要绘制调用addTracker(Mat *img)方法 by lm---------------------------------------------/ + //addTracker(result, ObjCount); + + frame_count += 1; //帧数加一 + return ObjCount; + +} + + +// added by zsh 220719 +int Sort::update_v2(bool isUseDet, bool copy_ldmk, bool center_dist, float maxLen, vector< vector > &dets, det_objinfo *result, vector &deleteObjectID) +{ + //get predicted locations from existing trackers. + vector< vector > trks; + vector pos; + int ObjCount = 0; //by zl 本帧图像中的有效前景个数 + vector bbox; + + for (int i = 0; i < trackers.size(); i++ ) + { + pos = trackers[i].predict(); // 对跟踪列表中的框进行预测(包含初始化的和匹配后update的) + pos.push_back(1); + pos.push_back(trackers[i].cls); + trks.push_back(pos); + pos.clear(); + } + + if (isUseDet == true) + { + vector< vector > matched; + vector unmatched_dets; + vector unmatched_trks; + + if(center_dist) { + Sort::associate_detections_to_trackers_v2(matched, unmatched_dets, unmatched_trks, dets, trks, maxLen); // 中心距离匹配 + } + else { + Sort::associate_detections_to_trackers(matched, unmatched_dets, unmatched_trks, dets, trks, 0.3); // iou匹配 + } + //update matched trackers with assigned detections----匹配上的更新跟踪信息 + for (int matched_number = 0; matched_number < matched.size(); matched_number++) + { + trackers[matched[matched_number][1]].update(dets[matched[matched_number][0]]); + trackers[matched[matched_number][1]].score = dets[matched[matched_number][0]][4]; + trackers[matched[matched_number][1]].cls = dets[matched[matched_number][0]][5]; + if (copy_ldmk)//存入关键点信息 + { + for (int m = 0; m < 50; ++m) + { + trackers[matched[matched_number][1]].ldmk.push_back(dets[matched[matched_number][0]][m + 6]); + } + // added by zsh 姿态角信息-------------------------------------------------------- + trackers[matched[matched_number][1]].roll = dets[matched[matched_number][0]][56]; + trackers[matched[matched_number][1]].yaw = dets[matched[matched_number][0]][57]; + trackers[matched[matched_number][1]].pitch = dets[matched[matched_number][0]][58]; + //-------------------------------------------------------------------------------- + } + } + + //create and initialise new trackers for unmatched detections----为未匹配上的检测框分配新tracker + for (int unmatched_dets_number = 0; unmatched_dets_number < unmatched_dets.size(); unmatched_dets_number++) + { + KalmanBoxTracker tracker = KalmanBoxTracker(dets[unmatched_dets[unmatched_dets_number]], max_track_length); + tracker.id = -1; + tracker.FusionInterval = FusionInterval; //221117byzsh + trackers.push_back(tracker); + trackers[trackers.size() - 1].score = dets[unmatched_dets[unmatched_dets_number]][4];//by zl 20170525 解决第一次检测时置信度为0问题 + + if (copy_ldmk)//存入关键点信息 + { + for (int m = 0; m < 50; ++m) + { + trackers[trackers.size() - 1].ldmk.push_back(dets[unmatched_dets[unmatched_dets_number]][m + 6]); + } + // added by zsh 姿态角信息------------------------------------------------------------ + trackers[trackers.size() - 1].roll = dets[unmatched_dets[unmatched_dets_number]][56]; + trackers[trackers.size() - 1].yaw = dets[unmatched_dets[unmatched_dets_number]][57]; + trackers[trackers.size() - 1].pitch = dets[unmatched_dets[unmatched_dets_number]][58]; + //----------------------------------------------------------------------------------- + } + + // cout << "trackers size: " << trackers.size() << endl; + + } + + for (int trackers_number = 0; trackers_number < trackers.size();) + { + // cout << trackers[trackers_number].id << " " < max_age) // 失配次数超过max_age,放入轨迹消失列表,从跟踪列表中删除 + { + if (trackers[trackers_number].id != -1) + { + deleteObjectID.push_back(trackers[trackers_number].id); + } + + trackcount++; + std::vector().swap(trackers[trackers_number].ldmk); + trackers.erase(trackers.begin() + trackers_number); + continue; + } + // 失配次数小于FusionInterval且满足最小匹配次数则返回 + if (ObjCount < MAX_OBJ_COUNT && (trackers[trackers_number].time_since_update < FusionInterval) && ((trackers[trackers_number].hit_streak >= min_hits) || (frame_count <= (min_hits * FusionInterval)))) + { + + if (trackers[trackers_number].id == -1) + trackers[trackers_number].id = trackcount++; + result[ObjCount].id = trackers[trackers_number].id; + result[ObjCount].num = trackers[trackers_number].frame_count; + + bbox = trackers[trackers_number].get_state(); + result[ObjCount].left = bbox[0]; // bbout[i][0]; + result[ObjCount].top = bbox[1]; //bbout[i][1]; + result[ObjCount].right = bbox[2]; //bbout[i][2]; + result[ObjCount].bottom = bbox[3]; //bbout[i][3]; + result[ObjCount].confidence = trackers[trackers_number].score; // bbout[i][4]; + result[ObjCount].index = trackers[trackers_number].cls; // bbout[i][5] - 1; + result[ObjCount].center_x = result[ObjCount].left + (result[ObjCount].right - result[ObjCount].left) * 0.5; // 中心点 add by 20170227 + result[ObjCount].center_y = result[ObjCount].top + (result[ObjCount].bottom - result[ObjCount].top) * 0.5; // 中心点 + if (trackers[trackers_number].age == 2 * FusionInterval) + { + result[ObjCount].snap_flag = 1; // 中心点 + } + else + { + result[ObjCount].snap_flag = 0; // 中心点 + } + + if (copy_ldmk) // 存入关键点信息 + { + for (int m = 0; m < 25; ++m) + { + result[ObjCount].landmark_point[m].x_ = trackers[trackers_number].ldmk[2 * m]; + result[ObjCount].landmark_point[m].y_ = trackers[trackers_number].ldmk[2 * m + 1]; + } + // added by zsh 姿态角信息-------------------------------- + result[ObjCount].roll = trackers[trackers_number].roll; + result[ObjCount].yaw = trackers[trackers_number].yaw; + result[ObjCount].pitch = trackers[trackers_number].pitch; + //-------------------------------------------------------- + } +#if _Debug + printf("trackers_number = %d, trackers.size() = %d, update: index = %d, id = %d, (%d, %d), (%d, %d)\n", trackers_number, trackers.size(), result[ObjCount].index, result[ObjCount].id, result[ObjCount].left, result[ObjCount].top, result[ObjCount].right, result[ObjCount].bottom); +#endif + ObjCount++; + } + trackers_number++;//共多少条轨迹 + } + } + else + { + for (int trackers_number = 0; trackers_number < trackers.size() && ObjCount < MAX_OBJ_COUNT; trackers_number++) + { + if (trackers[trackers_number].id == -1) + trackers[trackers_number].id = trackcount++; + result[trackers_number].num = trackers[trackers_number].frame_count; + bbox = trackers[trackers_number].get_state(); + result[trackers_number].id = trackers[trackers_number].id; + result[trackers_number].left = bbox[0]; // bbout[i][0]; + result[trackers_number].top = bbox[1]; //bbout[i][1]; + result[trackers_number].right = bbox[2]; //bbout[i][2]; + result[trackers_number].bottom = bbox[3]; //bbout[i][3]; + result[trackers_number].confidence = trackers[trackers_number].score; // bbout[i][4]; + result[trackers_number].index = trackers[trackers_number].cls;//bbox[5] - 1;// trackers[trackers_number].cls - 1; // bbout[i][5] - 1; + result[trackers_number].center_x = (int)(result[trackers_number].left + (result[trackers_number].right - result[trackers_number].left) * 0.5); // 中心点 add by 20170227 + result[trackers_number].center_y = (int)(result[trackers_number].top + (result[trackers_number].bottom - result[trackers_number].top) * 0.5); // 中心点 + + if (copy_ldmk)//存入关键点信息 + { + for (int m = 0; m < 25; ++m) + { + result[trackers_number].landmark_point[m].x_ = trackers[trackers_number].ldmk[2 * m]; + result[trackers_number].landmark_point[m].y_ = trackers[trackers_number].ldmk[2 * m + 1]; + } + // added by zsh 姿态角信息--------------------------------------- + result[trackers_number].roll = trackers[trackers_number].roll; + result[trackers_number].yaw = trackers[trackers_number].yaw; + result[trackers_number].pitch = trackers[trackers_number].pitch; + //-------------------------------------------------------------- + } + + result[ObjCount].snap_flag = 0; // 中心点 + + ObjCount++; + } + } + + //---------------------------注释掉了这步操作 用了新的绘制轨迹的函数 需要绘制调用addTracker(Mat *img)方法 by lm---------------------------------------------/ + //addTracker(result, ObjCount); + + frame_count += 1; //帧数加一 + return ObjCount; + +} + + +//---------------------------利用trackers中的history 绘制路径 -by lm ---------------------------------------------/ +//固定长度的轨迹,采用循环队列,仅保存目前最前N length的轨迹,避免对于停留在画面中目标 导致的内存一直增长 +int Sort::addTracker(cv::Mat *img) +{ + map> tracker; + vector bbox; + + + int x_1, y_1, x_2, y_2; + for (auto iter : trackers) + { + if (iter.time_since_update < FusionInterval) + { + int index = iter.history.getFront(); + int trackerSize = iter.history.size(); + + for (int i = 0; i < trackerSize; i++) + { + if (i == 0) + { + x_1 = iter.history.get(index).x; + y_1 = iter.history.get(index).y; + } + else + { + x_2 = iter.history.get(index).x; + y_2 = iter.history.get(index).y; + int colorIndex = iter.id % 11; + cv::line(*img, cvPoint(x_1, y_1), cvPoint(x_2, y_2), cvScalar(color[colorIndex][0], color[colorIndex][1], color[colorIndex][2]), 1); + + //drawLineOnGPU() + + x_1 = x_2; + y_1 = y_2; + } + + index = (index + 1) % trackerSize; + } + } + + } + + return 1; +} + +//不固定长度的轨迹版本 采用vector,轨迹一直保留,对于停留在画面中的物体,会有内存一直增长的隐患 +//int Sort::addTracker(cv::Mat *img) +//{ +// map> tracker; +// vector bbox; +// +// +// int x_1, y_1, x_2, y_2; +// for (auto iter : trackers) +// { +// if (iter.time_since_update < FusionInterval) +// { +// for (int i = 0; i < iter.history.size(); i++) +// { +// +// if (i == 0) +// { +// x_1 = iter.history[i][0] + (iter.history[i][2] - iter.history[i][0]) / 2; +// y_1 = iter.history[i][1] + (iter.history[i][3] - iter.history[i][1]) / 2; +// } +// else +// { +// x_2 = iter.history[i][0] + (iter.history[i][2] - iter.history[i][0]) / 2; +// y_2 = iter.history[i][1] + (iter.history[i][3] - iter.history[i][1]) / 2; +// int colorIndex = iter.id % 11; +// cv::line(*img, cvPoint(x_1, y_1), cvPoint(x_2, y_2), cvScalar(color[colorIndex][0], color[colorIndex][1], color[colorIndex][2]), 1); +// +// //drawLineOnGPU() +// +// x_1 = x_2; +// y_1 = y_2; +// } +// } +// } +// +// } +// +// return 1; +//} + +void Sort::Release() +{ + //tracker.clear(); + //vector ().swap(tracker); + trackers.clear(); + vector().swap(trackers); +} +bool Sort::GetState() +{ + return WORK; +} + +void Sort::Pause() +{ + WORK = false; +} + +void Sort::ReSet() +{ + WORK = true; + //Release(); + //max_age = 1; + //min_hits = 3; + //frame_count = 0; + + ////-----------------by zl---------------------// + //istraffic = false; //by zl 不统计交通量 + //trackcount = 0; + ////-----------------by zl---------------------// +} + +//---------------------------by zl ---------------------------------------------/ +bool line_rect_intersection(cv::Point start_p, cv::Point end_p, int left, int top, int right, int bottom) +{ + int a = start_p.y - end_p.y; + int b = end_p.x - start_p.x; + int c = start_p.x* end_p.y - end_p.x* start_p.y; + + ////思路:先看线段所在直线是否与矩形相交,如果不相交则必为 “F”, + ////如果相交,则看线段的两个点是否在矩形的同一边(即两点的 x(y) 坐标都比矩形的小 x(y) 坐标小,或者大), + ////若在同一边则为“F”,否则就是相交的情况。 + if ((a* left + b*top + c >= 0 && a* right + b* bottom + c <= 0) || + (a* left + b*top + c <= 0 && a* right + b* bottom + c >= 0) || + (a* left + b*bottom + c >= 0 && a* right + b* top + c <= 0) || + (a* left + b*bottom + c >= 0 && a* right + b* top + c <= 0)) + + { + if (left > right) + { + swap(left, right); + } + if (top < bottom) + { + swap(top, bottom); + } + if ((start_p.x < left && end_p.x < left) || + (start_p.x > right && end_p.x < left) || + (start_p.y > top && end_p.y > top) || + (start_p.y < bottom && end_p.y < bottom)) ///判断线段是否在矩形一侧 + { + return false; + } + else + { + return true; + } + } + else + { + return false; + } +} + +void RectboundCheck(int Width, int Height, det_objinfo * result) //防止坐标越界 by zl +{ + if (result->left < 0) + result->left = 0; + if (result->left >= Width) + result->left = Width; + + if (result->top < 0) + result->top = 0; + if (result->top >= Height) + result->top = Height; + + if (result->right <= result->left) + result->right = result->left + 1; + if (result->right >= Width) + result->right = Width; + + if (result->bottom < result->top) + result->bottom = result->top + 1; + if (result->bottom >= Height) + result->bottom = Height; + + +} +//------------------------------------其他函数----------------------------------------// +void Sort::associate_detections_to_trackers(vector< vector > &matched, vector &unmatched_dets, vector &unmatched_trks, vector< vector > &dets, vector< vector > &trks, float iou_threshold) +{ + + if (0 == trks.size()) + { + for (int x = 0; x < dets.size(); x++) + { + unmatched_dets.push_back(x); + } + } + else if (0 == dets.size()) + { + for (int x = 0; x < trks.size(); x++) + { + unmatched_trks.push_back(x); + } + } + else + { + cv::Mat IoUMat(dets.size(), trks.size(), CV_32FC1); + for (int i = 0; i < dets.size(); i++) + for (int j = 0; j < trks.size(); j++) + { + //cls区分 + if (1) + //if (dets[i][5] == trks[j][5]) + { + IoUMat.at(i, j) = IoU(dets[i], trks[j]); + } + else + { + IoUMat.at(i, j) = 0; + } + + } + + //匈牙利算法 + vector assignment; + munkres(IoUMat, assignment); + + vector::iterator iter; + for (int trackers_indices = 0; trackers_indices < trks.size(); trackers_indices++) + { + iter = find(assignment.begin(), assignment.end(), trackers_indices); + if (iter == assignment.end()) + { + //assignment中不存在trackers_indices值 + unmatched_trks.push_back(trackers_indices); + } + } + + vector matched_row_col; + for (int detections_indices = 0; detections_indices < assignment.size(); detections_indices++) + { + if (assignment[detections_indices] == -1) + { + unmatched_dets.push_back(detections_indices); + } + else if (IoUMat.at(detections_indices, assignment[detections_indices]) > iou_threshold) + { + matched_row_col.push_back(detections_indices); + matched_row_col.push_back(assignment[detections_indices]); + matched.push_back(matched_row_col); + matched_row_col.clear(); + } + else + { + unmatched_dets.push_back(detections_indices); + unmatched_trks.push_back(assignment[detections_indices]); + } + } + } +} + + +// added by zsh 220719 人脸等小目标采取中心距离匹配 +void Sort::associate_detections_to_trackers_v2(vector< vector > &matched, vector &unmatched_dets, vector &unmatched_trks, vector< vector > &dets, vector< vector > &trks, float maxLen) +{ + + if (0 == trks.size()) + { + for (int x = 0; x < dets.size(); x++) + { + unmatched_dets.push_back(x); + } + } + else if (0 == dets.size()) + { + for (int x = 0; x < trks.size(); x++) + { + unmatched_trks.push_back(x); + } + } + else + { + // --------------------------------------------------------------------------- +#if 1 + static bool firstRun = 1; + float distanceWeight = 1; + float disNorm = 0; + float updateSpeed = 0.2; + float max_distance = 0.5; + for (auto& det : dets) { + float w1 = det[2] - det[0]; + float h1 = det[3] - det[1]; + disNorm += sqrt(w1 * w1 + h1 * h1) /maxLen; + } + disNorm = disNorm / dets.size(); + if (firstRun) { + max_distance = disNorm * distanceWeight; // face & hs + // max_distance = disNorm * 1.5; // car for gaoxinxing + firstRun = 0; + } else { + max_distance = disNorm * distanceWeight * updateSpeed + max_distance * (1 - updateSpeed); // face & hs + // max_distance = disNorm * 1.5 * updateSpeed + max_distance * (1 - updateSpeed); // car for gaoxinxing + } +#endif + // ------------------------------------------------------------------------- + cv::Mat IoUMat(dets.size(), trks.size(), CV_32FC1); + for (int i = 0; i < dets.size(); i++) + for (int j = 0; j < trks.size(); j++) + { + //cls区分 + if (1) + //if (dets[i][5] == trks[j][5]) + { + // IoUMat.at(i, j) = IoU(dets[i], trks[j]); + // ----------------------------------------------------------------- + IoUMat.at(i, j) = center_distance(dets[i], trks[j], maxLen); + float tmp = IoUMat.at(i, j); + if(tmp > max_distance) IoUMat.at(i, j) = max_distance + 1e-5; + // ----------------------------------------------------------------- + } + else + { + IoUMat.at(i, j) = 0; + } + + } + + //匈牙利算法 + vector assignment; + //----------------------------------------------- + const int rows = IoUMat.rows, cols = IoUMat.cols; + cv::Mat O = cv::Mat::ones(rows, cols, CV_32FC1); + cv::Mat costMat(rows, cols, CV_32FC1); + absdiff(O, IoUMat, costMat); + munkres(costMat, assignment); + //----------------------------------------------- + // munkres(IoUMat, assignment); + + vector::iterator iter; + for (int trackers_indices = 0; trackers_indices < trks.size(); trackers_indices++) + { + iter = find(assignment.begin(), assignment.end(), trackers_indices); + if (iter == assignment.end()) + { + //assignment中不存在trackers_indices值 + unmatched_trks.push_back(trackers_indices); + } + } + + vector matched_row_col; + for (int detections_indices = 0; detections_indices < assignment.size(); detections_indices++) + { + if (assignment[detections_indices] == -1) + { + unmatched_dets.push_back(detections_indices); + } + // else if (IoUMat.at(detections_indices, assignment[detections_indices]) > iou_threshold) + else if (IoUMat.at(detections_indices, assignment[detections_indices]) <= max_distance) + { + matched_row_col.push_back(detections_indices); + matched_row_col.push_back(assignment[detections_indices]); + matched.push_back(matched_row_col); + matched_row_col.clear(); + } + else + { + unmatched_dets.push_back(detections_indices); + unmatched_trks.push_back(assignment[detections_indices]); + } + } + } +} +//判断两条线是否相交 + +///------------alg 2------------ +//叉积 +double mult(cv::Point a, cv::Point b, cv::Point c) +{ + return (a.x - c.x)*(b.y - c.y) - (b.x - c.x)*(a.y - c.y); +} + +//aa, bb为一条线段两端点 cc, dd为另一条线段的两端点 相交返回true, 不相交返回false +bool intersect(cv::Point aa, cv::Point bb, cv::Point cc, cv::Point dd) +{ + if (max(aa.x, bb.x) +// #include +#include "opencv2/opencv.hpp" +#include +#include +#include +#include + +#include "../../ai_platform/det_obj_header.h" + +using namespace std; + + +#define LOSTMAXFRAMECCOUNT 5 //by zl +#define SNAPSHOTFRAMECOUNT 24 //下标从0开始 取第十帧为快照帧 + +struct TrackerResult +{ + vector< vector > trackers_box; + vector< vector< vector > > trackers_history; +}; + + +typedef struct mylist +{ + vector listinfo; + int lost; //丢失的帧数 >LOSTMAXFRAMECCOUNT 则认为彻底丢失目标 + long id; + bool isupdate; + bool istraffic; + int index;// 行人类别 + int num; // 该ID序列下的第num帧 20170306 从0开始计数 + int startframe; //轨迹开始帧 + int endframe; //轨迹结束帧 +}mylist; + + + +class Sort +{ +public: + Sort(); + int update(bool isUseDet, bool copy_ldmk, vector< vector > &dets, det_objinfo *result, vector &deleteObjectID); + int update_v2(bool isUseDet, bool copy_ldmk, bool center_dist, float maxLen, vector< vector > &dets, det_objinfo *result, vector &deleteObjectID); // added by zsh 220719 + void Release(); + void ReSet(); + void Pause(); + bool GetState(); + int addTracker(cv::Mat *img); +public: + vector trackers; + int FusionInterval = 5; //221117 + int max_age = 0; + int min_hits = 0; + int frame_count =0; + int trackcount = 0; + int max_track_length = 0; + +private: + int linecount = 0; + bool istraffic = 0; //by zl 是否统计交通量 + //vector tracker; + bool WORK = false; + +private: + void associate_detections_to_trackers(vector< vector > &matched, vector &unmatched_dets, vector &unmatched_trks, vector< vector > &dets, vector< vector > &trks, float iou_threshold = 0.3); + void associate_detections_to_trackers_v2(vector< vector > &matched, vector &unmatched_dets, vector &unmatched_trks, vector< vector > &dets, vector< vector > &trks, float maxLen); //added by zsh 220719 + //int addTracker(VPT_ObjInfo *result, int resultcount); + int Traffic(); +}; +//辅助函数 +void RectboundCheck(int Width, int Height, det_objinfo * result); //防止坐标越界 by zl +bool intersect(cv::Point aa, cv::Point bb, cv::Point cc, cv::Point dd); //判断两个线条是否相交 暂时未用到 +bool line_rect_intersection(cv::Point start_p, cv::Point end_p, int left, int top, int right, int bottom); //判断矩形框与线条是否相交 +#endif \ No newline at end of file diff --git a/src/ai_engine_module/vpt.h b/src/ai_engine_module/vpt.h new file mode 100644 index 0000000..10e588f --- /dev/null +++ b/src/ai_engine_module/vpt.h @@ -0,0 +1,121 @@ +/******************************************************************************************* +* Version: vpt_det_v0.0.0 +* CopyRight: 中科院自动化研究所模式识别实验室图像视频组 +* UpdateDate: 20190327 +* Content: 人车物检测 +********************************************************************************************/ + +#ifndef VPT_DET_H_ +#define VPT_DET_H_ + +#ifdef _MSC_VER +#ifdef VPT_DET_EXPORTS +#define VPT_DET_API __declspec(dllexport) +#else +#define VPT_DET_API __declspec(dllimport) +#endif +#else +#define VPT_DET_API __attribute__ ((visibility ("default"))) +#endif + +#include "sy_common.h" + +//extern "C" +//{ + +#ifndef MAX_BATCH_SIZE +#define MAX_BATCH_SIZE 16 +#endif + +#define MAX_DET_COUNT 50 + + //Utools Obj Results +#ifndef __VPT_OBJ_RESULT__ +#define __VPT_OBJ_RESULT__ + typedef struct vpt_obj_result + { + int obj_id; //不开启跟踪时对应batch输入顺序,开启后对应目标的id + sy_rect obj_rect; //位置 + int obj_index; + float obj_score; + }vpt_obj_result; +#endif + + //Utools Results +#ifndef __VPT_RESULT__ +#define __VPT_RESULT__ + typedef struct vpt_result + { + int obj_count_; //返回特征数组总个数 < 检测中:单batch检测总数 / 分类中:Multi数 > + vpt_obj_result *obj_results_; //单batch中 所有的结果 batch size <= MAX_BATCH_SIZE + }vpt_result; +#endif //by Junlin 190121 + +#ifndef __VPT_PARAM__ +#define __VPT_PARAM__ + typedef struct vpt_param + { + // int mode; //运行模式(DEVICE_GPU / DEVICE_CPU) + int devId; //ָ指定显卡id + char* modelNames; + // char* modelNames_b10; + float threshold; + bool isTrk; //是否开启跟踪 + //vpt_param() :mode(DEVICE_GPU), gpuid(0), threshold(0.6) {}; + }vpt_param; +#endif + + /************************************************************************* + * FUNCTION: hcp_init + * PURPOSE: 初始化 + * PARAM: + [out] tools - 句柄 + [in] param - 初始化参数 + * RETURN: + [out] int - 初始化是否成功(SUCCEEDED表示成功,FAILED表示失败) + * NOTES: + *************************************************************************/ + VPT_DET_API int vpt_init(void **handle, vpt_param param); + + /************************************************************************* + * FUNCTION: hcp_process + * PURPOSE: 人骑车属性检测 + * PARAM: + [in] tools - 句柄 + [in] img_data - 检测图像数据 + [in] width - 检测图像宽度 + [in] height - 检测图像高度 + [in] channels - 检测图像通道数 + [in] result - 检测结果 + * RETURN: + [out] int - 检测是否成功(SUCCEEDED表示成功,FAILED表示失败) + * NOTES: + *************************************************************************/ + // VPT_DET_API int vpt_process(void * handle, sy_img img, vpt_result *result); + + + VPT_DET_API int vpt_batch(void * handle, sy_img *batch_img, int batchsize, vpt_result **result); + + // VPT_DET_API int vpt_batch10(void * handle, sy_img *batch_img, int batchsize, vpt_result **result); + + /************************************************************************* + * FUNCTION: hcp_release + * PURPOSE: 资源释放 + * PARAM: + [in] tools - 处理句柄 + * RETURN: NULL + * NOTES: + *************************************************************************/ + VPT_DET_API void vpt_release(void **handle); + + + /************************************************************************* + * FUNCTION: hcp_get_version + * PURPOSE: + * PARAM: NULL + * RETURN: 版本号 + * NOTES: + *************************************************************************/ + VPT_DET_API const char * vpt_get_version(); +//} +#endif diff --git a/src/ai_platform/ErrorInfo.h b/src/ai_platform/ErrorInfo.h new file mode 100644 index 0000000..e98d269 --- /dev/null +++ b/src/ai_platform/ErrorInfo.h @@ -0,0 +1,110 @@ +#ifndef ERRORINFO_H_ +#define ERRPRINFO_H_ + + +//--------------------------------通用------------------------------------// + +#define SUCCESS 0 //成功 +#define FAILED -1 //失败 + +//1.通用错误 预留编号:(-199) - (-100) +#define PARAMS_NULL_ERROR -100 //参数为空 +#define FILE_NOTFOUND_ERROR -101 //文件找不到 +#define HANDLE_NULL_ERROR -102 //句柄为空 +#define TYPE_UNKNOWN -103 //未知类型 +#define IMG_DATA_ERROR -104 //图像数据错误 +#define IMG_PARAMS_ERROR -105 //图像参数(宽 高 或者 通道数)有错误 +#define AUTHOR_ERROR -106 //授权失败 +#define VERSION_EXPIRED -107 //时间限制下的版本过期 +#define VIDEOFILEERROR -108 //视频打开失败 +#define BUFFNOTENOUGH -109 //缓冲区太小 + +#define MEAN_ERROR -110 //均值错误 +#define MODEL_IMG_PARAMS_ERROR -111 // +#define GPU_DEVICE_ERROR -112 //GPU显卡参数错误 + +#define CONFIG_FILE_NOTFOUND_ERROR -117 //配置文件找不到 +#define TIMEOUT_ERROR -118 //等待超时 + +//------------------------------------------------------------------------// + + +//-----------------------------深度学习相关-------------------------------// + +//1.通用模块 预留编号:(-299) - (-200) + +//a. caffe部分 预留编号:(-239) - (-200) +#define BATCH_SIZE_NO_EQUAL_INPUT -200 //BATCH_SIZE不匹配 +#define LAYER_NO_REGISTER -201 //层未注册 + +//b. 网络和模型部分 预留编号:(-279) - (-240) +#define PROTOFILE_MODEL_MISMATCH -240 //网络和模型不匹配 +#define PROTOFILEORVECTOR_NOTFOUND -241 //网络文件或者数组找不到 +#define PROTOFILE_NOTFOUND -242 //网络文件找不到 +#define PROTOVECTOR_NOTFOUND -243 //网络数组找不到 +#define MODELFILE_NOTFOUND -244 //模型文件找不到 +#define MODELLENGTH_ERROE -245 //模型数组长度错误 +#define MODELVECTOR_ERROE -246 //模型数组错误 + +//c. 其他深度学习通用错误 预留编号:(-299) - (-280) + + +//----------------------------------------// + + +//2.人脸模块 预留编号:(-349) - (-300) + + +#define QUALITY_INIT_ERROR -300 //质量检测初始化失败 +#define ROTATIONCUT_INIT_ERROR -301 //切割旋转初始化失败 +#define FACERECG_INITFAILD_ERROR -302 //人脸识别初始化失败 +#define FACECUT_INITFAILD_ERROR -303 //人脸切割旋转初始化失败 +#define LDMK_INIT_ERROR -304 //关键点检测初始化失败 +#define FACEDETECT_INIT_ERROR -305 //人脸检测初始化失败 + + + +//----------------------------------------// + + +//3.跟踪模块 预留编号:(-399) - (-350) +#define TRACKER_INIT_ERROR -350 //轨迹跟踪初始化失败 + + +//----------------------------------------// + + +//4.快照模块 预留编号:(-449) - (-400) +#define SHAPSHOT_INIT_ERROR -400 //快照初始化失败 + + +//----------------------------------------// + + +//5.流量统计模块 预留编号:(-499) - (-450) +#define TRAFFICSTATISTICS_INIT_ERROR -450 //流量统计初始化失败 + + + + +//------------------------------------------------------------------------// + + +//-----------------------------授权部分相关-------------------------------// + +//1.授权通用模块 预留编号:(-600) - (-500) +#define AUTHOR_TIMEEXPIRED_ERROR -500 //超出有效期 +#define AUTHOR_SERVER_ERROR -501 //服务器出错 +#define AUTHOR_NOAUTHORIZATION_ERROR -502 //未注册且没有装机剩余量 +#define AUTHOR_NOCOMMUNICATION_ERROR -503 //无法通信 +#define AUTHOR_NET_ERROR -504 //网络出错 + + + +// mq 预留编号:(-650) - (-600) +#define MQ_CONN_ERROR -601 + + + + +#endif \ No newline at end of file diff --git a/src/ai_platform/Makefile b/src/ai_platform/Makefile new file mode 100644 index 0000000..a456115 --- /dev/null +++ b/src/ai_platform/Makefile @@ -0,0 +1,80 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +DEFS = -DENABLE_DVPP_INTERFACE + +# 最终目标文件 +TARGET:=$(BUILD_DIR)/bin/demo + + +include_dir=-I/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/include + +lib_dir=-L/usr/lib \ + -L/usr/local/lib \ + -L/usr/local/Ascend/driver/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/atc/lib64\ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64 \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64/stub \ + -L/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/lib64 \ + -L/usr/local/Ascend/driver/lib64/driver + +lib=-lacl_dvpp -lascendcl -lmmpa -lglog -lgflags -lpthread -lz -lacl_dvpp_mpi -lruntime -lascendalog -lc_sec -lmsprofiler -lgert -lge_executor -lge_common \ + -lgraph -lascend_protobuf -lprofapi -lerror_manager -lexe_graph -lregister -lplatform + +INCLUDE= -I $(TOP_DIR)/interface \ + +LIBSPATH= -L $(BUILD_DIR)/interface/lib -l:interface.a \ + -L $(BUILD_DIR)/dvpp/lib -l:dvpp.a + +CXXFLAGS= -g -O0 -fPIC $(INCLUDE) $(include_dir) $(LIBSPATH) $(INCS) $(LIBS) $(lib_dir) $(lib) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl + # -DUNICODE -D_UNICODE + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET): $(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @echo -e "$(CXX) -o $@ $^ $(DEPFLAGS) $(CXXFLAGS) $(MACROS)" + $(CXX) -o $@ $^ $(DEPFLAGS) $(CXXFLAGS) $(MACROS) + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @echo -e "$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $<" + $(CXX) -c $(DEPFLAGS) $(CXXFLAGS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/ai_platform/MultiSourceProcess.cpp b/src/ai_platform/MultiSourceProcess.cpp new file mode 100644 index 0000000..e51bfc7 --- /dev/null +++ b/src/ai_platform/MultiSourceProcess.cpp @@ -0,0 +1,557 @@ +#include "MultiSourceProcess.h" +#include "../common/logger.hpp" + +#include +#include +#include +#include +#include + +#include "../decoder/interface/DecoderManager.h" +#include "../decoder/interface/utiltools.hpp" +#include "../util/vpc_util.h" +#include "../util/crop_process.h" +#include "../helpers/time_helper.hpp" +#include "../helpers/os_helper.hpp" +#include "../helpers/gen_json.hpp" +#include "../reprocessing_module/save_snapshot_reprocessing.h" + +#include "macro_definition.h" + +#define VEHICLE_MULTI_BOXES + +using namespace std; + + +struct decode_cbk_userdata{ + string task_id; + void* opaque; + void* opaque1; +}; + + + +/** + * 注意: gpuFrame 在解码器设置的显卡上,后续操作要十分注意这一点,尤其是多线程情况 + * */ +void post_decod_cbk(const void * userPtr, DeviceMemory* devFrame){ + decode_cbk_userdata* ptr = (decode_cbk_userdata*)userPtr; + if (ptr!= nullptr) + { + CMultiSourceProcess* _this = (CMultiSourceProcess*)ptr->opaque; + if(nullptr != _this){ + _this->decoded_cbk(devFrame); + } + } +} + +void decode_finished_cbk(const void * userPtr){ + decode_cbk_userdata* ptr = (decode_cbk_userdata*)userPtr; + if (ptr!= nullptr) + { + CMultiSourceProcess* _this = (CMultiSourceProcess*)ptr->opaque; + if(nullptr != _this){ + _this->task_finished(ptr->task_id); + } + } + delete ptr; + ptr = nullptr; +} + +CMultiSourceProcess::CMultiSourceProcess(){ + aclInit(nullptr); +} + +CMultiSourceProcess::~CMultiSourceProcess(){ + dvpp_crop_release(); + aclFinalize(); +} + +int CMultiSourceProcess::InitAlgorthim(tsl_aiplatform_param vptParam){ + + set_default_logger(LogLevel(vptParam.log_level), "multi_source_process", vptParam.log_path, vptParam.log_mem, vptParam.log_mem); + LOG_INFO("编译时间:{} {}", __DATE__, __TIME__); + + skip_frame_ = 5; + m_batch_size = 16; + + m_devId = vptParam.gpuid; + + VPTProcess_PARAM vparam; + vparam.gpuid = m_devId; + vparam.max_batch = m_batch_size; + vparam.threshold = 0.4; + + aclrtSetDevice(m_devId); + + int ret = vpt_process.init(vparam); + if (ret < 0){ + return ret; + } + + m_task_param_manager = task_param_manager::getInstance(); + m_snapshot_reprocessing = snapshot_reprocessing::getInstance(); + m_save_snapshot_reprocessing = new save_snapshot_reprocessing(m_devId); + + dvpp_crop_init(m_devId); + + m_pAlgorthimThread = new thread([](void* arg) { + CMultiSourceProcess* process = (CMultiSourceProcess*)arg ; + process->algorthim_process_thread(); + return (void*)0; + } + , this); + + return 0; +} + +#ifdef POST_USE_RABBITMQ +/* MQ队列的初始化 */ +int CMultiSourceProcess::AddMqConn(mq_type_t mq_type, rabbitmq_conn_params_t mq_conn_param) { + /* 初始化MQ队列 */ + if (!mq_manager_->add_conn(mq_type, mq_conn_param)) { + LOG_ERROR("Connection MQ failed, ip: {} port: {} uname: {} passwd: {}", mq_conn_param.ip, mq_conn_param.port, + mq_conn_param.uname, mq_conn_param.passwd); + return MQ_CONN_ERROR; + } + + /* 为报警类 绑定回调 传入mq_manager_.publish 内部直接调用*/ + if (mq_type_t::ALARM_MQ == mq_type) + m_save_snapshot_reprocessing->set_callback( + std::bind(&mq::Manager::publish, mq_manager_, mq_type, std::placeholders::_1, true)); + + return SUCCESS; +} + +/* 获取任务的状态 MQ返回 */ +int CMultiSourceProcess::GetTaskStatus(const string taskID) { + + DecoderManager* pDecManager = DecoderManager::getInstance(); + + std::vector taskids; + std::vector statues; + if(pDecManager->isPausing(taskID)){ + taskids.emplace_back(taskID); + statues.emplace_back(2); + }else if(pDecManager->isRunning(taskID)){ + taskids.emplace_back(taskID); + statues.emplace_back(1); + } + + if (!taskids.empty()) { + auto json_str = helpers::gen_json::gen_task_status_json(taskids, statues); + mq_manager_->publish(mq_type_t::GET_TASK_MQ, json_str.c_str(),true); + } + + return SUCCESS; +} +#endif + +bool CMultiSourceProcess::AddTask(task_param _cur_task_param){ + DecoderManager* pDecManager = DecoderManager::getInstance(); + + const char* task_id = _cur_task_param.task_id; + + MgrDecConfig config; + config.name = task_id; + config.cfg.uri = _cur_task_param.ipc_url; + config.cfg.post_decoded_cbk = post_decod_cbk; + config.cfg.decode_finished_cbk = decode_finished_cbk; + config.cfg.force_tcp = true; // rtsp用tcp + config.cfg.gpuid = to_string(m_devId); + config.cfg.skip_frame = skip_frame_; + + if (1 == _cur_task_param.dec_type){ + config.cfg.port = _cur_task_param.port; + config.dec_type = DECODER_TYPE_GB28181; + config.cfg.uri = task_id; + if(_cur_task_param.protocal == 0){ + // 指定用udp协议 + config.cfg.force_tcp = false; + } + config.cfg.request_stream_cbk = _cur_task_param.gb28181_request_stream_callback ; + }else if (2 == _cur_task_param.dec_type){ + config.dec_type = DECODER_TYPE_DVPP; + }else { + config.dec_type = DECODER_TYPE_FFMPEG; + } + + AbstractDecoder* dec = pDecManager->createDecoder(config); + if (!dec) + { + return false; + } + + decode_cbk_userdata* userPtr = new decode_cbk_userdata; + userPtr->task_id = string(task_id); + userPtr->opaque = this; + userPtr->opaque1 = dec; + pDecManager->setPostDecArg(config.name, userPtr); + pDecManager->setFinishedDecArg(config.name, userPtr); + + // pDecManager->setDecKeyframe(config.name, true); // 只对关键帧解码 + + + // 保存新添加任务的配置参数 + m_task_param_manager->add_task_param(task_id, _cur_task_param); + + int input_image_width = 0; + int input_image_height = 0; + pDecManager->getResolution(config.name, input_image_width, input_image_height); + LOG_INFO("task_id: {} width: {} height:{}", task_id, input_image_width, input_image_height); + + // 所有参数都准备好之后再启动解码 + bool bStart = pDecManager->startDecodeByName(config.name); + if (!bStart){ + LOG_INFO("started task {} failed!", config.name); + pDecManager->closeDecoderByName(config.name); + return false; + } + + // 人车物跟踪 + if (task_has_vpt_algor(task_id)) + vpt_process.addTaskTracker(task_id, 1, 1, skip_frame_); + + m_FinishedTaskMtx.lock(); + m_FinishedTaskMap[task_id] = false; + m_FinishedTaskMtx.unlock(); + + LOG_INFO("started task {} successed!", config.name); + + return true; +} + +bool CMultiSourceProcess::task_has_vpt_algor(const std::string &task_id){ + //! TODO: create enum iterator. + auto algor_map = m_task_param_manager->get_task_other_param(task_id); + if (algor_map == nullptr) + return false; + + return (algor_map->find(algorithm_type_t::HUMAN_GATHER) != algor_map->end() || + algor_map->find(algorithm_type_t::HUMAN_SNAPSHOT) != algor_map->end() || + algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_SNAPSHOT) != algor_map->end() || + algor_map->find(algorithm_type_t::SMOKING_DET) != algor_map->end() || + algor_map->find(algorithm_type_t::NO_REFLECTIVE_CLOTHING) != algor_map->end() || + algor_map->find(algorithm_type_t::NO_SAFETY_HELMET) != algor_map->end() || + algor_map->find(algorithm_type_t::CALL_PHONE_DET) != algor_map->end() || + algor_map->find(algorithm_type_t::VEHICLE_SNAPSHOT) != algor_map->end() || + algor_map->find(algorithm_type_t::TAKEAWAY_MEMBER_CLASSIFICATION) != algor_map->end() || + algor_map->find(algorithm_type_t::PEDESTRIAN_FALL) != algor_map->end() || + algor_map->find(algorithm_type_t::PEDESTRIAN_FIGHT) != algor_map->end() || + algor_map->find(algorithm_type_t::PEDESTRIAN_RETROGRADE) != algor_map->end() || + algor_map->find(algorithm_type_t::VEHICLE_RETROGRADE) != algor_map->end() || + algor_map->find(algorithm_type_t::PEDESTRIAN_TRESPASS) != algor_map->end() || + algor_map->find(algorithm_type_t::VEHICLE_TRESPASS) != algor_map->end()); +} + +void CMultiSourceProcess::decoded_cbk(DeviceMemory* devFrame){ + do{ + if(m_bfinish){ + break; + } + m_DataListMtx.lock(); + if(m_RgbDataList.size() >= 30){ + m_DataListMtx.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + continue; + } + m_RgbDataList.push_back(devFrame); + m_DataListMtx.unlock(); + break; + }while (true); +} + +void CMultiSourceProcess::task_finished(const string task_id){ + + std::lock_guard l(m_FinishedTaskMtx); + + m_FinishedTaskMap[task_id] = true; + + LOG_INFO("task {} finished!", task_id); +} + +bool CMultiSourceProcess::PauseTask(const string taskID){ + return false; +} + +bool CMultiSourceProcess::RestartTask(const string taskID){ + return false; +} + +bool CMultiSourceProcess::FinishTask(const string taskID){ + DecoderManager* pDecManager = DecoderManager::getInstance(); + return pDecManager->closeDecoderByName(taskID); +} + +int CMultiSourceProcess::SnapShot(task_param param){ + return 0; +} + +void CMultiSourceProcess::CloseAllTask(){ + m_bfinish = true; + + DecoderManager* pDecManager = DecoderManager::getInstance(); + pDecManager->closeAllDecoder(); + + if(m_pAlgorthimThread){ + m_pAlgorthimThread->join(); + m_pAlgorthimThread = nullptr; + } + + m_DataListMtx.lock(); + while (!m_RgbDataList.empty()){ + DeviceMemory* gpuMem = m_RgbDataList.front(); + delete gpuMem; + gpuMem = nullptr; + m_RgbDataList.pop_front(); + } + m_DataListMtx.unlock(); + + int size = m_RgbDataList.size(); + bool bEmpty = m_RgbDataList.empty(); + + LOG_INFO("CloseAllTask exit."); +} + +void CMultiSourceProcess::clear_finished_task(){// 清理已经结束的任务 + + std::lock_guard l1(m_FinishedTaskMtx); + std::lock_guard l2(m_DataListMtx); + + for (auto iter_finished = m_FinishedTaskMap.begin(); iter_finished!=m_FinishedTaskMap.end(); ){ + if(iter_finished->second){ + // 解码已经结束 + // 判断数据对列中是否还有数据 + string task_id = iter_finished->first; + bool bFinished = true; + for (auto iter = m_RgbDataList.begin(); iter!=m_RgbDataList.end(); ++ iter){ + DeviceMemory* gpuMem = *iter; + if(task_id == gpuMem->getId()){ + bFinished = false; + break; + } + } + + if (bFinished){ + // 解码器已经结束,且数据队列中没有改任务的数据,则做最后任务清理工作 + finish_task(task_id,false); + iter_finished = m_FinishedTaskMap.erase(iter_finished); + continue; + } + } + + ++ iter_finished; + } +} + +bool CMultiSourceProcess::finish_task(const string taskID, const bool delete_snapshot){ + + // 任务结束,关闭跟踪 + if (!vpt_process.finishTaskTracker(taskID)) + LOG_ERROR("Finish VPT Tracker failed, task_id: {}", taskID); + +#ifdef POST_USE_RABBITMQ + auto json_str = helpers::gen_json::gen_office_task_heart_beat_json({taskID}); + mq_manager_->publish(mq_type_t::HEART_BEAT_MQ, json_str.c_str(), true); +#endif + + m_task_param_manager->delete_task_param(taskID); + + return true; +} + +int CMultiSourceProcess::algorthim_process_thread(){ + LOG_INFO("algorthim_process_thread start..."); + + ACL_CALL(aclrtSetDevice(m_devId), ACL_ERROR_NONE, 1); + aclrtContext ctx; + ACL_CALL(aclrtCreateContext(&ctx, m_devId), ACL_ERROR_NONE, 1); + + while (true){ + if(m_bfinish){ + break; + } + + clear_finished_task(); + + vector vec_gpuMem; + m_DataListMtx.lock(); + while (!m_RgbDataList.empty()){ + DeviceMemory* gpuMem = m_RgbDataList.front(); + vec_gpuMem.push_back(gpuMem); + m_RgbDataList.pop_front(); + if(vec_gpuMem.size() >= m_batch_size){ + break; + } + } + m_DataListMtx.unlock(); + + if(vec_gpuMem.size() <= 0){ + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + continue; + } + + ACL_CALL(aclrtSetCurrentContext(ctx), ACL_ERROR_NONE, 1); + algorthim_vpt(vec_gpuMem); + + for(int i=0;i < vec_gpuMem.size(); i++){ + DeviceMemory* mem = vec_gpuMem[i]; + if(mem->getSize() <= 0){ + continue; + } + delete mem; + mem = nullptr; + } + vec_gpuMem.clear(); + + } + + LOG_INFO("algorthim_process_thread exit."); + + return 0; +} + +int CMultiSourceProcess::algorthim_vpt(vector vec_gpuMem){ + + vector vpt_interest_task_id; + vector vpt_interest_imgs(0); + vector vec_vptMem; + for (int i = 0; i < vec_gpuMem.size(); i++) { + DeviceMemory* mem = vec_gpuMem[i]; + if (!task_has_vpt_algor(mem->getId())){ + continue; + } + + sy_img img; + img.w_ = mem->getWidth(); + img.h_ = mem->getHeight(); + img.data_ = mem->getMem(); + vpt_interest_imgs.push_back(img); + vpt_interest_task_id.push_back(mem->getId()); + vec_vptMem.push_back(mem); + } + + /* 待检测的图片不为空 开始检测 */ + if (!vpt_interest_imgs.empty()) { + vector> deleteObjectID; + deleteObjectID.resize(vpt_interest_task_id.size()); + vector> unUsedResult; + vector vptResult(0); + + /* 一级检测器,内部已完成跟踪操作 */ + vpt_process.process_gpu(vpt_interest_imgs.data(), vpt_interest_task_id, vptResult, deleteObjectID, unUsedResult); // do det & track. + + m_snapshot_reprocessing->screen_effective_snapshot(vpt_interest_task_id, vptResult); + +#ifndef VEHICLE_MULTI_BOXES + /* 快照优选(内部可实现不同的快照优选策略) */ + m_snapshot_reprocessing->update_bestsnapshot(vpt_interest_task_id, vpt_interest_imgs.data(), vptResult, deleteObjectID); +#else + algorithm_vehicle_relult(vec_vptMem, vptResult, deleteObjectID); + + // send_locus_finished_msg(vpt_interest_task_id, deleteObjectID); +#endif + + if(vptResult.size() > 0){ + cout << vptResult[0].obj_count<< endl; + } + } + + return 0; +} + +int CMultiSourceProcess::algorithm_vehicle_relult(vector vec_devMem, vector& vptResult, vector>& delete_object_id) { + + vector results = m_snapshot_reprocessing->get_vehicle_snapshot(vec_devMem, vptResult, skip_frame_); + + for (auto &result : results) { + if(result.objs.size() <= 0){ + continue; + } + auto task_id = result.task_id; + auto task_other_params = m_task_param_manager->get_task_other_param(task_id); + const auto &algor_other_params = task_other_params->find(algorithm_type_t::VEHICLE_SNAPSHOT); + if (algor_other_params == task_other_params->end()) { + LOG_ERROR("[Error] taskId {} not found algor {}", task_id.c_str(), (int)algorithm_type_t::VEHICLE_SNAPSHOT); + continue; + } + const algor_basic_config_param_t *basic_param = algor_other_params->second->basic_param; + + std::string cur_timestamp_ms = std::to_string(helpers::timer::get_cur_time_ms()); + const std::string fpath_origin = basic_param->result_folder + helpers::os::sep + task_id + "_" + + std::to_string(result.objs.size()) + "_" + std::to_string(result.id) + "_" + cur_timestamp_ms + ".jpg"; + + ImgSaveInfo saveInfo; + saveInfo.file_path = fpath_origin; + saveInfo.img_info = dvpp_devMem2vpcImg(result.memPtr); + m_save_snapshot_reprocessing->reprocessing_process_wo_locus_async(saveInfo); + + vector vec_obj_info_list = dvpp_crop_batch(result.memPtr, result.objs); + if(vec_obj_info_list.size() != result.objs.size()){ + LOG_ERROR("vpc_crop size error !"); + dvpp_imgList_release(vec_obj_info_list); + continue; + } + + // 保存抠图并发MQ + for(int i =0; i < result.objs.size(); i++){ + video_object_info obj = result.objs[i]; + + std::string cur_timestamp_ms = std::to_string(helpers::timer::get_cur_time_ms()); + const std::string fpath_roi = basic_param->result_folder_little + helpers::os::sep + task_id + "_" + + std::to_string(obj.object_id) + "_" + cur_timestamp_ms + ".jpg"; + + video_object_snapshot new_obj_ss_info; + new_obj_ss_info.analysisRes = nullptr; + new_obj_ss_info.object_id = obj.object_id; + new_obj_ss_info.obj_info.set_data(obj.index, obj.confidence, obj.left, obj.top, obj.right, obj.bottom); + strcpy(new_obj_ss_info.task_id, task_id.c_str()); + strcpy(new_obj_ss_info.video_image_path, fpath_origin.c_str()); + strcpy(new_obj_ss_info.snapshot_image_path, fpath_roi.c_str()); + new_obj_ss_info.nFinished = 0; + string json_str = "1111";//helpers::gen_json::gen_multi_obj_json(algorithm_type_t::VEHICLE_SNAPSHOT, new_obj_ss_info); + + ImgSaveInfo save_info; + save_info.file_path = fpath_roi; + save_info.img_info = vec_obj_info_list[i]; + save_info.json_str = json_str; + m_save_snapshot_reprocessing->reprocessing_process_wo_locus_async(save_info); + } + + vec_obj_info_list.clear(); + } + + return 0; +} + +void CMultiSourceProcess::send_locus_finished_msg(vector& vpt_interest_task_id, vector> deleteObjectID){ + auto task_iter = vpt_interest_task_id.begin(); + + for (int i = 0; i < deleteObjectID.size(); i++, ++task_iter) // loop taskId. + { + string task_id = *task_iter; + for (int &j : deleteObjectID[i]) // loop algor type. + { + OBJ_KEY obj_key = {task_id, j}; + + auto task_param_ptr = m_task_param_manager->get_task_algor_param(task_id); + auto task_other_param_ptr = m_task_param_manager->get_task_other_param(task_id); + + // 该路任务开启了抓拍功能 开始抓拍保存;若未开启抓拍,清空显存资源 + // if (task_param_ptr->vehicle_algors.find(algorithm_type_t::VEHICLE_SNAPSHOT) != task_param_ptr->vehicle_algors.end()) { + // std::lock_guard l(m_total_mutex); + // if (m_total_snapshot_info_multi_object.find(obj_key) != m_total_snapshot_info_multi_object.end()) { + // video_object_snapshot new_obj_ss_info; + // new_obj_ss_info.object_id = j; + // new_obj_ss_info.nFinished = 1; + // strcpy(new_obj_ss_info.task_id, task_id.c_str()); + // string json_str = helpers::gen_json::gen_multi_obj_json(algorithm_type_t::VEHICLE_SNAPSHOT, new_obj_ss_info); + // // 通知结束的轨迹 + // m_save_snapshot_reprocessing->reprocessing_finish_locus_async(obj_key,json_str); + + // m_total_snapshot_info_multi_object.erase(obj_key); + // } + // } + } + } +} \ No newline at end of file diff --git a/src/ai_platform/MultiSourceProcess.h b/src/ai_platform/MultiSourceProcess.h new file mode 100644 index 0000000..8f49517 --- /dev/null +++ b/src/ai_platform/MultiSourceProcess.h @@ -0,0 +1,82 @@ +#include "header.h" +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" +#include "task_param_manager.h" +#include "../ai_engine_module/VPTProcess.h" +#include "../reprocessing_module/snapshot_reprocessing.h" +#include "../reprocessing_module/save_snapshot_reprocessing.h" + +#include +#include +#include +#include +#include +#include + + + +using namespace std; + +class DeviceMemory; + +class CMultiSourceProcess { +public: + CMultiSourceProcess(); + ~CMultiSourceProcess(); + + int InitAlgorthim(tsl_aiplatform_param vptParam); + bool AddTask(task_param _cur_task_param); + bool PauseTask(const string taskID); + bool RestartTask(const string taskID); + bool FinishTask(const string taskID); + void CloseAllTask(); + int SnapShot(task_param param); + +#ifdef POST_USE_RABBITMQ + int AddMqConn(mq_type_t mq_type, rabbitmq_conn_params_t mq_conn_param); + int GetTaskStatus(const string taskID); +#endif + +public: + int algorthim_process_thread(); // 算法处理线程 + void task_finished(const string task_id); + void decoded_cbk(DeviceMemory* devFrame); + +private: + // 算法相关 + int algorthim_vpt(vector vec_gpuMem); + +private: + // 工具处理函数 + bool task_has_vpt_algor(const std::string &task_id); + void clear_finished_task(); + bool finish_task(const string taskID, const bool delete_snapshot); + int algorithm_vehicle_relult(vector vec_devMem, vector& vptResult, vector>& delete_object_id); + void send_locus_finished_msg(vector& vpt_interest_task_id, vector> deleteObjectID); + +private: + int m_devId; + + snapshot_reprocessing *m_snapshot_reprocessing{nullptr}; + task_param_manager *m_task_param_manager{nullptr}; + save_snapshot_reprocessing *m_save_snapshot_reprocessing{nullptr}; + + VPTProcess vpt_process; + int skip_frame_ = 5; // 控制跳帧参数 + + deque m_RgbDataList; + mutex m_DataListMtx; + + mutex m_FinishedTaskMtx; + map m_FinishedTaskMap; + + thread* m_pAlgorthimThread; + bool m_bfinish{false}; + + int m_batch_size{1}; + +#ifdef POST_USE_RABBITMQ + mq::Manager *mq_manager_{nullptr}; +#endif + +}; \ No newline at end of file diff --git a/src/ai_platform/common_header.h b/src/ai_platform/common_header.h new file mode 100644 index 0000000..f3db5ba --- /dev/null +++ b/src/ai_platform/common_header.h @@ -0,0 +1,33 @@ +#ifndef ___COMMON_HEADER_H__ +#define ___COMMON_HEADER_H__ + +#include +#include + +struct point_t { + int x, y; +}; + +struct box_t { + long id; // -1: placeholder. + float score; + int top, left, right, bottom, cls; + + int width() const { + return std::max(0, right - left); + } + + int height() const { + return std::max(0, bottom - top); + } + + int cx() const { + return std::max(0, int((left + right) * 0.5f)); + } + + int cy() const { + return std::max(0, int((top + bottom) * 0.5f)); + } +}; + +#endif // ___COMMON_HEADER_H__ \ No newline at end of file diff --git a/src/ai_platform/det_obj_header.h b/src/ai_platform/det_obj_header.h new file mode 100644 index 0000000..19a5f88 --- /dev/null +++ b/src/ai_platform/det_obj_header.h @@ -0,0 +1,99 @@ +/* + * @Author: yangzilong + * @Date: 2021-11-24 11:39:57 + */ + +#pragma once + +#include "header.h" +#include +#include +#include + +using namespace std; + +#define VTTYPECOUNT 10 //支持的最大类别数 +#define MAX_OBJ_COUNT 100 + +//设置最小检测框,直接指定sy_rect的宽高即可,各种类目标小于最小检测框大小时不进行快照的保存和后续二次属性分析 +//sy_rect m_boxsize[DETECTTYPE] = { sy_rect(0,0,40, 90), sy_rect(0,0,50, 80), sy_rect(0,0,50, 80), sy_rect(0,0,60, 80), sy_rect(0,0,80, 80), sy_rect(0,0,90, 90), sy_rect(0,0,100, 100), sy_rect(0,0,100, 100), sy_rect(0,0,100, 100) }; //行人 自行�?摩托�?三轮�?小型�?大车 卡车 拖拉�?中巴 + +struct OBJ_INDEX { + int index; + int count; //用于对index的计数 + OBJ_INDEX() : count(0), index(0) {} +}; + +// 0-行人 1-自行车 2-摩托车 3-三轮车 4-小型车 5-大车 6-卡车 7-拖拉机 8-中巴 +enum class det_class_label_t +{ + HUMAN = 0, + + BICYCLE = 1, + MOTOCYCLE = 2, + TRICYCLE = 3, + + SMALL_CAR = 4, + LARGE_CAR = 5, + TRUCK = 6, + TRACTOR = 7, + MEDIUM_BUS = 8, +}; + +typedef struct det_objinfo //结果结构体 +{ + int left; + int top; + int right; + int bottom; + int center_x; + int center_y; + + int index; // 行人/车辆类别,支持10类 + long id; // 目标唯一ID,同一ID为同一目标 + int num; // 该ID序列下的第num帧 + double confidence; // 置信度 + int snap_flag; + sy_point landmark_point[25];//人脸关键点位置信息 + //-added by zsh 220719 人脸姿态角- + float roll = 0.0; + float yaw = 0.0; + float pitch = 0.0; + //------------------------------- +}det_objinfo; + +typedef struct onelevel_det_result +{ + string task_id; + int obj_count; + det_objinfo obj[MAX_OBJ_COUNT]; +}onelevel_det_result; + + +struct OBJ_KEY { + string video_id; + int obj_id; + + bool operator< (OBJ_KEY const& _A) const + { + if (strcmp(video_id.c_str(), _A.video_id.c_str()) < 0) return true; + if (strcmp(video_id.c_str(), _A.video_id.c_str()) == 0) return obj_id < _A.obj_id; + + return false; + } + bool operator== (OBJ_KEY const& _A) const + { + if (strcmp(video_id.c_str(), _A.video_id.c_str())==0 && obj_id == _A.obj_id) + return true; + else + return false; + } +}; + +#define EDGESIZE 4 +#define SCALE_OUT 10 // 外扩信息 + +const sy_rect m_boxsize[DETECTTYPE] = { sy_rect(0, 0, 40, 90), sy_rect(0, 0, 50, 80), sy_rect(0, 0, 50, 80), sy_rect(0, 0, 60, 80), sy_rect(0, 0, 80, 80), +sy_rect(0, 0, 90, 90), sy_rect(0, 0, 100, 100), sy_rect(0, 0, 100, 100), sy_rect(0, 0, 100, 100) }; //行人 自行车 摩托车 三轮车 小型车 大车 卡车 拖拉机 中巴 +// const int minDistance[EDGESIZE] = { 35, 50, 35, 50 }; +const int minDistance[EDGESIZE] = { 80, 100, 80, 100 }; diff --git a/src/ai_platform/header.h b/src/ai_platform/header.h new file mode 100644 index 0000000..111a59a --- /dev/null +++ b/src/ai_platform/header.h @@ -0,0 +1,581 @@ +#pragma once + +#ifdef _MSC_VER +#include +#else + +#include + +#endif + +#include "sy_common.h" +#include +#include + +#define DETECTTYPE 9 +// #define MTASK_DEBUG_ + +enum class algorithm_type_t { + PLACEHOLDER = -2, + UNKNOWN = -1, + VIDEO_SNAPSHOT = 100, // 220802byzsh 视频快照 + FACE_SNAPSHOT = 101, + VIDEO_TIMING_SNAPSHOT = 102, // 230220byzsh 视频定时抓拍 + HUMAN_SNAPSHOT = 201, + + PEDESTRIAN_FALL = 202, + PEDESTRIAN_FIGHT = 203, + HUMAN_GATHER = 204, + SMOKING_DET = 206, + CALL_PHONE_DET = 207, + NO_REFLECTIVE_CLOTHING = 208, + NO_SAFETY_HELMET = 209, + PEDESTRIAN_RETROGRADE = 210, + PEDESTRIAN_TRESPASS = 211, + ROAD_WORK_DET = 212, // 221026byzsh施工占道 + + VEHICLE_SNAPSHOT = 301, + VEHICLE_RETROGRADE = 310, + VEHICLE_TRESPASS = 311, + + NONMOTOR_VEHICLE_SNAPSHOT = 401, + TAKEAWAY_MEMBER_CLASSIFICATION = 402, +}; + + +typedef algorithm_type_t algo_type; + + +static bool is_support_algorithm_type(int algor_type) { + return (int) algorithm_type_t::FACE_SNAPSHOT <= algor_type && + (int) algorithm_type_t::TAKEAWAY_MEMBER_CLASSIFICATION >= algor_type; +}; + +static bool is_support_algorithm_type(algorithm_type_t algor_type) { + return is_support_algorithm_type((int) algor_type); +}; + + +//二次属性分析结果结构体 +#ifndef __CLASSIFY_OBJ_RESULT__ +#define __CLASSIFY_OBJ_RESULT__ +typedef struct classify_obj_res //分类结果结构体 +{ + int res_index; //分类结果 + float res_prob; //分类结构体 + classify_obj_res() : res_index(0), res_prob(0) {}; +} classify_obj_res; +#endif + +//检测结果结构体 +#ifndef __DETECTION_OBJ_RESULT__ +#define __DETECTION_OBJ_RESULT__ +typedef struct detection_obj_res //分类结果结构体 +{ + int res_index; + float res_prob; + int res_left; + int res_top; + int res_right; + int res_bottom; + + detection_obj_res() : res_index(0), res_prob(0), res_left(0), res_top(0), res_right(0), res_bottom(0) {}; + + void set_data(int _res_index, float _res_prob, int _res_left, int _res_top, int _res_right, int _res_bottom) { + res_index = _res_index; + res_prob = _res_prob; + res_left = _res_left; + res_top = _res_top; + res_right = _res_right; + res_bottom = _res_bottom; + } +} detection_obj_res; +#endif + + +//行人二次属性分析结构 + 特征结果 +#ifndef __HP_OBJ_RESULT__ +#define __HP_OBJ_RESULT__ +const int HP_FIR_INDEX_SIZE = 16; +const int HF_FEA_SIZE = 128; +typedef struct hp_res { + classify_obj_res res_objs[HP_FIR_INDEX_SIZE]{}; //分类结果 +} hp_res; + +#ifndef __INT8__ +#define __INT8__ +typedef unsigned char int8; +#endif + +typedef struct hp_result { + hp_res res_objs{}; //分类结果 + int8 feature[HF_FEA_SIZE]{}; //特征 +} hp_result; +#endif + +//行人打架/跌倒结果 +#ifndef __HP_FALLFIGHT_RESULT__ +#define __HP_FALLFIGHT_RESULT__ +typedef struct hp_fallfight_result { + float fall_score; //跌倒得分 + float fight_score; //打架得分 + float background_score; //背景得分 +} hp_fallfight_result; +#endif + + +//人骑车二次属性分析结构 + 特征结果 +#ifndef __HCP_OBJ_RESULT__ +#define __HCP_OBJ_RESULT__ +const int HCP_FIR_INDEX_SIZE = 14; +const int HCF_FEA_SIZE = 128; +typedef struct hcp_res { + classify_obj_res res_objs[HCP_FIR_INDEX_SIZE]{}; //分类结果 +} hcp_res; + +typedef struct hcp_result //人骑车二次属性分析以及特征结果 +{ + hcp_res res_objs{}; //分类结果 + int8 feature[HCF_FEA_SIZE]{}; //特征 + classify_obj_res kuaidiyuan_res; //快递员识别结果 + classify_obj_res waimaiyuan_res; //外卖员识别结果 +} hcp_result; + +#endif + + +#define VEHICLE_FEA_SIZE 128 +#define PLATENUM 8 //车牌号码位数 +#define MAX_PALTE_COUNT 10 //每张图片中最多检测出10个车牌 + +#define SINGLETYPE_BLUE 0 //单排蓝色 +#define SINGLETYPE_YELLOW 1 //单排黄色 +#define SINGLETYPE_WHITE 2 //单排白色 +#define SINGLETYPE_BLACK 3 //单排黑色 +#define DOUBLETYPE_YELLOW 4 //双排黄色 +#define DOUBLETYPE_WHITE 5 //双排白色 +#define NEWENERGYTYPE_YELLOWGREEN 6 //新能源黄绿色 +#define NEWENERGYTYPE_WHITEGRA 7 //新能源白绿色 + +//车牌号码 +#ifndef VPLATENUM_RESULT_ +#define VPLATENUM_RESULT_ +typedef struct vplate_num { + char character[4]; + float maxprob; +} vplate_num; +#endif + +#ifndef VP_RESULT_ +#define VP_RESULT_ +typedef struct vplate_result { + sy_rect rect; + float detect_score; + vplate_num recg[PLATENUM]; + float num_score; + int type; //车牌类型 +} vplate_result; +#endif + + +#ifndef VR_RESULT_ +#define VR_RESULT_ +typedef struct vr_result //结果 +{ + char vehicle_brand[260]; //车辆品牌 + char vehicle_subbrand[260]; //车辆子品牌 + char vehicle_issue_year[260]; //车辆年款 + char vehicle_type[260]; //车辆类型 + char freight_ton[260]; //货车吨级 + float name_score; //识别置信度 +} vr_result; +#endif + +#ifndef VC_RESULT_ +#define VC_RESULT_ +typedef struct vc_result { + int res_index; //车颜色结果index + float res_prob; //识别置信度 + vc_result() : res_index(0), res_prob(0) {}; +} vc_result; +#endif + +//VEHICLE +#ifndef __VEHICLE_OBJ_RESULT__ +#define __VEHICLE_OBJ_RESULT__ +typedef struct vehicle_result //车二次属性分析结果 +{ + vr_result vr_res; //车型识别结果 + vc_result vc_res; //车颜色识别结果 + vplate_result vp_res; //车牌检测结果 + int8 feature[VEHICLE_FEA_SIZE]{}; //车辆特征 +} vehicle_result; +#endif + +//返回的检测物体快照结果 +#ifndef __VIDEO_OBJECT_SNAPSHOT__ +#define __VIDEO_OBJECT_SNAPSHOT__ +typedef struct video_object_snapshot { + char task_id[128]; //该物体属于的任务ID号 + int object_id; //该物体的ID号 + char video_image_path[256]; //该物体快照的视频截图保存路径 + char snapshot_image_path[256]; //该物体快照抠图保存路径 + + detection_obj_res obj_info; + void *analysisRes; //二次属性分析结果 + int nFinished; // 轨迹是否已经结束 +} video_object_snapshot; +#endif + +//返回的检测物体结果信息 +#ifndef __VIDEO_OBJECT_INFO__ +#define __VIDEO_OBJECT_INFO__ +typedef struct video_object_info { + int task_id; //该物体属于的任务ID号 + int task_frame_count; //该物体当前出现的帧号 + int object_id; //该物体的ID号 + int left; //该物体位置的左坐标 + int top; //该物体位置的上坐标 + int right; //该物体位置的右坐标 + int bottom; //该物体位置的下坐标 + int index; //该物体所属类别的编号 + double confidence; //该物体的置信度 +} video_object_info; +#endif + +// 人员聚集参数结构体 +#ifndef ___HUMAN_GATHER_ALGOR_CONFIG_PARAM__ +#define ___HUMAN_GATHER_ALGOR_CONFIG_PARAM__ +typedef struct algor_config_param_human_gather { + int frame_stride; //人数推送间隔(实际间隔 = frame_stride * 内部跳帧数) + int human_count_threshold; //人数报警阈值 + algor_config_param_human_gather() + : frame_stride(1), human_count_threshold(0) {} +} algor_config_param_human_gather; +#endif // #ifndef ___HUMAN_GATHER_ALGOR_CONFIG_PARAM__ + + + +// 施工占道参数结构体 221026byzsh +#ifndef ___ROAD_WORK_ALGOR_CONFIG_PARAM__ +#define ___ROAD_WORK_ALGOR_CONFIG_PARAM__ +typedef struct algor_config_param_road_work { + int frame_stride; //推送间隔(实际间隔 = frame_stride * 内部跳帧数) + int rblock_count_threshold; //报警阈值 + algor_config_param_road_work() + : frame_stride(1), rblock_count_threshold(3) {} +} algor_config_param_road_work; +#endif // #ifndef ___ROAD_WORK_ALGOR_CONFIG_PARAM__ + + +// 视频定时抓拍参数结构体 230220byzsh +#ifndef ___VIDEO_TIMING_SNAPSHOT_CONFIG_PARAM__ +#define ___VIDEO_TIMING_SNAPSHOT_CONFIG_PARAM__ +typedef struct algor_config_video_timing_snapshot { + int frame_stride; //推送间隔(实际间隔 = frame_stride * 内部跳帧数) + algor_config_video_timing_snapshot() + : frame_stride(150) {} +} algor_config_video_timing_snapshot; +#endif // #ifndef ___VIDEO_TIMING_SNAPSHOT_CONFIG_PARAM__ + + +// 人员跌倒参数结构体 +#ifndef ___PEDESTRIAN_FALL_ALGOR_CONFIG_PARAM__ +#define ___PEDESTRIAN_FALL_ALGOR_CONFIG_PARAM__ +typedef struct algor_config_param_pedestrian_fall { + float threshold; + int pedestrian_min_height, pedestrian_min_width, pedestrian_confidence_threshold; + + algor_config_param_pedestrian_fall() + : threshold(0.8), pedestrian_min_width(0), pedestrian_min_height(0), + pedestrian_confidence_threshold(0.0f) {} +} algor_config_param_pedestrian_fall; +#endif // #ifndef ___PEDESTRIAN_FALL_ALGOR_CONFIG_PARAM__ + + +// 人员跌倒参数结构体 +#ifndef ___PEDESTRIAN_FIGHT_ALGOR_CONFIG_PARAM__ +#define ___PEDESTRIAN_FIGHT_ALGOR_CONFIG_PARAM__ +typedef struct algor_config_param_pedestrian_fight { + float threshold; + float iou_threshold; + int pedestrian_min_height, pedestrian_min_width, pedestrian_confidence_threshold; + + algor_config_param_pedestrian_fight() + : threshold(0.8), iou_threshold(0.1), pedestrian_min_width(0), pedestrian_min_height(0), + pedestrian_confidence_threshold(0.0f) {} +} algor_config_param_pedestrian_fight; +#endif // #ifndef ___PEDESTRIAN_FIGHT_ALGOR_CONFIG_PARAM__ + + + +// 外卖员识别参数结构体 +#ifndef ___TAKEAWAY_MEMBER_CLASSIFICATION_ALGOR_CONFIG_PARAM__ +#define ___TAKEAWAY_MEMBER_CLASSIFICATION_ALGOR_CONFIG_PARAM__ +typedef struct algor_config_param_takeaway_member_classification { + int m, n; + float threshold; + int pedestrian_min_height, pedestrian_min_width, pedestrian_confidence_threshold; + + algor_config_param_takeaway_member_classification() + : m(10), n(8), threshold(0.7), pedestrian_min_width(0), pedestrian_min_height(0), + pedestrian_confidence_threshold(0.0f) {} +} algor_config_param_takeaway_member_classification; +#endif // #ifndef ___TAKEAWAY_MEMBER_CLASSIFICATION_ALGOR_CONFIG_PARAM__ + + + +// 行人安全检测参数 +#ifndef ___PEDESTRIAN_SAFETY_DETECTOR_ALGOR_CONFIG_PARAM__ +#define ___PEDESTRIAN_SAFETY_DETECTOR_ALGOR_CONFIG_PARAM__ + +typedef struct algor_config_param_pedestrian_safety_detector_basic { + unsigned m, n; + float conf_threshold; + float pedestrian_confidence_threshold; + unsigned pedestrian_min_height, pedestrian_min_width; + + algor_config_param_pedestrian_safety_detector_basic() + : m(10), n(8), conf_threshold(0.0f), pedestrian_min_width(0), pedestrian_min_height(0), + pedestrian_confidence_threshold(0.0f) {} +} algor_config_param_pedestrian_safety_detector_basic; + + +//! C style. +typedef algor_config_param_pedestrian_safety_detector_basic algor_config_param_smoking; +typedef algor_config_param_pedestrian_safety_detector_basic algor_config_param_call_phone; +typedef algor_config_param_pedestrian_safety_detector_basic algor_config_param_no_reflective_clothing; +typedef algor_config_param_pedestrian_safety_detector_basic algor_config_param_no_safety_helmet; + +// using algor_config_param_no_safety_helmet = algor_config_param_pedestrian_safety_detector_basic; + +#endif // #ifndef ___PEDESTRIAN_SAFETY_DETECTOR_ALGOR_CONFIG_PARAM__ + + + +// 行人安全检测参数 +#ifndef ___RETROGRADE_ALGOR_CONFIG_PARAM__ +#define ___RETROGRADE_ALGOR_CONFIG_PARAM__ + +typedef struct algor_config_param_retrograde_basic { + int direction; + float conf_threshold; + unsigned px1, py1, px2, py2; + unsigned minmum_height, minmum_width; + + algor_config_param_retrograde_basic() + : direction(0), px1(0), py1(0), px2(0), py2(0), conf_threshold(0.0f), minmum_height(0), minmum_width(0) { + + } + +} algor_config_param_retrograde_basic; + + +typedef algor_config_param_retrograde_basic algor_config_param_pedestrian_retrograde; +typedef algor_config_param_retrograde_basic algor_config_param_vehicle_retrograde; + +#endif // #ifndef ___RETROGRADE_ALGOR_CONFIG_PARAM__ + + +// 行人安全检测参数 +#ifndef ___TRESPASS_ALGOR_CONFIG_PARAM__ +#define ___TRESPASS_ALGOR_CONFIG_PARAM__ +#define TRESPASS_MAX_POINT 24 + +typedef struct algor_config_param_trespass_basic { + float conf_threshold; + unsigned minmum_height, minmum_width; + sy_point points[TRESPASS_MAX_POINT]; + int points_count; + + algor_config_param_trespass_basic() + : points_count(0), conf_threshold(0.0f), minmum_height(0), minmum_width(0) { + } + +} algor_config_param_trespass_basic; + +typedef algor_config_param_trespass_basic algor_config_param_pedestrian_trespass; +typedef algor_config_param_trespass_basic algor_config_param_vehicle_trespass; + +#endif // #ifndef ___RETROGRADE_ALGOR_CONFIG_PARAM__ + + +// 抓拍算法配置参数(所有抓拍算法共享该参数) +#ifndef __SNAPSHOT_ALGOR_CONFIG_PARAM__ +#define __SNAPSHOT_ALGOR_CONFIG_PARAM__ +typedef struct algor_config_param_snapshot { + float threshold; + int snap_frame_interval; + algor_config_param_snapshot() + : threshold(.6f) , snap_frame_interval(0){} +} algor_config_param_snapshot; +#endif + + + +// 算法的初始化参数 +#ifndef __ALGOR_CONFIG_PARAM__BASIC__ +#define __ALGOR_CONFIG_PARAM__BASIC__ +typedef struct algor_basic_config_param_t { + sy_rect algor_valid_rect; + char *result_folder_little; //目标快照抠图保存地址 + char *result_folder; //目标快照大图保存地址 + explicit algor_basic_config_param_t() + : result_folder_little(nullptr), result_folder(nullptr) {} +} algor_basic_config_param_t; +#endif // #ifndef __ALGOR_CONFIG_PARAM__BASIC__ + + + + +//算法的初始化参数 +#ifndef __ALGOR_CONFIG_PARAM__ +#define __ALGOR_CONFIG_PARAM__ + +typedef struct algor_init_config_param_t { + void *algor_param; //此处只传入针对该路的定制化参数 + algor_basic_config_param_t *basic_param; +} algor_init_config_param_t; + +typedef struct algor_config_param { + algo_type algor_type; //算法类型() + algor_init_config_param_t *algor_init_config_param; +} algor_config_param; +#endif + + +// TASK初始化参数 +#ifndef __TASK_PARAM__ +#define __TASK_PARAM__ + +typedef bool(*GB28181_REQUEST_STREAM_CALLBACK)(const char*); + +typedef struct task_param { + const char *ipc_url; //rtsp流地址 + const char *task_id; //外部传入任务id + algor_config_param *algor_config_params; //该路rtsp流配置的所有算法参数 + int algor_counts; //该路rtsp流共配置几种算法 + + int dec_type{0}; // 0: ffmpeg 1: gb28181 2:dvpp + int port; // gb28181时port为必填 + int protocal; // gb28181 数据接收协议 0 : udp 1: tcp + GB28181_REQUEST_STREAM_CALLBACK gb28181_request_stream_callback; + + int result_output_interval{0}; // 同一目标保存结果的帧间隔 +} task_param; +#endif + +#ifndef __AI_LOG_LEVEL__ +#define __AI_LOG_LEVEL__ +enum ai_log_level { + AI_LOG_LEVEL_CLOSE = -1, // 关闭日志 + AI_LOG_LEVEL_TRACE = 0, // 跟踪变量 + AI_LOG_LEVEL_DEBUG = 1, // 调试日志 + AI_LOG_LEVEL_INFO = 2, // 普通日志信息 (如:无关紧要的信息输出) + AI_LOG_LEVEL_WARNING = 3, // 警告日志通知,模块一切正常(如:重要流程通知) + AI_LOG_LEVEL_ERROR = 4, // 重要日志,如结果和严重错误 +}; +#endif + + +// #define POST_USE_RABBITMQ + +#ifdef POST_USE_RABBITMQ +/** + * @brief rabbit MQ params define here. + */ +#ifndef __TSL_AIPLATFORM_RABBITMQ_PARAM__ +#define __TSL_AIPLATFORM_RABBITMQ_PARAM__ + + +enum class mq_type_t { + DEL_TASK_MQ = 0, + GET_TASK_MQ = 1, + HEART_BEAT_MQ = 2, + ALARM_MQ = 3, + SCREENSHORT_TASK_MQ = 4, // 220809 视频截图队列 + TIMING_SCREENSHORT_TASK_MQ = 5, // 230809 定时视频截图队列 + // DEL_TASK = 0, + // GET_TASK = 1, + // HEART_BEAT = 2, + // GET_ALARM = 3, + + +}; + + +#if 1 +#define MQ_MAX_CHAR_SIZE 256 +typedef struct rabbitmq_conn_params_t { + int port; + // char *ip[12+3+1]; + char ip[MQ_MAX_CHAR_SIZE]; + char uname[MQ_MAX_CHAR_SIZE]; + char passwd[MQ_MAX_CHAR_SIZE]; + char vhost[MQ_MAX_CHAR_SIZE]; + + char exchange[MQ_MAX_CHAR_SIZE]; + char exchange_type[MQ_MAX_CHAR_SIZE]; + char queue[MQ_MAX_CHAR_SIZE]; + char routing_key[MQ_MAX_CHAR_SIZE]; + + bool durable_exchange, durable_queue; +} rabbitmq_conn_params_t; +#else + +typedef struct rabbitmq_conn_params_t +{ + int port; + // char *ip[12+3+1]; + const char* ip; + const char* uname; + const char* passwd; + const char* vhost; + + const char* exchange; + const char* exchange_type; + const char* queue; + const char* routing_key; + + bool durable_exchange, durable_queue; +} rabbitmq_conn_params_t; + +#endif + + +#endif // #ifndef __TSL_AIPLATFORM_RABBITMQ_PARAM__ +#endif //#ifdef POST_USE_RABBITMQ + + +//VPT初始化参数 +#ifndef __TSL_AIPLATFORM_PARAM__ +#define __TSL_AIPLATFORM_PARAM__ +typedef struct tsl_aiplatform_param { + int gpuid; //指定显卡id + char *trt_serialize_file; //缓存文件保存路径 + + ai_log_level log_level; + char *log_path; //日志文件路径 + int log_days; //日志保存周期 + double log_mem; //每个日志最大大小 + float vpt_thred = 0.45; //一级检测器阈值 221216add + float rblock_thred = 0.4; //安全锥检测阈值 221216add + /********************************************************************/ +} tsl_aiplatform_param; +#endif + + +#ifndef _MSC_VER + +#include + +#define MACRO_COUNT_TIME_START struct timeval macro_tv_start;\ + struct timeval macro_tv_end;\ + gettimeofday(¯o_tv_start,NULL); + +#define MACRO_COUNT_TIME_END(___total_count___) gettimeofday(¯o_tv_end,NULL);\ + if(___total_count___<=0)\ + printf("time cost: %.2f ms \n", ( (double)(macro_tv_end.tv_sec-macro_tv_start.tv_sec)*1000000+(double)(macro_tv_end.tv_usec-macro_tv_start.tv_usec) )/1000);\ + else\ + printf("time cost: %.2f ms \n", ( (double)(macro_tv_end.tv_sec-macro_tv_start.tv_sec)*1000000+(double)(macro_tv_end.tv_usec-macro_tv_start.tv_usec) )/1000/___total_count___); +#endif \ No newline at end of file diff --git a/src/ai_platform/macro_definition.h b/src/ai_platform/macro_definition.h new file mode 100644 index 0000000..1b81c1f --- /dev/null +++ b/src/ai_platform/macro_definition.h @@ -0,0 +1,15 @@ +#ifndef __MACRO_DEFINITION_H__ +#define __MACRO_DEFINITION_H__ + + +#define ACL_CALL(ret, expect, errCode)\ + do {\ + if (ret != expect) {\ + if (errCode == 0)\ + return ret;\ + else\ + return errCode;\ + }\ + } while(0) + +#endif \ No newline at end of file diff --git a/src/ai_platform/mvpt_process_assist.cpp b/src/ai_platform/mvpt_process_assist.cpp new file mode 100644 index 0000000..f8e188d --- /dev/null +++ b/src/ai_platform/mvpt_process_assist.cpp @@ -0,0 +1,273 @@ +#include "mvpt_process_assist.h" +#include "../common/logger.hpp" + + +//******** 判断位置是否合法函数 **********// +// 目的:剔除掉靠近摄像头时,面积最大,但是检测物体已经不完整的情况 +// 1. 设定阈值,靠近边缘不要了(阈值目前设定为自身宽高的20%) +//bool sy_legal_pos(bitset flags, int left, int top, int right, int bottom, int img_height, int img_width) +//{ +// int pos[4] = { left, top, right, bottom }; +// int edges[4] = { 0, 0, img_width, img_height }; +// +// for (int i = 0; i < EDGESIZE; i++) +// { +// if (flags[i]) //是需要判断的边 +// { +// if (abs(pos[i] - edges[i]) < minDistance[i]) +// return false; +// } +// } +// return true; +//} + +bool LegalMinArea(int width, int height, sy_rect min_box) +{ + return (width >= min_box.width_ && height >= min_box.height_); +} + +//******** 判断面积是否合法函数 **********// +// 目的:选取框最大最完整的那帧 +// 1. 比之前面积小的不要 +// 2. 突变的面积不要 +bool LegalArea(int maxArea, int lastArea, int left, int top, int right, int bottom) +{ + //不需要通过MINBOX来判断,直接返回true + + int newArea = (bottom - top)*(right - left); + + if (lastArea == 0) + return true; + + if (newArea < maxArea) + return false; + + else if ((newArea - lastArea) / lastArea > 0.5) //阈值测试之后再确定,看是否需要分种类来确定不同的阈值 + return false; + else return true; +} + + +//******** 辅助函数:根据目标运动的轨迹,判断需要特别外扩的方向 **********// +// 目的:因为跳帧的存在,目标运动较快时,框会有一定的滞后的情况(车向前运动,车头被裁掉的情况尤其明显),框滞后的方向需要额外外扩 +void ExpandMargin(int direction_x, int direction_y, int boundary_w, int boundary_h, + int &boundary_left, int &boundary_right, int &boundary_top, int &boundary_bottom) +{ + if (abs(direction_x) > abs(direction_y)) + { + if (direction_x > 0) + { + boundary_right = 2.5 * boundary_w; + } + else + { + boundary_left = 2.5 * boundary_w; + } + } + else + { + if (direction_y > 0) + { + boundary_bottom = 2.5 * boundary_h; + } + else + { + boundary_top = 2.5 * boundary_h; + } + } + /*int max_dis = max(max(max(dis_left, dis_right), dis_top), dis_bottom); + + if (max_dis == dis_left) + boundary_left = 3 * boundary_w; + else if (max_dis == dis_right) + boundary_right = 3 * boundary_w; + else if (max_dis == dis_top) + boundary_top = 3 * boundary_h; + else + boundary_bottom = 3 * boundary_h;*/ +} + +int CreateDir(char *pszDir) +{ + int i = 0; + int iRet; + int iLen = strlen(pszDir); + if (pszDir[iLen - 1] != '\\' && pszDir[iLen - 1] != '/') + { + pszDir[iLen] = '/'; + pszDir[iLen + 1] = '\0'; + } + iLen = strlen(pszDir); + + if (iLen > 2 && ((pszDir[i] == '\\' && pszDir[i + 1] == '\\') || (pszDir[i] == '/' && pszDir[i + 1] == '/'))) + { + i = 2; + for (; i <= iLen; i++) + if (pszDir[i] == '\\' || pszDir[i] == '/') + break; + + i++; + + for (; i <= iLen; i++) + { + if (pszDir[i] == '\\' || pszDir[i] == '/') + { + pszDir[i] = '\0'; + //printf("file access %s\n", pszDir); + iRet = ACCESS(pszDir, 0); + //printf("file access %d\n", iRet); + if (iRet != 0) + { + //printf("file mkdir %s\n", pszDir); + iRet = MKDIR(pszDir); + //printf("file mkdir %d\n", iRet); + if (iRet != 0) + { + LOG_ERROR("Create Folder Failed!"); + return -1; + } + } + pszDir[i] = '/'; + + } + } + return 0; + } + + if (pszDir[i] != '\\' && pszDir[i] != '/') + i = 0; + else + i = 1; + for (; i <= iLen; i++) + { + if (pszDir[i] == '\\' || pszDir[i] == '/') + { + pszDir[i] = '\0'; + iRet = ACCESS(pszDir, 0); + if (iRet != 0) + { + iRet = MKDIR(pszDir); + if (iRet != 0) + { + return -1; + } + } + pszDir[i] = '/'; + + } + } + return 0; +} + + +void CreateResultFolder(char* resultFolder, const char* jointFolder) +{ + if (strlen(resultFolder) > 240) //?too long + { + LOG_ERROR("Folder Name is too Long!"); + return; + } + else if (strlen(resultFolder) < 1) //?too short + { + LOG_ERROR("Folder Name is too Short!"); + return; + } + + char dir[260]; + + sprintf(dir, "%s%s/", resultFolder, jointFolder); + if (CreateDir(dir) != 0) + { + LOG_ERROR("Create Folder Failed!"); + return; + } +} + + +bool best_snapshot_judge_algor(const OBJ_KEY& obj_key, const OBJ_VALUE& obj_value, int left, int top, int width, int height, int image_width, int image_height) +{ + return snapshot_legal_pos(obj_value.flags, left, top, left + width, top + height, image_width, image_height) + && snapshot_legal_minarea(obj_value.index.index, width, height) + && snapshot_legal_inarea(width, height) + && snapshot_legal_area(obj_value.max_area, obj_value.last_area, left, top, left + width, top + height); + return true; +} + +bool snapshot_judge_algor(int index, int width, int height) +{ + return snapshot_legal_minarea(index, width, height) //判断最小面积 + && snapshot_legal_inarea(width, height); //判断在有效区域 + //&& snapshot_algor_open_config(obj_key); //判断算法开启,调整不用在此处判断,检测出来会进行过滤 +} + +bool snapshot_legal_minarea(int index, int width, int height) +{ + return (width >= m_boxsize[index].width_ && height >= m_boxsize[index].height_); +} + +bool snapshot_legal_pos(bitset flags, int left, int top, int right, int bottom, int image_width, int image_height) +{ + int pos[4] = { left, top, right, bottom }; + int edges[4] = { 0, 0, image_width, image_height }; + + for (int i = 0; i < EDGESIZE; i++) + { + if (flags[i]) //是需要判断的边 + { + if (abs(pos[i] - edges[i]) < minDistance[i]) + return false; + } + } + return true; +} + +//******** 判断面积是否合法函数 **********// +// 目的:选取框最大最完整的那帧 +// 1. 比之前面积小的不要 +// 2. 突变的面积不要 +bool snapshot_legal_area(int max_area, int last_area, int left, int top, int right, int bottom) +{ + //不需要通过MINBOX来判断,直接返回true + int new_area = (bottom - top)*(right - left); + if (last_area == 0) + return true; + + if (new_area < max_area) + return false; + // else if ((new_area - last_area) / last_area > 0.5) //阈值测试之后再确定,看是否需要分种类来确定不同的阈值 + else if ((new_area - max_area) / max_area > 0.5) //阈值测试之后再确定,看是否需要分种类来确定不同的阈值 modified by zsh + return false; + else return true; +} + +bool snapshot_legal_inarea(sy_rect algor_area, int left, int top, int right, int bottom) +{ + if (left < algor_area.left_ || top < algor_area.top_ || right>(algor_area.left_ + algor_area.width_) || bottom >(algor_area.top_ + algor_area.height_)) + return false; + + return true; +} + +bool snapshot_legal_inarea(int width, int height) +{ + return true; +} + +// added by zsh 220719 判断人脸姿态角是否满足要求 +float convert_score(float attitude_angle) { + if(fabs(attitude_angle) > 30) // 超过设置角度则过滤---暂未用到 + return 180; + else + return fabs(attitude_angle); +} + +bool snapshot_legal_pose(float last_roll, float last_yaw, float last_pitch, float roll, float yaw, float pitch) +{ + if(fabs(roll) > 30 || fabs(yaw) > 30 || fabs(pitch) > 30) + return false; + float last_score = convert_score(last_roll) + convert_score(last_yaw) + convert_score(last_pitch); + float cur_score = convert_score(roll) + convert_score(yaw) + convert_score(pitch); + if(last_score > cur_score) + return false; + return true; +} \ No newline at end of file diff --git a/src/ai_platform/mvpt_process_assist.h b/src/ai_platform/mvpt_process_assist.h new file mode 100644 index 0000000..9cec1b7 --- /dev/null +++ b/src/ai_platform/mvpt_process_assist.h @@ -0,0 +1,78 @@ +#ifndef __MVPT_PROCESS_ASSIST_H__ +#define __MVPT_PROCESS_ASSIST_H__ + +#include +#include "sy_common.h" +#include "det_obj_header.h" +#include + + +#ifdef _MSC_VER +#include +#include +#define ACCESS _access +#define MKDIR(a) _mkdir((a)) +#else +#include +#include +#include +#define ACCESS access +#define MKDIR(a) mkdir((a),0755) +#endif + +using namespace std; + +typedef struct DxGPUFrame +{ + void * frame; + unsigned int size; + unsigned int width; + unsigned int height; + unsigned long long timestamp; +}DxGPUFrame; + +struct OBJ_VALUE { + bool finishTracker; //轨迹结束可以保存了 + int frameCount; + bool isupdate; + int lost; + DxGPUFrame snapShot; + DxGPUFrame snapShotLittle; + sy_rect obj_pos; + double confidence; // 置信度 + float last_area; + float max_area; + OBJ_INDEX index; + + bitset< EDGESIZE > flags; //标志位,标记快照框应该如何判断,left:0 top:1 right:2 bottom:3 + sy_point landmark_point[25];//人脸关键点位置信息 + sy_rect position; //检测实际目标框 + //-added by zsh 220719 人脸姿态角- + float roll = 0.0; + float yaw = 0.0; + float pitch = 0.0; + //------------------------------- + +}; + + +int CreateDir(char *pszDir); +void CreateResultFolder(char* resultFolder, const char* jointFolder); +//bool sy_legal_pos(bitset flags, int left, int top, int right, int bottom, int imgHeight, int imgWidth); +bool LegalArea(int maxArea, int lastArea, int left, int top, int right, int bottom); +bool LegalMinArea(int width, int height, sy_rect min_box); +void ExpandMargin(int direction_x, int direction_y, int boundary_w, int boundary_h, + int &boundary_left, int &boundary_right, int &boundary_top, int &boundary_bottom); +void CreateResultFolder(char* resultFolder, const char* jointFolder); + +bool snapshot_legal_inarea(int width, int height); +bool snapshot_legal_inarea(sy_rect algor_area, int left, int top, int right, int bottom); +bool snapshot_legal_minarea(int index, int width, int height); +bool snapshot_algor_open_config(const OBJ_KEY& obj_key); +bool snapshot_legal_pos(bitset flags, int left, int top, int right, int bottom, int image_width, int image_height); +bool snapshot_legal_area(int max_area, int last_area, int left, int top, int right, int bottom); +bool snapshot_legal_pose(float last_roll, float last_yaw, float last_pitch, float roll, float yaw, float pitch); // added by zsh 220719 判断人脸姿态角 + + + +#endif // __MVPT_PROCESS_ASSIST_H__ \ No newline at end of file diff --git a/src/ai_platform/stl_aiplatform.cpp b/src/ai_platform/stl_aiplatform.cpp new file mode 100644 index 0000000..df41d35 --- /dev/null +++ b/src/ai_platform/stl_aiplatform.cpp @@ -0,0 +1,102 @@ +/* + * @Author: yangzilong + * @Date: 2021-12-15 17:59:50 + * @Last Modified by: yangzilong + * @Email: yangzilong@objecteye.com + * @Description: + */ +#include "stl_aiplatform.h" +#include "MultiSourceProcess.h" +#include "ErrorInfo.h" + + +int tsl_aiplatform_init(void **handle, tsl_aiplatform_param param) +{ + *handle = new CMultiSourceProcess(); + CMultiSourceProcess* tools = (CMultiSourceProcess*)*handle; + return tools->InitAlgorthim(param); +} + + +#ifdef POST_USE_RABBITMQ +int add_mq_conn(void *handle, mq_type_t tstatus, rabbitmq_conn_params_t mq_conn_param) +{ + CMultiSourceProcess* tools = (CMultiSourceProcess*)handle; + return tools->AddMqConn(tstatus, mq_conn_param); +} + +int get_task_status(void *handle, char *task_id) +{ + CMultiSourceProcess* tools = (CMultiSourceProcess*)handle; + return tools->GetTaskStatus(task_id); +} + +#endif + +int add_task(void *handle, task_param param) +{ + CMultiSourceProcess* tools = (CMultiSourceProcess*)handle; + int error_code = FAILED; + if (tools->AddTask(param)){ + error_code = SUCCESS; + } + return error_code; +} + + +int pause_task(void *handle, char * task_id, const int max_timeout_ms) +{ + int error_code = FAILED; + CMultiSourceProcess* tools = (CMultiSourceProcess*)handle; + if (tools->PauseTask(task_id)){ + error_code = SUCCESS; + } + return error_code; +} + + +int restart_task(void *handle, char * task_id, const int max_timeout_ms) +{ + int error_code = FAILED; + CMultiSourceProcess* tools = (CMultiSourceProcess*)handle; + if (tools->RestartTask(task_id)){ + error_code = SUCCESS; + } + return error_code; +} + +int finish_task(void *handle, char * task_id, const int max_timeout_ms) +{ + int error_code = FAILED; + CMultiSourceProcess* tools = (CMultiSourceProcess*)handle; + if (tools->FinishTask(task_id)){ + error_code = SUCCESS; + } + return error_code; +} + +// added by zsh 220801 +int screenshot_task(void *handle, task_param param) +{ + CMultiSourceProcess* tools = (CMultiSourceProcess*)handle; + return tools->SnapShot(param); +} + +int tsl_aiplatform_release(void **handle) +{ + if (*handle) + { + CMultiSourceProcess* tools = (CMultiSourceProcess*)*handle; + tools->CloseAllTask(); + + delete tools; + tools = NULL; + } + return SUCCESS; +} + + +const char* get_tsl_aiplatform_version() +{ + return "sy_stl_aiplatform_version:0.0.0.221202.gpu.x64"; +} \ No newline at end of file diff --git a/src/ai_platform/stl_aiplatform.h b/src/ai_platform/stl_aiplatform.h new file mode 100644 index 0000000..99d6dc6 --- /dev/null +++ b/src/ai_platform/stl_aiplatform.h @@ -0,0 +1,132 @@ +/******************************************************************************************* +* Version: tsl_aipaltform_v0.0.0 +* CopyRight:中科视语(北京)科技有限公司 +* UpdateDate: 20210918 +* Content: 特斯联-AI视频智能SAAS平台 +********************************************************************************************/ + +#ifndef TSL_AIPLATFORM_H_ +#define TSL_AIPLATFORM_H_ +#ifdef _MSC_VER +#ifdef TSL_AIPLATFORM_EXPORTS +#define TSL_AIPLATFORM_API __declspec(dllexport) +#else +#define TSL_AIPLATFORM_API __declspec(dllimport) +#endif +#else +#define TSL_AIPLATFORM_API __attribute__ ((visibility ("default"))) +#endif +#include "header.h" + + +extern "C" +{ + /************************************************************************* + * FUNCTION: tsl_aiplatform_init + * PURPOSE: 初始化 + * PARAM: + [out] handle - 句柄 + [in] param - 初始化参数 + * RETURN: + * NOTES: + *************************************************************************/ + TSL_AIPLATFORM_API int tsl_aiplatform_init(void **handle, tsl_aiplatform_param param); + +#ifdef POST_USE_RABBITMQ + /** + * @brief add new rabbitmq connection + * + * @param handle + * @param tstatus + * @param mq_conn_param + * @return TSL_AIPLATFORM_API + */ + TSL_AIPLATFORM_API int add_mq_conn(void *handle, mq_type_t tstatus, rabbitmq_conn_params_t mq_conn_param); + + + + TSL_AIPLATFORM_API int get_task_status(void *handle, char *task_id); + +#endif + + /************************************************************************* + * FUNCTION: add_task + * PURPOSE: 添加任务 + * PARAM: + [in] handle - 句柄 + [in] param - 添加任务初始化参数 + * RETURN: 成功/失败 + * NOTES: + *************************************************************************/ + TSL_AIPLATFORM_API int add_task(void *handle, task_param param); + + + /************************************************************************* + * FUNCTION: pause_task + * PURPOSE: 暂停任务 + * PARAM: + [in] handle - 句柄 + [in] task_id - 暂停任务ID号 + * RETURN: + * NOTES: + *************************************************************************/ + TSL_AIPLATFORM_API int pause_task(void *handle, char * task_id, const int max_timeout_ms); + + + /************************************************************************* + * FUNCTION: restart_task + * PURPOSE: 重启任务 + * PARAM: + [in] handle - 句柄 + [in] task_id - 重启任务ID号 + * RETURN: + * NOTES: + *************************************************************************/ + TSL_AIPLATFORM_API int restart_task(void *handle, char * task_id, const int max_timeout_ms); + + + /************************************************************************* + * FUNCTION: finish_task + * PURPOSE: 结束任务 + * PARAM: + [in] handle - 句柄 + [in] task_id - 结束任务ID号 + * RETURN: + * NOTES: + *************************************************************************/ + TSL_AIPLATFORM_API int finish_task(void *handle, char * task_id, const int max_timeout_ms); + + + /************************************************************************* + * FUNCTION: screenshot_task --added by zsh 220801 + * PURPOSE: 视频截图-截取视频首帧 + * PARAM: + [in] handle - 句柄 + [in] param - 添加任务初始化参数 + * RETURN: 成功/失败 + * NOTES: + *************************************************************************/ + TSL_AIPLATFORM_API int screenshot_task(void *handle, task_param param); + + + /************************************************************************* + * FUNCTION: tsl_aiplatform_release + * PURPOSE: 资源释放 + * PARAM: + [in] handle - 处理句柄 + * RETURN: + * NOTES: + *************************************************************************/ + TSL_AIPLATFORM_API int tsl_aiplatform_release(void **handle); + + + /************************************************************************* + * FUNCTION: get_tsl_aiplatform_version + * PURPOSE: 获取SDK版本号 + * PARAM: + * RETURN: sdk版本号 + * NOTES: + *************************************************************************/ + TSL_AIPLATFORM_API const char* get_tsl_aiplatform_version(); +} +#endif diff --git a/src/ai_platform/task_param_manager.cpp b/src/ai_platform/task_param_manager.cpp new file mode 100644 index 0000000..2641ca9 --- /dev/null +++ b/src/ai_platform/task_param_manager.cpp @@ -0,0 +1,421 @@ +/* + * @Author: yangzilong + * @Date: 2021-12-08 17:45:57 + * @Last Modified by: yangzilong + * @Last Modified time: Do not edit + * @Email: yangzilong@objecteye.com + * @Description: + */ + +#include "task_param_manager.h" +#include "header.h" +#include "mvpt_process_assist.h" + +#include "../common/logger.hpp" + +// ############################################################ // +// ! Auxiliary Function ! // +// ############################################################ // + +/* 任务配置参数的深拷贝 添加新算法 添加新case拷贝后续需要的参数 */ +bool copy_algor_param_aux(const algorithm_type_t &algor_type, const std::string &task_id, + task_param_manager::algo_param_type_t_ *&copied_algor_param, void *&algor_param, + map &m_algor_config_params) { + //! Check. + if (!copied_algor_param || !algor_param) + return false; + + switch (algor_type) { + case algorithm_type_t::FACE_SNAPSHOT: + m_algor_config_params[task_id].human_face_algors.insert(algor_type); + goto _snapshot_param_copy; + case algorithm_type_t::HUMAN_SNAPSHOT: + m_algor_config_params[task_id].human_algors.insert(algor_type); + goto _snapshot_param_copy; + case algorithm_type_t::VEHICLE_SNAPSHOT: + m_algor_config_params[task_id].vehicle_algors.insert(algor_type); + goto _snapshot_param_copy; + case algorithm_type_t::NONMOTOR_VEHICLE_SNAPSHOT: { + m_algor_config_params[task_id].nonmotor_vehicle_algors.insert(algor_type); + _snapshot_param_copy : { + using algor_config_param_type = algor_config_param_snapshot; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } + } break; + + case algorithm_type_t::HUMAN_GATHER: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_human_gather; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + + //221026byzsh--------------------------------------------------------- + case algorithm_type_t::ROAD_WORK_DET: { + m_algor_config_params[task_id].vehicle_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_road_work; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + //-------------------------------------------------------------------- + + //230220byzsh--------------------------------------------------------- + case algorithm_type_t::VIDEO_TIMING_SNAPSHOT: { + m_algor_config_params[task_id].vehicle_algors.insert(algor_type); + using algor_config_param_type = algor_config_video_timing_snapshot; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + //-------------------------------------------------------------------- + + case algorithm_type_t::PEDESTRIAN_FALL: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_pedestrian_fall; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::PEDESTRIAN_FIGHT: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_pedestrian_fight; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::TAKEAWAY_MEMBER_CLASSIFICATION: { + m_algor_config_params[task_id].nonmotor_vehicle_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_takeaway_member_classification; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::SMOKING_DET: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_smoking; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::CALL_PHONE_DET: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_call_phone; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::NO_REFLECTIVE_CLOTHING: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_no_reflective_clothing; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::NO_SAFETY_HELMET: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_no_safety_helmet; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::PEDESTRIAN_RETROGRADE: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_pedestrian_retrograde; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::VEHICLE_RETROGRADE: { + m_algor_config_params[task_id].vehicle_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_vehicle_retrograde; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::PEDESTRIAN_TRESPASS: { + m_algor_config_params[task_id].human_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_pedestrian_trespass; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + case algorithm_type_t::VEHICLE_TRESPASS: { + m_algor_config_params[task_id].vehicle_algors.insert(algor_type); + using algor_config_param_type = algor_config_param_vehicle_trespass; + copied_algor_param->algor_param = new algor_config_param_type; + *((algor_config_param_type *)(copied_algor_param->algor_param)) = + *((algor_config_param_type *)algor_param); // deep copy. + } break; + + default: { + LOG_WARN("Not Support Algorithm type {} Task id {}", int(algor_type), task_id); + return false; + } break; + } + + return true; +} + +task_param_manager::task_param_manager() { +} + +/* 保存新添加任务的配置参数 */ +void task_param_manager::add_task_param(string task_id, task_param task_param) { + const int task_algor_count = task_param.algor_counts; + printf("task_algor_count: %d\n", task_algor_count); + for (int idx = 0; idx < task_algor_count; idx++) // loop every algor param. + { + algo_param_type_t_ *copied_algor_param = new algo_param_type_t_; + auto &algor_config_param = task_param.algor_config_params[idx]; + auto &algor_param = algor_config_param.algor_init_config_param->algor_param; + auto &algor_type = algor_config_param.algor_type; + + /* 拷贝该算法特定的算法参数 */ + if (!copy_algor_param_aux(algor_type, task_id, copied_algor_param, algor_param, m_algor_config_params)) { + if (copied_algor_param != nullptr) { + delete copied_algor_param; + copied_algor_param = nullptr; + } + LOG_ERROR("copy param faileure task_id {} algor_type {}", task_id, int(algor_type)); + continue; + } + + /* 拷贝通用的算法参数 */ + /* copy public param. */ + copied_algor_param->basic_param = new algor_basic_config_param_t; + + auto src_basic_param = algor_config_param.algor_init_config_param->basic_param; + auto dst_basic_param = ((algor_init_config_param_t *)copied_algor_param)->basic_param; + + if (src_basic_param->result_folder_little) { + dst_basic_param->result_folder_little = new char[strlen(src_basic_param->result_folder_little) + 1]; + strcpy(dst_basic_param->result_folder_little, src_basic_param->result_folder_little); + CreateResultFolder(dst_basic_param->result_folder_little, ""); + } else + dst_basic_param->result_folder_little = nullptr; + + if (src_basic_param->result_folder) { + dst_basic_param->result_folder = new char[strlen(src_basic_param->result_folder) + 1]; + strcpy(dst_basic_param->result_folder, src_basic_param->result_folder); + CreateResultFolder(dst_basic_param->result_folder, ""); + } else + dst_basic_param->result_folder = nullptr; + + dst_basic_param->algor_valid_rect.left_ = src_basic_param->algor_valid_rect.left_; + dst_basic_param->algor_valid_rect.top_ = src_basic_param->algor_valid_rect.top_; + dst_basic_param->algor_valid_rect.width_ = src_basic_param->algor_valid_rect.width_; + dst_basic_param->algor_valid_rect.height_ = src_basic_param->algor_valid_rect.height_; + + copied_algor_param->basic_param = dst_basic_param; + m_task_params[task_id][algor_config_param.algor_type] = copied_algor_param; + } +} + +/* 删除结束任务的配置参数 */ +void task_param_manager::delete_task_param(string task_id) { + auto it = m_task_params.find(task_id); + if(it == m_task_params.end()){ + return; + } + + for (auto iter : m_task_params[task_id]) // 依次删除算法配置参数 + { + algor_basic_config_param_t *cur_param = + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->basic_param; + if (cur_param->result_folder_little) { + delete[] cur_param->result_folder_little; + cur_param->result_folder_little = nullptr; + } + if (cur_param->result_folder) { + delete[] cur_param->result_folder; + cur_param->result_folder = nullptr; + } + if (cur_param) { + delete ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->basic_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->basic_param = nullptr; + } + + switch (iter.first) { + case algorithm_type_t::PEDESTRIAN_FALL: { + algor_config_param_pedestrian_fall *algor_param = + (algor_config_param_pedestrian_fall *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + if (algor_param) { + delete (algor_config_param_pedestrian_fall *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + case algorithm_type_t::PEDESTRIAN_FIGHT: { + algor_config_param_pedestrian_fight *algor_param = + (algor_config_param_pedestrian_fight *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + if (algor_param) { + delete (algor_config_param_pedestrian_fight *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + case algorithm_type_t::HUMAN_GATHER: { + algor_config_param_human_gather *algor_param = + (algor_config_param_human_gather *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + if (algor_param) { + delete (algor_config_param_human_gather *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + + + //221026byzsh--------------------------------------------------------- + case algorithm_type_t::ROAD_WORK_DET: { + algor_config_param_road_work *algor_param = + (algor_config_param_road_work *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + if (algor_param) { + delete (algor_config_param_road_work *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + //-------------------------------------------------------------------- + + //230220byzsh--------------------------------------------------------- + case algorithm_type_t::VIDEO_TIMING_SNAPSHOT: { + algor_config_video_timing_snapshot *algor_param = + (algor_config_video_timing_snapshot *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + if (algor_param) { + delete (algor_config_video_timing_snapshot *)((algor_init_config_param_t *)m_task_params[task_id][iter.first]) + ->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + //-------------------------------------------------------------------- + + case algorithm_type_t::TAKEAWAY_MEMBER_CLASSIFICATION: { + algor_config_param_takeaway_member_classification *algor_param = + (algor_config_param_takeaway_member_classification *)((algor_init_config_param_t *) + m_task_params[task_id][iter.first]) + ->algor_param; + if (algor_param) { + delete (algor_config_param_takeaway_member_classification *)((algor_init_config_param_t *) + m_task_params[task_id][iter.first]) + ->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + case algorithm_type_t::NO_REFLECTIVE_CLOTHING: { + using ptr_t = algor_config_param_no_reflective_clothing; + ptr_t *algor_param = (ptr_t *)((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param; + if (algor_param) { + delete (ptr_t *)((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + case algorithm_type_t::NO_SAFETY_HELMET: { + using ptr_t = algor_config_param_no_safety_helmet; + ptr_t *algor_param = (ptr_t *)((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param; + if (algor_param) { + delete (ptr_t *)((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + case algorithm_type_t::CALL_PHONE_DET: { + using ptr_t = algor_config_param_call_phone; + ptr_t *algor_param = (ptr_t *)((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param; + if (algor_param) { + delete (ptr_t *)((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + case algorithm_type_t::SMOKING_DET: { + using ptr_t = algor_config_param_smoking; + ptr_t *algor_param = (ptr_t *)((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param; + if (algor_param) { + delete (ptr_t *)((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param; + ((algor_init_config_param_t *)m_task_params[task_id][iter.first])->algor_param = nullptr; + } + break; + } + default: + break; + } + + if ((algor_init_config_param_t *)m_task_params[task_id][iter.first]) { + delete (algor_init_config_param_t *)m_task_params[task_id][iter.first]; + m_task_params[task_id][iter.first] = nullptr; + } + } + m_task_params.erase(task_id); +} + +void task_param_manager::task_param_manager_release() { + for (auto iter : m_task_params) + delete_task_param(iter.first); +} + +/* 获取指定任务的算法配置参数 */ +const algor_open_config_param *const task_param_manager::get_task_algor_param(const string &task_id) { + auto res = m_algor_config_params.find(task_id); + if (res == m_algor_config_params.end()) + return nullptr; + return &res->second; +} + +/* 获取指定任务&指定算法的配置参数 */ +const task_param_manager::algo_param_type_t_ *const +task_param_manager::get_task_other_param(const string &task_id, const algo_type &_algo_type) { + auto task_algor_param = get_task_other_param(task_id); + if (task_algor_param != nullptr){ + auto res = task_algor_param->find(_algo_type); + if (res != task_algor_param->end()) + return res->second; + } + + return nullptr; +} + +/* 获取指定任务的任务配置参数 */ +const map *const +task_param_manager::get_task_other_param(const string &task_id) { + auto res = m_task_params.find(task_id); + if (res == m_task_params.end()) + return nullptr; + return &res->second; +} + +/* 获取所有任务的算法配置参数 */ +map task_param_manager::get_task_algor_params() { + return m_algor_config_params; +} + +/* 获取所有任务的其他配置参数 */ +map> task_param_manager::get_task_other_params() { + return m_task_params; +} diff --git a/src/ai_platform/task_param_manager.h b/src/ai_platform/task_param_manager.h new file mode 100644 index 0000000..cebb772 --- /dev/null +++ b/src/ai_platform/task_param_manager.h @@ -0,0 +1,52 @@ +/* + * @Author: yangzilong + * @Date: 2021-11-30 18:58:46 + * @Last Modified by: yangzilong + * @Last Modified time: Do not edit + * @Email: yangzilong@objecteye.com + * @Description: + */ +#pragma once +#include "header.h" +#include "det_obj_header.h" + +#include +#include +using namespace std; + +struct algor_open_config_param +{ + set human_face_algors; + set human_algors; + set nonmotor_vehicle_algors; + set vehicle_algors; +}; + +class task_param_manager +{ +public: + using algo_param_type_t_ = algor_init_config_param_t; + + static task_param_manager* getInstance() + { + static task_param_manager task_param_instance; + return &task_param_instance; + } + + void add_task_param(string task_id, task_param task_param); + void delete_task_param(string task_id); + const algor_open_config_param *const get_task_algor_param(const string &task_id); + const map *const get_task_other_param(const string& task_id); + const algo_param_type_t_ *const get_task_other_param(const string& task_id, const algo_type &_algo_type); + + map get_task_algor_params(); + map> get_task_other_params(); + void task_param_manager_release(); + +private: + task_param_manager(); + task_param_manager(const task_param_manager& other); + + map> m_task_params; + map m_algor_config_params; +}; \ No newline at end of file diff --git a/src/ai_platform/vpt_proj.cpp1 b/src/ai_platform/vpt_proj.cpp1 new file mode 100644 index 0000000..7cbd277 --- /dev/null +++ b/src/ai_platform/vpt_proj.cpp1 @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include + +#include "vpt.h" + +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" + +#include "../decoder/interface/DecoderManager.h" +#include "../decoder/interface/utiltools.hpp" + +using namespace std; + +#define ACL_CALL(ret, expect, errCode)\ + do {\ + if (ret != expect) {\ + if (errCode == 0)\ + return ret;\ + else\ + return errCode;\ + }\ + } while(0) + + +string test_uri = "/home/huchunming/data/caishenkezhan.mp4"; + +queue memQueue; +mutex mem_mutex; + +static void postDecoded(const void * userPtr, DeviceMemory* devFrame){ + AbstractDecoder* decoder = (AbstractDecoder*)userPtr; + if (decoder!= nullptr) + { + } + + std::lock_guard l(mem_mutex); + memQueue.push(devFrame); + + // if(devFrame){ + // delete devFrame; + // devFrame = nullptr; + // } +} + +static void decode_finished_cbk(const void* userPtr){ + cout << "当前时间戳: " << UtilTools::get_cur_time_ms() << endl; +} + +static void createDvppDecoder(int index, char* devId){ + DecoderManager* pDecManager = DecoderManager::getInstance(); + MgrDecConfig config; + config.name = "dec" + to_string(index); + config.cfg.uri = test_uri; + config.cfg.post_decoded_cbk = postDecoded; + config.cfg.decode_finished_cbk = decode_finished_cbk; + config.cfg.force_tcp = true; + config.dec_type = DECODER_TYPE_DVPP; + + config.cfg.gpuid = devId; + + AbstractDecoder* decoder = pDecManager->createDecoder(config); + if (!decoder) + { + cout << "创建解码器失败" << endl; + return ; + } + pDecManager->setPostDecArg(config.name, decoder); + pDecManager->setFinishedDecArg(config.name, decoder); + pDecManager->startDecodeByName(config.name); +} + + +int main(){ + cout << vpt_get_version() << endl; + + vpt_param param; + + // param.modelNames = "vtp0716x.om"; + param.modelNames = "../models/vpt0715_310p.om"; + param.threshold = 0.4; + param.devId = 0; + param.isTrk = false; + + ACL_CALL(aclInit(nullptr), ACL_ERROR_NONE, 1); + ACL_CALL(aclrtSetDevice(param.devId), ACL_ERROR_NONE, 1); + aclrtContext ctx; + ACL_CALL(aclrtCreateContext(&ctx, param.devId), ACL_ERROR_NONE, 1); + + void* handle = nullptr; + int ret = vpt_init(&handle, param); + if(ret != 0){ + printf("init error \n"); + return -1; + } + + createDvppDecoder(0,"0"); + + DecoderManager* pDecManager = DecoderManager::getInstance(); + const int batchsize = 1; + int index = 0; + while (pDecManager->isRunning("dec0")) + { + if(index > 30){ + break; + } + if(memQueue.size() <= 0){ + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + + vector vec_mem; + + vector imgs; + + std::lock_guard l(mem_mutex); + for (int b = 0; b < batchsize; b++) { + DeviceMemory* mem = memQueue.front(); + sy_img img; + img.w_ = mem->getWidth(); + img.h_ = mem->getHeight(); + img.data_ = mem->getMem(); + imgs.push_back(img); + vec_mem.push_back(mem); + memQueue.pop(); + } + + if(vec_mem.size() <= 0){ + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + continue; + } + + ACL_CALL(aclrtSetCurrentContext(ctx), ACL_ERROR_NONE, 1); + vpt_result* results; + int ret = vpt_batch(handle, imgs.data(), imgs.size(), &results); + + for(int batchIdx = 0; batchIdx < batchsize; batchIdx ++){ + printf("debug det num:%d\n",results[batchIdx].obj_count_); + } + + for(int i=0;i < vec_mem.size(); i++){ + DeviceMemory* mem = vec_mem[i]; + delete mem; + mem = nullptr; + } + vec_mem.clear(); + + index ++; + } + + pDecManager->closeDecoderByName("dec0"); + + pDecManager->closeAllDecoder(); + + ret = aclrtDestroyContext(ctx); + if(ret != ACL_ERROR_NONE){ + printf("aclrtDestroyContext failed ! \n"); + } + + + + aclFinalize(); +} \ No newline at end of file diff --git a/src/common/SimpleList.hpp b/src/common/SimpleList.hpp new file mode 100644 index 0000000..637c225 --- /dev/null +++ b/src/common/SimpleList.hpp @@ -0,0 +1,346 @@ +#ifndef __LIST_HPP__ +#define __LIST_HPP__ + +#include + + +// 先声明链表类,便于node将其声明为友元 +template class SimpleList; + +// 链表节点类 +template +class node +{ +public: + node() : next(nullptr){} + node(T val) : data(val), next(nullptr) {} +private: + T data; + node* next; + friend class SimpleList; +}; + +/* +链表操作 +1、删除节点 +2、添加节点 +3、 +*/ + +template +class SimpleList +{ +public: + SimpleList(); // 构造函数 + SimpleList(const SimpleList& l); // 拷贝构造 + ~SimpleList(); // 析构函数 + SimpleList& operator= (const SimpleList& l); // 拷贝赋值 + void insert(int index, T val); // 在index处插入结点 + void remove(int index); // 删除index处结点 + T get_node(int index); // 获取index处结点值 + int find(int value); // 查找值value,找到返回index,找不到返回-1 + int size(); // 获取链表长度 + void push_back(T val); // 在链表尾部插入数据 + T front(); // 获取第一个 + void pop_front(); // 删除第一个 + void clear(); // 清空 + bool empty(); + T begin(); // 第一个 + +private: + node* head_ptr; // 链表头指针 + int length; // 链表长度 +}; + + // 构造函数 +template +SimpleList::SimpleList() +{ + this->head_ptr = nullptr; + this->length = 0; +} + +// 拷贝构造 +template +SimpleList::SimpleList(const SimpleList& l) +{ + if(l.head_ptr == nullptr) + { + this->head_ptr = nullptr; + this->length = 0; + } + else + { + this->head_ptr = new node; + node* p1 = this->head_ptr; + node* p2 = nullptr; + // 拷贝链表 + for(p2 = l.head_ptr; p2->next != nullptr; p2 = p2->next) + { + p1->data = p2->data; + p1->next = new node; + p1 = p1->next; + } + p1->data = p2->data; + p1->next = nullptr; + this->length = l.length; + } + + +} + +// 拷贝赋值 +template +SimpleList& SimpleList::operator= (const SimpleList& l) +{ + if(this->head_ptr == nullptr) // 原链表空 + { + if(l.head_ptr == nullptr) + { + this->head_ptr = nullptr; + this->length = 0; + } + else + { + this->head_ptr = new node; + node* p1 = this->head_ptr; + node* p2 = nullptr; + // 拷贝链表 + for(p2 = l.head_ptr; p2->next != nullptr; p2 = p2->next) + { + p1->data = p2->data; + p1->next = new node; + p1 = p1->next; + } + p1->data = p2->data; + p1->next = nullptr; + this->length = l.length; + } + } + else // 原链表非空 + { + if(l.head_ptr == nullptr) + { + // 清空链表 + node* p1 = this->head_ptr; + node* p2 = p1->next; + while(p2 != nullptr) + { + delete p1; + p1 = p2; + p2 = p2->next; + } + delete p1; + this->length = 0; + } + else + { + if(l.length > this->length) // 待复制的链表更长,先将原链表填满再申请空间 + { + node* p1 = this->head_ptr; + node* p2 = l.head_ptr; + for(int i = 0; i < this->length - 1; i++) + { + p1->data = p2->data; + p1 = p1->next; + p2 = p2->next; + } + p1->next = new node; + for(int i = this->length - 1; i < l.length - 1; i++) + { + p1->data = p2->data; + p1->next = new node; + p1 = p1->next; + p2 = p2->next; + } + p1->data = p2->data; + p1->next = nullptr; + } + else // 待复制的链表更短或相等,更短时需要释放原链表多余空间 + { + node* p1 = this->head_ptr; + node* p2 = l.head_ptr; + // 复制数据 + for(int i = 0; i < l.length; i++) + { + p1->data = p2->data; + p1 = p1->next; + p2 = p2->next; + } + // 删除多余结点 + while(p1 != nullptr) + { + p2 = p1->next; + delete p1; + p1 = p2; + } + } + } + this->length = l.length; + } + + return *this; +} + +// 在index处插入结点 +template +void SimpleList::insert(int index, T val) +{ + if((index > this->length)) // 超过索引,最多可以插到当前结点的下一个结点,否则就是超过索引 + { + throw runtime_error("index out of this SimpleList`s range"); + } + else if((this->head_ptr == nullptr) && (index == 0)) // 插在空链表的头 + { + this->head_ptr = new node; + this->head_ptr->next = nullptr; + this->head_ptr->data = val; + this->length++; + } + else // 一般情况 + { + node* p1 = this->head_ptr; + node* p2 = new node; + for(int i = 0; i < index - 1; i++) + { + p1 = p1->next; + } + p2->data = val; + p2->next = p1->next; + p1->next = p2; + this->length++; + } +} + +// 删除index处结点 +template +void SimpleList::remove(int index) +{ + node* p1 = this->head_ptr; + node* p2 = nullptr; + for(int i = 0; i < index - 1; i++) + { + p1 = p1->next; + } + p2 = p1->next->next; + delete p1->next; + p1->next = p2; + this->length--; +} + + +// 获取index处结点值 +template +T SimpleList::get_node(int index) +{ + if(index > this->length - 1) // 超过索引 + { + throw runtime_error("index out of this SimpleList`s range"); + } + + node* p1 = this->head_ptr; + for(int i = 0; i < index; i++){ + p1 = p1->next; + } + + return p1->data; +} + +// 获取第一个 +template +T SimpleList::front() +{ + return get_node(0); +} + +// 删除index处结点 +template +void SimpleList::pop_front() +{ + remove(0); +} + +// 删除index处结点 +template +void SimpleList::clear() +{ + node* p; + while (head_ptr != NULL) + { + p = head_ptr; + head_ptr = head_ptr->next; + delete p; + p = nullptr; + } +} + +// 删除index处结点 +template +T SimpleList::begin(){ + return head_ptr; +} + +// 查找值value,找到返回index,找不到返回-1 +template +int SimpleList::find(int value) +{ + node* p1 = this->head_ptr; + for(int i = 0; i < this->length; i++) + { + if(p1->data == value) + { + return i; + } + p1 = p1->next; + } + + return -1; +} + +// 获取链表长度 +template +int SimpleList::size() +{ + return this->length; +} + +// 链表是否为空 +template +bool SimpleList::empty() +{ + return size() == 0 ? true : false ; +} + +// 在链表尾部插入数据 +template +void SimpleList::push_back(T val) +{ + if(this->head_ptr == nullptr) // 链表为空 + { + this->head_ptr = new node; + this->head_ptr->data = val; + this->head_ptr->next = nullptr; + } + else + { + node* p1 = this->head_ptr; + node* p2 = new node; + p2->data = val; + p2->next = nullptr; + while(p1->next != nullptr) + { + p1 = p1->next; + } + p1->next = p2; + } + this->length++; +} + +// 析构函数 +template +SimpleList::~SimpleList(){ + // 清空链表 + clear(); +} + +#endif \ No newline at end of file diff --git a/src/common/dvpp/dvpp_cropandpaste.cpp b/src/common/dvpp/dvpp_cropandpaste.cpp new file mode 100644 index 0000000..0211596 --- /dev/null +++ b/src/common/dvpp/dvpp_cropandpaste.cpp @@ -0,0 +1,525 @@ +/** +* Copyright 2020 Huawei Technologies Co., Ltd +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + +* http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + +* File dvpp_process.cpp +* Description: handle dvpp process +*/ + +#include +#include "acl/acl.h" +#include "utils.h" +#include "dvpp_cropandpaste.h" +#include "sy_errorinfo.h" +using namespace std; + +DvppCropAndPaste::DvppCropAndPaste(aclrtStream& stream, acldvppChannelDesc *dvppChannelDesc, + uint32_t width, uint32_t height) +: stream_(stream), dvppChannelDesc_(dvppChannelDesc), +vpcInputDesc_(nullptr), vpcOutputDesc_(nullptr), +vpcOutBufferDev_(nullptr),vpcOutBufferSize_(0){ + size_.width = width; + size_.height = height; +} + +DvppCropAndPaste::~DvppCropAndPaste() +{ + DestroyCropAndPasteResource(); +} + +int DvppCropAndPaste::InitCropAndPasteInputDesc(ImageData& inputImage) +{ + originalImageWidth_ = inputImage.width; + originalImageHeight_ = inputImage.height; + uint32_t alignWidth = inputImage.alignWidth; + uint32_t alignHeight = inputImage.alignHeight; + // printf("image w %d, h %d, align w%d, h%d",inputImage.width, inputImage.height, alignWidth, alignHeight); + if (alignWidth == 0 || alignHeight == 0) { + ERROR_LOG("InitResizeInputDesc AlignmentHelper failed. image w %d, h %d, align w%d, h%d", + inputImage.width, inputImage.height, alignWidth, alignHeight); + return SY_FAILED; + } + uint32_t inputBufferSize = YUV420SP_SIZE(alignWidth, alignHeight); + vpcInputDesc_ = acldvppCreatePicDesc(); + if (vpcInputDesc_ == nullptr) { + ERROR_LOG("acldvppCreatePicDesc vpcInputDesc_ failed"); + return SY_FAILED; + } + + acldvppSetPicDescData(vpcInputDesc_, inputImage.data.get()); // JpegD . vpcResize + acldvppSetPicDescFormat(vpcInputDesc_, format_); + acldvppSetPicDescWidth(vpcInputDesc_, inputImage.width); + acldvppSetPicDescHeight(vpcInputDesc_, inputImage.height); + acldvppSetPicDescWidthStride(vpcInputDesc_, alignWidth); + acldvppSetPicDescHeightStride(vpcInputDesc_, alignHeight); + acldvppSetPicDescSize(vpcInputDesc_, inputBufferSize); + return SY_SUCCESS; +} + +int DvppCropAndPaste::InitCropAndPasteOutputDesc() +{ + int resizeOutWidth = size_.width; + int resizeOutHeight = size_.height; + int resizeOutWidthStride = ALIGN_UP16(resizeOutWidth); + int resizeOutHeightStride = ALIGN_UP2(resizeOutHeight); + + if (resizeOutWidthStride == 0 || resizeOutHeightStride == 0) { + ERROR_LOG("InitResizeOutputDesc AlignmentHelper failed"); + return SY_FAILED; + } + + vpcOutBufferSize_ = YUV420SP_SIZE(resizeOutWidthStride, resizeOutHeightStride); + aclError aclRet = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_); + //debug======================================================================== + uint32_t size = ALIGN_UP(vpcOutBufferSize_,32) + 32; + aclRet = aclrtMemset(vpcOutBufferDev_,size, 128, size); + // aclRet = aclrtMemset(vpcOutBufferDev_,vpcOutBufferSize_, 0, vpcOutBufferSize_); + //debug end==================================================================== + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppMalloc vpcOutBufferDev_ failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + vpcOutputDesc_ = acldvppCreatePicDesc(); + if (vpcOutputDesc_ == nullptr) { + ERROR_LOG("acldvppCreatePicDesc vpcOutputDesc_ failed"); + return SY_FAILED; + } + acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_); + acldvppSetPicDescFormat(vpcOutputDesc_, format_); + acldvppSetPicDescWidth(vpcOutputDesc_, resizeOutWidth); + acldvppSetPicDescHeight(vpcOutputDesc_, resizeOutHeight); + acldvppSetPicDescWidthStride(vpcOutputDesc_, resizeOutWidthStride); + acldvppSetPicDescHeightStride(vpcOutputDesc_, resizeOutHeightStride); + acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_); + + return SY_SUCCESS; +} + +int DvppCropAndPaste::InitRightCropAndPasteOutputDesc() +{ + int resizeOutWidth = size_.width; + int resizeOutHeight = size_.height; + int resizeOutWidthStride = ALIGN_UP16(resizeOutWidth); + int resizeOutHeightStride = ALIGN_UP2(resizeOutHeight); + if (resizeOutWidthStride == 0 || resizeOutHeightStride == 0) { + ERROR_LOG("InitResizeOutputDesc AlignmentHelper failed"); + return SY_FAILED; + } + + vpcOutBufferSize_ = YUV420SP_SIZE(resizeOutWidthStride, resizeOutHeightStride); + //aclError aclRet = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_); + // if (aclRet != ACL_SUCCESS) { + // ERROR_LOG("acldvppMalloc vpcOutBufferDev_ failed, aclRet = %d", aclRet); + // return SY_FAILED; + // } + vpcOutputDesc_ = acldvppCreatePicDesc(); + if (vpcOutputDesc_ == nullptr) { + ERROR_LOG("acldvppCreatePicDesc vpcOutputDesc_ failed"); + return SY_FAILED; + } + acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_ + vpcOutBufferSize_); + acldvppSetPicDescFormat(vpcOutputDesc_, format_); + acldvppSetPicDescWidth(vpcOutputDesc_, resizeOutWidth); + acldvppSetPicDescHeight(vpcOutputDesc_, resizeOutHeight); + acldvppSetPicDescWidthStride(vpcOutputDesc_, resizeOutWidthStride); + acldvppSetPicDescHeightStride(vpcOutputDesc_, resizeOutHeightStride); + acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_); + + return SY_SUCCESS; +} + + +// IN/OUT Desc +int DvppCropAndPaste::InitCropAndPasteResource(ImageData& inputImage) { + format_ = static_cast(PIXEL_FORMAT_YUV_SEMIPLANAR_420); + if (SY_SUCCESS != InitCropAndPasteInputDesc(inputImage)) { + ERROR_LOG("InitCropAndPasteInputDesc failed"); + return SY_FAILED; + } + + if (SY_SUCCESS != InitCropAndPasteOutputDesc()) { + ERROR_LOG("InitCropAndPasteOutputDesc failed"); + return SY_FAILED; + } + + return SY_SUCCESS; +} + +int DvppCropAndPaste::InitRightCropAndPasteResource(ImageData& inputImage) { + format_ = static_cast(PIXEL_FORMAT_YUV_SEMIPLANAR_420); + if (SY_SUCCESS != InitCropAndPasteInputDesc(inputImage)) { + ERROR_LOG("InitCropAndPasteInputDesc failed"); + return SY_FAILED; + } + + if (SY_SUCCESS != InitRightCropAndPasteOutputDesc()) { + ERROR_LOG("InitCropAndPasteOutputDesc failed"); + return SY_FAILED; + } + + return SY_SUCCESS; +} + +int DvppCropAndPaste::ResizeWithPadding(ImageData& resizedImage, ImageData& srcImage) +{ + if (SY_SUCCESS != InitCropAndPasteResource(srcImage)) { + ERROR_LOG("Dvpp cropandpaste failed for init error"); + return SY_FAILED; + } + + uint32_t cropLeftOffset = 0; // must even + uint32_t cropTopOffset = 0; // must even + uint32_t cropRightOffset = (((cropLeftOffset + originalImageWidth_) >> 1) << 1) -1; // must odd + uint32_t cropBottomOffset = (((cropTopOffset + originalImageHeight_) >> 1) << 1) -1; // must odd + + cropArea_ = acldvppCreateRoiConfig(cropLeftOffset, cropRightOffset, + cropTopOffset, cropBottomOffset); + if (cropArea_ == nullptr) { + ERROR_LOG("acldvppCreateRoiConfig cropArea_ failed"); + return SY_FAILED; + } + // cout << "====================================================" << endl; + // printf("debug crop area: %d %d %d %d\n", cropLeftOffset, cropTopOffset, cropRightOffset, cropBottomOffset); + + bool widthRatioSmaller = true; + // The scaling ratio is based on the smaller ratio to ensure the smallest edge to fill the targe edge + float resizeRatio = static_cast(size_.width) / srcImage.width; + if (resizeRatio > (static_cast(size_.height) / srcImage.height)) { + resizeRatio = static_cast(size_.height) / srcImage.height; + widthRatioSmaller = false; + } + + const int halfValue = 2; + uint32_t pasteLeftOffset = 0; + uint32_t pasteRightOffset = 0; + uint32_t pasteTopOffset = 0; + uint32_t pasteBottomOffset = 0; + // The left and up must be even, right and down must be odd which is required by acl + if (widthRatioSmaller) { //宽较长 + pasteLeftOffset = 0; // must even + pasteRightOffset = (((pasteLeftOffset + size_.width) >> 1) << 1) -1; // must odd + // pasteTopOffset = ((static_cast((size_.height - srcImage.height * resizeRatio) / halfValue) >> 1) << 1); // must even + // pasteBottomOffset = (((size_.height - pasteTopOffset) >> 1) << 1) -1; // must odd + //debug=============================================================================================== + float pady = ((size_.height - srcImage.height * resizeRatio) / halfValue); + pasteTopOffset = ((static_cast(pady) >> 1) << 1); // must even + pasteBottomOffset = ((static_cast(size_.height - pady) >> 1) << 1) -1; // must odd + // if((int)(size_.height - srcImage.height * resizeRatio) % 2 ==0){ + // pasteBottomOffset = ((static_cast(size_.height - pady) >> 1) << 1) -1; // must odd + // }else{ + // pasteBottomOffset = ((static_cast(size_.height - pady + 1) >> 1) << 1) -1; // must odd + // } + //debug end============================================================================================ + }else{ //高较长 + uint32_t pad = (static_cast((size_.width - srcImage.width * resizeRatio) / halfValue)); + // printf("debug pad:%d\n",pad); + pasteLeftOffset = (pad + 8) / 16 * 16; // must even,作贴图区域时,需16对齐 + // pasteLeftOffset = ALIGN_UP16(pad); // must even,作贴图区域时,需16对齐 + pasteRightOffset = (((size_.width - pad) >> 1) << 1) -1; // must odd + pasteTopOffset = 0; // must even + pasteBottomOffset = (((pasteTopOffset + size_.height) >> 1) << 1) -1; // must odd + + } + + pasteArea_ = acldvppCreateRoiConfig(pasteLeftOffset, pasteRightOffset, + pasteTopOffset, pasteBottomOffset); + if (pasteArea_ == nullptr) { + ERROR_LOG("acldvppCreateRoiConfig pasteArea_ failed"); + return SY_FAILED; + } + // printf("debug paste area: %d %d %d %d\n", pasteLeftOffset, pasteTopOffset, pasteRightOffset, pasteBottomOffset); + // crop and patse pic + aclError aclRet = acldvppVpcCropAndPasteAsync(dvppChannelDesc_, vpcInputDesc_, + vpcOutputDesc_, cropArea_, pasteArea_, stream_); + //printf("debug crop line:%d\n",__LINE__); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppVpcCropAndPasteAsync failed, aclRet = %d", aclRet); + return SY_FAILED; + } + aclRet = aclrtSynchronizeStream(stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("crop and paste aclrtSynchronizeStream failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + resizedImage.width = size_.width; + resizedImage.height = size_.height; + resizedImage.alignWidth = ALIGN_UP16(size_.width); + resizedImage.alignHeight = ALIGN_UP2(size_.height); + resizedImage.size = vpcOutBufferSize_; + resizedImage.data = SHARED_PRT_DVPP_BUF(vpcOutBufferDev_); + + DestroyCropAndPasteResource(); + + return SY_SUCCESS; +} + + + +int DvppCropAndPaste::PatchProcess(ImageData& resizedImage, ImageData& srcImage, uint32_t xmin, uint32_t ymin, + uint32_t xmax, uint32_t ymax) +{ + if (SY_SUCCESS != InitCropAndPasteResource(srcImage)) { + ERROR_LOG("Dvpp cropandpaste failed for init error"); + return SY_FAILED; + } + + uint32_t cropLeftOffset = ((xmin >> 1) << 1); // must even + uint32_t cropTopOffset = ((ymin >> 1) << 1); // must even + uint32_t cropRightOffset = ((xmax >> 1) << 1) -1; // must odd + uint32_t cropBottomOffset = ((ymax >> 1) << 1) -1; // must odd + + cropArea_ = acldvppCreateRoiConfig(cropLeftOffset, cropRightOffset, + cropTopOffset, cropBottomOffset); + if (cropArea_ == nullptr) { + ERROR_LOG("acldvppCreateRoiConfig cropArea_ failed"); + return SY_FAILED; + } + //printf("debug crop area: %d %d %d %d\n", cropLeftOffset, cropTopOffset, cropRightOffset, cropBottomOffset); + + uint32_t pasteLeftOffset = 0; // must even + uint32_t pasteTopOffset = 0; // must even + uint32_t pasteRightOffset = (((pasteLeftOffset + size_.width) >> 1) << 1) -1; // must odd + uint32_t pasteBottomOffset = (((pasteTopOffset + size_.height) >> 1) << 1) -1; // must odd + + pasteArea_ = acldvppCreateRoiConfig(pasteLeftOffset, pasteRightOffset, + pasteTopOffset, pasteBottomOffset); + if (pasteArea_ == nullptr) { + ERROR_LOG("acldvppCreateRoiConfig pasteArea_ failed"); + return SY_FAILED; + } + //printf("debug paste area: %d %d %d %d\n", pasteLeftOffset, pasteTopOffset, pasteRightOffset, pasteBottomOffset); + + // crop and patse pic + aclError aclRet = acldvppVpcCropAndPasteAsync(dvppChannelDesc_, vpcInputDesc_, + vpcOutputDesc_, cropArea_, pasteArea_, stream_); + //printf("debug crop line:%d\n",__LINE__); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppVpcCropAndPasteAsync failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + aclRet = aclrtSynchronizeStream(stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("crop and paste aclrtSynchronizeStream failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + resizedImage.width = size_.width; + resizedImage.height = size_.height; + resizedImage.alignWidth = ALIGN_UP16(size_.width); + resizedImage.alignHeight = ALIGN_UP2(size_.height); + resizedImage.size = vpcOutBufferSize_; + resizedImage.data = SHARED_PRT_DVPP_BUF(vpcOutBufferDev_); + + DestroyCropAndPasteResource(); + + return SY_SUCCESS; +} + +int DvppCropAndPaste::Crop2Process(ImageData& resizedImage, ImageData& leftImage, ImageData& rightImage, ImageData& srcImage) +{ + //left + if (SY_SUCCESS != InitCropAndPasteResource(srcImage)) { + ERROR_LOG("Dvpp cropandpaste failed for init error"); + return SY_FAILED; + } + uint32_t lcropLeftOffset = 0; // must even + uint32_t lcropTopOffset = 0; // must even + uint32_t lcropRightOffset = ((srcImage.width/2 >> 1) << 1) -1; // must odd + uint32_t lcropBottomOffset = ((srcImage.height >> 1) << 1) -1; // must odd + cropArea_ = acldvppCreateRoiConfig(lcropLeftOffset, lcropRightOffset,lcropTopOffset, lcropBottomOffset); + if (cropArea_ == nullptr) { + ERROR_LOG("left acldvppCreateRoiConfig cropArea_ failed"); + return SY_FAILED; + } + //printf("debug left crop area: %d %d %d %d\n", lcropLeftOffset, lcropTopOffset, lcropRightOffset, lcropBottomOffset); + + uint32_t lpasteLeftOffset = 0; // must even + uint32_t lpasteTopOffset = 0; // must even + uint32_t lpasteRightOffset = (((lpasteLeftOffset + size_.width) >> 1) << 1) -1; // must odd + uint32_t lpasteBottomOffset = (((lpasteTopOffset + size_.height) >> 1) << 1) -1; // must odd + pasteArea_ = acldvppCreateRoiConfig(lpasteLeftOffset, lpasteRightOffset,lpasteTopOffset, lpasteBottomOffset); + if (pasteArea_ == nullptr) { + ERROR_LOG("left acldvppCreateRoiConfig pasteArea_ failed"); + return SY_FAILED; + } + //printf("debug left paste area: %d %d %d %d\n", lpasteLeftOffset, lpasteTopOffset, lpasteRightOffset, lpasteBottomOffset); + + // crop and patse pic + aclError aclRet = acldvppVpcCropAndPasteAsync(dvppChannelDesc_, vpcInputDesc_, + vpcOutputDesc_, cropArea_, pasteArea_, stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("left acldvppVpcCropAndPasteAsync failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + aclRet = aclrtSynchronizeStream(stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("left crop and paste aclrtSynchronizeStream failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + leftImage.width = size_.width; + leftImage.height = size_.height; + leftImage.alignWidth = ALIGN_UP16(size_.width); + leftImage.alignHeight = ALIGN_UP2(size_.height); + leftImage.size = vpcOutBufferSize_; + leftImage.data = SHARED_PRT_DVPP_BUF(vpcOutBufferDev_); + + DestroyCropAndPasteResource(); + + //right + if (SY_SUCCESS != InitRightCropAndPasteResource(srcImage)) { + ERROR_LOG("Dvpp cropandpaste failed for init error"); + return SY_FAILED; + } + + uint32_t rcropLeftOffset = ((srcImage.width/2 >> 1) << 1); // must even + uint32_t rcropTopOffset = 0; // must even + uint32_t rcropRightOffset = ((srcImage.width >> 1) << 1) -1; // must odd + uint32_t rcropBottomOffset = ((srcImage.height >> 1) << 1) -1; // must odd + cropArea_ = acldvppCreateRoiConfig(rcropLeftOffset, rcropRightOffset, rcropTopOffset, rcropBottomOffset); + if (cropArea_ == nullptr) { + ERROR_LOG("right acldvppCreateRoiConfig cropArea_ failed"); + return SY_FAILED; + } + //printf("debug right crop area: %d %d %d %d\n", rcropLeftOffset, rcropTopOffset, rcropRightOffset, rcropBottomOffset); + + uint32_t rpasteLeftOffset = 0; // must even + uint32_t rpasteTopOffset = 0; // must even + uint32_t rpasteRightOffset = (((rpasteLeftOffset + size_.width) >> 1) << 1) -1; // must odd + uint32_t rpasteBottomOffset = (((rpasteTopOffset + size_.height) >> 1) << 1) -1; // must odd + pasteArea_ = acldvppCreateRoiConfig(rpasteLeftOffset, rpasteRightOffset, rpasteTopOffset, rpasteBottomOffset); + if (pasteArea_ == nullptr) { + ERROR_LOG("right acldvppCreateRoiConfig pasteArea_ failed"); + return SY_FAILED; + } + //printf("debug right paste area: %d %d %d %d\n", rpasteLeftOffset, rpasteTopOffset, rpasteRightOffset, rpasteBottomOffset); + + // crop and patse pic + aclRet = acldvppVpcCropAndPasteAsync(dvppChannelDesc_, vpcInputDesc_, + vpcOutputDesc_, cropArea_, pasteArea_, stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("right acldvppVpcCropAndPasteAsync failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + aclRet = aclrtSynchronizeStream(stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("right crop and paste aclrtSynchronizeStream failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + rightImage.width = size_.width; + rightImage.height = size_.height; + rightImage.alignWidth = ALIGN_UP16(size_.width); + rightImage.alignHeight = ALIGN_UP2(size_.height); + rightImage.size = vpcOutBufferSize_; + rightImage.data = SHARED_PRT_DVPP_BUF(vpcOutBufferDev_); + // rightImage.data = SHARED_PRT_DVPP_BUF(vpcOutBufferDev_ + vpcOutBufferSize_); + + DestroyCropAndPasteResource(); + + resizedImage.size = leftImage.size + rightImage.size; + resizedImage.data = SHARED_PRT_DVPP_BUF(vpcOutBufferDev_); + + return SY_SUCCESS; +} + + +int DvppCropAndPaste::Process(ImageData& resizedImage, ImageData& srcImage) +{ + if (SY_SUCCESS != InitCropAndPasteResource(srcImage)) { + ERROR_LOG("Dvpp cropandpaste failed for init error"); + return SY_FAILED; + } + + uint32_t cropLeftOffset = 0; // must even + uint32_t cropTopOffset = 0; // must even + uint32_t cropRightOffset = (((cropLeftOffset + originalImageWidth_) >> 1) << 1) -1; // must odd + uint32_t cropBottomOffset = (((cropTopOffset + originalImageHeight_) >> 1) << 1) -1; // must odd + + cropArea_ = acldvppCreateRoiConfig(cropLeftOffset, cropRightOffset, + cropTopOffset, cropBottomOffset); + if (cropArea_ == nullptr) { + ERROR_LOG("acldvppCreateRoiConfig cropArea_ failed"); + return SY_FAILED; + } + //printf("debug crop area: %d %d %d %d\n", cropLeftOffset, cropTopOffset, cropRightOffset, cropBottomOffset); + + uint32_t pasteLeftOffset = 0; // must even + uint32_t pasteTopOffset = 0; // must even + uint32_t pasteRightOffset = (((pasteLeftOffset + size_.width) >> 1) << 1) -1; // must odd + uint32_t pasteBottomOffset = (((pasteTopOffset + size_.height) >> 1) << 1) -1; // must odd + + pasteArea_ = acldvppCreateRoiConfig(pasteLeftOffset, pasteRightOffset, + pasteTopOffset, pasteBottomOffset); + if (pasteArea_ == nullptr) { + ERROR_LOG("acldvppCreateRoiConfig pasteArea_ failed"); + return SY_FAILED; + } + //printf("debug paste area: %d %d %d %d\n", pasteLeftOffset, pasteTopOffset, pasteRightOffset, pasteBottomOffset); + + // crop and patse pic + aclError aclRet = acldvppVpcCropAndPasteAsync(dvppChannelDesc_, vpcInputDesc_, + vpcOutputDesc_, cropArea_, pasteArea_, stream_); + //printf("debug crop line:%d\n",__LINE__); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppVpcCropAndPasteAsync failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + aclRet = aclrtSynchronizeStream(stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("crop and paste aclrtSynchronizeStream failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + resizedImage.width = size_.width; + resizedImage.height = size_.height; + resizedImage.alignWidth = ALIGN_UP16(size_.width); + resizedImage.alignHeight = ALIGN_UP2(size_.height); + resizedImage.size = vpcOutBufferSize_; + resizedImage.data = SHARED_PRT_DVPP_BUF(vpcOutBufferDev_); + + DestroyCropAndPasteResource(); + + return SY_SUCCESS; +} + + +void DvppCropAndPaste::DestroyCropAndPasteResource() +{ + if (cropArea_ != nullptr) { + (void)acldvppDestroyRoiConfig(cropArea_); + cropArea_ = nullptr; + } + + if (pasteArea_ != nullptr) { + (void)acldvppDestroyRoiConfig(pasteArea_); + pasteArea_ = nullptr; + } + + if (vpcInputDesc_ != nullptr) { + (void)acldvppDestroyPicDesc(vpcInputDesc_); + vpcInputDesc_ = nullptr; + } + + if (vpcOutputDesc_ != nullptr) { + (void)acldvppDestroyPicDesc(vpcOutputDesc_); + vpcOutputDesc_ = nullptr; + } +} diff --git a/src/common/dvpp/dvpp_cropandpaste.h b/src/common/dvpp/dvpp_cropandpaste.h new file mode 100644 index 0000000..fa24657 --- /dev/null +++ b/src/common/dvpp/dvpp_cropandpaste.h @@ -0,0 +1,97 @@ +/** +* Copyright 2020 Huawei Technologies Co., Ltd +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + +* http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + +* File dvpp_process.h +* Description: handle dvpp process +*/ +#pragma once +#include + +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" +#include "utils.h" + +class DvppCropAndPaste { +public: + /** + * @brief Constructor + * @param [in] stream: stream + */ + DvppCropAndPaste(aclrtStream &stream, acldvppChannelDesc *dvppChannelDesc, + uint32_t width, uint32_t height); + + /** + * @brief Destructor + */ + ~DvppCropAndPaste(); + + /** + * @brief dvpp global init + * @return result + */ + int InitResource(); + + /** + * @brief init dvpp output para + * @param [in] modelInputWidth: model input width + * @param [in] modelInputHeight: model input height + * @return result + */ + int InitOutputPara(int modelInputWidth, int modelInputHeight); + + /** + * @brief dvpp process + * @return result + */ + int Process(ImageData& resizedImage, ImageData& srcImage); + int Crop2Process(ImageData& resizedImage, ImageData& leftImage, ImageData& rightImage, ImageData& srcImage); + int PatchProcess(ImageData& resizedImage, ImageData& srcImage, uint32_t xmin, uint32_t ymin, + uint32_t xmax, uint32_t ymax); + + int ResizeWithPadding(ImageData& resizedImage, ImageData& srcImage); + +private: + int InitCropAndPasteResource(ImageData& inputImage); + int InitCropAndPasteInputDesc(ImageData& inputImage); + int InitCropAndPasteOutputDesc(); + + int InitRightCropAndPasteResource(ImageData& inputImage); + int InitRightCropAndPasteOutputDesc(); + + void DestroyCropAndPasteResource(); + + aclrtStream stream_; + acldvppChannelDesc *dvppChannelDesc_; + + + // IN/OUT Desc + acldvppPicDesc *vpcInputDesc_; + acldvppPicDesc *vpcOutputDesc_; + + uint32_t originalImageWidth_; + uint32_t originalImageHeight_; + + acldvppRoiConfig *cropArea_; + acldvppRoiConfig *pasteArea_; + + // output buffer + void *vpcOutBufferDev_; + uint32_t vpcOutBufferSize_; + + //model [W][H] + Resolution size_; + acldvppPixelFormat format_; +}; + diff --git a/src/common/dvpp/dvpp_jpegd.cpp b/src/common/dvpp/dvpp_jpegd.cpp new file mode 100644 index 0000000..6e26cd3 --- /dev/null +++ b/src/common/dvpp/dvpp_jpegd.cpp @@ -0,0 +1,135 @@ +/** +* Copyright 2020 Huawei Technologies Co., Ltd +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + +* http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + +* File dvpp_process.cpp +* Description: handle dvpp process +*/ + +#include +#include "acl/acl.h" +#include "dvpp_jpegd.h" +#include "utils.h" +#include "sy_errorinfo.h" +using namespace std; + +DvppJpegD::DvppJpegD(aclrtStream& stream, acldvppChannelDesc *dvppChannelDesc) + : stream_(stream), dvppChannelDesc_(dvppChannelDesc), + decodeOutBufferDev_(nullptr), decodeOutputDesc_(nullptr), + decodeOutWidthStride_(0), decodeOutHeightStride_(0) +{ +} + +DvppJpegD::~DvppJpegD() +{ + DestroyDecodeResource(); +} + + +int DvppJpegD::InitDecodeOutputDesc(ImageData& inputImage) +{ + //230316 ascend310p兼容================================================= + auto socVersion = aclrtGetSocName(); + if (strncmp(socVersion, "Ascend310P3", sizeof("Ascend310P3") - 1) == 0) { + decodeOutWidth_ = ALIGN_UP2(inputImage.width); + decodeOutHeight_ = ALIGN_UP2(inputImage.height); + decodeOutWidthStride_ = ALIGN_UP64(inputImage.width); // 64-byte alignment + decodeOutHeightStride_ = ALIGN_UP16(inputImage.height); // 16-byte alignment + } else { + decodeOutWidth_ = inputImage.width; + decodeOutHeight_ = inputImage.height; + decodeOutWidthStride_ = ALIGN_UP128(inputImage.width); // 128-byte alignment + decodeOutHeightStride_ = ALIGN_UP16(inputImage.height); // 16-byte alignment + } + if (decodeOutWidthStride_ == 0 || decodeOutHeightStride_ == 0) { + ERROR_LOG("InitDecodeOutputDesc AlignmentHelper failed"); + return SY_FAILED; + } + //===================================================================== + + acldvppJpegPredictDecSize(inputImage.data.get(), inputImage.size, + PIXEL_FORMAT_YUV_SEMIPLANAR_420, &decodeOutBufferSize_); + + aclError aclRet = acldvppMalloc(&decodeOutBufferDev_, decodeOutBufferSize_); + //debug======================================================================== + uint32_t size = ALIGN_UP(decodeOutBufferSize_,32) + 32; + aclRet = aclrtMemset(decodeOutBufferDev_,size, 128, size); + // aclRet = aclrtMemset(decodeOutBufferDev_,decodeOutBufferSize_, 0, decodeOutBufferSize_); + //debug end==================================================================== + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppMalloc decodeOutBufferDev_ failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + decodeOutputDesc_ = acldvppCreatePicDesc(); + if (decodeOutputDesc_ == nullptr) { + ERROR_LOG("acldvppCreatePicDesc decodeOutputDesc_ failed"); + return SY_FAILED; + } + + acldvppSetPicDescData(decodeOutputDesc_, decodeOutBufferDev_); + acldvppSetPicDescFormat(decodeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + acldvppSetPicDescWidth(decodeOutputDesc_, decodeOutWidth_); + acldvppSetPicDescHeight(decodeOutputDesc_, decodeOutHeight_); + acldvppSetPicDescWidthStride(decodeOutputDesc_, decodeOutWidthStride_); + acldvppSetPicDescHeightStride(decodeOutputDesc_, decodeOutHeightStride_); + acldvppSetPicDescSize(decodeOutputDesc_, decodeOutBufferSize_); + return SY_SUCCESS; +} + + +int DvppJpegD::Process(ImageData& dest, ImageData& src) +{ + int ret = InitDecodeOutputDesc(src); + if (ret != SY_SUCCESS) { + ERROR_LOG("InitDecodeOutputDesc failed"); + return SY_FAILED; + } + + ImageData imageDevice; + Utils::CopyImageDataToDvpp(imageDevice, src); + + //TODO: + aclError aclRet = acldvppJpegDecodeAsync(dvppChannelDesc_, reinterpret_cast(imageDevice.data.get()), + imageDevice.size, decodeOutputDesc_, stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppJpegDecodeAsync failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + aclRet = aclrtSynchronizeStream(stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("decode aclrtSynchronizeStream failed, aclRet = %d", aclRet); + return SY_FAILED; + } + + dest.width = decodeOutWidth_; + dest.height = decodeOutHeight_; + dest.alignWidth = decodeOutWidthStride_; + dest.alignHeight = decodeOutHeightStride_; + dest.size = YUV420SP_SIZE(dest.alignWidth, dest.alignHeight); + dest.data = SHARED_PRT_DVPP_BUF(decodeOutBufferDev_); + // cout << "dvpp w:" << dest.width << " h:" << dest.height << " alignw:" << dest.alignWidth <<" alignh:" < +#include +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" +#include "utils.h" + + +/** + * DvppProcess + */ +class DvppJpegD { +public: + /** + * @brief Constructor + * @param [in] stream: stream + */ + DvppJpegD(aclrtStream &stream, acldvppChannelDesc *dvppChannelDesc); + + /** + * @brief Destructor + */ + ~DvppJpegD(); + + /** + * @brief dvpp global init + * @return result + */ + int InitResource(); + + /** + * @brief init dvpp output para + * @param [in] modelInputWidth: model input width + * @param [in] modelInputHeight: model input height + * @return result + */ + int InitOutputPara(int modelInputWidth, int modelInputHeight); + + /** + * @brief set jpegd input + * @param [in] inDevBuffer: device buffer of input pic + * @param [in] inDevBufferSize: device buffer size of input pic + * @param [in] inputWidth:width of pic + * @param [in] inputHeight:height of pic + */ + void SetInput4JpegD(uint8_t* inDevBuffer, int inDevBufferSize, int inputWidth, int inputHeight); + int InitDecodeOutputDesc(ImageData& inputImage); + /** + * @brief gett dvpp output + * @param [in] outputBuffer: pointer which points to dvpp output buffer + * @param [out] outputSize: output size + */ + void GetOutput(void **outputBuffer, int &outputSize); + int Process(ImageData& dest, ImageData& src); + /** + * @brief release encode resource + */ + void DestroyEncodeResource(); + +private: + void DestroyDecodeResource(); + void DestroyResource(); + void DestroyOutputPara(); + + aclrtStream stream_; + acldvppChannelDesc *dvppChannelDesc_; + + void* decodeOutBufferDev_; // decode output buffer + acldvppPicDesc *decodeOutputDesc_; //decode output desc + + uint8_t *inDevBuffer_; // input pic dev buffer + uint32_t inDevBufferSizeD_; // input pic size for decode + + void *vpcOutBufferDev_; // vpc output buffer + uint32_t vpcOutBufferSize_; // vpc output size + //230316added + uint32_t decodeOutWidth_; + uint32_t decodeOutHeight_; + uint32_t decodeOutWidthStride_; + uint32_t decodeOutHeightStride_; + uint32_t decodeOutBufferSize_; +}; + diff --git a/src/common/dvpp/dvpp_process.cpp b/src/common/dvpp/dvpp_process.cpp new file mode 100644 index 0000000..b00a460 --- /dev/null +++ b/src/common/dvpp/dvpp_process.cpp @@ -0,0 +1,136 @@ +/** +* Copyright 2020 Huawei Technologies Co., Ltd +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + +* http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + +* File dvpp_process.cpp +* Description: handle dvpp process +*/ + +#include +#include "acl/acl.h" +#include "dvpp_cropandpaste.h" +#include "dvpp_jpegd.h" +#include "dvpp_process.h" +#include "sy_errorinfo.h" + +using namespace std; + +DvppProcess::DvppProcess() + : isInitOk_(false), dvppChannelDesc_(nullptr) { + isGlobalContext_ = false; +} + +DvppProcess::~DvppProcess() +{ + DestroyResource(); +} + +void DvppProcess::DestroyResource() +{ + aclError aclRet; + if (dvppChannelDesc_ != nullptr) { + aclRet = acldvppDestroyChannel(dvppChannelDesc_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppDestroyChannel failed, aclRet = %d", aclRet); + } + + (void)acldvppDestroyChannelDesc(dvppChannelDesc_); + dvppChannelDesc_ = nullptr; + } + + //INFO_LOG("end to destroy context"); +} + +int DvppProcess::InitResource(aclrtStream& stream) +{ + aclError aclRet; + + dvppChannelDesc_ = acldvppCreateChannelDesc(); + if (dvppChannelDesc_ == nullptr) { + ERROR_LOG("acldvppCreateChannelDesc failed"); + return SY_FAILED; + } + + aclRet = acldvppCreateChannel(dvppChannelDesc_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppCreateChannel failed, aclRet = %d", aclRet); + return SY_FAILED; + } + stream_ = stream; + isInitOk_ = true; + //INFO_LOG("dvpp init resource ok"); + return SY_SUCCESS; +} + +// int DvppProcess::CropAndPaste(ImageData& dest, ImageData& src, +// uint32_t width, uint32_t height) { +// DvppCropAndPaste cropandpasteOp(stream_, dvppChannelDesc_, width, height); +// return cropandpasteOp.Process(dest, src); +// } + +// int DvppProcess::Crop2Paste(ImageData& dest, ImageData& leftImage, ImageData& rightImage, +// ImageData& src,uint32_t width, uint32_t height) { +// DvppCropAndPaste cropandpasteOp(stream_, dvppChannelDesc_, width, height); +// return cropandpasteOp.Crop2Process(dest, leftImage, rightImage, src); +// } + +// int DvppProcess::CropAndPadding(ImageData& dest, ImageData& src, +// uint32_t width, uint32_t height) { +// DvppCropAndPaste cropandpasteOp(stream_, dvppChannelDesc_, width, height); +// return cropandpasteOp.ResizeWithPadding(dest, src); +// } + +// int DvppProcess::PatchCropAndPaste(ImageData& dest, ImageData& src, uint32_t xmin, uint32_t ymin, +// uint32_t xmax, uint32_t ymax, uint32_t width, uint32_t height) { +// DvppCropAndPaste cropandpasteOp(stream_, dvppChannelDesc_, width, height); +// return cropandpasteOp.PatchProcess(dest, src, xmin, ymin, xmax, ymax); +// } + +// int DvppProcess::CvtJpegToYuv420sp(ImageData& dest, ImageData& src) { +// DvppJpegD jpegD(stream_, dvppChannelDesc_); +// return jpegD.Process(dest, src); +// } + + +int DvppProcess::CropAndPaste(ImageData& dest, ImageData& src, + uint32_t width, uint32_t height) { + DvppCropAndPaste cropandpasteOp(stream_, dvppChannelDesc_, width, height); + return cropandpasteOp.Process(dest, src); +} + +int DvppProcess::Crop2Paste(ImageData& dest, ImageData& leftImage, ImageData& rightImage, + ImageData& src,uint32_t width, uint32_t height) { + DvppCropAndPaste cro2pasteOp(stream_, dvppChannelDesc_, width, height); + return cro2pasteOp.Crop2Process(dest, leftImage, rightImage, src); +} + + +int DvppProcess::CropAndPadding(ImageData& dest, ImageData& src, + uint32_t width, uint32_t height) { + DvppCropAndPaste cropandpaddingOp(stream_, dvppChannelDesc_, width, height); + return cropandpaddingOp.ResizeWithPadding(dest, src); +} + + +int DvppProcess::PatchCropAndPaste(ImageData& dest, ImageData& src, uint32_t xmin, uint32_t ymin, + uint32_t xmax, uint32_t ymax, uint32_t width, uint32_t height) { + DvppCropAndPaste patchcropandpasteOp(stream_, dvppChannelDesc_, width, height); + return patchcropandpasteOp.PatchProcess(dest, src, xmin, ymin, xmax, ymax); +} + +int DvppProcess::CvtJpegToYuv420sp(ImageData& dest, ImageData& src) { + DvppJpegD jpegD(stream_, dvppChannelDesc_); + return jpegD.Process(dest, src); +} + diff --git a/src/common/dvpp/dvpp_process.h b/src/common/dvpp/dvpp_process.h new file mode 100644 index 0000000..8a5158a --- /dev/null +++ b/src/common/dvpp/dvpp_process.h @@ -0,0 +1,54 @@ +/** +* Copyright 2020 Huawei Technologies Co., Ltd +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + +* http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + +* File dvpp_process.h +* Description: handle dvpp process +*/ +#pragma once +#include + +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" +#include "utils.h" + +/** + * DvppProcess + */ +class DvppProcess { +public: + DvppProcess(); + + ~DvppProcess(); + + int CropAndPadding(ImageData& src, ImageData& dest, + uint32_t width, uint32_t height); + int CropAndPaste(ImageData& src, ImageData& dest, + uint32_t width, uint32_t height); + int PatchCropAndPaste(ImageData& dest, ImageData& src, uint32_t xmin, uint32_t ymin, + uint32_t xmax, uint32_t ymax, uint32_t width, uint32_t height); + int Crop2Paste(ImageData& dest, ImageData& leftImage, ImageData& rightImage, + ImageData& src,uint32_t width, uint32_t height); + int CvtJpegToYuv420sp(ImageData& src, ImageData& dest); + int InitResource(aclrtStream& stream); + void DestroyResource(); + +protected: + int isInitOk_; + aclrtStream stream_; + acldvppChannelDesc *dvppChannelDesc_; + bool isGlobalContext_; + +}; + diff --git a/src/common/logger.hpp b/src/common/logger.hpp new file mode 100644 index 0000000..1d67fea --- /dev/null +++ b/src/common/logger.hpp @@ -0,0 +1,344 @@ +/* + * @Author: yangzilong + * @Date: 2021-12-21 11:07:11 + * @Last Modified by: yangzilong + * @Email: yangzilong@objecteye.com + * @Description: + */ + +#pragma once + +// #include "define.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +#define LOG_TRACE_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_TRACE(logger, __VA_ARGS__);} +#define LOG_DEBUG_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_DEBUG(logger, __VA_ARGS__);} +#define LOG_WARN_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_WARN(logger, __VA_ARGS__);} +#define LOG_ERROR_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_ERROR(logger, __VA_ARGS__);} +#define LOG_INFO_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_INFO(logger, __VA_ARGS__);} +#define LOG_CRITICAL_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_CRITICAL(logger, __VA_ARGS__);} + + +// use fmt lib, e.g. LOG_WARN("warn log, {1}, {1}, {2}", 1, 2); +#define LOG_TRACE(msg, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::trace, msg, ##__VA_ARGS__) +#define LOG_DEBUG(msg, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::debug, msg, ##__VA_ARGS__) +#define LOG_INFO(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::info, msg, ##__VA_ARGS__) +#define LOG_WARN(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::warn, msg, ##__VA_ARGS__) +#define LOG_ERROR(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::err, msg, ##__VA_ARGS__) +#define LOG_FATAL(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::critical, msg, ##__VA_ARGS__) + + + +namespace spdlog +{ + namespace sinks + { + template + class easy_file_sink final : public base_sink + { + public: + easy_file_sink(filename_t base_filename, size_t max_size, size_t max_keep_days = 0) + : base_filename_(std::move(base_filename)) + , max_size_(max_size) + , max_keep_days_(max_keep_days) + { + auto now = log_clock::now(); + auto filename = gen_filename_by_daliy(base_filename_, now_tm(now)); + + file_helper_.open(filename, false); + current_size_ = file_helper_.size(); + rotation_tp_ = next_rotation_tp_(); + + if (max_keep_days_ > 0) + { + filespath_q_.push_back(std::move(std::set())); + filespath_q_[filespath_q_.size() - 1].insert(filename); + } + } + + filename_t filename() + { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); + } + + protected: + void sink_it_(const details::log_msg &msg) override + { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + current_size_ += formatted.size(); + + auto time = msg.time; + if (time >= rotation_tp_) + { + file_helper_.close(); + auto filename = gen_filename_by_daliy(base_filename_, now_tm(time)); + file_helper_.open(filename, false); + current_size_ = file_helper_.size(); + rotation_tp_ = next_rotation_tp_(); + + { + filespath_q_.push_back(std::move(std::set())); + filespath_q_[filespath_q_.size() - 1].emplace(filename); + } + + // Do the cleaning only at the end because it might throw on failure. + if (max_keep_days_ > 0 && filespath_q_.size() > max_keep_days_) + delete_old_(); + } + else if (current_size_ >= max_size_) + { + file_helper_.close(); + auto src_name = gen_filename_by_daliy(base_filename_, now_tm(time)); + auto target_name = gen_filename_by_filesize(base_filename_, now_tm(time), filespath_q_[filespath_q_.size() - 1].size()); + + // rename file if failed then us `target_name` as src_name. + if (!rename_file_(src_name, target_name)) + { + details::os::sleep_for_millis(200); + if (!rename_file_(src_name, target_name)) + { + fprintf(stderr, "%s:%d rename %s to %s failed\n", __FILENAME__, __LINE__, src_name.c_str(), target_name.c_str()); + src_name = target_name; + } + } + + filespath_q_[filespath_q_.size() - 1].emplace(src_name); + if (src_name != target_name) + filespath_q_[filespath_q_.size() - 1].emplace(target_name); + + file_helper_.open(src_name, false); + current_size_ = file_helper_.size(); + rotation_tp_ = next_rotation_tp_(); + } + + file_helper_.write(formatted); + + + } + + void flush_() override + { + file_helper_.flush(); + } + + private: + + tm now_tm(log_clock::time_point tp) + { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + /** + * @brief Get next day tm. + * + * @return log_clock::time_point + */ + log_clock::time_point next_rotation_tp_() + { + auto now = log_clock::now(); + tm date = now_tm(now); + date.tm_hour = 0; + date.tm_min = 0; + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) + return rotation_time; + return {rotation_time + std::chrono::hours(24)}; + } + + // Delete the file N rotations ago. + // Throw spdlog_ex on failure to delete the old file. + void delete_old_() + { + for (auto iter = filespath_q_.begin(); iter != filespath_q_.end();) + { + if (filespath_q_.size() <= max_keep_days_) + break; + + for (auto it = iter->begin(); it != iter->end(); ++it) + { + bool ok = details::os::remove_if_exists(*it) == 0; + if (!ok) + throw_spdlog_ex("Failed removing daily file " + details::os::filename_to_str(*it), errno); + } + filespath_q_.erase(iter); + } + } + + /* */ + static filename_t gen_filename_by_daliy(const filename_t &filename, const tm &now_tm) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt::format(SPDLOG_FILENAME_T("{}_{:04d}_{:02d}_{:02d}{}"), + basename, + now_tm.tm_year + 1900, + now_tm.tm_mon + 1, + now_tm.tm_mday, + ext); + } + + // + static filename_t gen_filename_by_filesize(const filename_t &filename, const tm &now_tm, const int &idx) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt::format(SPDLOG_FILENAME_T("{}_{:04d}_{:02d}_{:02d}_{:02d}{:02d}{:02d}.{:d}{}"), + basename, + now_tm.tm_year + 1900, + now_tm.tm_mon + 1, + now_tm.tm_mday, + now_tm.tm_hour, + now_tm.tm_min, + now_tm.tm_sec, + idx, + ext); + } + + static bool rename_file_(const filename_t &src_filename, const filename_t &target_filename) + { + (void)details::os::remove(target_filename); + return details::os::rename(src_filename, target_filename) == 0; + } + + filename_t base_filename_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + std::size_t max_size_; + std::size_t max_keep_days_; + std::size_t current_size_; + // std::vector<> filespath_q_; + std::vector> filespath_q_; + }; + + using easy_file_sink_mt = easy_file_sink; + using easy_file_sink_st = easy_file_sink; + + } // namespace sinks + + template + inline std::shared_ptr easy_logger_mt( + const std::string &logger_name, const filename_t &filename, size_t max_size, size_t max_keep_days = -1) + { + return Factory::template create(logger_name, filename, max_size, max_keep_days); + } + + template + inline std::shared_ptr easy_logger_st( + const std::string &logger_name, const filename_t &filename, size_t max_size, size_t max_keep_days = -1) + { + return Factory::template create(logger_name, filename, max_size, max_keep_days); + } + +} // namespace spdlog + + +enum class LogLevel +{ + CLOSE = -1, + TRACE = 0, + DEBUG = 1, + INFO = 2, + WARN = 3, + ERROR = 4, + FATAL = 5, +}; + + +class LoggerGenerator +{ +public: + static LoggerGenerator* get_instance() + { + static LoggerGenerator logger; + return &logger; + } + + void destory(LoggerGenerator *ptr) + { + if (ptr != nullptr) + { + delete ptr; + ptr = nullptr; + } + } + + std::shared_ptr gen_logger(const LogLevel &level, const std::string &logger_name, + const std::string &file_path, size_t max_file_size, size_t max_keep_days) + { + spdlog::level::level_enum spd_level; + if (LogLevel::TRACE == level) + spd_level = spdlog::level::trace; + else if (LogLevel::DEBUG == level) + spd_level = spdlog::level::debug; + else if (LogLevel::INFO == level) + spd_level = spdlog::level::info; + else if (LogLevel::WARN == level) + spd_level = spdlog::level::warn; + else if (LogLevel::ERROR == level) + spd_level = spdlog::level::err; + else if (LogLevel::FATAL == level) + spd_level = spdlog::level::critical; + else if (LogLevel::CLOSE == level) + spd_level = spdlog::level::off; + + auto sink_ptr = std::make_shared(file_path, max_file_size, max_keep_days); + auto logger = std::make_shared(logger_name, sink_ptr); + logger->set_level(spd_level); + logger->set_pattern("%s(%#): [%L %D %T.%e %P %t %!] %v"); + + return logger; + } + + void set_default_logger(const LogLevel &level, const std::string &logger_name, + const std::string &file_name, size_t max_file_size, size_t max_keep_days) + { + + auto logger = gen_logger(level, logger_name, file_name, max_file_size, max_keep_days); + spdlog::set_default_logger(logger); + spdlog::set_level(logger->level()); + spdlog::set_pattern("%s(%#): [%L %D %T.%e %P %t %!] %v"); + + spdlog::flush_on(spdlog::level::trace); + spdlog::flush_every(std::chrono::seconds(1)); + } + +}; + + +static void set_default_logger(const LogLevel &level, const std::string &logger_name, + const std::string &file_path, size_t max_file_size, size_t max_keep_days) +{ + static LoggerGenerator loggerGenerator; + loggerGenerator.set_default_logger(level, logger_name, file_path, max_file_size, max_keep_days); +} + + +static std::shared_ptr get_simple_logger(const LogLevel &level, const std::string &logger_name, + const std::string &file_path, size_t max_file_size, size_t max_keep_days) +{ + static LoggerGenerator loggerGenerator; + return loggerGenerator.gen_logger(level, logger_name, file_path, max_file_size, max_keep_days); +} diff --git a/src/common/stream_data.h b/src/common/stream_data.h new file mode 100644 index 0000000..5b3131b --- /dev/null +++ b/src/common/stream_data.h @@ -0,0 +1,15 @@ +#ifndef _STREAM_DATA_H_ +#define _STREAM_DATA_H_ + +#include + +struct ImageData { + uint32_t width = 0; + uint32_t height = 0; + uint32_t alignWidth = 0; + uint32_t alignHeight = 0; + uint32_t size = 0; + std::shared_ptr data; +}; + +#endif \ No newline at end of file diff --git a/src/common/sy_common.h b/src/common/sy_common.h new file mode 100644 index 0000000..a9d8f96 --- /dev/null +++ b/src/common/sy_common.h @@ -0,0 +1,95 @@ +#ifndef __SY_COMMON_H__ +#define __SY_COMMON_H__ + +#define DEVICE_GPU 10 +#define DEVICE_CPU 11 + + +#define MODEL_SSD 100 +#define MODEL_FPN 101 +#define MODEL_CLASSFY 102 +#define MODEL_CRNN 103 +#define MODEL_SSD_FACE 104 +#define MODEL_POSE_COCO 105 +#define MODEL_RFCN 106 +#define MODEL_CRNN_CNW 107 +#define MODEL_SSD_LDMK 109 +#define MODEL_CTDET 110 +#define MODEL_CTDET_FEATURE 111 + +#define ENGINE_MCAFFE2 200 +#define ENGINE_TENSORRT 201 + + +//��Զ๦��SDK�����ڳ�ʼ���������ã����ݸò������ж�����Ӧ�Ĺ���ģ���Ƿ��������� +#ifndef __SY_COMMAND__ +#define __SY_COMMAND__ +typedef enum sy_command { + SY_CONFIG_OPEN, //�ù������� + SY_CONFIG_CLOSE //�ù��ܲ����� +}; +#endif + + +//����ָ�������ͼ�����ݵĸ�ʽ +#ifndef __SY_FORMAT__ +#define __SY_FORMAT__ +typedef enum sy_format { + SY_FORMAT_BGR888, //Ŀǰֻ֧�ָ��ֽ����ʽ + SY_FORMAT_BGRA888, + SY_FORMAT_GRAY8, + SY_FORMAT_YUV4420P, + SY_FORMAT_NV12, + SY_FORMAT_NV21 +}; +#endif + +//Point +#ifndef __SY_POINT__ +#define __SY_POINT__ +typedef struct sy_point +{ + int x_; + int y_; + sy_point(int m_x, int m_y) :x_(m_x), y_(m_y) {}; + sy_point() {}; +} sy_point; +#endif + + +//Rect +#ifndef __SY_RECT__ +#define __SY_RECT__ +typedef struct sy_rect +{ + int left_; + int top_; + int width_; + int height_; + sy_rect(int m_left, int m_top, int m_width, int m_height) :left_(m_left), top_(m_top), width_(m_width), height_(m_height) {}; + sy_rect() {}; +} sy_rect; +#endif + + +//ImgData +#ifndef __SY_IMG__ +#define __SY_IMG__ +typedef struct sy_img +{ + unsigned char * data_; + int w_; + int h_; + int c_; + void set_data(int m_w, int m_h, int m_c, unsigned char * m_data) + { + w_ = m_w; + h_ = m_h; + c_ = m_c; + data_ = m_data; //Shallow copy + } +} sy_img; +#endif + + +#endif //__SY_COMMON_H__ diff --git a/src/common/sy_errorinfo.h b/src/common/sy_errorinfo.h new file mode 100644 index 0000000..f5600f4 --- /dev/null +++ b/src/common/sy_errorinfo.h @@ -0,0 +1,152 @@ +#ifndef __SY_ERRORINFO_H__ +#define __SY_ERRORINFO_H__ + + +//--------------------------------通用------------------------------------// + +#define SY_SUCCESS 0 //成功 +#define SY_FAILED -1 //失败 + +//1.通用错误 预留编号:(-199) - (-100) +#define SY_PARAMS_NULL_ERROR -100 //参数为空 +#define SY_FILE_NOTFOUND_ERROR -101 //文件找不到 +#define SY_HANDLE_NULL_ERROR -102 //句柄为空 +#define SY_TYPE_UNKNOWN -103 //未知类型 +#define SY_IMG_DATA_ERROR -104 //图像数据错误 +#define SY_IMG_PARAMS_ERROR -105 //图像参数(宽 高 或者 通道数)有错误 +#define SY_AUTHOR_ERROR -106 //授权失败 +#define SY_VERSION_EXPIRED -107 //时间限制下的版本过期 +#define SY_VIDEOFILEERROR -108 //视频打开失败 +#define SY_BUFFNOTENOUGH -109 //缓冲区太小 + +#define SY_MEAN_ERROR -110 //均值错误 +#define SY_MODEL_IMG_PARAMS_ERROR -111 // +#define SY_NEW_MEM_ERROR -112 //内存申请失败 +#define SY_GPUID_PARAM_ERROR -113 //gpu id param error +#define SY_CODEC_FORMAT_ERROR -114 //codec format error +#define SY_PARAMS_INVALID_ERROR -115 //参数值无效 +#define SY_FEATURE_ERROR -116 //特征无效 +//hisi img process error, added by jinxin +#define SY_IMG_RESIZE_ERROR -117 // image resize error +#define SY_IMG_CSC_ERROR -118 // image csc error +//------------------------------------------------------------------------// + + +//-----------------------------深度学习相关-------------------------------// + +//1.通用模块 预留编号:(-299) - (-200) + +//a. caffe部分 预留编号:(-239) - (-200) +#define SY_BATCH_SIZE_NO_EQUAL_INPUT -200 //BATCH_SIZE不匹配 +#define SY_LAYER_NO_REGISTER -201 //层未注册 + +//b. 网络和模型部分 预留编号:(-279) - (-240) +#define SY_PROTOFILE_MODEL_MISMATCH -240 //网络和模型不匹配 +#define SY_PROTOFILEORVECTOR_NOTFOUND -241 //网络文件或者数组找不到 +#define SY_PROTOFILE_NOTFOUND -242 //网络文件找不到 +#define SY_PROTOVECTOR_NOTFOUND -243 //网络数组找不到 +#define SY_MODELFILE_NOTFOUND -244 //模型文件找不到 +#define SY_MODELLENGTH_ERROR -245 //模型数组长度错误 +#define SY_MODELVECTOR_ERROR -246 //模型数组错误 +// hisi added by jinxin +#define SY_MODEL_LOAD_ERROR -247 // load model failed +#define SY_MODELPARAMS_INIT_ERROR -248 // model params init failed +#define SY_MODELPARAMS_RELEASE_ERROR -249 // model params release failed +#define SY_MODEL_FORWARD_ERROR -250 // model forward failed +#define SY_MODEL_FORWARD_TIMEOUT -251 // model forward timeout +#define SY_MODEL_GETRESULT_ERROR -252 // model get results failed + +//c. 其他深度学习通用错误 预留编号:(-299) - (-280) + +//----------------------------------------// + + +//2.人脸模块 预留编号:(-349) - (-300) + +//a. 人脸检测错误返回 预留编号:(-319) - (-300) +#define SY_QUALITY_INIT_ERROR -300 //质量检测初始化失败 +#define SY_ROTATIONCUT_INIT_ERROR -301 //切割旋转初始化失败 +#define SY_FACERECG_INITFAILD_ERROR -302 //人脸识别初始化失败 +#define SY_FACECUT_INITFAILD_ERROR -303 //人脸切割旋转初始化失败 +#define SY_LDMK_INIT_ERROR -304 //关键点检测初始化失败 +#define SY_FACEDETECT_INIT_ERROR -305 //人脸检测初始化失败 +#define SY_POSE_INIT_ERROR -306 //人脸角度初始化失败 +#define SY_SCORE_INIT_ERROR -307 //人脸置信度初始化失败 +#define SY_DB_OPEN_DB_ERROR -308 //数据库打开失败(数据库错误) +#define SY_DB_OPEN_SYS_ERROR -309 //数据库打开失败(程序内部错误) +#define SY_DB_ADD_DATA_EXIST_ERROR -310 //数据库插入数据失败(已存在) +#define SY_DB_ADD_DATA_NOTFOUND -311 //数据库插入数据失败 +#define SY_FACEATTRIBUTES_INITFAILD_ERROR -312 //人脸属性初始化失败 + + +//c. 其他人脸模块错误 预留编号:(-349) - (-340) + + +//----------------------------------------// + + +//3.跟踪模块 预留编号:(-399) - (-350) +#define SY_TRACKER_INIT_ERROR -350 //轨迹跟踪初始化失败 + + +//----------------------------------------// + + +//4.快照模块 预留编号:(-449) - (-400) +#define SY_SHAPSHOT_INIT_ERROR -400 //快照初始化失败 + + +//----------------------------------------// + + +//5.流量统计模块 预留编号:(-499) - (-450) +#define SY_TRAFFICSTATISTICS_INIT_ERROR -450 //流量统计初始化失败 + +//------------------------------------------------------------------------// + + +//-----------------------------授权部分相关-------------------------------// + +//1.授权通用模块 预留编号:(-600) - (-500) +#define SY_AUTHOR_TIMEEXPIRED_ERROR -500 //超出有效期 +#define SY_AUTHOR_SERVER_ERROR -501 //服务器出错 +#define SY_AUTHOR_NOAUTHORIZATION_ERROR -502 //未注册且没有装机剩余量 +#define SY_AUTHOR_NOCOMMUNICATION_ERROR -503 //无法通信 +#define SY_AUTHOR_NET_ERROR -504 //网络出错 +#define SY_LICENCE_SERVICECHECK_ERROR -505 //服务检查未成功 +#define SY_LICENCE_SERVICENOTRUNNING_ERROR -506 //服务未开启 +#define SY_LICENCE_LICENCEDATA_ERROR -507 //授权文件数据错误 +#define SY_LICENCE_LICENCEINVALID_ERROR -508 //授权文件无效 +#define SY_LICENCE_LICENCENOTEXIST_ERROR -509 //授权文件不存在 + +//------------------------------------------------------------------------// + + +//--------------------------------sdk相关---------------------------------// + +//1.视频结构化模块 预留编号:(-699) - (-600) + + +//a.二次属性错误返回 预留编号:(-649) - (-600) + +#define SY_HUMANPARSING_INIT_ERROR -600 //行人结构化初始化失败 +#define SY_HUMANCARPARSING_INIT_ERROR -601 //人骑车结构化初始化失败 +#define SY_VEHICLECOLOR_INIT_ERROR -602 //车颜色识别初始化失败 +#define SY_VEHICLEPLATEDETECT_INIT_ERROR -603 //车牌检测初始化失败 +#define SY_VEHICLEPLATERECOG_INIT_ERROR -604 //车牌识别初始化失败 +#define SY_VEHICLERECOG_INIT_ERROR -605 //车型识别初始化失败 +#define SY_VPT_DET_INIT_ERROR -606 //人车物检测初始化失败 +#define SY_VEHICLE_FEA_INIT_ERROR -607 //车型特征初始化失败 +//c.其他模块错误 预留编号:(-699) - (-650) + +//------------------------------------------------------------------------// + +//------------------------------rtsp--------------------------------------// +#define SY_STREAM_NOT_FIND_ERROR -700 //流获取失败 +#define SY_STREAM_END_ERROR -701 //流异常结束 +#define SY_STREAM_BLOCK_ERROR -702 //流发送阻塞 +#define SY_STREAM_END -703 //流正常结束 +#define SY_STREAM_MEMORYOUT_ERROR -704 //流内存不足 + + +#endif // __SY_ERRORINFO_H__ diff --git a/src/common/utils.cpp b/src/common/utils.cpp new file mode 100644 index 0000000..7b39046 --- /dev/null +++ b/src/common/utils.cpp @@ -0,0 +1,306 @@ +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sy_errorinfo.h" +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" +#include +#include + +using namespace std; +aclrtRunMode Utils::runMode_ = ACL_DEVICE; + +void* Utils::CopyDataHostToDvpp(void* data, int size) { + void* buffer = nullptr; + auto aclRet = acldvppMalloc(&buffer, size); + //debug==================================================== + aclrtMemset(buffer,size, 0, size); + //debug end================================================ + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acl malloc dvpp data failed, dataSize=%u, ret=%d", + size, aclRet); + return nullptr; + } + // INFO_LOG("malloc dvpp memory size %d ok", size); + // copy input to device memory + aclRet = aclrtMemcpy(buffer, size, data, size, ACL_MEMCPY_HOST_TO_DEVICE); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acl memcpy data to dvpp failed, size %u, error %d", size, aclRet); + acldvppFree(buffer); + return nullptr; + } + //INFO_LOG("copy data to dvpp ok"); + + return buffer; +} + +void* Utils::CopyDataDeviceToDvpp(void* data, int size) { + void* buffer = nullptr; + auto aclRet = acldvppMalloc(&buffer, size); + //debug==================================================== + aclrtMemset(buffer,size, 0, size); + //debug end================================================ + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acl malloc dvpp data failed, dataSize=%u, ret=%d", + size, aclRet); + return nullptr; + } + // INFO_LOG("malloc dvpp memory size %d ok", size); + // copy input to device memory + aclRet = aclrtMemcpy(buffer, size, data, size, ACL_MEMCPY_DEVICE_TO_DEVICE); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acl memcpy data to dvpp failed, size %u, error %d", size, aclRet); + acldvppFree(buffer); + return nullptr; + } + //INFO_LOG("copy data to dvpp ok"); + + return buffer; +} + + +int Utils::CopysyImageDataToDvpp(ImageData& imageDevice, sy_img srcImage) { + aclError ret = aclrtGetRunMode(&runMode_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("acl get run mode failed"); + return SY_FAILED; + } + + void* buffer = nullptr; + //230316 ascend310p兼容================================================= + uint32_t alignWidth = 0, alignHeight = 0; + auto socVersion = aclrtGetSocName(); + if (strncmp(socVersion, "Ascend310P3", sizeof("Ascend310P3") - 1) == 0) { + alignWidth = ALIGN_UP64(srcImage.w_); // 64-byte alignment + alignHeight = ALIGN_UP16(srcImage.h_); // 16-byte alignment + } else { + alignWidth = ALIGN_UP128(srcImage.w_); // 128-byte alignment + alignHeight = ALIGN_UP16(srcImage.h_); // 16-byte alignment + } + if (alignWidth == 0 || alignHeight == 0) { + ERROR_LOG("Input image width %d or height %d invalid",srcImage.w_, srcImage.h_); + return SY_FAILED; + } + //===================================================================== + uint32_t size = YUV420SP_SIZE(alignWidth, alignHeight); + // cout << srcImage.w_ << " " << srcImage.h_ << " "<< alignWidth << " "<< alignHeight << " " << size << endl; + if (runMode_ == ACL_HOST){ + // printf("1111111111\n"); + buffer = Utils::CopyDataHostToDvpp(srcImage.data_, size); + if (buffer == nullptr) { + ERROR_LOG("Copy image to device failed"); + return SY_FAILED; + } + } + else{ + // printf("2222222222\n"); + buffer = Utils::CopyDataDeviceToDvpp(srcImage.data_, size); + if (buffer == nullptr) { + ERROR_LOG("Copy image to device failed"); + return SY_FAILED; + } + } + + imageDevice.width = srcImage.w_; + imageDevice.height = srcImage.h_; + imageDevice.alignWidth = alignWidth; + imageDevice.alignHeight = alignHeight; + imageDevice.size = size; + imageDevice.data.reset((uint8_t*)buffer, [](uint8_t* p) { acldvppFree((void *)p); }); + + return SY_SUCCESS; +} + +int Utils::CopyImageDataToDvpp(ImageData& imageDevice, ImageData srcImage) { + aclError ret = aclrtGetRunMode(&runMode_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("acl get run mode failed"); + return SY_FAILED; + } + + void* buffer = nullptr; + if (runMode_ == ACL_HOST){ + buffer = Utils::CopyDataHostToDvpp(srcImage.data.get(), srcImage.size); + if (buffer == nullptr) { + ERROR_LOG("Copy image to device failed"); + return SY_FAILED; + } + } + else{ + buffer = Utils::CopyDataDeviceToDvpp(srcImage.data.get(), srcImage.size); + if (buffer == nullptr) { + ERROR_LOG("Copy image to device failed"); + return SY_FAILED; + } + } + + imageDevice.width = srcImage.width; + imageDevice.height = srcImage.height; + imageDevice.size = srcImage.size; + imageDevice.data.reset((uint8_t*)buffer, [](uint8_t* p) { acldvppFree((void *)p); }); + return SY_SUCCESS; +} + +void* Utils::CopyDataDeviceToLocal(void* deviceData, uint32_t dataSize) { + uint8_t* buffer = new uint8_t[dataSize]; + if (buffer == nullptr) { + ERROR_LOG("New malloc memory failed"); + return nullptr; + } + + aclError aclRet = aclrtMemcpy(buffer, dataSize, deviceData, dataSize, ACL_MEMCPY_DEVICE_TO_HOST); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("Copy device data to local failed, aclRet is %d", aclRet); + delete[](buffer); + return nullptr; + } + + return (void*)buffer; +} + +void* Utils::CopyDataToDevice(void* data, uint32_t dataSize, aclrtMemcpyKind policy) { + void* buffer = nullptr; + aclError aclRet = aclrtMalloc(&buffer, dataSize, ACL_MEM_MALLOC_HUGE_FIRST); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("malloc device data buffer failed, aclRet is %d", aclRet); + return nullptr; + } + + aclRet = aclrtMemcpy(buffer, dataSize, data, dataSize, policy); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("Copy data to device failed, aclRet is %d", aclRet); + (void)aclrtFree(buffer); + return nullptr; + } + + return buffer; +} + +void* Utils::CopyDataDeviceToDevice(void* deviceData, uint32_t dataSize) { + return CopyDataToDevice(deviceData, dataSize, ACL_MEMCPY_DEVICE_TO_DEVICE); +} + +void* Utils::CopyDataHostToDevice(void* deviceData, uint32_t dataSize) { + return CopyDataToDevice(deviceData, dataSize, ACL_MEMCPY_HOST_TO_DEVICE); +} + +int Utils::CopyImageDataToDevice(ImageData& imageDevice, ImageData srcImage, aclrtRunMode mode) { + void * buffer; + if (mode == ACL_HOST) + buffer = Utils::CopyDataHostToDevice(srcImage.data.get(), srcImage.size); + else + buffer = Utils::CopyDataDeviceToDevice(srcImage.data.get(), srcImage.size); + + if (buffer == nullptr) { + ERROR_LOG("Copy image to device failed"); + return SY_FAILED; + } + + imageDevice.width = srcImage.width; + imageDevice.height = srcImage.height; + imageDevice.size = srcImage.size; + imageDevice.data.reset((uint8_t*)buffer, [](uint8_t* p) { aclrtFree((void *)p); }); + + return SY_SUCCESS; +} + + +int Utils::ReadImageFile(ImageData& image, std::string fileName) { + struct stat sBuf; + int fileStatus = stat(fileName.data(), &sBuf); + if (fileStatus == -1) { + ERROR_LOG("failed to get file"); + return SY_FAILED; + } + if (S_ISREG(sBuf.st_mode) == 0) { + ERROR_LOG("%s is not a file, please enter a file", fileName.c_str()); + return SY_FAILED; + } + std::ifstream binFile(fileName, std::ifstream::binary); + if (binFile.is_open() == false) { + ERROR_LOG("open file %s failed", fileName.c_str()); + return SY_FAILED; + } + + binFile.seekg(0, binFile.end); + uint32_t binFileBufferLen = binFile.tellg(); + if (binFileBufferLen == 0) { + ERROR_LOG("binfile is empty, filename is %s", fileName.c_str()); + binFile.close(); + return SY_FAILED; + } + + binFile.seekg(0, binFile.beg); + + uint8_t* binFileBufferData = new(std::nothrow) uint8_t[binFileBufferLen]; + if (binFileBufferData == nullptr) { + ERROR_LOG("malloc binFileBufferData failed"); + binFile.close(); + return SY_FAILED; + } + binFile.read((char *)binFileBufferData, binFileBufferLen); + binFile.close(); + + int32_t ch = 0; + acldvppJpegGetImageInfo(binFileBufferData, binFileBufferLen, + &(image.width), &(image.height), &ch); + image.data.reset(binFileBufferData, [](uint8_t* p) { delete[](p); }); + image.size = binFileBufferLen; + + return SY_SUCCESS; +} + + +float Utils::sigmoid(float val){ + return 1.0/(1.0+exp(-val)); +} + + +// double Power(double base, int n) { +// double res = 1,curr = base; +// int exponent; +// if(n>0){ +// exponent = n; +// }else if(n==0){ +// return 1; +// }else{ +// exponent = -n; +// } +// while(exponent!=0){ +// if((exponent&1)==1) +// res*=curr; +// curr*=curr;// 翻倍 +// exponent>>=1;// 右移一位 +// } +// return n>=0?res:(1/res); +// } + + +// float Utils::sigmoid1(float val){ +// return 1.0/(1.0+Power(exp(1.),-val)); +// } + +float FastExp(float x) { + float d; + //将尾数后32位抹零 + *(reinterpret_cast(&d) + 0) = 0; + //计算指数位 + *(reinterpret_cast(&d) + 1) = static_cast(184 * x + (16256-7)); + return d; +} + +float Utils::FastSigmoid(float x) { + // float x_ = x / 4096.; //int32 + float x_ = x; + return 1. / (FastExp(0 - x_) + 1.); +} + + diff --git a/src/common/utils.h b/src/common/utils.h new file mode 100644 index 0000000..a5f7f0a --- /dev/null +++ b/src/common/utils.h @@ -0,0 +1,88 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include +#include +#include +#include "acl/acl.h" +#include "stream_data.h" +#include "sy_common.h" + +// #include "opencv2/opencv.hpp" +// #include "opencv2/imgcodecs/legacy/constants_c.h" +// #include "opencv2/imgproc/types_c.h" + +using namespace std; + +#define INFO_LOG(fmt, args...) fprintf(stdout, "[INFO] " fmt "\n", ##args) +#define WARN_LOG(fmt, args...) fprintf(stdout, "[WARN] " fmt "\n", ##args) +#define ERROR_LOG(fmt, args...) fprintf(stdout, "[ERROR] " fmt "\n", ##args) + +#define RGBU8_IMAGE_SIZE(width, height) ((width) * (height) * 3) +#define YUV420SP_SIZE(width, height) ((width) * (height) * 3 / 2) + +#define ALIGN_UP(num, align) (((num) + (align) - 1) & ~((align) - 1)) +#define ALIGN_UP2(num) ALIGN_UP(num, 2) +#define ALIGN_UP16(num) ALIGN_UP(num, 16) +#define ALIGN_UP64(num) ALIGN_UP(num, 64) //230316added +#define ALIGN_UP128(num) ALIGN_UP(num, 128) + +#define SHARED_PRT_DVPP_BUF(buf) (shared_ptr((uint8_t *)(buf), [](uint8_t* p) { acldvppFree(p); })) +#define SHARED_PRT_U8_BUF(buf) (shared_ptr((uint8_t *)(buf), [](uint8_t* p) { delete[](p); })) + +#define ACL_CALL(ret, expect, errCode)\ + do {\ + if (ret != expect) {\ + if (errCode == 0)\ + return ret;\ + else\ + return errCode;\ + }\ + } while(0) + +template +std::shared_ptr MakeSharedNoThrow() { + try { + return std::make_shared(); + } + catch (...) { + return nullptr; + } +} + +#define MAKE_SHARED_NO_THROW(memory, memory_type) \ + do { \ + memory = MakeSharedNoThrow(); \ + }while(0); + +struct Resolution { + uint32_t width = 0; + uint32_t height = 0; +}; + +/** + * Utils + */ +class Utils { +public: + static aclrtRunMode runMode_; + + static void* CopyDataToDevice(void* data, uint32_t dataSize, aclrtMemcpyKind policy); + static void* CopyDataDeviceToLocal(void* deviceData, uint32_t dataSize); + static void* CopyDataHostToDevice(void* deviceData, uint32_t dataSize); + static void* CopyDataDeviceToDevice(void* deviceData, uint32_t dataSize); + static int ReadImageFile(ImageData& image, std::string fileName); + static int CopyImageDataToDevice(ImageData& imageDevice, ImageData srcImage, aclrtRunMode mode); + static int CopyImageDataToDvpp(ImageData& imageDevice, ImageData srcImage); + static int CopysyImageDataToDvpp(ImageData& imageDevice, sy_img srcImage); + static void* CopyDataHostToDvpp(void* data, int size); + static bool CreateFolder(std::string folderPath, mode_t mode = 0700); + static bool WriteImage(unsigned char* data, int32_t size, const char* filename); + static void* CopyDataDeviceToDvpp(void* data, int size); + // static float sigmoid1(float val); + static float sigmoid(float val); + static float FastSigmoid(float x); +}; + + +#endif \ No newline at end of file diff --git a/src/decoder/dvpp/CircularQueue.hpp b/src/decoder/dvpp/CircularQueue.hpp new file mode 100644 index 0000000..368291c --- /dev/null +++ b/src/decoder/dvpp/CircularQueue.hpp @@ -0,0 +1,138 @@ +#ifndef __CIRCULAR_QUEUE_HPP__ +#define __CIRCULAR_QUEUE_HPP__ + +#include +#include +#include +#include + +using namespace std; + + +// 循环队列 +template +class CircularQueue +{ +private: + /* data */ +public: + CircularQueue(); + ~CircularQueue(); + + bool init(vector data); + T getTail(); + void addTail(); + T deQueue(); + T getHead(); + void addHead(); + void clearQueue(); + + int length(); + bool isEmpty(); + +private: + vector base; + atomic front; + atomic rear; + mutex m_mutex; + int max_size; +}; + + +template +CircularQueue::CircularQueue() +{ + front = rear = 0;//头指针和尾指针置为零,队列为空 +} + +template +CircularQueue::~CircularQueue() +{ + base.clear(); + rear = front = 0; +} + +template +bool CircularQueue::init(vector data){ + base = data; + front = rear = 0;//头指针和尾指针置为零,队列为空 + max_size = data.size(); + + return true; +} + +//循环队列的入队 +template +T CircularQueue::getTail() +{ + std::lock_guard l(m_mutex); + //插入一个元素e为Q的新的队尾元素 + if ((rear + 1) % max_size == front) + return nullptr;//队满 + return base[rear];//获取队尾元素 +} + +// 将队尾元素添加到队列中 +template +void CircularQueue::addTail() +{ + std::lock_guard l(m_mutex); + rear = (rear + 1) % max_size;//队尾指针加1 +} + +//循环队列的出队 +template +T CircularQueue::deQueue() +{ + std::lock_guard l(m_mutex); + //删除Q的队头元素,用e返回其值 + if (front == rear) + return nullptr;//队空 + T e = base[front];//保存队头元素 + front = (front + 1) % max_size;//队头指针加1 + return e; +} + +//取循环队列的队头元素 +template +T CircularQueue::getHead() +{ + std::lock_guard l(m_mutex); + //返回Q的队头元素,不修改队头指针 + if (front == rear) + return nullptr;//队列为空,取元素失败 + return base[front]; +} + +template +void CircularQueue::addHead() +{ + std::lock_guard l(m_mutex); + front = (front + 1) % max_size;//队头指针加1 +} + +template +int CircularQueue::length() +{ + std::lock_guard l(m_mutex); + return (rear - front + max_size) % max_size; +} + +template +bool CircularQueue::isEmpty() +{ + std::lock_guard l(m_mutex); + if (front == rear) + return true; + + return false; +} + +template +void CircularQueue::clearQueue() +{ + std::lock_guard l(m_mutex); + rear = front = 0; +} + +#endif \ No newline at end of file diff --git a/src/decoder/dvpp/DvppDataMemory.hpp b/src/decoder/dvpp/DvppDataMemory.hpp new file mode 100644 index 0000000..2ebe58a --- /dev/null +++ b/src/decoder/dvpp/DvppDataMemory.hpp @@ -0,0 +1,38 @@ +#include + +#include "dvpp_headers.h" + +using namespace std; + +class DvppDataMemory : public DeviceMemory +{ +public: + DvppDataMemory(int _channel, int _width, int _width_stride, int _height, int _height_stride, int _size, string _id, string _dev_id, bool _key_frame) + :DeviceMemory(_channel, _width, _width_stride, _height, _height_stride, _id, _dev_id, _key_frame, false){ + data_size = _size; + int ret = acldvppMalloc((void **)&pHwRgb, data_size); + if(ret != ACL_ERROR_NONE){ + cout << "acldvppMalloc failed" << endl; + } + } + + DvppDataMemory( int _width, int _width_stride, int _height, int _height_stride, int _size, string _id, string _dev_id, bool _key_frame, unsigned char * pHwData) + :DeviceMemory(3, _width, _width_stride, _height, _height_stride, _id, _dev_id, _key_frame, false){ + data_size = _size; + data_type = 1; + pHwRgb = pHwData; + } + + ~DvppDataMemory(){ + if (pHwRgb) { + int ret = acldvppFree((uint8_t*)pHwRgb); + if(ret != ACL_ERROR_NONE){ + cout << "acldvppFree failed" << endl; + } + pHwRgb = nullptr; + } + } + +public: + int data_type; // 0: rgb , 1: NV12 +}; \ No newline at end of file diff --git a/src/decoder/dvpp/DvppDec.cpp b/src/decoder/dvpp/DvppDec.cpp new file mode 100644 index 0000000..5092e81 --- /dev/null +++ b/src/decoder/dvpp/DvppDec.cpp @@ -0,0 +1,466 @@ +#include "DvppDec.h" +#include "DvppSourceManager.h" + +#include "../../util/vpc_util.h" + +struct Vdec_CallBack_UserData { + uint64_t frameId; + long startTime; + long sendTime; + // void* vdecOutputBuf; + DvppDec* self; + shared_ptr inBufNode; + Vdec_CallBack_UserData() { + frameId = 0; + } +}; + +static const int g_pkt_size = 1024 * 1024; + + DvppDec::DvppDec(){ + m_decode_thread = 0; + } + + DvppDec::~DvppDec(){ + releaseResource(); + } + + bool DvppDec::init_vdpp(DvppDecConfig cfg){ + + m_dec_name = cfg.dec_name; + + LOG_INFO("[{}]- Init device start...", m_dec_name); + + m_dvpp_deviceId = atoi(cfg.dev_id.c_str()); + + if(cfg.codec_id == 0){ + // 66:Baseline,77:Main,>=100:High + if(cfg.profile == 77){ + enType = H264_MAIN_LEVEL; + }else if(cfg.profile < 77){ + enType = H264_BASELINE_LEVEL; + }else{ + enType = H264_HIGH_LEVEL; + } + }else if(cfg.codec_id == 1){ + // h265只有main + enType = H265_MAIN_LEVEL; + }else { + LOG_ERROR("[{}]- codec_id is not supported!", m_dec_name); + return false; + } + + post_decoded_cbk = cfg.post_decoded_cbk; + m_pktQueueptr = cfg.pktQueueptr; + + // DvppSourceManager 创建时包含 aclInit,析构时包含 aclFinalize + DvppSourceManager* pSrcMgr = DvppSourceManager::getInstance(); + m_context = pSrcMgr->getContext(m_dvpp_deviceId); + m_dvpp_channel = pSrcMgr->getChannel(m_dvpp_deviceId); + if(m_dvpp_channel < 0){ + LOG_ERROR("[{}]-该设备channel已经用完了!", m_dec_name); + return false; + } + + do + { + CHECK_AND_BREAK(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed !"); + + int ret = 0; + // int ret = picConverter.init(m_context, m_dec_name); + // if(ret != ACL_ERROR_NONE){ + // LOG_ERROR("[{}]- acldvppMalloc failed!, ret:{}", m_dec_name, ret); + // break; + // } + + // queue_size 最小应大于16,否则关键帧之间距离太远的时候会导致回调函数与循环队列卡死 + for (size_t i = 0; i < 20; i++){ + void *vdecInputbuf = nullptr; + ret = acldvppMalloc((void **)&vdecInputbuf, g_pkt_size); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- acldvppMalloc failed!, ret:{}", m_dec_name, ret); + // 析构函数中有对channel 的补救性释放,所以这里可以直接return + return false;; + } + m_vec_vdec.push_back(vdecInputbuf); + } + + if(!m_vdecQueue.init(m_vec_vdec)){ + break; + } + + m_vdec_out_size = cfg.width * cfg.height * 3 / 2; + + LOG_INFO("[{}]- init vdpp success! device:{} channel:{}", m_dec_name, m_dvpp_deviceId, m_dvpp_channel); + return true; + + } while (0); + + LOG_INFO("[{}]- init vdpp failed!", m_dec_name); + // 初始化失败,释放channel + pSrcMgr->releaseChannel(m_dvpp_deviceId, m_dvpp_channel); + return false; +} + +bool DvppDec::start(){ + m_bRunning = true; + + pthread_create(&m_decode_thread,0, + [](void* arg) + { + DvppDec* a=(DvppDec*)arg; + a->decode_thread(); + return (void*)0; + } + ,this); + + return true; +} + +static void *ReportThd(void *arg) +{ + DvppDec *self = (DvppDec *)arg; + if(nullptr != self){ + self->doProcessReport(); + } + return (void *)0; +} + +void DvppDec::doProcessReport(){ + + aclError ret = aclrtSetDevice(m_dvpp_deviceId); + if(ret != ACL_ERROR_NONE){ + // cout << "aclrtSetDevice failed" << endl; + LOG_ERROR("aclrtSetDevice failed !"); + return ; + } + + aclrtContext ctx; + ret = aclrtCreateContext(&ctx, m_dvpp_deviceId); + if (ret != ACL_ERROR_NONE) { + // cout << "aclrtCreateContext failed " << endl; + LOG_ERROR("aclrtCreateContext failed !"); + return ; + } + + CHECK_AND_RETURN_NOVALUE(aclrtSetCurrentContext(ctx), "aclrtSetCurrentContext failed"); + // 阻塞等待vdec线程开始 + + while (!m_bExitReportThd) { + aclrtProcessReport(1000); + } + + ret = aclrtDestroyContext(ctx); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("aclrtDestroyContext failed !"); + } + LOG_INFO("doProcessReport exit."); +} + +static void VdecCallback(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData) +{ + Vdec_CallBack_UserData *userData = (Vdec_CallBack_UserData *) pUserData; + if(nullptr != userData){ + DvppDec* self = userData->self; + if(self != nullptr){ + + self->doVdppVdecCallBack(input, output); + } + delete userData; + userData = nullptr; + } +} + +void DvppDec::doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output){ + + // dvpp_crop(output); + + CHECK_AND_RETURN_NOVALUE(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed"); + + void *inputDataDev = acldvppGetStreamDescData(input); + void *outputDataDev = acldvppGetPicDescData(output); + uint32_t outputSize = acldvppGetPicDescSize(output); + uint32_t width = acldvppGetPicDescWidth(output); + uint32_t width_stride = acldvppGetPicDescWidthStride(output); + uint32_t height = acldvppGetPicDescHeight(output); + uint32_t height_stride = acldvppGetPicDescHeightStride(output); + + DvppDataMemory* mem = new DvppDataMemory(width, width_stride, height, height_stride, outputSize, m_dec_name, to_string(m_dvpp_deviceId), false, (unsigned char *)outputDataDev); + post_decoded_cbk(m_postDecArg, mem); + +// DvppDataMemory* rgbMem = picConverter.convert2bgr(output, width, height, false); +// if(rgbMem != nullptr){ +// #ifdef TEST_DECODER +// // D2H +// if(vdecHostAddr == nullptr){ +// CHECK_NOT_RETURN(aclrtMallocHost(&vdecHostAddr, width * height * 3), "aclrtMallocHost failed"); +// } +// uint32_t data_size = rgbMem->getSize(); +// CHECK_AND_RETURN_NOVALUE(aclrtMemcpy(vdecHostAddr, data_size, rgbMem->getMem(), data_size, ACL_MEMCPY_DEVICE_TO_HOST), "D2H aclrtMemcpy failed"); + +// // 保存vdec结果 +// if(count_frame > 45 && count_frame < 50) +// { +// string file_name = "./yuv_pic/vdec_out_"+ m_dec_name +".rgb" ; +// FILE *outputFile = fopen(file_name.c_str(), "a"); +// if(outputFile){ +// fwrite(vdecHostAddr, data_size, sizeof(char), outputFile); +// fclose(outputFile); +// } +// } +// else if(count_frame > 50 && vdecHostAddr != nullptr){ +// CHECK_NOT_RETURN(aclrtFreeHost(vdecHostAddr), "aclrtFreeHost failed"); +// vdecHostAddr = nullptr; +// } +// count_frame++; +// #endif +// post_decoded_cbk(m_postDecArg, rgbMem); +// }else{ +// LOG_ERROR("[{}]- convert2bgr failed !", m_dec_name); +// } + +// acldvppFree(outputDataDev); +// outputDataDev = nullptr; + + m_vdecQueue.addHead(); + + CHECK_AND_RETURN_NOVALUE(acldvppDestroyStreamDesc(input), "acldvppDestroyStreamDesc failed"); + CHECK_AND_RETURN_NOVALUE(acldvppDestroyPicDesc(output), "acldvppDestroyPicDesc failed"); +} + +void DvppDec::close(){ + m_bRunning=false; + + if(m_decode_thread != 0){ + pthread_join(m_decode_thread,0); + } +} + +bool DvppDec::sendVdecEos(aclvdecChannelDesc *vdecChannelDesc){ + // create stream desc + acldvppStreamDesc *streamInputDesc = acldvppCreateStreamDesc(); + if (streamInputDesc == nullptr) { + LOG_ERROR("[{}]- fail to create input stream desc", m_dec_name); + return false; + } + aclError ret = acldvppSetStreamDescEos(streamInputDesc, 1); + if (ret != ACL_SUCCESS) { + LOG_ERROR("[{}]- fail to set eos for stream desc, errorCode = {}", m_dec_name, static_cast(ret)); + (void)acldvppDestroyStreamDesc(streamInputDesc); + return false; + } + + // send vdec eos frame. when all vdec callback are completed, aclvdecSendFrame can be returned. + LOG_INFO("[{}]- send eos", m_dec_name); + ret = aclvdecSendFrame(vdecChannelDesc, streamInputDesc, nullptr, nullptr, nullptr); + if (ret != ACL_SUCCESS) { + LOG_ERROR("[{}]- fail to send eos frame, ret={}", m_dec_name, ret); + (void)acldvppDestroyStreamDesc(streamInputDesc); + return false; + } + (void)acldvppDestroyStreamDesc(streamInputDesc); + + return true; +} + +void DvppDec::releaseResource(){ + for(int i = 0; i < m_vec_vdec.size(); i++){ + if(m_vec_vdec[i] != nullptr){ + acldvppFree(m_vec_vdec[i]); + m_vec_vdec[i] = nullptr; + } + } + m_vec_vdec.clear(); + + DvppSourceManager* pSrcMgr = DvppSourceManager::getInstance(); + pSrcMgr->releaseChannel(m_dvpp_deviceId, m_dvpp_channel); +} + +void DvppDec::decode_thread(){ + + long startTime = UtilTools::get_cur_time_ms(); + + int ret = -1; + + // // dvpp解码参数 + // CHECK_AND_RETURN_NOVALUE(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed"); + + m_bExitReportThd = false; + pthread_t report_thread; + ret = pthread_create(&report_thread, nullptr, ReportThd, (void *)this); + if(ret != 0){ + LOG_ERROR("[{}]- pthread_create failed", m_dec_name); + return; + } + + aclrtSetDevice(m_dvpp_deviceId); + aclrtContext ctx; + ret = aclrtCreateContext(&ctx, m_dvpp_deviceId); + if (ret != ACL_ERROR_NONE) { + // cout << "aclrtCreateContext failed " << endl; + LOG_ERROR("aclrtCreateContext failed !"); + return ; + } + + // 创建aclvdecChannelDesc类型的数据 + aclvdecChannelDesc *vdecChannelDesc = aclvdecCreateChannelDesc(); + if (vdecChannelDesc == nullptr) { + LOG_ERROR("[{}]- aclvdecCreateChannelDesc failed", m_dec_name); + return; + } + do{ + // 创建 channel dec结构体 + // 通道ID在dvpp层面为0~31 + CHECK_AND_BREAK(aclvdecSetChannelDescChannelId(vdecChannelDesc, m_dvpp_channel), "aclvdecSetChannelDescChannelId failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescThreadId(vdecChannelDesc, report_thread), "aclvdecSetChannelDescThreadId failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescCallback(vdecChannelDesc, VdecCallback), "aclvdecSetChannelDescCallback failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescEnType(vdecChannelDesc, enType), "aclvdecSetChannelDescEnType failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescOutPicFormat(vdecChannelDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420), "aclvdecSetChannelDescOutPicFormat failed"); + CHECK_AND_BREAK(aclvdecCreateChannel(vdecChannelDesc), "aclvdecCreateChannel failed"); + + uint64_t frame_count = 0; + bool bBreak = false; + while (m_bRunning) + { + if (m_bPause){ + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + int ret = sentFrame(vdecChannelDesc, frame_count); + if(ret == 2){ + break; + bBreak = true; + }else if(ret == 1){ + continue; + } + + frame_count++; + } + + // 尽量保证数据全部解码完成 + int sum = 0; + if(!bBreak){ + aclrtSetDevice(m_dvpp_deviceId); + aclrtSetCurrentContext(ctx); + while(!m_pktQueueptr->isEmpty()){ + int ret = sentFrame(vdecChannelDesc, frame_count); + if(ret == 2){ + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + sum++; + if(sum > 40){ + // 避免卡死 + break; + } + } + } + + sendVdecEos(vdecChannelDesc); + + CHECK_NOT_RETURN(aclvdecDestroyChannel(vdecChannelDesc), "aclvdecDestroyChannel failed"); + }while(0); + + CHECK_NOT_RETURN(aclvdecDestroyChannelDesc(vdecChannelDesc), "aclvdecDestroyChannelDesc failed"); + + // report_thread 需后于destroy退出 + m_bRunning = false; + m_bExitReportThd = true; + CHECK_NOT_RETURN(pthread_join(report_thread, nullptr), "pthread_join failed"); + + releaseResource(); + LOG_INFO("[{}]- decode thread exit.", m_dec_name); +} + +int DvppDec::sentFrame(aclvdecChannelDesc *vdecChannelDesc, uint64_t frame_count){ + + AVPacket * pkt = m_pktQueueptr->getHead(); + if(pkt == nullptr){ + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + return 1; + } + // 解码 + void *vdecInputbuf = m_vdecQueue.getTail(); + if(vdecInputbuf == nullptr){ + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + return 1; + } + + int ret = aclrtMemcpy(vdecInputbuf, pkt->size, pkt->data, pkt->size, ACL_MEMCPY_HOST_TO_DEVICE); + if(ACL_ERROR_NONE != ret){ + LOG_ERROR("[{}]- aclrtMemcpy failed", m_dec_name); + return 2; + } + + void *vdecOutputBuf = nullptr; + ret = acldvppMalloc((void **)&vdecOutputBuf, m_vdec_out_size); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- acldvppMalloc failed", m_dec_name); + return 2; + } + + acldvppStreamDesc *input_stream_desc = nullptr; + acldvppPicDesc *output_pic_desc = nullptr; + do{ + input_stream_desc = acldvppCreateStreamDesc(); + if (input_stream_desc == nullptr) { + LOG_ERROR("[{}]- acldvppCreateStreamDesc failed", m_dec_name); + break; + } + output_pic_desc = acldvppCreatePicDesc(); + if (output_pic_desc == nullptr) { + LOG_ERROR("[{}]- acldvppCreatePicDesc failed", m_dec_name); + break; + } + CHECK_AND_BREAK(acldvppSetStreamDescData(input_stream_desc, vdecInputbuf), "acldvppSetStreamDescData failed"); + CHECK_AND_BREAK(acldvppSetStreamDescSize(input_stream_desc, pkt->size), "acldvppSetStreamDescSize failed"); + CHECK_AND_BREAK(acldvppSetPicDescData(output_pic_desc, vdecOutputBuf), "acldvppSetPicDescData failed"); + CHECK_AND_BREAK(acldvppSetPicDescSize(output_pic_desc, m_vdec_out_size), "acldvppSetPicDescSize failed"); + + Vdec_CallBack_UserData *user_data = NULL; + user_data = new Vdec_CallBack_UserData; + user_data->frameId = frame_count; + // user_data->startTime = startTime; + user_data->sendTime = UtilTools::get_cur_time_ms(); + user_data->self = this; + ret = aclvdecSendFrame(vdecChannelDesc, input_stream_desc, output_pic_desc, nullptr, reinterpret_cast(user_data)); + av_packet_unref(pkt); + m_pktQueueptr->addHead(); + if(ret != ACL_ERROR_NONE){ + delete user_data; + user_data = nullptr; + LOG_ERROR("[{}]- aclvdecSendFrame failed", m_dec_name); + break; + } + + m_vdecQueue.addTail(); + + return 0; + }while (0); + + // 报错情形 + if(input_stream_desc){ + CHECK_NOT_RETURN(acldvppDestroyStreamDesc(input_stream_desc), "acldvppDestroyStreamDesc failed"); + } + if(output_pic_desc){ + CHECK_NOT_RETURN(acldvppDestroyPicDesc(output_pic_desc), "acldvppDestroyPicDesc failed"); + } + + acldvppFree(vdecOutputBuf); + vdecOutputBuf = nullptr; + + return 1; +} + + +void DvppDec::setPostDecArg(const void* postDecArg){ + m_postDecArg = postDecArg; +} + +void DvppDec::pause(){ + m_bPause = true; +} + +void DvppDec::resume(){ + m_bPause = false; +} \ No newline at end of file diff --git a/src/decoder/dvpp/DvppDec.h b/src/decoder/dvpp/DvppDec.h new file mode 100644 index 0000000..adc9dda --- /dev/null +++ b/src/decoder/dvpp/DvppDec.h @@ -0,0 +1,85 @@ +#include +#include + +#include "dvpp_headers.h" +#include "depend_headers.h" +#include "user_mem.h" +#include "CircularQueue.hpp" +#include "VpcPicConverter.h" +#include "FFReceiver.h" + +#include + +using namespace std; + +#define TEST_DECODER + +struct DvppDecConfig{ + string dec_name; + POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 + string dev_id; // gpu id + bool force_tcp{true}; // 是否指定使用tcp连接 + int skip_frame{1}; // 跳帧数 + int codec_id; // 0 : h264 1:h265 + int profile; + CircularQueue *pktQueueptr; + + int width; + int height; +}; + + +class DvppDec { +public: + DvppDec(); + ~DvppDec(); + bool init_vdpp(DvppDecConfig cfg); + void setPostDecArg(const void* postDecArg); + bool start(); + void close(); + void pause(); + void resume(); + +public: + void doProcessReport(); + void doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output); + +private: + void decode_thread(); + void releaseResource(); + bool sendVdecEos(aclvdecChannelDesc *vdecChannelDesc); + int sentFrame(aclvdecChannelDesc *vdecChannelDesc, uint64_t frame_count); + +private: + + bool m_bRunning{false}; + bool m_bPause{false}; + bool m_bExitReportThd{false}; + + int m_dvpp_deviceId {-1}; + int m_dvpp_channel {-1}; + aclrtContext m_context; + acldvppStreamFormat enType; + + pthread_t m_decode_thread; + + DvppDecConfig m_cfg; + string m_dec_name; + + vector m_vec_vdec; + CircularQueue m_vdecQueue; + CircularQueue *m_pktQueueptr; + + const void * m_postDecArg; + POST_DECODE_CALLBACK post_decoded_cbk; + + VpcPicConverter picConverter; + + int m_vdec_out_size {-1}; + +#ifdef TEST_DECODER + void *vdecHostAddr = nullptr; + int count_frame = 0; +#endif + +}; \ No newline at end of file diff --git a/src/decoder/dvpp/DvppDecoder.cpp b/src/decoder/dvpp/DvppDecoder.cpp new file mode 100644 index 0000000..45c4738 --- /dev/null +++ b/src/decoder/dvpp/DvppDecoder.cpp @@ -0,0 +1,137 @@ +#include "DvppDecoder.h" + +void receiver_finish_cbk(const void* userPtr){ + if(userPtr != nullptr){ + DvppDecoder* self = (DvppDecoder*)userPtr; + self->taskFinishing(); + } +} + +DvppDecoder::DvppDecoder(){ + m_pktQueueptr = new CircularQueue(); +} + +DvppDecoder::~DvppDecoder(){ + delete m_pktQueueptr; + m_pktQueueptr = nullptr; +} + +bool DvppDecoder::init(FFDecConfig cfg){ + + m_dec_name = cfg.dec_name; + + ReceiverConfig receiver_config; + receiver_config.uri = cfg.uri.c_str(); + receiver_config.dec_name = cfg.dec_name; + receiver_config.force_tcp = cfg.force_tcp; + receiver_config.pktQueueptr = m_pktQueueptr; + receiver_config.receiver_finished_cbk = receiver_finish_cbk; + AVCodecContext* avctx = m_receiver.init_FFmpeg(receiver_config); + if(avctx == nullptr){ + return false; + } + m_receiver.setFinishCbkArg(this); + + DvppDecConfig dec_cfg; + if(avctx->codec_id == AV_CODEC_ID_H264){ + dec_cfg.codec_id = 0; + }else if(avctx->codec_id == AV_CODEC_ID_HEVC){ + dec_cfg.codec_id = 1; + }else { + return false; + } + dec_cfg.dec_name = cfg.dec_name; + dec_cfg.post_decoded_cbk = cfg.post_decoded_cbk; + dec_cfg.dev_id = cfg.gpuid; + dec_cfg.force_tcp = cfg.force_tcp; + dec_cfg.skip_frame = cfg.skip_frame; + dec_cfg.profile = avctx->profile; + dec_cfg.pktQueueptr = m_pktQueueptr; + dec_cfg.width = avctx->width; + dec_cfg.height = avctx->height; + bool bRet = m_decoder.init_vdpp(dec_cfg); + if(!bRet){ + return false; + } + + m_cfg = cfg; + + decode_finished_cbk = cfg.decode_finished_cbk; + + m_bFinished = false; + + return true; +} + +bool DvppDecoder::isSurport(FFDecConfig& cfg){ + return true; +} + +bool DvppDecoder::start(){ + m_receiver.start(); + m_decoder.start(); + return true; +} + +void DvppDecoder::close(){ + m_receiver.close(); +} + +void DvppDecoder::setPostDecArg(const void* postDecArg){ + m_decoder.setPostDecArg(postDecArg); +} + +void DvppDecoder::setFinishedDecArg(const void* finishedDecArg){ + m_finishedDecArg = finishedDecArg; +} + +void DvppDecoder::pause(){ + m_receiver.pause(); +} + +void DvppDecoder::resume(){ + m_receiver.resume(); +} + +void DvppDecoder::setDecKeyframe(bool bKeyframe){ + m_receiver.setDecKeyframe(bKeyframe); +} + +bool DvppDecoder::isRunning(){ + return m_receiver.isRunning(); +} + +bool DvppDecoder::isFinished(){ + return m_bFinished; +} + +bool DvppDecoder::isPausing(){ + return m_receiver.isPausing(); +} + +bool DvppDecoder::getResolution(int &width, int &height){ + return m_receiver.getResolution(width, height); +} + +float DvppDecoder::fps(){ + return m_receiver.fps(); +} + +FFImgInfo* DvppDecoder::snapshot(){ + // TODO + return nullptr; +} + +int DvppDecoder::getCachedQueueLength(){ + return 0; +} + +void DvppDecoder::taskFinishing(){ + // receiver 中读取线程结束时执行 + m_decoder.close(); + decode_finished_cbk(m_finishedDecArg); + + m_bFinished = true; + + LOG_INFO("[{}]- task finished.", m_dec_name); +} \ No newline at end of file diff --git a/src/decoder/dvpp/DvppDecoder.h b/src/decoder/dvpp/DvppDecoder.h new file mode 100644 index 0000000..c6b32fd --- /dev/null +++ b/src/decoder/dvpp/DvppDecoder.h @@ -0,0 +1,62 @@ +#include + +#include "depend_headers.h" +#include "CircularQueue.hpp" +#include "FFReceiver.h" +#include "DvppDec.h" + +using namespace std; + +class DvppDecoder{ +public: + DvppDecoder(); + ~DvppDecoder(); + bool init(FFDecConfig cfg); + void close(); + bool start(); + void pause(); + void resume(); + + void setDecKeyframe(bool bKeyframe); + + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + + bool isSurport(FFDecConfig& cfg); + + float fps(); + + void setName(string nm){ + m_dec_name = nm; + } + + string getName(){ + return m_dec_name; + } + + FFImgInfo* snapshot(); + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); + + int getCachedQueueLength(); + +public: + void taskFinishing(); + +private: + FFDecConfig m_cfg; + string m_dec_name; + + CircularQueue *m_pktQueueptr; + FFReceiver m_receiver; + DvppDec m_decoder; + + const void * m_finishedDecArg; + DECODE_FINISHED_CALLBACK decode_finished_cbk; + + bool m_bFinished{false}; + +}; \ No newline at end of file diff --git a/src/decoder/dvpp/DvppDecoderApi.cpp b/src/decoder/dvpp/DvppDecoderApi.cpp new file mode 100644 index 0000000..44ed20e --- /dev/null +++ b/src/decoder/dvpp/DvppDecoderApi.cpp @@ -0,0 +1,133 @@ +#include "DvppDecoderApi.h" +#include "DvppDecoder.h" + +DvppDecoderApi::DvppDecoderApi(){ + m_pDecoder = nullptr; +} + +DvppDecoderApi::~DvppDecoderApi(){ + if(m_pDecoder != nullptr){ + delete m_pDecoder; + m_pDecoder = nullptr; + } +} + +bool DvppDecoderApi::init(FFDecConfig& cfg){ + m_pDecoder = new DvppDecoder(); + if(m_pDecoder != nullptr){ + return m_pDecoder->init(cfg); + } + return false; +} + +void DvppDecoderApi::close(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->close(); + } +} + +bool DvppDecoderApi::start(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->start(); + } + return false; +} + +void DvppDecoderApi::pause(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->pause(); + } +} + +void DvppDecoderApi::resume(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->resume(); + } +} + +void DvppDecoderApi::setDecKeyframe(bool bKeyframe){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setDecKeyframe(bKeyframe); + } +} + +bool DvppDecoderApi::isRunning(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isRunning(); + } + return false; +} + +bool DvppDecoderApi::isFinished(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isFinished(); + } + return false; +} + +bool DvppDecoderApi::isPausing(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isPausing(); + } + return false; +} + +bool DvppDecoderApi::getResolution(int &width, int &height){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getResolution(width, height); + } + return false; +} + +bool DvppDecoderApi::isSurport(FFDecConfig& cfg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->isSurport(cfg); + } + return false; +} + +float DvppDecoderApi::fps(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->fps(); + } + return 0.0; +} + +int DvppDecoderApi::getCachedQueueLength(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getCachedQueueLength(); + } + return 0; +} + +void DvppDecoderApi::setName(string nm){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setName(nm); + } +} + +string DvppDecoderApi::getName(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->getName(); + } + return nullptr; +} + +FFImgInfo* DvppDecoderApi::snapshot(){ + if(m_pDecoder != nullptr){ + return m_pDecoder->snapshot(); + } + return nullptr; +} + +void DvppDecoderApi::setPostDecArg(const void* postDecArg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setPostDecArg(postDecArg); + } +} + +void DvppDecoderApi::setFinishedDecArg(const void* finishedDecArg){ + if(m_pDecoder != nullptr){ + return m_pDecoder->setFinishedDecArg(finishedDecArg); + } +} \ No newline at end of file diff --git a/src/decoder/dvpp/DvppDecoderApi.h b/src/decoder/dvpp/DvppDecoderApi.h new file mode 100644 index 0000000..b020d75 --- /dev/null +++ b/src/decoder/dvpp/DvppDecoderApi.h @@ -0,0 +1,44 @@ +#include +#include + +#include "depend_headers.h" +#include "../interface/AbstractDecoder.h" + +using namespace std; + +class DvppDecoder; + +class DvppDecoderApi : public AbstractDecoder { +public: + DvppDecoderApi(); + ~DvppDecoderApi(); + bool init(FFDecConfig& cfg); + void close(); + bool start(); + void pause(); + void resume(); + + void setDecKeyframe(bool bKeyframe); + + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + + bool isSurport(FFDecConfig& cfg); + + int getCachedQueueLength(); + + float fps(); + + FFImgInfo* snapshot(); + + DECODER_TYPE getDecoderType(){ return DECODER_TYPE_DVPP; } + void setName(string nm); + string getName(); + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); +private: + DvppDecoder* m_pDecoder; +}; \ No newline at end of file diff --git a/src/decoder/dvpp/DvppSourceManager.cpp b/src/decoder/dvpp/DvppSourceManager.cpp new file mode 100644 index 0000000..c928e42 --- /dev/null +++ b/src/decoder/dvpp/DvppSourceManager.cpp @@ -0,0 +1,66 @@ +#include "DvppSourceManager.h" + +#include "dvpp_headers.h" +#include "depend_headers.h" + +using namespace std; + +DvppSourceManager::~DvppSourceManager() +{ + for(auto iter = ctxMap.begin(); iter != ctxMap.end(); iter++){ + aclError ret = aclrtDestroyContext(iter->second); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("aclrtDestroyContext failed !"); + continue; + } + } + ctxMap.clear(); + channelMap.clear(); + + // aclFinalize(); +} + +aclrtContext DvppSourceManager::getContext(int devId) +{ + aclrtContext ctx = ctxMap[devId]; + if (ctx == nullptr) + { + // 初始化硬件解码器 + aclError ret = aclrtSetDevice(devId); + if(ret != ACL_ERROR_NONE){ + // cout << "aclrtSetDevice failed" << endl; + LOG_ERROR("aclrtSetDevice failed !"); + return nullptr; + } + + ret = aclrtCreateContext(&ctx, devId); + if (ret != ACL_ERROR_NONE) { + // cout << "aclrtCreateContext failed " << endl; + LOG_ERROR("aclrtCreateContext failed !"); + return nullptr; + } + ctxMap[devId] = ctx; + } + return ctx; +} + +int DvppSourceManager::getChannel(int devId){ + // channel 最大值暂定为32, 华为没有接口获取最大channel,只有文档说明 + for(int iChannel = 0; iChannel < 32; iChannel++){ + string channelKey = "channel_" + to_string(devId) + "_" + to_string(iChannel) ; + auto it = channelMap.find(channelKey); + if(it == channelMap.end()){ + channelMap[channelKey] = iChannel; + return iChannel; + } + } + return -1; +} + +void DvppSourceManager::releaseChannel(int devId, int iChannel){ + string channelKey = "channel_" + to_string(devId) + "_" + to_string(iChannel) ; + auto it = channelMap.find(channelKey); + if(it != channelMap.end()){ + channelMap.erase(channelKey); + } +} \ No newline at end of file diff --git a/src/decoder/dvpp/DvppSourceManager.h b/src/decoder/dvpp/DvppSourceManager.h new file mode 100644 index 0000000..9efdbd3 --- /dev/null +++ b/src/decoder/dvpp/DvppSourceManager.h @@ -0,0 +1,36 @@ + +#include +#include + +#include "dvpp_headers.h" + +using namespace std; + +class DvppSourceManager{ +public: + static DvppSourceManager* getInstance(){ + static DvppSourceManager* singleton = nullptr; + if (singleton == nullptr){ + singleton = new DvppSourceManager(); + // int ret = aclInit(nullptr); + // if (ret != ACL_ERROR_NONE) { + // cout << "aclInit failed" << endl; + // return nullptr; + // } + } + return singleton; + } + + aclrtContext getContext(int devId); + + int getChannel(int devId); + void releaseChannel(int devId, int channel); + +private: + DvppSourceManager(){} + ~DvppSourceManager(); + +private: + map ctxMap; + map channelMap; +}; \ No newline at end of file diff --git a/src/decoder/dvpp/FFReceiver.cpp b/src/decoder/dvpp/FFReceiver.cpp new file mode 100644 index 0000000..26685a6 --- /dev/null +++ b/src/decoder/dvpp/FFReceiver.cpp @@ -0,0 +1,282 @@ +#include "FFReceiver.h" +#include + +const int g_pkt_size = 1024 * 1024; // 单个AVPacket大小的最大值 + +FFReceiver::FFReceiver(/* args */) +{ + fmt_ctx = nullptr; + m_bRunning = false; + + stream = nullptr; + stream_index = -1; + pix_fmt = AV_PIX_FMT_NONE; + m_dec_name = ""; + + m_bPause = false; + m_bReal = true; + + m_bFinished = false; + m_dec_keyframe = false; + m_fps = 0.0; + + m_read_thread = 0; +} + +FFReceiver::~FFReceiver() +{ + releaseFFmpeg(); + + // 这个只能放在析构函数中,因为会影响到解码类中的m_pktQueueptr队列 + // 所以应当确保在所有工作线程都退出后才释放 + for(int i = 0; i < m_vec_pkt.size(); i++){ + av_packet_free(&m_vec_pkt[i]); + } +} + +AVCodecContext* FFReceiver::init_FFmpeg(ReceiverConfig config){ + +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100) + av_register_all(); +#endif +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) + avcodec_register_all(); +#endif + + avformat_network_init(); + + const char* uri = config.uri; + fstream infile(uri); + if (infile.is_open()){ + m_bReal = false; + infile.close(); + }else { + m_bReal = true; + } + + m_dec_name = config.dec_name; + m_pktQueueptr = config.pktQueueptr; + receiver_finished_cbk = config.receiver_finished_cbk; + + // 打开输入视频文件 + AVDictionary *options = nullptr; + av_dict_set( &options, "bufsize", "655360", 0 ); + av_dict_set( &options, "rtsp_transport", config.force_tcp ? "tcp" : "udp", 0 ); + av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 + + fmt_ctx = avformat_alloc_context(); + const char* input_file = uri; + if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) { + LOG_ERROR("[{}]- Cannot open input file: {}", m_dec_name, input_file); + return nullptr; + } + av_dump_format(fmt_ctx, 0, input_file, 0); + + // 查找流信息 + if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) { + LOG_ERROR("[{}]- Cannot find input stream information!", m_dec_name); + return nullptr; + } + + // 查找视频流信息 + AVCodec *decoder = nullptr; + stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); + if (stream_index < 0) { + LOG_ERROR("[{}]- Cannot find a video stream in the input file!", m_dec_name); + return nullptr; + } + AVCodec *vcodec = avcodec_find_decoder(decoder->id); + + avctx = avcodec_alloc_context3(vcodec); + if(avctx == nullptr){ + LOG_ERROR("[{}]- alloc AVCodecContext failed!", m_dec_name); + return nullptr; + } + + do{ + // 得到视频流对象 + AVStream* stream = fmt_ctx->streams[stream_index]; + AVCodecParameters *codecpar = stream->codecpar; + if (avcodec_parameters_to_context(avctx, codecpar) < 0) + break; + + const AVBitStreamFilter * filter = nullptr; + if(codecpar->codec_id == AV_CODEC_ID_H264){ + filter = av_bsf_get_by_name("h264_mp4toannexb"); + }else if(codecpar->codec_id == AV_CODEC_ID_HEVC){ + filter = av_bsf_get_by_name("hevc_mp4toannexb"); + }else { + LOG_ERROR("[{}]- codec_id is not supported!", m_dec_name); + break; + } + + int ret = av_bsf_alloc(filter, &h264bsfc); + if (ret < 0){ + break; + } + + avcodec_parameters_copy(h264bsfc->par_in, codecpar); + av_bsf_init(h264bsfc); + + frame_width = codecpar->width; + frame_height = codecpar->height; + pix_fmt = (AVPixelFormat)codecpar->format; + m_fps = av_q2d(stream ->avg_frame_rate); + + LOG_INFO("[{}]- init ffmpeg success! input:{} frame_width:{} frame_height:{} fps:{} ", m_dec_name, input_file, frame_width, frame_height, m_fps); + + for(int i = 0; i<5; i++){ + AVPacket* pkt = av_packet_alloc(); + av_init_packet( pkt ); + m_vec_pkt.push_back(pkt); + } + m_pktQueueptr->init(m_vec_pkt); + + return avctx; + }while(0); + + LOG_ERROR("[{}]- init ffmpeg failed ! input:{} ", m_dec_name); + + return nullptr; +} + +void FFReceiver::releaseFFmpeg(){ + m_dec_keyframe = false; + if(h264bsfc){ + av_bsf_free(&h264bsfc); + h264bsfc = nullptr; + } + if (fmt_ctx){ + avformat_close_input(&fmt_ctx); + fmt_ctx = nullptr; + } + if(avctx){ + avcodec_free_context(&avctx); + avctx = nullptr; + } +} + +void FFReceiver::read_thread(){ + + int frame_count = 0; + int ret = -1; + while (m_bRunning) + { + if (!m_bReal) + { + if (m_bPause) + { + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + continue; + } + } + + AVPacket* pkt = m_pktQueueptr->getTail(); + if(pkt == nullptr){ + std::this_thread::sleep_for(std::chrono::milliseconds(3)); + continue; + } + + int result = av_read_frame(fmt_ctx, pkt); + if (result == AVERROR_EOF || result < 0) + { + LOG_ERROR("[{}]- Failed to read frame!", m_dec_name); + break; + } + + if (m_dec_keyframe && !(pkt->flags & AV_PKT_FLAG_KEY)) { + av_packet_unref(pkt); + continue; + } + + if (stream_index == pkt->stream_index){ + + ret = av_bsf_send_packet(h264bsfc, pkt); + if(ret < 0) { + LOG_ERROR("[{}]- av_bsf_send_packet error!", m_dec_name); + } + + while ((ret = av_bsf_receive_packet(h264bsfc, pkt)) == 0) { + if(pkt->size > g_pkt_size){ + LOG_ERROR("[{}]- pkt size 大于最大预设值!", m_dec_name); + break; + } + + if(!m_bRunning){ + break; + } + + m_pktQueueptr->addTail(); + + frame_count++; + } + } + } + + LOG_INFO("[{}]- read thread exit.", m_dec_name); + m_bFinished = true; + + receiver_finished_cbk(m_finishedReceiveArg); +} + +bool FFReceiver::start(){ + m_bRunning = true; + + pthread_create(&m_read_thread,0, + [](void* arg) + { + FFReceiver* a=(FFReceiver*)arg; + a->read_thread(); + return (void*)0; + } + ,this); + + return true; +} + +void FFReceiver::close(){ + m_bRunning=false; + + if(m_read_thread != 0){ + pthread_join(m_read_thread,0); + } +} + +float FFReceiver::fps(){ + return m_fps; +} + +bool FFReceiver::getResolution( int &width, int &height ){ + width = frame_width; + height = frame_height; + return true; +} + +void FFReceiver::pause(){ + m_bPause = true; +} + +void FFReceiver::resume(){ + m_bPause = false; +} + +void FFReceiver::setDecKeyframe(bool bKeyframe) +{ + m_dec_keyframe = bKeyframe; +} + +bool FFReceiver::isRunning(){ + return m_bRunning; +} + +bool FFReceiver::isFinished(){ + return m_bFinished; +} + +bool FFReceiver::isPausing(){ + return m_bPause; +} + +void FFReceiver::setFinishCbkArg(const void* userPtr){ + m_finishedReceiveArg = userPtr; +} \ No newline at end of file diff --git a/src/decoder/dvpp/FFReceiver.h b/src/decoder/dvpp/FFReceiver.h new file mode 100644 index 0000000..a380628 --- /dev/null +++ b/src/decoder/dvpp/FFReceiver.h @@ -0,0 +1,81 @@ +#ifndef __FFRECEIVER_H__ +#define __FFRECEIVER_H__ + +#include "depend_headers.h" +#include "CircularQueue.hpp" + +typedef void(*RECEIVER_FINISHED_CALLBACK)(const void* userPtr); + +struct ReceiverConfig{ + const char* uri; + string dec_name; + bool force_tcp; + CircularQueue *pktQueueptr; + RECEIVER_FINISHED_CALLBACK receiver_finished_cbk; // 解码线程结束后的回调接口 +}; + +class FFReceiver +{ +public: + FFReceiver(/* args */); + ~FFReceiver(); + + AVCodecContext* init_FFmpeg(ReceiverConfig config); + void releaseFFmpeg(); + void close(); + bool start(); + + void pause(); + void resume(); + void setDecKeyframe(bool bKeyframe); + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + float fps(); + + void setName(string nm){ + m_dec_name = nm; + } + + void setFinishCbkArg(const void* userPtr); + +private: + void read_thread(); + +private: + string m_dec_name; + + AVStream* stream; + int stream_index; + AVFormatContext *fmt_ctx; + AVPixelFormat pix_fmt; + int frame_width{0}; + int frame_height{0}; + + pthread_t m_read_thread; + + bool m_bRunning; + bool m_bFinished; + + bool m_bPause; + + bool m_bReal; // 是否实时流 + + float m_fps; + + FFDecConfig m_cfg; + bool m_dec_keyframe; + + AVCodecContext *avctx{nullptr}; + AVBSFContext * h264bsfc{nullptr}; + + vector m_vec_pkt; + CircularQueue *m_pktQueueptr; + + const void * m_finishedReceiveArg; + RECEIVER_FINISHED_CALLBACK receiver_finished_cbk; +}; + + +#endif \ No newline at end of file diff --git a/src/decoder/dvpp/Makefile b/src/decoder/dvpp/Makefile new file mode 100644 index 0000000..8bca911 --- /dev/null +++ b/src/decoder/dvpp/Makefile @@ -0,0 +1,66 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +DEFS = -DENABLE_DVPP_INTERFACE + +# 最终目标文件 +TARGET:=$(LIB_DIR)/$(MODULE).a + +export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/runtime/lib64:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/6.3.RC1.alpha001/lib64:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBRARY_PATH + +include_dir=-I/usr/local/Ascend/ascend-toolkit/latest/acllib/include +lib_dir=-L/usr/lib -L/usr/local/lib -L/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64 -L/usr/local/Ascend/driver/lib64 -L/usr/local/Ascend/ascend-toolkit/latest/atc/lib64 +lib=-lacl_dvpp -lascendcl -lmmpa -lglog -lgflags -lpthread -lz + +CXXFLAGS= -g -O0 -fPIC $(include_dir) $(INCS) $(LIBS) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl + # -DUNICODE -D_UNICODE + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET):$(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @ar -rc $@ $^ + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(LDFLAGS) $(lib_dir) $(lib) $(MACROS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/decoder/dvpp/VpcPicConverter.cpp b/src/decoder/dvpp/VpcPicConverter.cpp new file mode 100644 index 0000000..136506a --- /dev/null +++ b/src/decoder/dvpp/VpcPicConverter.cpp @@ -0,0 +1,79 @@ +#include "VpcPicConverter.h" +#include "depend_headers.h" + +#define ALIGN_UP(val, align) (((val) % (align) == 0) ? (val) : (((val) / (align) + 1) * (align))) + +VpcPicConverter::VpcPicConverter(){ + +} + +VpcPicConverter::~VpcPicConverter(){ + if(nullptr == stream_){ + aclrtDestroyStream(stream_); + } +} + +int VpcPicConverter::init(aclrtContext context, string dec_name){ + + m_dec_name = dec_name; + + CHECK_AND_RETURN(aclrtSetCurrentContext(context), "aclrtSetCurrentContext failed"); + CHECK_AND_RETURN(aclrtCreateStream(&stream_), "aclrtCreateStream failed! "); + + dvppChannelDesc_ = acldvppCreateChannelDesc(); + + int ret = ACL_ERROR_NONE; + do + { + ret = acldvppCreateChannel(dvppChannelDesc_); + CHECK_AND_BREAK(ret, "acldvppCreateChannel failed !"); + + ret = acldvppSetChannelDescMode(dvppChannelDesc_, DVPP_CHNMODE_VPC); + CHECK_AND_BREAK(ret, "acldvppSetChannelDescMode failed !"); + } while (0); + + return ret; +} + +DvppDataMemory* VpcPicConverter::convert2bgr(acldvppPicDesc *inputDesc_, int out_width, int out_height, bool key_frame){ + + int out_buf_width = ALIGN_UP(out_width, 16) * 3; + int out_buf_height = ALIGN_UP(out_height, 2); + int out_buf_size = out_buf_width * out_buf_height; + + DvppDataMemory* rgbMem = new DvppDataMemory(3, out_buf_width, out_buf_width, out_buf_height, out_buf_height, out_buf_size, "", to_string(m_devId), key_frame); + void *outBufferDev_ = (void*)rgbMem->getMem(); + + acldvppPicDesc *outputDesc_= acldvppCreatePicDesc(); + acldvppSetPicDescData(outputDesc_, outBufferDev_); + acldvppSetPicDescFormat(outputDesc_, PIXEL_FORMAT_BGR_888); + acldvppSetPicDescWidth(outputDesc_, out_width); + acldvppSetPicDescHeight(outputDesc_, out_height); + acldvppSetPicDescWidthStride(outputDesc_, out_buf_width); + acldvppSetPicDescHeightStride(outputDesc_, out_buf_height); + acldvppSetPicDescSize(outputDesc_, out_buf_size); + + aclError ret = ACL_ERROR_NONE; + do{ + // 9. 执行异步色域转换,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 + ret = acldvppVpcConvertColorAsync(dvppChannelDesc_, inputDesc_, outputDesc_, stream_); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("acldvppVpcConvertColorAsync failed - out_width:{} out_height:{} out_buf_width:{} out_buf_height:{} out_buf_size:{}", out_width, out_height, out_buf_width, out_buf_height, out_buf_size); + break; + } + ret = aclrtSynchronizeStream(stream_); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("aclrtSynchronizeStream failed - out_width:{} out_height:{} out_buf_width:{} out_buf_height:{} out_buf_size:{}", out_width, out_height, out_buf_width, out_buf_height, out_buf_size); + break; + } + }while(0); + + acldvppDestroyPicDesc(outputDesc_); + + if(ret != ACL_ERROR_NONE){ + delete rgbMem; + rgbMem = nullptr; + } + + return rgbMem; +} \ No newline at end of file diff --git a/src/decoder/dvpp/VpcPicConverter.h b/src/decoder/dvpp/VpcPicConverter.h new file mode 100644 index 0000000..1973949 --- /dev/null +++ b/src/decoder/dvpp/VpcPicConverter.h @@ -0,0 +1,20 @@ +#include "dvpp_headers.h" +#include "depend_headers.h" +#include "DvppDataMemory.hpp" + + +class VpcPicConverter{ +public: + VpcPicConverter(); + ~VpcPicConverter(); + int init(aclrtContext context, string dec_name); + + DvppDataMemory* convert2bgr(acldvppPicDesc *input, int out_width, int out_height, bool key_frame); + +private: + aclrtContext context_; + aclrtStream stream_; + int m_devId; + acldvppChannelDesc *dvppChannelDesc_ ; + string m_dec_name; +}; \ No newline at end of file diff --git a/src/decoder/dvpp/depend_headers.h b/src/decoder/dvpp/depend_headers.h new file mode 100644 index 0000000..84b2bc7 --- /dev/null +++ b/src/decoder/dvpp/depend_headers.h @@ -0,0 +1,38 @@ +#ifndef __DEPEND_HEADERS_H__ +#define __DEPEND_HEADERS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +* 依赖模块外部的代码或库 +* 不要在此处添加模块内部的头文件 +*/ + +// ffmpeg 是c库 所以编译的时候要加入从 extern导入的C 来声明否则连接失败 +extern "C" { + #include "libavutil/imgutils.h" + #include "libavutil/samplefmt.h" + #include "libavformat/avformat.h" + #include "libavcodec/avcodec.h" +} + + +#include "../interface/logger.hpp" +#include "../interface/DeviceMemory.hpp" +#include "../interface/interface_headers.h" +#include "../interface/utiltools.hpp" + +#endif \ No newline at end of file diff --git a/src/decoder/dvpp/dvpp_headers.h b/src/decoder/dvpp/dvpp_headers.h new file mode 100644 index 0000000..3d981af --- /dev/null +++ b/src/decoder/dvpp/dvpp_headers.h @@ -0,0 +1,40 @@ +/* +* 模块内部的头文件请在此处添加 +*/ + +#ifndef __DVPP_HEADERS_H__ +#define __DVPP_HEADERS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acl/acl_mdl.h" +#include "acl/acl_base.h" +#include "acl/acl_rt.h" +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" + + +#define CHECK_AND_RETURN(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); return ret;} +#define CHECK_NOT_RETURN(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message);} +#define CHECK_AND_RETURN_NOVALUE(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); return;} +#define CHECK_AND_BREAK(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); break;} + +#endif + diff --git a/src/decoder/dvpp/threadsafe_queue.h b/src/decoder/dvpp/threadsafe_queue.h new file mode 100644 index 0000000..5a5b0f9 --- /dev/null +++ b/src/decoder/dvpp/threadsafe_queue.h @@ -0,0 +1,128 @@ + +#ifndef __THREADSAFE_QUEUE_H__ +#define __THREADSAFE_QUEUE_H__ + +#include +#include +#include +#include + +#include +using std::queue; +using namespace std; + +template +class ThreadedQueue : public queue { +public: + ThreadedQueue(); + ~ThreadedQueue(); + bool empty() const; + size_t size() const; + void push(const T& val); + void push(T& val); + bool pop(); + T& front(); + const T& front() const; + T& back(); + const T& back() const; + + void Put(T &data); + + T Take(); + void Get(T &data); + bool GetEmpty(); + + condition_variable *condition; + mutex *lock; +}; + +template +ThreadedQueue::ThreadedQueue() { + lock = new mutex; + condition = new condition_variable; +} + +template +ThreadedQueue::~ThreadedQueue() { + if(condition != nullptr){ + delete condition; + condition = nullptr; + } + if(lock != nullptr){ + delete lock; + lock = nullptr; + } +} + +template +T ThreadedQueue:: Take() +{ + std::unique_lock lk(this->lock); + this->condition->wait(lk, [this]{return !this->empty();}); + T val = this->front(); + this->pop(); + return val; +} + +template +void ThreadedQueue:: Put(T &data) +{ + std::unique_lock lk(*lock); + this->push(data); + this->condition->notify_one(); + return; +} + +template +void ThreadedQueue:: Get(T &data) +{ + std::unique_lock lk(*lock); + this->condition->wait(lk, [this]{return !this->empty();}); + data = this->front(); + this->pop(); +} + +template +bool ThreadedQueue::GetEmpty() +{ + std::unique_lock lk(*lock); + this->condition->wait(lk, [this]{return !this->empty();}); + return true; +} + + +template +bool ThreadedQueue::empty() const { + bool result = queue::empty(); + return result; +} + +template +size_t ThreadedQueue::size() const { + size_t result = queue::size(); + return result; +} + +template +void ThreadedQueue::push(T& val) { + queue::push(val); +} + + +template +T& ThreadedQueue::front() { + T& result = queue::front(); + return result; +} + +template +bool ThreadedQueue::pop() { + bool result = false; + if(!queue::empty()) { + queue::pop(); + result = true; + } + return result; +} + +#endif diff --git a/src/decoder/dvpp/user_mem.h b/src/decoder/dvpp/user_mem.h new file mode 100644 index 0000000..e6a7d11 --- /dev/null +++ b/src/decoder/dvpp/user_mem.h @@ -0,0 +1,33 @@ +#ifndef __USER_MEM_H__ +#define __USER_MEM_H__ + +#include +#include +#include +#include +#include "threadsafe_queue.h" + +#define ALIGN_MEM(val, align) (((val) % (align) == 0) ? (val) : (((val) / (align) + 1) * (align))) + +using namespace std; + +typedef enum { + RTSP_MEM, + VDEC_MEM, +} MemType; + +class MemNode{ +public: + uint8_t *bufAddr; + MemType memType; + + MemNode(){ + std::cout << "构造" << endl; + } + + ~MemNode(){ + std::cout << "析构" << std::endl; + } +} ; + +#endif \ No newline at end of file diff --git a/src/decoder/interface/AbstractDecoder.cpp b/src/decoder/interface/AbstractDecoder.cpp new file mode 100644 index 0000000..244dd45 --- /dev/null +++ b/src/decoder/interface/AbstractDecoder.cpp @@ -0,0 +1,25 @@ +#include "AbstractDecoder.h" + +#include "logger.hpp" +#include "utiltools.hpp" + + +bool AbstractDecoder::isSnapTime(){ + if(m_snap_time_interval <= 0){ + return false; + } + long cur_time = UtilTools::get_cur_time_ms(); + if(cur_time - m_last_snap_time > m_snap_time_interval){ + return true; + } + return false; +} + +void AbstractDecoder::updateLastSnapTime(){ + m_last_snap_time = UtilTools::get_cur_time_ms(); +} + +void AbstractDecoder::setSnapTimeInterval(long interval){ + m_snap_time_interval = interval; + m_last_snap_time = UtilTools::get_cur_time_ms(); +} \ No newline at end of file diff --git a/src/decoder/interface/AbstractDecoder.h b/src/decoder/interface/AbstractDecoder.h new file mode 100644 index 0000000..9f4cb3f --- /dev/null +++ b/src/decoder/interface/AbstractDecoder.h @@ -0,0 +1,54 @@ +#ifndef _ABSTRACT_DECODER_H_ +#define _ABSTRACT_DECODER_H_ + +#include "interface_headers.h" + +using namespace std; + +class AbstractDecoder{ +public: + virtual ~AbstractDecoder(){}; + virtual bool init(FFDecConfig& cfg) = 0; + virtual void close() = 0; + virtual bool start() = 0; + virtual void pause() = 0; + virtual void resume() = 0; + + virtual void setDecKeyframe(bool bKeyframe) = 0; + + virtual bool isRunning() = 0; + virtual bool isFinished() = 0; + virtual bool isPausing() = 0; + virtual bool getResolution( int &width, int &height ) = 0; + + virtual bool isSurport(FFDecConfig& cfg) = 0; + + virtual int getCachedQueueLength() = 0; + + virtual float fps() = 0; + + virtual DECODER_TYPE getDecoderType() = 0; + + virtual FFImgInfo* snapshot() = 0; + + virtual void setName(string nm) = 0; + + virtual string getName() = 0; + + virtual void setPostDecArg(const void* postDecArg) = 0; + virtual void setFinishedDecArg(const void* finishedDecArg) = 0; + +public: + bool isSnapTime(); + + void updateLastSnapTime(); + + void setSnapTimeInterval(long interval); + +public: + long m_snap_time_interval{-1}; + long m_last_snap_time; + long m_index{0}; +}; + +#endif // _ABSTRACT_DECODER_H_ \ No newline at end of file diff --git a/src/decoder/interface/DecoderManager.cpp b/src/decoder/interface/DecoderManager.cpp new file mode 100644 index 0000000..396bf94 --- /dev/null +++ b/src/decoder/interface/DecoderManager.cpp @@ -0,0 +1,494 @@ +#include "DecoderManager.h" + +#ifdef USE_NVDEC +#include "../nvdec/FFNvDecoder.h" +#include "../gb28181/FFGB28181Decoder.h" +#endif + +#ifdef USE_DVPP +#include "../dvpp/DvppDecoderApi.h" +#endif + +#include "logger.hpp" + +using namespace std; + + +AbstractDecoder* DecoderManager::createDecoder(MgrDecConfig config){ + + closeAllFinishedDecoder(); + + if (config.cfg.post_decoded_cbk == nullptr || config.cfg.decode_finished_cbk== nullptr){ + return nullptr; + } + + std::lock_guard l(m_mutex); + + auto it = decoderMap.find(config.name); + if (it != decoderMap.end()){ + LOG_ERROR("已存在name为{}的解码器", config.name); + return nullptr; + } + + AbstractDecoder* dec = nullptr; +#ifdef USE_NVDEC + if(DECODER_TYPE_FFMPEG == config.dec_type){ + dec = new FFNvDecoder(); + } + + if(DECODER_TYPE_GB28181 == config.dec_type){ + dec = new FFGB28181Decoder(); + } +#endif + +#ifdef USE_DVPP + if(DECODER_TYPE_DVPP == config.dec_type){ + dec = new DvppDecoderApi(); + } +#endif + + if (dec == nullptr){ + LOG_ERROR("没有指定解码器类型"); + return nullptr; + } + + config.cfg.dec_name = config.name; + bool bRet= dec->init(config.cfg); + if (bRet) + { + decoderMap[config.name] = dec; + + LOG_INFO("[{}][{}]- 解码器初始化成功",config.name, config.cfg.uri); + return dec; + } + + // 创建失败,关闭解码器 + dec->close(); + delete dec; + + LOG_ERROR("[{}][{}]- 解码器初始化失败!",config.name, config.cfg.uri); + return nullptr; +} + +bool DecoderManager::setPostDecArg(const string name, const void * userPtr) +{ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + dec->second->setPostDecArg(userPtr); + return true; + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +bool DecoderManager::setFinishedDecArg(const string name, const void * userPtr) +{ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + dec->second->setFinishedDecArg(userPtr); + return true; + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +AbstractDecoder* DecoderManager::getDecoderByName(const string name) +{ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return nullptr; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + return dec->second; + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return nullptr; +} + +bool DecoderManager::startDecode(AbstractDecoder* dec){ + if (dec != nullptr && !dec->isRunning()) + { + return dec->start(); + } + return false; +} + +bool DecoderManager::startDecodeByName(const string name){ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + return dec->second->start(); + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +void DecoderManager::startAllDecode(){ + + std::lock_guard l(m_mutex); + + for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ + if (!iter->second->isRunning()) + { + iter->second->start(); + } + } +} + +bool DecoderManager::closeDecoderByName(const string name){ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + dec->second->close(); + delete dec->second; + dec->second = nullptr; + decoderMap.erase(dec); + + return true; + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +void DecoderManager::closeAllDecoder() +{ + std::lock_guard l(m_mutex); + + for(auto iter = decoderMap.begin(); iter != decoderMap.end(); iter++){ + iter->second->close(); + delete iter->second; + iter->second = nullptr; + } + decoderMap.clear(); +} + +void DecoderManager::closeAllFinishedDecoder() +{ + std::lock_guard l(m_mutex); + + for(auto iter = decoderMap.begin(); iter != decoderMap.end(); ){ + if (iter->second->isFinished()) + { + delete iter->second; + iter->second = nullptr; + iter = decoderMap.erase(iter); + } + else + { + iter++ ; + } + } +} + +int DecoderManager::count() +{ + closeAllFinishedDecoder(); + + std::lock_guard l(m_mutex); + return decoderMap.size(); +} + +bool DecoderManager::pauseDecoder(const string name) +{ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + dec->second->pause(); + return true; + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +bool DecoderManager::resumeDecoder(const string name) +{ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + dec->second->resume(); + return true; + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +bool DecoderManager::isSurport(MgrDecConfig& config) +{ + { + std::lock_guard l(m_mutex); + + auto it = decoderMap.find(config.name); + if (it != decoderMap.end()){ + LOG_ERROR("已存在name所标记的解码器"); + return false; + } + } + + AbstractDecoder* dec = nullptr; +#ifdef USE_NVDEC + if(DECODER_TYPE_FFMPEG == config.dec_type){ + dec = new FFNvDecoder(); + } + + if(DECODER_TYPE_GB28181 == config.dec_type){ + dec = new FFGB28181Decoder(); + } +#endif + +#ifdef USE_DVPP + if(DECODER_TYPE_DVPP == config.dec_type){ + dec = new DvppDecoderApi(); + } +#endif + + if (dec == nullptr){ + LOG_ERROR("没有指定解码器类型"); + return false; + } + + bool bRet = dec->isSurport(config.cfg); + delete dec; + dec = nullptr; + + return bRet; +} + +bool DecoderManager::isRunning(const string name){ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + return dec->second->isRunning(); + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +bool DecoderManager::isFinished(const string name){ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + return dec->second->isFinished(); + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +bool DecoderManager::isPausing(const string name){ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + return dec->second->isPausing(); + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +bool DecoderManager::setDecKeyframe(const string name, bool bKeyframe) +{ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + dec->second->setDecKeyframe(bKeyframe); + return true; + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +bool DecoderManager::getResolution(const string name, int &width, int &height) +{ + if (name.empty()) + { + LOG_ERROR("name 为空!"); + return false; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()) + { + dec->second->getResolution(width, height); + return true; + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return false; +} + +vector DecoderManager::getAllDecodeName(){ + + closeAllFinishedDecoder(); + + std::lock_guard l(m_mutex); + + vector decode_names; + for(auto it = decoderMap.begin(); it != decoderMap.end(); ++it){ + decode_names.push_back(it->first); + } + return decode_names; +} + +int DecoderManager::getCachedQueueLength(const string name){ + if (name.empty()){ + LOG_ERROR("name 为空!"); + return -1; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()){ + return dec->second->getCachedQueueLength(); + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return -1; +} + +void DecoderManager::releaseFFImgInfo(FFImgInfo* info){ + if(nullptr != info){ + if(info->pData != nullptr){ + free(info->pData); + info->pData = nullptr; + } + delete info; + info = nullptr; + } +} + +FFImgInfo* DecoderManager::snapshot_in_task(const string name){ + if (name.empty()){ + LOG_ERROR("name 为空!"); + return nullptr; + } + + std::lock_guard l(m_mutex); + + auto dec = decoderMap.find(name); + if (dec != decoderMap.end()){ + return dec->second->snapshot(); + } + + LOG_ERROR("没有找到name为{}的解码器",name); + return nullptr; +} + +vector DecoderManager::timing_snapshot_all(){ + + closeAllFinishedDecoder(); + + std::lock_guard l(m_mutex); + + vector vec; + for(auto it = decoderMap.begin(); it != decoderMap.end(); ++it){ + if(it->second->isSnapTime()){ + FFImgInfo* imginfo = it->second->snapshot(); + if(imginfo != nullptr){ + vec.push_back(imginfo); + } + it->second->updateLastSnapTime(); + } + } + + return vec; +} \ No newline at end of file diff --git a/src/decoder/interface/DecoderManager.h b/src/decoder/interface/DecoderManager.h new file mode 100644 index 0000000..3cb82e6 --- /dev/null +++ b/src/decoder/interface/DecoderManager.h @@ -0,0 +1,261 @@ +#include "AbstractDecoder.h" +#include +#include +#include + +#include + +using namespace std; + +struct MgrDecConfig +{ + DECODER_TYPE dec_type; // 解码器类型 + FFDecConfig cfg; // 解码器配置 + string name{""}; // 解码器名称 +}; + +// #define USE_NVDEC +#define USE_DVPP +/** + * 解码器管理类,单例类 + * 谨防死锁 + **/ +class DecoderManager { +public: + /************************************************** + * 接口:getInstance + * 功能:获取解码器管理者实例 + * 参数:无 + * 返回:成功返回 解码器管理者实例, 失败返回 nullptr + * 备注:调用其他接口前,需要先调用该接口获取管理者实例 + **************************************************/ + static DecoderManager* getInstance(){ + static DecoderManager* singleton = nullptr; + if (singleton == nullptr){ + singleton = new DecoderManager(); + } + return singleton; + } + + ~DecoderManager() + { + closeAllDecoder(); + } + + /************************************************** + * 接口:createDecoder + * 功能:根据配置信息创建解码器 + * 参数:MgrDecConfig& config 解码器配置信息 + * 返回:成功返回解码器, 失败返回 nullptr + * 备注: + **************************************************/ + AbstractDecoder* createDecoder(MgrDecConfig config); + + /************************************************** + * 接口:setPostDecArg + * 功能:设置解码数据回调接口的用户自定义参数 + * 参数:string name 解码器名称 + * const void * userPtr 用户自定义的要传到解码数据回调接口的数据 + * 返回:设置成功返回true,失败返回false + * 备注: + **************************************************/ + bool setPostDecArg(const string name, const void * userPtr); + + /************************************************** + * 接口:setFinishedDecArg + * 功能:设置解码结束回调接口的用户自定义参数 + * 参数:string name 解码器名称 + * const void * userPtr 用户自定义的要传到解码数据回调接口的数据 + * 返回:设置成功返回true,失败返回false + * 备注: + **************************************************/ + bool setFinishedDecArg(const string name, const void * userPtr); + + /************************************************** + * 接口:getDecoderByName + * 功能:根据解码器名称返回解码器对象指针 + * 参数:const string name 解码器名称 + * 返回:成功返回对应的解码器对象的指针,失败返回nullptr + * 备注: + **************************************************/ + AbstractDecoder* getDecoderByName(const string name); + + /************************************************** + * 接口:startDecode + * 功能:启动解码 + * 参数:FFNvDecoder* 解码器指针 + * 返回:void + * 备注: + **************************************************/ + bool startDecode(AbstractDecoder*); + + /************************************************** + * 接口:startAllDecode + * 功能:启动全部解码 + * 参数:void + * 返回:void + * 备注: + **************************************************/ + void startAllDecode(); + + /************************************************** + * 接口:startDecodeByName + * 功能:启动名称对应的解码器 + * 参数:string name 解码器名称 + * 返回:成功返回true,失败返回false + * 备注: + **************************************************/ + bool startDecodeByName(const string name); + + /************************************************** + * 接口:closeDecoderByName + * 功能:关闭解码器名称对应的解码 + * 参数:const string name 解码器名称 + * 返回:成功返回true,失败返回false + * 备注: + **************************************************/ + bool closeDecoderByName(const string name); + + /************************************************** + * 接口:closeAllDecoder + * 功能:关闭全部解码器 + * 参数:void + * 返回:void + * 备注: + **************************************************/ + void closeAllDecoder(); + + /************************************************** + * 接口:closeAllDecoderByGpuid + * 功能:关闭某张显卡撒花姑娘的全部解码器 + * 参数:const string gpuid gpu的id + * 返回:void + * 备注: + **************************************************/ + void closeAllDecoderByGpuid(const string gpuid); + + /************************************************** + * 接口:pauseDecoder + * 功能:暂停指定名称的解码器 + * 参数:const string name 解码器名称 + * 返回:成功返回true,失败返回false + * 备注: + **************************************************/ + bool pauseDecoder(const string name); + + /************************************************** + * 接口:pauseDecoder + * 功能:恢复指定名称的解码器 + * 参数:const string name 解码器名称 + * 返回:成功返回true,失败返回false + * 备注: + **************************************************/ + bool resumeDecoder(const string name); + + /************************************************** + * 接口:isSurport + * 功能:是否支持指定配置的解码 + * 参数:FFDecConfig& cfg 解码器配置 + * 返回:支持返回true,不支持返回false + * 备注: + **************************************************/ + bool isSurport(MgrDecConfig& config); + + /************************************************** + * 接口:isRunning + * 功能:根据解码器名称判断解码器是否正在运行 + * 参数:const string name 解码器名称 + * 返回:正在运行返回true,否则返回false + * 备注: + **************************************************/ + bool isRunning(const string name); + + /************************************************** + * 接口:isFinished + * 功能:根据解码器名称判断解码器是否已经结束 + * 参数:const string name 解码器名称 + * 返回:正在运行返回true,否则返回false + * 备注: + **************************************************/ + bool isFinished(const string name); + + /************************************************** + * 接口:isPausing + * 功能:根据解码器名称判断解码器是否暂停 + * 参数:const string name 解码器名称 + * 返回:正在运行返回true,否则返回false + * 备注: + **************************************************/ + bool isPausing(const string name); + + /************************************************** + * 接口:count + * 功能:获取正在运行的解码器数量 + * 参数:void + * 返回:正在运行的解码器数量 + * 备注: + **************************************************/ + int count(); + + /************************************************** + * 接口:setDecKeyframe + * 功能:设置是否只解码关键帧。默认全解 + * 参数:const string name 解码器名称 + * bool bKeyframe 是否只解码关键帧。true,只解码关键帧;false,普通的全解码 + * 返回:bool 成功返回true,失败返回false + * 备注: + **************************************************/ + bool setDecKeyframe(const string name, bool bKeyframe); + + /************************************************** + * 接口:getResolution + * 功能:获取视频分辨率 + * 参数:const string name 解码器名称 + * int &width 从 width 返回视频宽度 + * int &height 从 height 返回视频高度 + * 返回:bool 成功获取返回true,失败返回false + * 备注: + **************************************************/ + bool getResolution(const string name, int &width, int &height); + + /************************************************** + * 接口:getAllDecodeName + * 功能:获取全部解码器名称 + * 参数:void + * 返回:vector 返回全部解码器名称 + * 备注: + **************************************************/ + vector getAllDecodeName(); + + /************************************************** + * 接口:getCachedQueueLength + * 功能:获取解码缓冲队列当前长度 + * 参数:const string name 解码器名称 + * 返回:int 解码缓冲队列当前长度 + * 备注: + **************************************************/ + int getCachedQueueLength(const string name); + + /************************************************** + * 接口:releaseFFImgInfo + * 功能:释放视频快照信息 + * 参数:FFImgInfo* info 视频快照信息 + * 返回:void + * 备注: + **************************************************/ + void releaseFFImgInfo(FFImgInfo* info); + + FFImgInfo* snapshot_in_task(const string name); + + vector timing_snapshot_all(); + +private: + DecoderManager(){} + + void closeAllFinishedDecoder(); + +private: + map decoderMap; + + mutex m_mutex; +}; \ No newline at end of file diff --git a/src/decoder/interface/DeviceMemory.hpp b/src/decoder/interface/DeviceMemory.hpp new file mode 100644 index 0000000..5404af4 --- /dev/null +++ b/src/decoder/interface/DeviceMemory.hpp @@ -0,0 +1,98 @@ +#ifndef __DEVICE_RGB_MEMORY_H__ +#define __DEVICE_RGB_MEMORY_H__ + +#include + +#include "utiltools.hpp" + +using namespace std; + +class DeviceMemory{ + +public: + DeviceMemory(int _channel, int _width, int _width_stride, int _height, int _height_stride, string _id, string _dev_id, bool _key_frame, bool _isused){ + channel = _channel; + width = _width; + width_stride = _width_stride; + height = _height; + height_stride = _height_stride; + data_size = channel * width * height; + isused = _isused; + id = _id; + device_id = _dev_id; + key_frame = _key_frame; + timestamp = UtilTools::get_cur_time_ms(); + } + + virtual ~DeviceMemory(){} + + int getSize() { + return data_size; + } + + bool isIsused() { + return isused; + } + + void setIsused(bool _isused) { + isused = _isused; + // 更新时间戳 + timestamp = UtilTools::get_cur_time_ms(); + } + + string getId() { + return id; + } + + string getDeviceId() { + return device_id; + } + + unsigned char* getMem(){ + return pHwRgb; + } + + long long getTimesstamp(){ + return timestamp; + } + + int getWidth(){ + return width; + } + + int getWidthStride(){ + return width_stride; + } + + int getHeight(){ + return height; + } + + int getHeightStride(){ + return height_stride; + } + + int getChannel(){ + return channel; + } + + bool isKeyFrame(){ + return key_frame; + } + +public: + int data_size; + bool isused; + string id; + string device_id; + unsigned char * pHwRgb{nullptr}; + long long timestamp; + int width{0}; + int width_stride{0}; + int height{0}; + int height_stride{0}; + int channel{3}; + bool key_frame; +}; + +#endif \ No newline at end of file diff --git a/src/decoder/interface/Makefile b/src/decoder/interface/Makefile new file mode 100644 index 0000000..a856501 --- /dev/null +++ b/src/decoder/interface/Makefile @@ -0,0 +1,76 @@ +# 各项目录 +LIB_DIR:=$(BUILD_DIR)/$(MODULE)/lib +DEP_DIR:=$(BUILD_DIR)/$(MODULE)/.dep +OBJ_DIR:=$(BUILD_DIR)/$(MODULE)/obj +SRC_DIR:=$(TOP_DIR)/$(MODULE) + +# 源文件以及中间目标文件和依赖文件 +SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp)) +OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS))) +DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d,a $(SRCS))) + +# 自动生成头文件依赖选项 +DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d + +JRTP_ROOT = $(THIRDPARTY_ROOT)/jrtp_export + +INCLUDE= -I $(TOP_DIR)/common/inc \ + -I $(TOP_DIR)/common/UtilNPP \ + -I $(TOP_DIR)/ \ + -I $(JRTP_ROOT)/jrtplib/include/jrtplib3 \ + -I $(JRTP_ROOT)/jthread/include/jthread \ + -I $(TOP_DIR)/src/gb28181 \ + -I $(TOP_DIR)/src/nvdec \ + -I $(CUDA_ROOT)/include \ + +LIBSPATH= -L $(JRTP_ROOT)/jthread/lib -l:libjthread.a \ + -L $(JRTP_ROOT)/jrtplib/lib -l:libjrtp.a \ + -L $(CUDA_ROOT)/lib64 -lcuda -lcudart -lnvcuvid -lcurand -lcublas -lnvjpeg \ + + +CXXFLAGS= -g -O0 -fPIC $(INCLUDE) $(LIBSPATH) $(DEFS) -lpthread -lrt -lz -fexceptions -std=c++11 -fvisibility=hidden -Wl,-Bsymbolic -ldl -Wwrite-strings + + +# 最终目标文件 +TARGET:=$(LIB_DIR)/$(MODULE).a + + +# 默认最终目标 +.PHONY:all +all:$(TARGET) + +# 生成最终目标 +$(TARGET):$(OBJS) | $(LIB_DIR) + @echo -e "\e[32m""Linking static library $(TARGET)""\e[0m" + @echo -e "ar -rc $@ $^" + @ar -rc $@ $^ + +# 若没有lib目录则自动生成 +$(LIB_DIR): + @mkdir -p $@ + +# 生成中间目标文件 +$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR) + @echo -e "\e[33m""Building object $@""\e[0m" + @echo -e "$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(INCS) $(LIBS) $(MACROS) -o $@ $<" +# @$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(INCS) $(LIBSPATH) $(MACROS) -o $@ $(MODULE_LIBS) $< + @$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(INCS) $(LIBS) $(MACROS) -o $@ $< + +# 若没有obj目录则自动生成 +$(OBJ_DIR): + @mkdir -p $@ + +# 若没有.dep目录则自动生成 +$(DEP_DIR): + @mkdir -p $@ + +# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错 +$(DEPS): + +# 引入中间目标文件头文件依赖关系 +include $(wildcard $(DEPS)) + +# 直接删除组件build目录 +.PHONY:clean +clean: + @rm -rf $(BUILD_DIR)/$(MODULE) diff --git a/src/decoder/interface/interface_headers.h b/src/decoder/interface/interface_headers.h new file mode 100644 index 0000000..93c96d7 --- /dev/null +++ b/src/decoder/interface/interface_headers.h @@ -0,0 +1,59 @@ +#ifndef _INTERFACE_HEADERS_H_ +#define _INTERFACE_HEADERS_H_ + + +#include +#include +#include + +#include "DeviceMemory.hpp" + +using namespace std; + +/************************************************** +* 接口:DXDECODER_CALLBACK +* 功能:解码数据回调接口 +* 参数:const dx_void * userPtr 用户自定义数据 +* AVFrame * gpuFrame 解码结果帧数据,在设置的对应的gpu上,要十分注意这一点,尤其是多线程情况 +* 返回:无 +* 备注:当解码库数据源为实时流时(RTSP/GB28181),本接 +* 口内不可进行阻塞/耗时操作。当解码库数据源为 +* 非实时流时(本地/网络文件),本接口可以进行 +* 阻塞/耗时操作 +**************************************************/ +typedef void(*POST_DECODE_CALLBACK)(const void * userPtr, DeviceMemory* devFrame); + +typedef void(*DECODE_FINISHED_CALLBACK)(const void* userPtr); + +typedef bool(*DECODE_REQUEST_STREAM_CALLBACK)(const char* deviceId); + +struct FFDecConfig{ + string uri; // 视频地址 + POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 + DECODE_FINISHED_CALLBACK decode_finished_cbk; // 解码线程结束后的回调接口 + string gpuid; // gpu id + bool force_tcp{true}; // 是否指定使用tcp连接 + int skip_frame{1}; // 跳帧数 + string dec_name; + + int port; // gb28181接收数据的端口号 + DECODE_REQUEST_STREAM_CALLBACK request_stream_cbk; // gb28181请求流 +}; + +enum DECODER_TYPE{ + DECODER_TYPE_GB28181, + DECODER_TYPE_FFMPEG, + DECODER_TYPE_DVPP +}; + +struct FFImgInfo{ + string dec_name; + int width; + int height; + unsigned char * pData; + int data_type; // 默认0=rgb, 1=nv12 + long timestamp; + long index; +}; + +#endif \ No newline at end of file diff --git a/src/decoder/interface/logger.hpp b/src/decoder/interface/logger.hpp new file mode 100644 index 0000000..1d67fea --- /dev/null +++ b/src/decoder/interface/logger.hpp @@ -0,0 +1,344 @@ +/* + * @Author: yangzilong + * @Date: 2021-12-21 11:07:11 + * @Last Modified by: yangzilong + * @Email: yangzilong@objecteye.com + * @Description: + */ + +#pragma once + +// #include "define.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +#define LOG_TRACE_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_TRACE(logger, __VA_ARGS__);} +#define LOG_DEBUG_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_DEBUG(logger, __VA_ARGS__);} +#define LOG_WARN_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_WARN(logger, __VA_ARGS__);} +#define LOG_ERROR_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_ERROR(logger, __VA_ARGS__);} +#define LOG_INFO_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_INFO(logger, __VA_ARGS__);} +#define LOG_CRITICAL_WITH_LOGGER(logger, ...) {SPDLOG_LOGGER_CRITICAL(logger, __VA_ARGS__);} + + +// use fmt lib, e.g. LOG_WARN("warn log, {1}, {1}, {2}", 1, 2); +#define LOG_TRACE(msg, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::trace, msg, ##__VA_ARGS__) +#define LOG_DEBUG(msg, ...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::debug, msg, ##__VA_ARGS__) +#define LOG_INFO(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::info, msg, ##__VA_ARGS__) +#define LOG_WARN(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::warn, msg, ##__VA_ARGS__) +#define LOG_ERROR(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::err, msg, ##__VA_ARGS__) +#define LOG_FATAL(msg,...) spdlog::log({__FILENAME__, __LINE__, __FUNCTION__}, spdlog::level::critical, msg, ##__VA_ARGS__) + + + +namespace spdlog +{ + namespace sinks + { + template + class easy_file_sink final : public base_sink + { + public: + easy_file_sink(filename_t base_filename, size_t max_size, size_t max_keep_days = 0) + : base_filename_(std::move(base_filename)) + , max_size_(max_size) + , max_keep_days_(max_keep_days) + { + auto now = log_clock::now(); + auto filename = gen_filename_by_daliy(base_filename_, now_tm(now)); + + file_helper_.open(filename, false); + current_size_ = file_helper_.size(); + rotation_tp_ = next_rotation_tp_(); + + if (max_keep_days_ > 0) + { + filespath_q_.push_back(std::move(std::set())); + filespath_q_[filespath_q_.size() - 1].insert(filename); + } + } + + filename_t filename() + { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); + } + + protected: + void sink_it_(const details::log_msg &msg) override + { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + current_size_ += formatted.size(); + + auto time = msg.time; + if (time >= rotation_tp_) + { + file_helper_.close(); + auto filename = gen_filename_by_daliy(base_filename_, now_tm(time)); + file_helper_.open(filename, false); + current_size_ = file_helper_.size(); + rotation_tp_ = next_rotation_tp_(); + + { + filespath_q_.push_back(std::move(std::set())); + filespath_q_[filespath_q_.size() - 1].emplace(filename); + } + + // Do the cleaning only at the end because it might throw on failure. + if (max_keep_days_ > 0 && filespath_q_.size() > max_keep_days_) + delete_old_(); + } + else if (current_size_ >= max_size_) + { + file_helper_.close(); + auto src_name = gen_filename_by_daliy(base_filename_, now_tm(time)); + auto target_name = gen_filename_by_filesize(base_filename_, now_tm(time), filespath_q_[filespath_q_.size() - 1].size()); + + // rename file if failed then us `target_name` as src_name. + if (!rename_file_(src_name, target_name)) + { + details::os::sleep_for_millis(200); + if (!rename_file_(src_name, target_name)) + { + fprintf(stderr, "%s:%d rename %s to %s failed\n", __FILENAME__, __LINE__, src_name.c_str(), target_name.c_str()); + src_name = target_name; + } + } + + filespath_q_[filespath_q_.size() - 1].emplace(src_name); + if (src_name != target_name) + filespath_q_[filespath_q_.size() - 1].emplace(target_name); + + file_helper_.open(src_name, false); + current_size_ = file_helper_.size(); + rotation_tp_ = next_rotation_tp_(); + } + + file_helper_.write(formatted); + + + } + + void flush_() override + { + file_helper_.flush(); + } + + private: + + tm now_tm(log_clock::time_point tp) + { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + /** + * @brief Get next day tm. + * + * @return log_clock::time_point + */ + log_clock::time_point next_rotation_tp_() + { + auto now = log_clock::now(); + tm date = now_tm(now); + date.tm_hour = 0; + date.tm_min = 0; + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) + return rotation_time; + return {rotation_time + std::chrono::hours(24)}; + } + + // Delete the file N rotations ago. + // Throw spdlog_ex on failure to delete the old file. + void delete_old_() + { + for (auto iter = filespath_q_.begin(); iter != filespath_q_.end();) + { + if (filespath_q_.size() <= max_keep_days_) + break; + + for (auto it = iter->begin(); it != iter->end(); ++it) + { + bool ok = details::os::remove_if_exists(*it) == 0; + if (!ok) + throw_spdlog_ex("Failed removing daily file " + details::os::filename_to_str(*it), errno); + } + filespath_q_.erase(iter); + } + } + + /* */ + static filename_t gen_filename_by_daliy(const filename_t &filename, const tm &now_tm) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt::format(SPDLOG_FILENAME_T("{}_{:04d}_{:02d}_{:02d}{}"), + basename, + now_tm.tm_year + 1900, + now_tm.tm_mon + 1, + now_tm.tm_mday, + ext); + } + + // + static filename_t gen_filename_by_filesize(const filename_t &filename, const tm &now_tm, const int &idx) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt::format(SPDLOG_FILENAME_T("{}_{:04d}_{:02d}_{:02d}_{:02d}{:02d}{:02d}.{:d}{}"), + basename, + now_tm.tm_year + 1900, + now_tm.tm_mon + 1, + now_tm.tm_mday, + now_tm.tm_hour, + now_tm.tm_min, + now_tm.tm_sec, + idx, + ext); + } + + static bool rename_file_(const filename_t &src_filename, const filename_t &target_filename) + { + (void)details::os::remove(target_filename); + return details::os::rename(src_filename, target_filename) == 0; + } + + filename_t base_filename_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + std::size_t max_size_; + std::size_t max_keep_days_; + std::size_t current_size_; + // std::vector<> filespath_q_; + std::vector> filespath_q_; + }; + + using easy_file_sink_mt = easy_file_sink; + using easy_file_sink_st = easy_file_sink; + + } // namespace sinks + + template + inline std::shared_ptr easy_logger_mt( + const std::string &logger_name, const filename_t &filename, size_t max_size, size_t max_keep_days = -1) + { + return Factory::template create(logger_name, filename, max_size, max_keep_days); + } + + template + inline std::shared_ptr easy_logger_st( + const std::string &logger_name, const filename_t &filename, size_t max_size, size_t max_keep_days = -1) + { + return Factory::template create(logger_name, filename, max_size, max_keep_days); + } + +} // namespace spdlog + + +enum class LogLevel +{ + CLOSE = -1, + TRACE = 0, + DEBUG = 1, + INFO = 2, + WARN = 3, + ERROR = 4, + FATAL = 5, +}; + + +class LoggerGenerator +{ +public: + static LoggerGenerator* get_instance() + { + static LoggerGenerator logger; + return &logger; + } + + void destory(LoggerGenerator *ptr) + { + if (ptr != nullptr) + { + delete ptr; + ptr = nullptr; + } + } + + std::shared_ptr gen_logger(const LogLevel &level, const std::string &logger_name, + const std::string &file_path, size_t max_file_size, size_t max_keep_days) + { + spdlog::level::level_enum spd_level; + if (LogLevel::TRACE == level) + spd_level = spdlog::level::trace; + else if (LogLevel::DEBUG == level) + spd_level = spdlog::level::debug; + else if (LogLevel::INFO == level) + spd_level = spdlog::level::info; + else if (LogLevel::WARN == level) + spd_level = spdlog::level::warn; + else if (LogLevel::ERROR == level) + spd_level = spdlog::level::err; + else if (LogLevel::FATAL == level) + spd_level = spdlog::level::critical; + else if (LogLevel::CLOSE == level) + spd_level = spdlog::level::off; + + auto sink_ptr = std::make_shared(file_path, max_file_size, max_keep_days); + auto logger = std::make_shared(logger_name, sink_ptr); + logger->set_level(spd_level); + logger->set_pattern("%s(%#): [%L %D %T.%e %P %t %!] %v"); + + return logger; + } + + void set_default_logger(const LogLevel &level, const std::string &logger_name, + const std::string &file_name, size_t max_file_size, size_t max_keep_days) + { + + auto logger = gen_logger(level, logger_name, file_name, max_file_size, max_keep_days); + spdlog::set_default_logger(logger); + spdlog::set_level(logger->level()); + spdlog::set_pattern("%s(%#): [%L %D %T.%e %P %t %!] %v"); + + spdlog::flush_on(spdlog::level::trace); + spdlog::flush_every(std::chrono::seconds(1)); + } + +}; + + +static void set_default_logger(const LogLevel &level, const std::string &logger_name, + const std::string &file_path, size_t max_file_size, size_t max_keep_days) +{ + static LoggerGenerator loggerGenerator; + loggerGenerator.set_default_logger(level, logger_name, file_path, max_file_size, max_keep_days); +} + + +static std::shared_ptr get_simple_logger(const LogLevel &level, const std::string &logger_name, + const std::string &file_path, size_t max_file_size, size_t max_keep_days) +{ + static LoggerGenerator loggerGenerator; + return loggerGenerator.gen_logger(level, logger_name, file_path, max_file_size, max_keep_days); +} diff --git a/src/decoder/interface/utiltools.hpp b/src/decoder/interface/utiltools.hpp new file mode 100644 index 0000000..a156ab9 --- /dev/null +++ b/src/decoder/interface/utiltools.hpp @@ -0,0 +1,18 @@ +#ifndef _UTIL_TOOLS_HPP_ +#define _UTIL_TOOLS_HPP_ + +#include + +using namespace std; + +namespace UtilTools{ + + static long get_cur_time_ms() { + chrono::time_point tpMicro + = chrono::time_point_cast(chrono::system_clock::now()); + return tpMicro.time_since_epoch().count(); + } + +} + +#endif \ No newline at end of file diff --git a/src/demo/demo.cpp b/src/demo/demo.cpp new file mode 100644 index 0000000..acdc43e --- /dev/null +++ b/src/demo/demo.cpp @@ -0,0 +1,551 @@ +#include "../ai_platform/stl_aiplatform.h" +#include + +using namespace std; + + +void set_task_params(task_param &tparam, const unsigned &idx, const algorithm_type_t &algor_type) { + auto algor_init_params = new algor_init_config_param_t; + switch (algor_type) { + case algorithm_type_t::FACE_SNAPSHOT: { + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + + basic_params->result_folder = "res/face"; + ; + basic_params->result_folder_little = "res/face_little"; + ; + } + auto algor_params = new algor_config_param_snapshot; + { algor_params->threshold = 0.5f; } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::HUMAN_SNAPSHOT: { + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + + basic_params->result_folder = "res/human"; + basic_params->result_folder_little = "res/human_little"; + } + auto algor_params = new algor_config_param_snapshot; + { algor_params->threshold = 0.5f; } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::PEDESTRIAN_FALL: { + auto algor_params = new algor_config_param_pedestrian_fall; + { algor_params->threshold = 0.7f; } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + + basic_params->result_folder = "res/fall"; + basic_params->result_folder_little = "res/fall_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::PEDESTRIAN_FIGHT: { + auto algor_params = new algor_config_param_pedestrian_fight; + { + algor_params->threshold = 0.7f; + algor_params->iou_threshold = 0.1f; + } + + auto basic_params = new algor_basic_config_param_t; + { + + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/fight"; + basic_params->result_folder_little = "res/fight_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::HUMAN_GATHER: { + + auto algor_params = new algor_config_param_human_gather; + { + algor_params->frame_stride = 1; + // algor_params->human_count_threshold = 3; + algor_params->human_count_threshold = 1; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/gather"; + basic_params->result_folder_little = "res/gather_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::NO_REFLECTIVE_CLOTHING: { + auto algor_params = new algor_config_param_no_reflective_clothing; + { + algor_params->conf_threshold = 0.3f; + algor_params->m = 10; + algor_params->n = 6; + algor_params->pedestrian_confidence_threshold = 0.3f; + algor_params->pedestrian_min_height = 0; + algor_params->pedestrian_min_width = 0; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/no_reflective_clothing"; + basic_params->result_folder_little = "res/no_reflective_clothing_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::NO_SAFETY_HELMET: { + auto algor_params = new algor_config_param_no_safety_helmet; + { + algor_params->conf_threshold = 0.3f; + algor_params->m = 10; + algor_params->n = 6; + algor_params->pedestrian_confidence_threshold = 0.3f; + algor_params->pedestrian_min_height = 0; + algor_params->pedestrian_min_width = 0; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/no_safety_helmet"; + basic_params->result_folder_little = "res/no_safety_helmet_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::CALL_PHONE_DET: { + auto algor_params = new algor_config_param_call_phone; + { + algor_params->conf_threshold = 0.3f; + algor_params->m = 2; + algor_params->n = 1; + algor_params->pedestrian_confidence_threshold = 0.1f; + algor_params->pedestrian_min_height = 0; + algor_params->pedestrian_min_width = 0; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/call_phone"; + basic_params->result_folder_little = "res/call_phone_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::SMOKING_DET: { + auto algor_params = new algor_config_param_smoking; + { + algor_params->conf_threshold = 0.3f; + algor_params->m = 10; + algor_params->n = 1; + algor_params->pedestrian_confidence_threshold = 0.3f; + algor_params->pedestrian_min_height = 0; + algor_params->pedestrian_min_width = 0; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/smoking"; + basic_params->result_folder_little = "res/smoking_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::VEHICLE_SNAPSHOT: { + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/vehicle"; + basic_params->result_folder_little = "res/vehicle_little"; + } + + auto algor_params = new algor_config_param_snapshot; + algor_params->threshold = 0.5f; + algor_params->snap_frame_interval = 5; + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::NONMOTOR_VEHICLE_SNAPSHOT: { + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/nonmotor"; + basic_params->result_folder_little = "res/nonmotor_little"; + } + + auto algor_params = new algor_config_param_snapshot; + { algor_params->threshold = 0.5f; } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::TAKEAWAY_MEMBER_CLASSIFICATION: { + auto algor_params = new algor_config_param_takeaway_member_classification; + { + algor_params->m = 10; + algor_params->n = 2; + algor_params->threshold = 0.7f; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/takeaway"; + basic_params->result_folder_little = "res/takeaway_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::PEDESTRIAN_RETROGRADE: { + // 578 1300 600 + auto algor_params = new algor_config_param_pedestrian_retrograde; + { + algor_params->conf_threshold = 0.5f; + algor_params->minmum_height = 10; + algor_params->minmum_width = 10; + algor_params->direction = 0; + + algor_params->px1 = 578; + algor_params->py1 = 600; + + algor_params->px2 = 1300; + algor_params->py2 = 600; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/pedestrian_retrograde"; + basic_params->result_folder_little = "res/pedestrian_retrograde_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + + } break; + + case algorithm_type_t::VEHICLE_RETROGRADE: { + // 578 1300 600 + auto algor_params = new algor_config_param_pedestrian_retrograde; + { + algor_params->conf_threshold = 0.5f; + algor_params->minmum_height = 10; + algor_params->minmum_width = 10; + algor_params->direction = 0; + + algor_params->px1 = 578; + algor_params->py1 = 600; + + algor_params->px2 = 1300; + algor_params->py2 = 600; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/vehicle_retrograde"; + basic_params->result_folder_little = "res/vehicle_retrograde_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + + } break; + + case algorithm_type_t::PEDESTRIAN_TRESPASS: { + // 578 1300 600 + auto algor_params = new algor_config_param_pedestrian_trespass; + { + algor_params->conf_threshold = 0.5f; + algor_params->minmum_height = 64; + algor_params->minmum_width = 32; + algor_params->points_count = 4; + + algor_params->points[0].x_ = 200; + algor_params->points[0].y_ = 200; + + algor_params->points[1].x_ = 600; + algor_params->points[1].y_ = 200; + + algor_params->points[2].x_ = 600; + algor_params->points[2].y_ = 500; + + algor_params->points[3].x_ = 200; + algor_params->points[3].y_ = 500; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/pedestrian_trespass"; + basic_params->result_folder_little = "res/pedestrian_trespass_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + + } break; + + case algorithm_type_t::VEHICLE_TRESPASS: { + // 578 1300 600 + auto algor_params = new algor_config_param_vehicle_trespass; + { + algor_params->conf_threshold = 0.5f; + algor_params->minmum_height = 64; + algor_params->minmum_width = 64; + algor_params->points_count = 4; + + algor_params->points[0].x_ = 500; + algor_params->points[0].y_ = 500; + + algor_params->points[1].x_ = 1500; + algor_params->points[1].y_ = 500; + + algor_params->points[2].x_ = 1500; + algor_params->points[2].y_ = 900; + + algor_params->points[3].x_ = 500; + algor_params->points[3].y_ = 900; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + basic_params->algor_valid_rect.width_ = 1920; + basic_params->algor_valid_rect.height_ = 1080; + basic_params->result_folder = "res/vehicle_trespass"; + basic_params->result_folder_little = "res/vehicle_trespass_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + + } break; + + case algorithm_type_t::VIDEO_SNAPSHOT: { + auto basic_params = new algor_basic_config_param_t; + { basic_params->result_folder = "res/video_snapshot"; } + algor_init_params->basic_param = basic_params; + } break; + + + case algorithm_type_t::ROAD_WORK_DET: { + + auto algor_params = new algor_config_param_road_work; + { + algor_params->frame_stride = 5; + algor_params->rblock_count_threshold = 3; + // algor_params->frame_stride = 1; + // algor_params->rblock_count_threshold = 1; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->algor_valid_rect.top_ = 0; + basic_params->algor_valid_rect.left_ = 0; + // basic_params->algor_valid_rect.width_ = 1920; + // basic_params->algor_valid_rect.height_ = 1080; + basic_params->algor_valid_rect.width_ = 2560; + basic_params->algor_valid_rect.height_ = 1440; + basic_params->result_folder = "res/road_work"; + basic_params->result_folder_little = "res/road_work_little"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + case algorithm_type_t::VIDEO_TIMING_SNAPSHOT: { + + auto algor_params = new algor_config_param_road_work; + { + algor_params->frame_stride = 5; + } + + auto basic_params = new algor_basic_config_param_t; + { + basic_params->result_folder = "res/video_timing_snapshot"; + } + + algor_init_params->algor_param = algor_params; + algor_init_params->basic_param = basic_params; + } break; + + default: { + if (algor_init_params != nullptr) { + delete algor_init_params; + algor_init_params = nullptr; + } + return; + } break; + } + + tparam.algor_config_params[idx].algor_type = algor_type; + tparam.algor_config_params[idx].algor_init_config_param = algor_init_params; +} + +static long long get_cur_time(){ + chrono::time_point tpMicro + = chrono::time_point_cast(chrono::system_clock::now()); + return tpMicro.time_since_epoch().count(); +} + +string createTask(void *handle, std::vector algor_vec, int gi){ + task_param tparam; + // tparam.ipc_url = "rtsp://admin:ad123456@192.168.60.108:554/cam/realmonitor?channel=1&subtype=0"; + // tparam.ipc_url = "/home/huchunming/data/caishenkezhan.mp4"; + tparam.ipc_url = "/home/cmhu/data/Street.uvf"; + // tparam.ipc_url = "rtsp://122.97.218.170:8604/openUrl/V5nXRHa?params=eyJwcm90b2NhbCI6InJ0c3AiLCJjbGllbnRUeXBlIjoib3Blbl9hcGkiLCJleHByaWVUaW1lIjotMSwicHJvdG9jb2wiOiJydHNwIiwiZXhwaXJlVGltZSI6MzAwLCJlbmFibGVNR0MiOnRydWUsImV4cGFuZCI6InN0YW5kYXJkPXJ0c3Amc3RyZWFtZm9ybT1ydHAiLCJhIjoiMTBjZjM4N2JjY2Y5NDg3YzhjNWYzNjE2M2ViMWUyNTJ8MXwwfDEiLCJ0IjoxfQ=="; + tparam.algor_counts = algor_vec.size(); + tparam.dec_type = 2; + + std::string task_id_str = "test_task_id_" + std::to_string(gi); + tparam.task_id = task_id_str.c_str(); + + tparam.algor_config_params = new algor_config_param[tparam.algor_counts]; + + for (size_t idx = 0; idx < algor_vec.size(); ++idx) + set_task_params(tparam, idx, algor_vec.at(idx)); + + const int result_code = add_task(handle, tparam); + if (result_code != 0) + printf("[Error]: "); + printf("--- task_id: %s result code: %d\n", tparam.task_id, result_code); + return task_id_str; +} + +int main(int argc, char *argv[]) { + printf("new test\n"); + + if (argc < 4) { + fprintf(stderr, "./xxx 0 2 10 1 ## [start_ai_id, end_ai_id) repeat_num gpu_id\n"); + return -1; + } + + //! load params. + int start_id = atoi(argv[1]); + int end_id = atoi(argv[2]); + int repeat_num = atoi(argv[3]); + int gpuID = atoi(argv[4]); + + tsl_aiplatform_param vptParam; + vptParam.gpuid = gpuID; + vptParam.trt_serialize_file = ""; + + vptParam.log_days = 1; + vptParam.log_level = AI_LOG_LEVEL_TRACE; + // vptParam.log_level = AI_LOG_LEVEL_DEBUG; + vptParam.log_mem = 64 * 1024 * 1024; // 64MB. + vptParam.log_path = "logs/main.log"; + vptParam.vpt_thred = 0.45; + vptParam.rblock_thred = 0.4; + + void *handle; + int flag = tsl_aiplatform_init(&handle, vptParam); + if (0 != flag) { + printf("Init Failed! Error Code: %d\n", flag); + system("pause"); + return 0; + } else { + printf("Init Success\n"); + } + + std::vector algor_vec = {algorithm_type_t::FACE_SNAPSHOT, algorithm_type_t::HUMAN_SNAPSHOT,algorithm_type_t::ROAD_WORK_DET, + algorithm_type_t::VEHICLE_SNAPSHOT, algorithm_type_t::NONMOTOR_VEHICLE_SNAPSHOT, algorithm_type_t::VIDEO_TIMING_SNAPSHOT}; + + string task_id = createTask(handle, algor_vec, 0); + + while (getchar() != 'q'); + + finish_task(handle, (char*)task_id.data(), 0); + + tsl_aiplatform_release(&handle); + printf("Done.\n"); + + return 0; +} \ No newline at end of file diff --git a/src/helpers/gen_json.hpp b/src/helpers/gen_json.hpp new file mode 100644 index 0000000..7b28451 --- /dev/null +++ b/src/helpers/gen_json.hpp @@ -0,0 +1,336 @@ +/* + * @Author: yangzilong + * @Last Modified by: yangzilong + * @Date: 2021-11-24 18:25:14 + * @Email: yangzilong@objecteye.com + * @Description: + */ + +#pragma once + +#include +#include "json/json.h" +#include "time_helper.hpp" +#include "../common/logger.hpp" +#include "../ai_platform/header.h" +#include "../ai_platform/common_header.h" + +namespace helpers +{ + namespace gen_json + { + + static std::string ORI_IMAGE_PATH_PLACEHOLDER = "___ORI_IMAGE_PATH_PLACEHOLDER___"; + static std::string ROI_IMAGE_PATH_PLACEHOLDER = "___ROI_IMAGE_PATH_PLACEHOLDER___"; + + static auto get_builder(const int float_precision = 5) -> Json::StreamWriterBuilder + { + Json::StreamWriterBuilder builder; + builder["indentation" ] = ""; + builder["emitUTF8" ] = true; + builder["precision"] = float_precision; + builder["precisionType"] = "decimal"; + return builder; + } + + static std::string gen_delete_task_json(const std::string &taskid, int error_code) + { + Json::Value root; + root["task_id"] = taskid; + root["code"] = std::to_string(error_code); + return Json::writeString(get_builder(), root); + } + + static std::string gen_task_status_json(const std::vector &taskids, const std::vector &statues) + { + if (taskids.size() != statues.size()) + { + LOG_ERROR("number of task_id must equal number of statues\n"); + return ""; + } + + Json::Value root; + for (int i = 0; i < taskids.size(); ++i) + { + Json::Value item; + item["task_id"] = taskids[i]; + item["status"] = std::to_string(statues[i]); + root.append(item); + } + + return Json::writeString(get_builder(), root); + }; + + static std::string gen_office_task_heart_beat_json(const std::vector &taskids) + { + Json::Value root; + for (int i = 0; i < taskids.size(); ++i) + { + Json::Value item; + item["task_id"] = taskids[i]; + root.append(item); + } + + return Json::writeString(get_builder(), root); + }; + + + static std::string gen_face_detection_json(const std::string &taskid, + const int &objid, const std::string &roi_fpath, const std::string &ori_fpath, + const sy_rect &box, const float &score, const sy_point *kpts, + const int &n_kpts = 25) + { + Json::Value root; + root["task_id"] = taskid; + root["object_id"] = objid; + root["algor_type"] = (int)algorithm_type_t::FACE_SNAPSHOT; + root["timestamp_ms"] = std::to_string(timer::get_timestamp()); + { + Json::Value data; + data["snapshot_image_path"] = roi_fpath; + data["video_image_path"] = ori_fpath; + + + { + Json::Value boxes; + { + Json::Value boxNode; + boxNode["top"] = box.top_; + boxNode["left"] = box.left_; + boxNode["right"] = box.left_ + box.width_; + boxNode["bottom"] = box.top_ + box.height_; + boxNode["score"] = score; + { + + Json::Value kptsNode; + for (int i = 0; i < n_kpts; ++i) + { + Json::Value kp; + kp.append(kpts[i].x_); + kp.append(kpts[i].y_); + kptsNode.append(kp); + } + boxNode["ldmk"] = kptsNode; + } + boxes.append(boxNode); + } + data["box"] = boxes; + } + root["data"] = data; + } + + return Json::writeString(get_builder(), root); + }; + + static std::string gen_snapshot_json(const algorithm_type_t &algor_type, video_object_snapshot const &algo_result) + { + Json::Value root; + root["task_id"] = algo_result.task_id; + root["algor_type"] = (int)algor_type; + root["object_id"] = algo_result.object_id; + root["timestamp_ms"] = std::to_string(timer::get_timestamp()); + + { + Json::Value dataNode; + Json::Value boxNode; + { + Json::Value boxNodeItem; + boxNodeItem["top"] = algo_result.obj_info.res_top; + boxNodeItem["left"] = algo_result.obj_info.res_left; + boxNodeItem["right"] = algo_result.obj_info.res_right; + boxNodeItem["bottom"] = algo_result.obj_info.res_bottom; + boxNodeItem["score"] = algo_result.obj_info.res_prob; + boxNodeItem["index"] = algo_result.obj_info.res_index; //221212byzsh + + boxNode.append(boxNodeItem); + dataNode["box"] = boxNode; + } + dataNode["video_image_path"] = algo_result.video_image_path; + dataNode["snapshot_image_path"] = algo_result.snapshot_image_path; + root["data"] = dataNode; + + } + return Json::writeString(get_builder(), root); + }; + + static std::string gen_multi_obj_json(const algorithm_type_t &algor_type, video_object_snapshot const &algo_result) + { + Json::Value root; + root["task_id"] = algo_result.task_id; + root["algor_type"] = (int)algor_type; + root["object_id"] = algo_result.object_id; + root["bfinished"] = algo_result.nFinished; + root["timestamp_ms"] = std::to_string(timer::get_timestamp()); + + if(algo_result.nFinished == 0){ + Json::Value dataNode; + Json::Value boxNode; + + Json::Value boxNodeItem; + boxNodeItem["top"] = algo_result.obj_info.res_top; + boxNodeItem["left"] = algo_result.obj_info.res_left; + boxNodeItem["right"] = algo_result.obj_info.res_right; + boxNodeItem["bottom"] = algo_result.obj_info.res_bottom; + boxNodeItem["score"] = algo_result.obj_info.res_prob; + boxNodeItem["index"] = algo_result.obj_info.res_index; //221212byzsh + boxNode.append(boxNodeItem); + + dataNode["box"] = boxNode; + + dataNode["video_image_path"] = algo_result.video_image_path; + dataNode["snapshot_image_path"] = algo_result.snapshot_image_path; + root["data"] = dataNode; + } + + return Json::writeString(get_builder(), root); + }; + + static std::string gen_generic_json(const std::string& taskId, long object_id, + const box_t &box, + const algorithm_type_t &algor_type, + const std::string &image_path) + { + Json::Value root; + root["task_id"] = taskId; + root["object_id"] = int(object_id); + root["algor_type"] = static_cast(algor_type); + root["timestamp_ms"] = std::to_string(timer::get_timestamp()); + { + Json::Value dataNode; + Json::Value boxNode; + { + Json::Value boxNodeItem; + boxNodeItem["top"] = box.top; + boxNodeItem["left"] = box.left; + boxNodeItem["right"] = box.right; + boxNodeItem["bottom"] = box.bottom; + boxNodeItem["score"] = box.score; + + boxNode.append(boxNodeItem); + dataNode["box"] = boxNode; + } + + dataNode["video_image_path"] = ORI_IMAGE_PATH_PLACEHOLDER; + dataNode["snapshot_image_path"] = ("" == image_path) ? ROI_IMAGE_PATH_PLACEHOLDER : image_path; + root["data"] = dataNode; + } + + + return Json::writeString(get_builder(), root); + } + + + static std::string gen_retrograde_json(const std::string& taskId, int object_id, + const box_t &box, + const algorithm_type_t &algor_type, + const std::string &image_path = "") + { + return gen_generic_json(taskId, object_id, box, algor_type, image_path); + } + + static std::string gen_pedestrian_safety_json(const std::string& taskId, int object_id, + const box_t &box, + const algorithm_type_t &algor_type, + const std::string &image_path = "") + { + return gen_generic_json(taskId, object_id, box, algor_type, image_path); + } + + + static std::string gen_takeaway_member_cls_json(const std::string& taskId, int object_id, + const box_t &box, const int &category, + const std::string &image_path = "") + { + return gen_generic_json(taskId, object_id, box, algorithm_type_t::TAKEAWAY_MEMBER_CLASSIFICATION, image_path); + } + + static std::string gen_human_gather_json(const std::string& taskId, std::vector boxes, const std::string &image_path) + { + Json::Value root; + root["task_id"] = taskId; + root["algor_type"] = (int)algorithm_type_t::HUMAN_GATHER; + root["timestamp_ms"] = std::to_string(timer::get_timestamp()); + { + Json::Value dataNode; + dataNode["snapshot_image_path"] = ""; + dataNode["video_image_path"] = ("" == image_path) ? ORI_IMAGE_PATH_PLACEHOLDER : image_path; + + { + Json::Value boxesNode; + for (auto &box: boxes) + { + Json::Value boxNode; + boxNode["top"] = box.top; + boxNode["left"] = box.left; + boxNode["right"] = box.right; + boxNode["bottom"] = box.bottom; + boxNode["score"] = box.score; + boxesNode.append(boxNode); + } + dataNode["box"] = boxesNode; + } + root["data"] = dataNode; + } + return Json::writeString(get_builder(), root); + } + + // added by zsh 220802 用于视频快照接口 + static std::string gen_screen_json(const std::string &taskid, const std::string &ori_fpath) + { + Json::Value root; + root["task_id"] = taskid; + root["algor_type"] = (int)algorithm_type_t::VIDEO_SNAPSHOT; + root["timestamp_ms"] = std::to_string(timer::get_timestamp()); + root["video_snapshot_path"] = ori_fpath; + return Json::writeString(get_builder(), root); + }; + + static std::string gen_boxes_json(const std::string& taskId, int algorithm_type, std::vector boxes, const std::string &image_path){ + Json::Value root; + root["task_id"] = taskId; + root["algor_type"] = algorithm_type; + root["timestamp_ms"] = std::to_string(timer::get_timestamp()); + { + Json::Value dataNode; + dataNode["snapshot_image_path"] = ""; + dataNode["video_image_path"] = ("" == image_path) ? ORI_IMAGE_PATH_PLACEHOLDER : image_path; + + { + Json::Value boxesNode; + for (auto &box: boxes) + { + Json::Value boxNode; + boxNode["top"] = box.top; + boxNode["left"] = box.left; + boxNode["right"] = box.right; + boxNode["bottom"] = box.bottom; + boxNode["score"] = box.score; + boxesNode.append(boxNode); + } + dataNode["box"] = boxesNode; + } + root["data"] = dataNode; + } + return Json::writeString(get_builder(), root); + } + + // 221026byzsh 施工占道 + static std::string gen_road_work_json(const std::string& taskId, std::vector boxes, const std::string &image_path) + { + return gen_boxes_json(taskId, (int)algorithm_type_t::ROAD_WORK_DET, boxes, image_path); + } + + // added by zsh 230220 用于视频定时抓拍 + static std::string gen_vtsnapshot_json(const std::string &taskid, const std::string &ori_fpath) + { + Json::Value root; + root["task_id"] = taskid; + root["algor_type"] = (int)algorithm_type_t::VIDEO_TIMING_SNAPSHOT; + root["timestamp_ms"] = std::to_string(timer::get_timestamp()); + root["video_snapshot_path"] = ori_fpath; + return Json::writeString(get_builder(), root); + }; + + } // namespace gen_json + +} // namespace helpers diff --git a/src/helpers/os_helper.hpp b/src/helpers/os_helper.hpp new file mode 100644 index 0000000..9435c33 --- /dev/null +++ b/src/helpers/os_helper.hpp @@ -0,0 +1,23 @@ + +#pragma once +#include +#include +#include +#include + + +namespace helpers +{ + namespace os + { + +#if defined(_WIN32) + static std::string sep = "\\"; +#else + static std::string sep = "/"; +#endif + + + } // namespace buffer +} // namespace helpers + diff --git a/src/helpers/time_helper.hpp b/src/helpers/time_helper.hpp new file mode 100644 index 0000000..8cbea66 --- /dev/null +++ b/src/helpers/time_helper.hpp @@ -0,0 +1,66 @@ +/* + * @Author: yangzilong + * @Date: 2021-12-17 17:45:43 + * @Last Modified by: yangzilong + * @Email: yangzilong@objecteye.com + * @Description: + */ +#ifndef __OLFIELD_UTILS_TIMER_HPP__ +#define __OLFIELD_UTILS_TIMER_HPP__ + + +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; + +namespace helpers +{ + namespace timer + { + + template + static inline long long get_timestamp() + { + auto now = std::chrono::system_clock::now(); + return std::chrono::duration_cast(now.time_since_epoch()).count(); + } + + static long long get_cur_time_ms(){ + chrono::time_point tpMicro + = chrono::time_point_cast(chrono::system_clock::now()); + + return tpMicro.time_since_epoch().count(); + } + + static std::string get_date(bool with_time = false) + { + std::chrono::system_clock::time_point t = std::chrono::system_clock::now(); + auto as_time_t = std::chrono::system_clock::to_time_t(t); + struct tm tm; + #if defined(WIN32) || defined(_WINDLL) + localtime_s(&tm, &as_time_t); // win api thread safe, but std::localtime can't thread safe. + #else + localtime_r(&as_time_t, &tm); // linux api thread safe. + #endif + char buf[256]{0}; + if (with_time) + snprintf(buf, sizeof(buf), "%04d%02d%02d_%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + else + snprintf(buf, sizeof(buf), "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + return std::string(buf); + } + + } // namespace timer +} // namespace helpers + + + +#endif // __OLFIELD_UTILS_TIMER_HPP__ + diff --git a/src/linux/test/Makefile b/src/linux/test/Makefile new file mode 100644 index 0000000..fab3504 --- /dev/null +++ b/src/linux/test/Makefile @@ -0,0 +1,51 @@ +CC = gcc +XX = c++ + +TARGET = start + +PROJ_ALL_PATH = $(PWD)/../../.. +CUR_PROJ_PATH = $(PWD)/../.. +OPENCV_PATH = $(PROJ_ALL_PATH)/third_party/opencv_4_1 +ACL_PATH = $(ASCEND_AICPU_PATH)/acllib + +INCLUDES = -I$(PROJ_ALL_PATH)/common \ + -I$(PROJ_ALL_PATH)/common/dvpp \ + -I$(CUR_PROJ_PATH)/src \ + -I$(OPENCV_PATH)/include \ + -I$(OPENCV_PATH)/include/opencv2 \ + -I$(ACL_PATH)/include \ + +CFLAGS = -O3 -std=c++11 $(INCLUDES) -DENABLE_DVPP_INTERFACE -D_GLIBCXX_USE_CXX11_ABI=0 + +local_shared_libs_dirs := \ + $(OPENCV_PATH)/lib \ + $(CUR_PROJ_PATH)/linux \ + $(ACL_PATH)/lib64 \ + +local_shared_libs := \ + opencv_world \ + vpt_det \ + ascendcl \ + acl_dvpp \ + +SHARED_LIBRARIES := $(foreach shared_lib, $(local_shared_libs), -l$(shared_lib)) +SHARED_LIBRARIES_DIRS := $(foreach shared_lib_dir, $(local_shared_libs_dirs), -L$(shared_lib_dir) -Wl,-z,relro,-z,now,-z,noexecstack,-rpath-link,$(shared_lib_dir)) + +SRCS := $(wildcard $(CUR_PROJ_PATH)/src/test/*.cpp) +SRCS += $(wildcard $(PROJ_ALL_PATH)/common/dvpp/*.cpp) + +DIRS := $(notdir $(SRCS)) +OBJS := $(patsubst %cpp, %o, $(DIRS)) + +all: $(TARGET) + +$(TARGET):$(OBJS) + $(XX) $(CFLAGS) -o $@ $^ $(SHARED_LIBRARIES_DIRS) $(SHARED_LIBRARIES) +%.o:$(CUR_PROJ_PATH)/src/test/%.cpp + $(XX) $(CFLAGS) -c $< +%.o:$(PROJ_ALL_PATH)/common/dvpp/%.cpp + $(XX) $(CFLAGS) -c $< + +clean: + @rm -f $(TARGET) + @rm -f $(OBJS) diff --git a/src/readme.txt b/src/readme.txt new file mode 100644 index 0000000..fbba678 --- /dev/null +++ b/src/readme.txt @@ -0,0 +1,23 @@ +人车物检测_x86_310p_v0.0.1.20230316_without_timelimit + +支持系统: + Atlas x86 linux +文件清单: + vpt.h: 接口文件 + libvpt_det.so: 依赖库文件 + models/vpt0715_310p.om: 模型文件 + test/: 测试文件 + test.cpp: 调用示例 + 0_38863.jpg,datacasia_20160821_003198.jpg:测试数据 + list.txt: 测试图片列表 + Atlas人车物检测SDK说明_v0.0.0.pdf: SDK说明文档 + +更新内容: + -2023.03.16 编译ascend310p x86版本 + +注意事项说明: + - 当前版本跟踪前三帧无结果输出 + +中科院自动化所 模式识别实验室图像视频组 + +2023年03月16日 \ No newline at end of file diff --git a/src/reprocessing_module/save_snapshot_reprocessing.cpp b/src/reprocessing_module/save_snapshot_reprocessing.cpp new file mode 100644 index 0000000..fab1d7f --- /dev/null +++ b/src/reprocessing_module/save_snapshot_reprocessing.cpp @@ -0,0 +1,119 @@ +#include "save_snapshot_reprocessing.h" +#include + +#include "opencv2/opencv.hpp" +#include +#include +#include "../common/logger.hpp" +#include "../util/JpegUtil.h" +#include "../util/vpc_util.h" + +const bool DRAW_ON_IMG = false; + +int save_img_thread_process(void* param) { + save_snapshot_reprocessing *pThreadParam = (save_snapshot_reprocessing *)param; + if (pThreadParam != nullptr){ + pThreadParam->save_img_process(); + } + return 0; +} + +// 初始化快照保存模块 开启图片保存线程 +save_snapshot_reprocessing::save_snapshot_reprocessing(int devId) { +#ifdef POST_USE_RABBITMQ + callback_ = nullptr; +#endif + + bFinish = false; + m_save_img_thread = std::thread(save_img_thread_process, this); + + m_devId = devId; + DVPP_UTIL::dvpp_jpeg_init(m_devId); +} + +save_snapshot_reprocessing::~save_snapshot_reprocessing(){ + // 结束线程 + bFinish = true; + m_save_img_thread.join(); + DVPP_UTIL::dvpp_jpeg_release(); +} + +// 释放资源 +void save_snapshot_reprocessing::save_snapshot_reprocessing_release() { + + std::unique_lock l(waitforsave_img_queue_mutex); + + while (!waitforsave_img_queue.empty()) { + ImgSaveInfo cur_image = waitforsave_img_queue.front(); + waitforsave_img_queue.pop(); + + if(!cur_image.file_path.empty()){ + dvpp_img_release(cur_image.img_info); + } + } + + l.unlock(); +} + +#ifdef POST_USE_RABBITMQ + +// 设置MQ返回回调函数 方便内部调用MQ推送结果 +void save_snapshot_reprocessing::set_callback(callback_t cb) { + callback_ = cb; +} + +#endif // #ifdef POST_USE_RABBITMQ + + +void save_snapshot_reprocessing::reprocessing_process_wo_locus_async(ImgSaveInfo saveInfo){ + + // dvpp_img_release(saveInfo.img_info); + // return; + + while(!bFinish){ + waitforsave_img_queue_mutex.lock(); + if(waitforsave_img_queue.size() > 100){ + waitforsave_img_queue_mutex.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + continue; + } + waitforsave_img_queue.push(saveInfo); + waitforsave_img_queue_mutex.unlock(); + break; + } + +} + +void save_snapshot_reprocessing::save_img_process() { + while (true) { + if (bFinish){ + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + std::unique_lock l(waitforsave_img_queue_mutex); + if (!waitforsave_img_queue.empty()) { + LOG_DEBUG("waitforsave_image_queue size: {}", waitforsave_img_queue.size()); + ImgSaveInfo cur_image = waitforsave_img_queue.front(); + waitforsave_img_queue.pop(); + l.unlock(); + + if(!cur_image.file_path.empty()){ + DVPP_UTIL::dvpp_jpeg_encode(cur_image.img_info.pic_desc, cur_image.file_path); + } + dvpp_img_release(cur_image.img_info); + +#ifdef POST_USE_RABBITMQ + if (callback_ != nullptr && cur_image.json_str.length() > 0) { + // LOG_DEBUG("mq publish process 00000000000000000"); + callback_(cur_image.json_str.c_str()); + // LOG_DEBUG("mq publish process 11111111111111111"); + } +#endif + + } else { + l.unlock(); + } + + } +} diff --git a/src/reprocessing_module/save_snapshot_reprocessing.h b/src/reprocessing_module/save_snapshot_reprocessing.h new file mode 100644 index 0000000..3bc0cc6 --- /dev/null +++ b/src/reprocessing_module/save_snapshot_reprocessing.h @@ -0,0 +1,64 @@ +/* + * @Author: yangzilong + * @Date: 2021-12-14 17:51:04 + * @Last Modified by: yangzilong + * @Email: yangzilong@objecteye.com + * @Description: + */ +#pragma once +#include "opencv2/opencv.hpp" +#include "opencv2/highgui/highgui.hpp" +#include +#include +#include +#include +#include + +#include "../ai_platform/det_obj_header.h" +#include "../util/vpc_util.h" + +#ifdef POST_USE_RABBITMQ +#include "post_reprocessing.hpp" +#include +#endif // #ifdef POST_USE_RABBITMQ + +using namespace std; + +class DeviceMemory; + +struct ImgSaveInfo{ + string file_path {""}; + vpc_img_info img_info; + string json_str {""}; +}; + +class save_snapshot_reprocessing +{ +public: + save_snapshot_reprocessing(int devId); + ~save_snapshot_reprocessing(); + void save_snapshot_reprocessing_release(); + +#ifdef POST_USE_RABBITMQ + void set_callback(callback_t cb); +#endif + + void reprocessing_process_wo_locus_async(ImgSaveInfo saveInfo); + +public: + void save_img_process(); + +private: + + queue waitforsave_img_queue; + mutable std::mutex waitforsave_img_queue_mutex; + std::thread m_save_img_thread; + + bool bFinish = false; + int m_devId; + +#ifdef POST_USE_RABBITMQ + callback_t callback_; + std::shared_ptr rbmq_handler_; +#endif +}; diff --git a/src/reprocessing_module/snapshot_reprocessing.cpp b/src/reprocessing_module/snapshot_reprocessing.cpp new file mode 100644 index 0000000..f9c9ead --- /dev/null +++ b/src/reprocessing_module/snapshot_reprocessing.cpp @@ -0,0 +1,173 @@ +#include "snapshot_reprocessing.h" + +#include "../common/logger.hpp" +#include "../ai_platform/mvpt_process_assist.h" +#include "../decoder/interface/DeviceMemory.hpp" + + +snapshot_reprocessing::snapshot_reprocessing() +{ + m_task_param_manager = task_param_manager::getInstance(); + + algor_index_table["human"] = { (int)det_class_label_t::HUMAN }; + algor_index_table["nonmotor_vehicle"] = { (int)det_class_label_t::BICYCLE, (int)det_class_label_t::MOTOCYCLE, (int)det_class_label_t::TRICYCLE }; + algor_index_table["vehicle"] = { (int)det_class_label_t::SMALL_CAR, (int)det_class_label_t::LARGE_CAR, (int)det_class_label_t::TRUCK, (int)det_class_label_t::TRACTOR, (int)det_class_label_t::MEDIUM_BUS }; +} + +static void box_expansion(video_object_info& obj_info, float expand_ratio, int frame_width, int frame_height){ + int origin_width = obj_info.right - obj_info.left; + int origin_height = obj_info.bottom - obj_info.top; + + int expansion_width = origin_width * expand_ratio; + int expansion_height = origin_height * expand_ratio; + + obj_info.left = max(obj_info.left - expansion_width, 0); + obj_info.top = max(obj_info.top - expansion_height, 0); + obj_info.right = min(obj_info.right + expansion_width, frame_width - 1); + obj_info.bottom = min(obj_info.bottom + expansion_height, frame_height - 1); +} + +/* 获取人车物目标快照图 */ +vector snapshot_reprocessing::get_vehicle_snapshot(vector vec_devMem, vector& ol_det_result, int skip_frame) +{ + vector task_in_play_id; + sy_img* images; + + // 过滤出车辆 + filter_vehicle(vec_devMem, ol_det_result); + + map && algor_config_param = m_task_param_manager->get_task_algor_params(); + map> && algor_param = m_task_param_manager->get_task_other_params(); + + vector results; + int idx = 0; + for (auto memPtr : vec_devMem) + { + string task_id = memPtr->getId(); + map> taskid_to_obj; + if (algor_config_param.count(task_id) && algor_config_param[task_id].vehicle_algors.count(algorithm_type_t::VEHICLE_SNAPSHOT)) + { + task_param_manager::algo_param_type_t_* cur_task_params = algor_param[task_id][algorithm_type_t::VEHICLE_SNAPSHOT]; + + // 同一目标间隔多少帧保存 + int snap_frame_interval = ((algor_config_param_snapshot*)cur_task_params->algor_param)->snap_frame_interval; + + onelevel_det_result &cur_task_ol_detres = ol_det_result[idx]; + + for (int c = 0; c < cur_task_ol_detres.obj_count; c++) + { + det_objinfo det_obj = cur_task_ol_detres.obj[c]; + if(snap_frame_interval > 0 && det_obj.num % snap_frame_interval >= skip_frame){ + continue; + } + int type_index = det_obj.index; + if ((type_index == 4 || type_index == 5 || type_index == 6 || type_index ==7 || type_index ==8) + && snapshot_legal_inarea(cur_task_params->basic_param->algor_valid_rect, det_obj.left, det_obj.top, det_obj.right, det_obj.bottom)) + { + video_object_info obj_info; + obj_info.top = det_obj.top; + obj_info.left = det_obj.left; + obj_info.right = det_obj.right; + obj_info.bottom = det_obj.bottom; + obj_info.confidence = det_obj.confidence; + obj_info.index = type_index; + obj_info.object_id = det_obj.id; + + int frame_height = memPtr->getHeight(); + int frame_width = memPtr->getWidth(); + box_expansion(obj_info, EXPANSION_PROPORTION, frame_width, frame_height); + + taskid_to_obj[task_id].emplace_back(std::move(obj_info)); + } + } + + if (taskid_to_obj.size() > 0) + { + static long long gid_ = 0; + + multi_obj_data_t data; + data.memPtr = memPtr; // modified byzsh + data.task_id = task_id; + data.objs = std::move(taskid_to_obj[task_id]); + data.id = gid_++; + results.emplace_back(std::move(data)); + LOG_TRACE("{} {} snap_frame_interval:{}", task_id.c_str(), (int)algorithm_type_t::VEHICLE_SNAPSHOT, snap_frame_interval); + } + } + + idx++; + } + return results; +} + +void snapshot_reprocessing::screen_effective_snapshot(const vector &taskid_inplay, vector &_onelevel_det_result){ + map algor_param = m_task_param_manager->get_task_algor_params(); + + int task_count = _onelevel_det_result.size(); + + int task_idx = 0; + + for (auto taskid : taskid_inplay) + { + int effective_count = 0; + int effective_idx = 0; + + det_objinfo *tmp_det_objinfo = _onelevel_det_result[task_idx].obj; + + for (int c = 0; c < _onelevel_det_result[task_idx].obj_count; c++) + { + // if (algor_index_table["human"].find(tmp_det_objinfo[c].index) != algor_index_table["human"].end() + // && (!algor_param[taskid].human_algors.empty() || !algor_param[taskid].human_face_algors.empty())) // 此处行人和人脸存在耦合,若同一路任务配置了人脸没有配置行人,存抓拍图时会出错 + if (algor_index_table["human"].find(tmp_det_objinfo[c].index) != algor_index_table["human"].end() + && (!algor_param[taskid].human_algors.empty())) // modified by zsh 220714 + { + tmp_det_objinfo[effective_idx++] = tmp_det_objinfo[c]; + effective_count++; + } + + if (algor_index_table["nonmotor_vehicle"].find(tmp_det_objinfo[c].index) != algor_index_table["nonmotor_vehicle"].end() + && !algor_param[taskid].nonmotor_vehicle_algors.empty()) + { + tmp_det_objinfo[effective_idx++] = tmp_det_objinfo[c]; + effective_count++; + } + + if (algor_index_table["vehicle"].find(tmp_det_objinfo[c].index) != algor_index_table["vehicle"].end() + && !algor_param[taskid].vehicle_algors.empty()) + { + tmp_det_objinfo[effective_idx++] = tmp_det_objinfo[c]; + effective_count++; + } + } + + _onelevel_det_result[task_idx++].obj_count = effective_count; + } +} + +void snapshot_reprocessing::filter_vehicle(vector vec_devMem, vector &_onelevel_det_result){ + map algor_param = m_task_param_manager->get_task_algor_params(); + + int task_idx = 0; + + for (auto memPtr : vec_devMem){ + string taskid = memPtr ->getId(); + + int effective_count = 0; + int effective_idx = 0; + + det_objinfo *tmp_det_objinfo = _onelevel_det_result[task_idx].obj; + + for (int c = 0; c < _onelevel_det_result[task_idx].obj_count; c++) + { + if (algor_index_table["vehicle"].find(tmp_det_objinfo[c].index) != algor_index_table["vehicle"].end() + && !algor_param[taskid].vehicle_algors.empty()) + { + tmp_det_objinfo[effective_idx++] = tmp_det_objinfo[c]; + effective_count++; + } + } + + _onelevel_det_result[task_idx].obj_count = effective_count; + task_idx++; + } +} \ No newline at end of file diff --git a/src/reprocessing_module/snapshot_reprocessing.h b/src/reprocessing_module/snapshot_reprocessing.h new file mode 100644 index 0000000..6e8ad66 --- /dev/null +++ b/src/reprocessing_module/snapshot_reprocessing.h @@ -0,0 +1,61 @@ +/* + * @Author: yangzilong + * @Date: 2021-12-17 20:27:57 + * @Last Modified by: yangzilong + * @Email: yangzilong@objecteye.com + * @Description: + */ +#pragma once + +#include "../ai_platform/det_obj_header.h" +#include +#include +#include +#include +#include +#include "../ai_platform/task_param_manager.h" +#include "../ai_platform/header.h" + +// #define EXPANSION_PROPORTION 0.1 +#define EXPANSION_PROPORTION 0.25 +#define FACE_EXPANSION_PROPORTION 0.5 +#define IMG_CHANNELS 3 + +// using namespace std; +using std::vector; +using std::map; +using std::set; + +class DeviceMemory; + +typedef struct multi_obj_data_t{ + long long id; + DeviceMemory *memPtr; + std::vector objs; + string task_id; +} multi_obj_data_t; + +class snapshot_reprocessing +{ +public: + //更新最优快照 + static snapshot_reprocessing* getInstance() + { + static snapshot_reprocessing snapshot_reprocessing_instance; + return &snapshot_reprocessing_instance; + } + + vector get_vehicle_snapshot(vector vec_devMem, vector& ol_det_result, int skip_frame); + +private: + snapshot_reprocessing(); + + map> algor_index_table; + task_param_manager *m_task_param_manager; + +public: + + void screen_effective_snapshot(const vector &taskid_inplay, vector &_onelevel_det_result); + void filter_vehicle(vector vec_devMem, vector &_onelevel_det_result); + +}; \ No newline at end of file diff --git a/src/test/0_38863.jpg b/src/test/0_38863.jpg new file mode 100644 index 0000000..ab94042 --- /dev/null +++ b/src/test/0_38863.jpg diff --git a/src/test/datacasia_20160821_003198.jpg b/src/test/datacasia_20160821_003198.jpg new file mode 100644 index 0000000..f5d820c --- /dev/null +++ b/src/test/datacasia_20160821_003198.jpg diff --git a/src/test/list.txt b/src/test/list.txt new file mode 100644 index 0000000..f23c534 --- /dev/null +++ b/src/test/list.txt @@ -0,0 +1,2 @@ +0_38863.jpg +datacasia_20160821_003198.jpg \ No newline at end of file diff --git a/src/test/test.cpp b/src/test/test.cpp new file mode 100644 index 0000000..df0a254 --- /dev/null +++ b/src/test/test.cpp @@ -0,0 +1,271 @@ +#include +#include +#include +#include "vpt.h" +#include "opencv2/opencv.hpp" +#include "opencv2/imgcodecs/legacy/constants_c.h" +#include "opencv2/imgproc/types_c.h" +#include "time.h" +#include "sys/time.h" +#include "sy_errorinfo.h" +#include "utils.h" +#include "dvpp_process.h" + +#include +#include + +using namespace std; +using namespace cv; + +double msecond() { + struct timeval tv; + gettimeofday(&tv, 0); + return (tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0); +} + + +void getAllNm(std::string pthNm, std::vector& fileList) +{ + DIR *dir; + struct dirent *ptr; + dir = opendir(pthNm.c_str()); ///open the dir + int filenum = 0; + while((ptr = readdir(dir)) != NULL) ///read the list of this dir + { + // char* to string + std::string curNm = ptr->d_name; + if(curNm != "." && curNm != "..") + { + filenum++; + fileList.push_back(curNm); + //printf("file %d name: %s\n", filenum, curNm.c_str()); + } + } + closedir(dir); +} + + +int main() { + cout << vpt_get_version() << endl; + + vpt_param param; + + // param.modelNames = "vtp0716x.om"; + param.modelNames = "vpt0715_310p.om"; + param.threshold = 0.4; + param.devId = 0; + param.isTrk = false; + + + void* handle = nullptr; + cout << "init start " << endl; + ACL_CALL(aclInit(nullptr), ACL_ERROR_NONE, SY_FAILED); + ACL_CALL(aclrtSetDevice(param.devId), ACL_ERROR_NONE, SY_FAILED); + aclrtContext ctx; + ACL_CALL(aclrtCreateContext(&ctx, param.devId), ACL_ERROR_NONE, SY_FAILED); + aclrtStream stream = nullptr; + ACL_CALL(aclrtCreateStream(&stream), ACL_ERROR_NONE, SY_FAILED); + DvppProcess* dvpp = new DvppProcess(); + dvpp->InitResource(stream); + int ret = vpt_init(&handle, param); + + + if (ret == 0) { + cout << "init success " << endl; + + ifstream infile("list.txt"); + string file; + if(1) { + //while (infile >> file) { + // string filename = "700W/" + file; + // string filename = "imgs/" + file; + // const char* img_file_path="examples/"; + const char* img_file_path="imgs/"; + std::vector fileList; + + getAllNm(img_file_path,fileList); + if (fileList.empty()) throw std::logic_error("No suitable images were found"); + + double t3 = 0; + for (auto & file : fileList) { + string filename = img_file_path + file; + + cout << "img path: " << filename << endl; + const int batchsize = 1; + sy_img imgs[batchsize]; + //debug==================================================================== + double pt1,pt2,st1,st2; + st1 = msecond(); + ImageData src[batchsize], dvpp_data[batchsize]; + for (int b = 0; b < batchsize; b++) { + Utils::ReadImageFile(src[b], filename); //将二进制图像读入内存,并读取宽高信息 + pt1 = msecond(); + ACL_CALL(dvpp->CvtJpegToYuv420sp(dvpp_data[b], src[b]), SY_SUCCESS, SY_FAILED); //解码 + pt2 = msecond(); + printf("debug decode time: %.2f\n", pt2 - pt1); + imgs[b].w_ = dvpp_data[b].width;//dvpp_data[b].alignWidth; + imgs[b].h_ = dvpp_data[b].height;//dvpp_data[b].alignHeight; + imgs[b].data_ = dvpp_data[b].data.get(); + } + st2 = msecond(); + printf("debug dvpp process time: %.2f\n", (st2 - st1)/batchsize); + // printf("debug:%d\n",__LINE__); + //debug end================================================================ + vpt_result* results; + double t1,t2; + t1 = msecond(); + int ret = vpt_batch(handle, imgs, batchsize, &results); + t2 = msecond(); + printf("debug mean process time: %.2f\n", (t2 - t1)/batchsize); + t3 = t3 + t2-t1; + + //debug========================================================== + // vpt_result* results_b10; + // t1 = msecond(); + // ret = vpt_batch10(handle, imgs, batchsize, &results_b10); + // t2 = msecond(); + // printf("debug mean batch process time: %.2f\n", (t2 - t1)/batchsize); + //debug end====================================================== + + + // draw results + Mat cvImg = imread(filename.c_str()); + for(int batchIdx = 0; batchIdx < batchsize; batchIdx ++) { + printf("debug det num:%d\n",results[batchIdx].obj_count_); + for (int i = 0; i < results[batchIdx].obj_count_; i++) { + // record=============================================================================================================== + float xmin = results[batchIdx].obj_results_[i].obj_rect.left_; + float ymin = results[batchIdx].obj_results_[i].obj_rect.top_; + float xmax = results[batchIdx].obj_results_[i].obj_rect.width_ + results[batchIdx].obj_results_[i].obj_rect.left_; + float ymax = results[batchIdx].obj_results_[i].obj_rect.height_ + results[batchIdx].obj_results_[i].obj_rect.top_; + float txc = (xmin + xmax) / 2.0; // x center + float tyc = (ymin + ymax) / 2.0; // y center + float tw = results[batchIdx].obj_results_[i].obj_rect.width_; + float th = results[batchIdx].obj_results_[i].obj_rect.height_; + int label = results[batchIdx].obj_results_[i].obj_index; + float score = results[batchIdx].obj_results_[i].obj_score; + //printf("=====:%d %8.12f %8.12f %8.12f %8.12f %8.12f\n",label, xmin/cvImg.cols,ymin/cvImg.rows,xmax/cvImg.cols,ymax/cvImg.rows, score); + //printf("%%%%%:%d %8.12f %8.12f %8.12f %8.12f %8.12f\n",label, txc/cvImg.cols,tyc/cvImg.rows,tw/cvImg.cols,th/cvImg.rows, score); + // record end=========================================================================================================== + Point lt(results[batchIdx].obj_results_[i].obj_rect.left_, results[batchIdx].obj_results_[i].obj_rect.top_); + Point rb((results[batchIdx].obj_results_[i].obj_rect.left_ + + results[batchIdx].obj_results_[i].obj_rect.width_), (results[batchIdx].obj_results_[i].obj_rect.top_ + + results[batchIdx].obj_results_[i].obj_rect.height_)); + rectangle(cvImg, lt, rb, cv::Scalar(0, 0, 255), 4); + // cout << results[batchIdx].obj_results_[i].obj_rect.left_ << " "<< results[batchIdx].obj_results_[i].obj_rect.top_ <<" " << results[batchIdx].obj_results_[i].obj_rect.width_ << " " << results[batchIdx].obj_results_[i].obj_rect.height_ << endl; + + char buffer[50]; + int fontface = cv::FONT_HERSHEY_SIMPLEX; + double scale = 0.8; + int thickness = 2; + int baseline = 0; + snprintf(buffer, sizeof(buffer), "%d:%.2f", results[batchIdx].obj_results_[i].obj_index,results[batchIdx].obj_results_[i].obj_score); + cv::Size text = cv::getTextSize(buffer, fontface, scale, thickness, &baseline); + cv::putText(cvImg, buffer, lt - cv::Point(0, baseline), fontface, + scale, cv::Scalar(0, 0, 255), thickness, 4); + + } + + string jpgSaveName = "result/" + file; + cv::imwrite(jpgSaveName, cvImg); + } + + // for(int batchIdx = 0; batchIdx < batchsize; batchIdx ++){ + // printf("debug det_b10 num:%d\n",results_b10[batchIdx].obj_count_); + // for (int i = 0; i < results_b10[batchIdx].obj_count_; i++) { + // Point lt(results_b10[batchIdx].obj_results_[i].obj_rect.left_, results_b10[batchIdx].obj_results_[i].obj_rect.top_); + // Point rb((results_b10[batchIdx].obj_results_[i].obj_rect.left_ + + // results_b10[batchIdx].obj_results_[i].obj_rect.width_), (results_b10[batchIdx].obj_results_[i].obj_rect.top_ + + // results_b10[batchIdx].obj_results_[i].obj_rect.height_)); + // rectangle(cvImg, lt, rb, cv::Scalar(0, 0, 255), 4); + // // cout << results[batchIdx].obj_results_[i].obj_rect.left_ << " "<< results[batchIdx].obj_results_[i].obj_rect.top_ <<" " << results[batchIdx].obj_results_[i].obj_rect.width_ << " " << results[batchIdx].obj_results_[i].obj_rect.height_ << endl; + + // char buffer[50]; + // int fontface = cv::FONT_HERSHEY_SIMPLEX; + // double scale = 0.8; + // int thickness = 2; + // int baseline = 0; + // snprintf(buffer, sizeof(buffer), "%d:%.2f", results_b10[batchIdx].obj_results_[i].obj_index,results_b10[batchIdx].obj_results_[i].obj_score); + // cv::Size text = cv::getTextSize(buffer, fontface, scale, thickness, &baseline); + // cv::putText(cvImg, buffer, lt - cv::Point(0, baseline), fontface, + // scale, cv::Scalar(0, 0, 255), thickness, 4); + + // } + + // string jpgSaveName = "result/" + file; + // cv::imwrite(jpgSaveName, cvImg); + // } + + } + printf("mean time cost:%f\n",t3/fileList.size()); + } + + + if(0) { + const int batchsize = 10; + sy_img imgs[batchsize]; + ImageData src[batchsize], dvpp_data[batchsize]; + int b = 0; + const char* img_file_path="imgs/"; + std::vector fileList; + + getAllNm(img_file_path,fileList); + if (fileList.empty()) throw std::logic_error("No suitable images were found"); + for (auto & file : fileList) { + string filename = img_file_path + file; + cout << "img path: " << filename << endl; + + //debug==================================================================== + if(b < batchsize) { + Utils::ReadImageFile(src[b], filename); //将二进制图像读入内存,并读取宽高信息 + ACL_CALL(dvpp->CvtJpegToYuv420sp(dvpp_data[b], src[b]), SY_SUCCESS, SY_FAILED); //解码 + imgs[b].w_ = dvpp_data[b].width; + imgs[b].h_ = dvpp_data[b].height; + imgs[b].data_ = dvpp_data[b].data.get(); + b ++; + } + if(b == batchsize) { + b = 0; + vpt_result* results; + double t1,t2; + t1 = msecond(); + int ret = vpt_batch(handle, imgs, batchsize, &results); + t2 = msecond(); + printf("debug mean process time: %.2f\n", (t2 - t1)/batchsize); + //debug========================================================== + // vpt_result* results_b10; + // t1 = msecond(); + // ret = vpt_batch10(handle, imgs, batchsize, &results_b10); + // t2 = msecond(); + // printf("debug mean batch process time: %.2f\n", (t2 - t1)/batchsize); + //debug end====================================================== + + //draw results + for(int batchIdx = 0; batchIdx < batchsize; batchIdx ++){ + printf("debug det num:%d\n",results[batchIdx].obj_count_); + // printf("debug det_b10 num:%d\n",results_b10[batchIdx].obj_count_); + } + + // debug================================ + // for (int b = 0; b < batchsize; b++) { + // delete [] src[b].data.get(); + // delete [] dvpp_data[b].data.get(); + // // delete[] imgs[b].data_ ; + // imgs[b].data_ = NULL; + // } + // debug end============================ + + } + } } + + } + + vpt_release(&handle); + aclrtDestroyStream(stream); + aclrtDestroyContext(ctx); + aclrtResetDevice(param.devId); + aclFinalize(); + + + return 0; +} diff --git a/src/util/JpegUtil.cpp b/src/util/JpegUtil.cpp new file mode 100644 index 0000000..71f7b4f --- /dev/null +++ b/src/util/JpegUtil.cpp @@ -0,0 +1,114 @@ +#include +#include +#include +#include "JpegUtil.h" + +using namespace std; + +namespace DVPP_UTIL { + + int32_t deviceId_; + aclrtContext context_; + aclrtStream stream_; + acldvppChannelDesc *dvppChannelDesc_; + + int dvpp_jpeg_init(int32_t devId){ + deviceId_ = devId; + + aclError ret; + /* 2.Run the management resource application, including Device, Context, Stream */ + aclrtSetDevice(deviceId_); + aclrtCreateContext(&context_, deviceId_); + aclrtCreateStream(&stream_); + + // channel 准备 + dvppChannelDesc_ = acldvppCreateChannelDesc(); + ret = acldvppCreateChannel(dvppChannelDesc_); + } + + void dvpp_jpeg_release(){ + aclError ret; + ret = aclrtSetDevice(deviceId_); + aclrtSetCurrentContext(context_); + + ret = acldvppDestroyChannel(dvppChannelDesc_); + ret = acldvppDestroyChannelDesc(dvppChannelDesc_); + dvppChannelDesc_ = nullptr; + + if (stream_ != nullptr) { + ret = aclrtDestroyStream(stream_); + if (ret != ACL_SUCCESS) { + printf("destroy stream failed"); + } + stream_ = nullptr; + } + printf("end to destroy stream"); + + if (context_ != nullptr) { + ret = aclrtDestroyContext(context_); + if (ret != ACL_SUCCESS) { + printf("destroy context failed"); + } + context_ = nullptr; + } + printf("end to destroy context"); + + ret = aclrtResetDevice(deviceId_); + if (ret != ACL_SUCCESS) { + printf("reset device failed"); + } + printf("end to reset device is %d", deviceId_); + } + + int32_t dvpp_jpege_save(char* pcData , uint32_t dataLen, string out_file_name) + { + FILE* fd = nullptr; + fd = fopen(out_file_name.c_str(), "wb"); + if (fd == nullptr) { + printf("open output file err\n"); + return 1; + } + + fwrite(pcData, dataLen, 1, fd); + fflush(fd); + + fclose(fd); + return 0; + } + + void dvpp_jpeg_encode(acldvppPicDesc *encodeInputDesc_, string out_file_name){ + + aclError aclRet ; + aclRet = aclrtSetDevice(deviceId_); + aclrtSetCurrentContext(context_); + + // 7. 创建图片编码配置数据,设置编码质量 + // 编码质量范围[0, 100],其中level 0编码质量与level 100差不多,而在[1, 100]内数值越小输出图片质量越差。 + acldvppJpegeConfig *jpegeConfig_ = acldvppCreateJpegeConfig(); + acldvppSetJpegeConfigLevel(jpegeConfig_, 100); + + // 8. 申请输出内存,申请Device内存encodeOutBufferDev_,存放编码后的输出数据 + uint32_t outBufferSize= 0; + int ret = acldvppJpegPredictEncSize(encodeInputDesc_, jpegeConfig_, &outBufferSize); + void *encodeOutBufferDev_ = nullptr; + ret = acldvppMalloc(&encodeOutBufferDev_, outBufferSize); + + // 9. 执行异步编码,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 + aclRet = acldvppJpegEncodeAsync(dvppChannelDesc_, encodeInputDesc_, encodeOutBufferDev_, &outBufferSize, jpegeConfig_, stream_); + aclRet = aclrtSynchronizeStream(stream_); + + // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存 + // 申请Host内存outputHostBuffer + void* outputHostBuffer = malloc(outBufferSize); + // 通过aclrtMemcpy接口将Device的处理结果数据传输到Host + aclRet = aclrtMemcpy(outputHostBuffer, outBufferSize, encodeOutBufferDev_, outBufferSize, ACL_MEMCPY_DEVICE_TO_HOST); + // 释放掉输入输出的device内存 + (void)acldvppFree(encodeOutBufferDev_); + encodeOutBufferDev_ = nullptr; + // 数据使用完成后,释放内存 + dvpp_jpege_save((char*)outputHostBuffer, outBufferSize, out_file_name); + free(outputHostBuffer); + outputHostBuffer = nullptr; + } + +} \ No newline at end of file diff --git a/src/util/JpegUtil.h b/src/util/JpegUtil.h new file mode 100644 index 0000000..c2147be --- /dev/null +++ b/src/util/JpegUtil.h @@ -0,0 +1,21 @@ +#ifndef __JPEG_UTIL_H__ +#define __JPEG_UTIL_H__ + +#include + +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" +#include "acl/dvpp/hi_dvpp.h" + +using namespace std; + +namespace DVPP_UTIL { + + int dvpp_jpeg_init(int32_t deviceId_); + + void dvpp_jpeg_release(); + + void dvpp_jpeg_encode(acldvppPicDesc *encodeInputDesc_, string out_file_name); +} + +#endif // __JPEG_UTIL_H__ \ No newline at end of file diff --git a/src/util/crop_process.cpp b/src/util/crop_process.cpp new file mode 100644 index 0000000..d68b0fa --- /dev/null +++ b/src/util/crop_process.cpp @@ -0,0 +1,416 @@ +/** +* @file dvpp_process.cpp +* +* Copyright (C) 2020. Huawei Technologies Co., Ltd. All rights reserved. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ +#include "crop_process.h" +#include +#include +#include +#include +#include +#include "utils.h" +#include "acl/acl_base.h" +#include "acl/acl_rt.h" +#include "acl/acl_op.h" +#include "acl/acl_mdl.h" +#include "acl/ops/acl_dvpp.h" +#include "acl/ops/acl_cblas.h" +#include "../decoder/interface/DeviceMemory.hpp" + +using namespace std; + +namespace { + uint32_t AlignSize(uint32_t origSize, uint32_t alignment) + { + if (alignment == 0) { + return 0; + } + uint32_t alignmentH = alignment - 1; + return (origSize + alignmentH) / alignment * alignment; + } +} + +DvppCropProcess::DvppCropProcess() + : dvppChannelDesc_(nullptr), inputBatchPicDesc_(nullptr), + outputBatchPicDesc_(nullptr), inputBatchSize_(0), outputBatchSize_(0) +{ +} + +DvppCropProcess::~DvppCropProcess() +{ + DestroyBatchCropResource(); +} + +Result DvppCropProcess::InitProcess() +{ + // create vpc channel description + dvppChannelDesc_ = acldvppCreateChannelDesc(); + if (dvppChannelDesc_ == nullptr) { + ERROR_LOG("acldvppCreateChannelDesc failed"); + return FAILED; + } + + // create vpc channel + aclError aclRet = acldvppCreateChannel(dvppChannelDesc_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppCreateChannel failed, errorCode = %d", static_cast(aclRet)); + return FAILED; + } + + // create dvpp resize config + resizeConfig_ = acldvppCreateResizeConfig(); + if (resizeConfig_ == nullptr) { + ERROR_LOG("acldvppCreateResizeConfig failed"); + return FAILED; + } + + INFO_LOG("dvpp init resource success"); + return SUCCESS; +} + +Result DvppCropProcess::InitBatchCropInputDesc(DeviceMemory *devMem) +{ + inputBatchPicDesc_ = acldvppCreateBatchPicDesc(inputBatchSize_); + if (inputBatchPicDesc_ == nullptr) { + ERROR_LOG("InitBatchCropInputDesc inBatchPicDesc failed"); + return FAILED; + } + + acldvppBatchPicDesc *inputBatchPicDesc_ = acldvppCreateBatchPicDesc(1); + acldvppPicDesc *vpcInputDesc_ = acldvppGetPicDesc(inputBatchPicDesc_, 0); + acldvppSetPicDescData(vpcInputDesc_, devMem->getMem()); + acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + acldvppSetPicDescWidth(vpcInputDesc_, devMem->getWidth()); + acldvppSetPicDescHeight(vpcInputDesc_, devMem->getHeight()); + acldvppSetPicDescWidthStride(vpcInputDesc_, devMem->getWidthStride()); + acldvppSetPicDescHeightStride(vpcInputDesc_, devMem->getHeightStride()); + acldvppSetPicDescSize(vpcInputDesc_, devMem->getSize()); + + // if (inputBatchSize_ > batchInput_.size()) { + // inputBatchSize_ = batchInput_.size(); + // } + // uint32_t inputWidth = devMem->getWidth(); + // for (uint32_t i = 0; i < inputBatchSize_; i++) { + // vecInPtr_.push_back(inputBufferDev); + // acldvppPicDesc *vpcInputDesc = acldvppGetPicDesc(inputBatchPicDesc_, i); + // (void)acldvppSetPicDescData(vpcInputDesc, devMem->getMem()); + // (void)acldvppSetPicDescFormat(vpcInputDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + // (void)acldvppSetPicDescWidth(vpcInputDesc, batchInput_[i].inputWidth); + // (void)acldvppSetPicDescHeight(vpcInputDesc, batchInput_[i].inputHeight); + // (void)acldvppSetPicDescWidthStride(vpcInputDesc, inputWidthStride_); + // (void)acldvppSetPicDescHeightStride(vpcInputDesc, inputHeightStride_); + // (void)acldvppSetPicDescSize(vpcInputDesc, inputBufferSize); + // INFO_LOG("set inputDesc success."); + // } + return SUCCESS; +} + +Result DvppCropProcess::InitBatchCropOutputDesc(vector objs) +{ + const uint32_t widthAlignment = 16; + const uint32_t heightAlignment = 16; + const uint32_t sizeAlignment = 3; + const uint32_t sizeNum = 2; + + outputBatchPicDesc_ = acldvppCreateBatchPicDesc(outputBatchSize_); + if (outputBatchPicDesc_ == nullptr) { + ERROR_LOG("acldvppCreatePicDesc outBatchPicDesc failed"); + return FAILED; + } + acldvppPicDesc *vpcOutputDesc = nullptr; + for (uint32_t i = 0; i < outputBatchSize_; i++) { + video_object_info obj = objs[i]; + + int outputWidth_ = obj.right - obj.left; + int outputHeight_ = obj.bottom - obj.top; + int modelInputLeft = obj.left; + int modelInputTop = obj.top; + + uint32_t outputWidthStride = AlignSize(outputWidth_, widthAlignment); + uint32_t outputHeightStride = AlignSize(outputHeight_, heightAlignment); + uint32_t outputBufferSize = outputWidthStride * outputHeightStride * sizeAlignment / sizeNum; + + void *vpcBatchOutputBufferDev = nullptr; + auto ret = acldvppMalloc(&vpcBatchOutputBufferDev, outputBufferSize); + if (ret != ACL_SUCCESS) { + ERROR_LOG("acldvppMalloc failed, size = %u, errorCode = %d.", + outputBufferSize, static_cast(ret)); + return FAILED; + } + vecOutPtr_.push_back(vpcBatchOutputBufferDev); + vpcOutputDesc = acldvppGetPicDesc(outputBatchPicDesc_, i); + (void)acldvppSetPicDescData(vpcOutputDesc, vpcBatchOutputBufferDev); + (void)acldvppSetPicDescFormat(vpcOutputDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + (void)acldvppSetPicDescWidth(vpcOutputDesc, outputWidth_); + (void)acldvppSetPicDescHeight(vpcOutputDesc, outputHeight_); + (void)acldvppSetPicDescWidthStride(vpcOutputDesc, outputWidthStride); + (void)acldvppSetPicDescHeightStride(vpcOutputDesc, outputHeightStride); + (void)acldvppSetPicDescSize(vpcOutputDesc, outputBufferSize); + } + return SUCCESS; +} + +static Result dvpp_jpege_save(char* pcData , uint32_t dataLen, string out_file_name) +{ + FILE* fd = nullptr; + fd = fopen(out_file_name.c_str(), "wb"); + if (fd == nullptr) { + printf("open output file err\n"); + return FAILED; + } + + fwrite(pcData, dataLen, 1, fd); + fflush(fd); + + fclose(fd); + return SUCCESS; +} + +static void dvpp_jpeg_encode(acldvppPicDesc *encodeInputDesc_, string out_file_name){ + + // 2.运行管理资源申请(依次申请Device、Context、Stream) + aclrtContext context_; + aclrtStream stream_; + aclrtSetDevice(0); + aclrtCreateContext(&context_, 0); + aclrtCreateStream(&stream_); + + // 3.创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型 + acldvppChannelDesc *dvppChannelDesc_ = acldvppCreateChannelDesc(); + + // 4.创建图片数据处理的通道 + aclError aclRet = acldvppCreateChannel(dvppChannelDesc_); + + // 7. 创建图片编码配置数据,设置编码质量 + // 编码质量范围[0, 100],其中level 0编码质量与level 100差不多,而在[1, 100]内数值越小输出图片质量越差。 + acldvppJpegeConfig *jpegeConfig_ = acldvppCreateJpegeConfig(); + acldvppSetJpegeConfigLevel(jpegeConfig_, 100); + + // 8. 申请输出内存,申请Device内存encodeOutBufferDev_,存放编码后的输出数据 + uint32_t outBufferSize= 0; + int ret = acldvppJpegPredictEncSize(encodeInputDesc_, jpegeConfig_, &outBufferSize); + void *encodeOutBufferDev_ = nullptr; + ret = acldvppMalloc(&encodeOutBufferDev_, outBufferSize); + + // 9. 执行异步编码,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 + aclRet = acldvppJpegEncodeAsync(dvppChannelDesc_, encodeInputDesc_, encodeOutBufferDev_, + &outBufferSize, jpegeConfig_, stream_); + aclRet = aclrtSynchronizeStream(stream_); + + // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存 + // 申请Host内存outputHostBuffer + void* outputHostBuffer = malloc(outBufferSize); + // 通过aclrtMemcpy接口将Device的处理结果数据传输到Host + aclRet = aclrtMemcpy(outputHostBuffer, outBufferSize, encodeOutBufferDev_, outBufferSize, ACL_MEMCPY_DEVICE_TO_HOST); + // 释放掉输入输出的device内存 + (void)acldvppFree(encodeOutBufferDev_); + // 数据使用完成后,释放内存 + dvpp_jpege_save((char*)outputHostBuffer, outBufferSize, out_file_name); + free(outputHostBuffer); + + acldvppDestroyChannel(dvppChannelDesc_); + (void)acldvppDestroyChannelDesc(dvppChannelDesc_); + dvppChannelDesc_ = nullptr; + + // 11. 释放运行管理资源(依次释放Stream、Context、Device) + aclrtDestroyStream(stream_); + aclrtDestroyContext(context_); + aclrtResetDevice(0); +} + +Result DvppCropProcess::ProcessBatchCrop(DeviceMemory *devMem, vector objs) +{ + inputBatchSize_ = 1; + outputBatchSize_ = objs.size(); + + INFO_LOG("ProcessBatchCrop start."); + const uint32_t oddNum = 1; + + std::unique_ptr + cropArea(new(std::nothrow) acldvppRoiConfig *[outputBatchSize_ * sizeof(acldvppRoiConfig *)]); + + for (uint32_t i = 0; i < outputBatchSize_; i++) { + video_object_info obj = objs[i]; + cropArea[i] = acldvppCreateRoiConfig(obj.left, obj.right, obj.top, obj.bottom); + if (cropArea[i] == nullptr) { + ERROR_LOG("acldvppCreateRoiConfig cropArea_ failed"); + return FAILED; + } + } + Result ret = InitBatchCropInputDesc(devMem); + if (ret != SUCCESS) { + ERROR_LOG("InitBatchCropInputDesc failed"); + return FAILED; + } + + ret = InitBatchCropOutputDesc(objs); + if (ret != SUCCESS) { + ERROR_LOG("InitBatchCropOutputDesc failed"); + return FAILED; + } + + // calculate total number of crop image + uint32_t totalNum = 0; + std::unique_ptr roiNums(new (std::nothrow) uint32_t[inputBatchSize_]); + if (roiNums != nullptr){ + for (int i = 0; i < inputBatchSize_; i++) { + // crop number of images from one source image is outputBatchSize_ / inputBatchSize_ + roiNums[i] = outputBatchSize_ / inputBatchSize_; + totalNum += roiNums[i]; + } + } + // crop number of images from last source image is + // outputBatchSize_ / inputBatchSize_ + outputBatchSize_ % inputBatchSize_ + if (outputBatchSize_ % inputBatchSize_ != 0) { + roiNums[inputBatchSize_ - 1] = (outputBatchSize_ - totalNum) + roiNums[inputBatchSize_ - 1]; + } + + aclError aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0); + aclRet = acldvppVpcBatchCropResizeAsync(dvppChannelDesc_, inputBatchPicDesc_, + roiNums.get(), inputBatchSize_, + outputBatchPicDesc_, cropArea.get(), resizeConfig_, stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppVpcBatchCropAsync failed, errorCode = %d", static_cast(aclRet)); + return FAILED; + } + + aclRet = aclrtSynchronizeStream(stream_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("crop aclrtSynchronizeStream failed, errorCode = %d", static_cast(aclRet)); + return FAILED; + } + + for (uint32_t i = 0; i < outputBatchSize_; i++) { + acldvppPicDesc *vpcOutputDesc = acldvppGetPicDesc(outputBatchPicDesc_, i); + string file_name = "output"; + file_name = file_name + to_string(i) + ".jpg"; + dvpp_jpeg_encode(vpcOutputDesc, file_name); + } + + for (uint32_t i = 0; i < outputBatchSize_; i++) { + if (cropArea[i] != nullptr) { + (void)acldvppDestroyRoiConfig(cropArea[i]); + cropArea[i] = nullptr; + } + } + INFO_LOG("ProcessBatchCrop success."); + return SUCCESS; +} + +void DvppCropProcess::DestroyBatchCropResource() +{ + INFO_LOG("DestroyBatchCropResource start."); + + if (inputBatchPicDesc_ != nullptr) { + (void)acldvppDestroyBatchPicDesc(inputBatchPicDesc_); + inputBatchPicDesc_ = nullptr; + } + for (auto ptr : vecOutPtr_) { + if (ptr != nullptr) { + (void)acldvppFree(ptr); + } + } + vecOutPtr_.clear(); + if (outputBatchPicDesc_ != nullptr) { + (void)acldvppDestroyBatchPicDesc(outputBatchPicDesc_); + outputBatchPicDesc_ = nullptr; + } + if (dvppChannelDesc_ != nullptr) { + aclError aclRet = acldvppDestroyChannel(dvppChannelDesc_); + if (aclRet != ACL_SUCCESS) { + ERROR_LOG("acldvppDestroyChannel failed, errorCode = %d", static_cast(aclRet)); + } + (void)acldvppDestroyChannelDesc(dvppChannelDesc_); + dvppChannelDesc_ = nullptr; + } + + if (resizeConfig_ != nullptr) { + (void)acldvppDestroyResizeConfig(resizeConfig_); + resizeConfig_ = nullptr; + } + + INFO_LOG("DestroyBatchCropResource end."); + return; +} + +Result DvppCropProcess::init(int deviceId) +{ + deviceId_ = deviceId; + + aclError ret; + // ret = aclInit(NULL); + // if (ret != ACL_SUCCESS) { + // ERROR_LOG("acl init failed, errorCode = %d", static_cast(ret)); + // return FAILED; + // } + // INFO_LOG("acl init success"); + + // set device + ret = aclrtSetDevice(deviceId_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("acl set device %d failed, errorCode = %d", deviceId_, static_cast(ret)); + return FAILED; + } + INFO_LOG("set device %d success", deviceId_); + + // create context (set current) + ret = aclrtCreateContext(&context_, deviceId_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("acl create context failed, deviceId = %d, errorCode = %d", + deviceId_, static_cast(ret)); + return FAILED; + } + INFO_LOG("create context success"); + + // create stream + ret = aclrtCreateStream(&stream_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("acl create stream failed, deviceId = %d, errorCode = %d", + deviceId_, static_cast(ret)); + return FAILED; + } + INFO_LOG("create stream success"); + + InitProcess(); + + return SUCCESS; +} + +void DvppCropProcess::DestroyResource() +{ + aclError ret; + if (stream_ != nullptr) { + ret = aclrtDestroyStream(stream_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("destroy stream failed, errorCode = %d", static_cast(ret)); + } + stream_ = nullptr; + } + INFO_LOG("end to destroy stream"); + + if (context_ != nullptr) { + ret = aclrtDestroyContext(context_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("destroy context failed, errorCode = %d", static_cast(ret)); + } + context_ = nullptr; + } + INFO_LOG("end to destroy context"); + + ret = aclrtResetDevice(deviceId_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("reset device %d failed, errorCode = %d", deviceId_, static_cast(ret)); + } + INFO_LOG("end to reset device %d", deviceId_); + + ret = aclFinalize(); + if (ret != ACL_SUCCESS) { + ERROR_LOG("finalize acl failed, errorCode = %d", static_cast(ret)); + } + INFO_LOG("end to finalize acl"); +} diff --git a/src/util/crop_process.h b/src/util/crop_process.h new file mode 100644 index 0000000..54c5dae --- /dev/null +++ b/src/util/crop_process.h @@ -0,0 +1,88 @@ +#ifndef ___CROP_PROCESS_H__ +#define ___CROP_PROCESS_H__ + +#include +#include "acl/ops/acl_dvpp.h" +#include "../ai_platform/header.h" + +using namespace std; + +class DeviceMemory; + +typedef enum Result { + SUCCESS = 0, + FAILED = 1 +} Result; + +class DvppCropProcess { +public: + /** + * @brief Constructor + * @param [in] stream: stream + */ + DvppCropProcess(); + + /** + * @brief Destructor + */ + ~DvppCropProcess(); + +public: + /** + * @brief Process Batch Crop + * @return result + */ + Result ProcessBatchCrop(DeviceMemory *devMem, vector objs); + + /** + * @brief init reousce + * @return result + */ + Result init(int deviceId); + + +private: + /** + * @brief InitBatchCropInputDesc + * @return Result + */ + Result InitBatchCropInputDesc(DeviceMemory *devMem); + + /** + * @brief InitBatchCropOutputDesc + * @return Result + */ + Result InitBatchCropOutputDesc(vector objs); + + /** + * @brief DestroyBatchCropResource + */ + void DestroyBatchCropResource(); + + + void DestroyResource(); + + /** + * @brief init reousce + * @return result + */ + Result InitProcess(); + +private: + int32_t deviceId_; + aclrtContext context_; + aclrtStream stream_; + + acldvppChannelDesc *dvppChannelDesc_; + acldvppResizeConfig *resizeConfig_; + + std::vector vecOutPtr_; + + acldvppBatchPicDesc *inputBatchPicDesc_; // vpc input desc + acldvppBatchPicDesc *outputBatchPicDesc_; // vpc output desc + + uint32_t inputBatchSize_; + uint32_t outputBatchSize_; +}; + +#endif // ___CROP_PROCESS_H__ \ No newline at end of file diff --git a/src/util/util_tools.cpp b/src/util/util_tools.cpp new file mode 100644 index 0000000..e3d1265 --- /dev/null +++ b/src/util/util_tools.cpp @@ -0,0 +1,12 @@ +#include "util_tools.h" + +using namespace std; + +namespace UtilTools{ + long long get_cur_time_ms(){ + chrono::time_point tpMicro + = chrono::time_point_cast(chrono::system_clock::now()); + + return tpMicro.time_since_epoch().count(); + } +} \ No newline at end of file diff --git a/src/util/util_tools.h b/src/util/util_tools.h new file mode 100644 index 0000000..af80ae7 --- /dev/null +++ b/src/util/util_tools.h @@ -0,0 +1,6 @@ +#include + + +namespace UtilTools{ + long long get_cur_time_ms(); +} diff --git a/src/util/vpc_util.cpp b/src/util/vpc_util.cpp new file mode 100644 index 0000000..bbf7c8b --- /dev/null +++ b/src/util/vpc_util.cpp @@ -0,0 +1,414 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" + +#include "vpc_util.h" +#include "JpegUtil.h" +#include "../decoder/interface/DeviceMemory.hpp" + +#define INFO_LOG(fmt, args...) fprintf(stdout, "[INFO] " fmt "\n", ##args) +#define WARN_LOG(fmt, args...) fprintf(stdout, "[WARN] " fmt "\n", ##args) +#define ERROR_LOG(fmt, args...) fprintf(stderr, "[ERROR] " fmt "\n", ##args) + +typedef enum Result { + SUCCESS = 0, + FAILED = 1 +} Result; + +typedef struct PicDesc { + std::string picName; + int width; + int height; +}PicDesc; + +typedef struct CropPicDesc { + std::string picName; + int left; + int top; + int width; + int height; +}CropPicDesc; + +int32_t deviceId_; +aclrtContext context_; +aclrtStream stream_; + +aclvdecChannelDesc *vdecChannelDesc_; +acldvppStreamDesc *streamInputDesc_; +acldvppPicDesc *picOutputDesc_; +acldvppChannelDesc *dvppChannelDesc_; +uint32_t inBufferSize; +uint32_t inputWidth; +uint32_t inputHeight; +aclrtRunMode runMode; + +PicDesc inPicDesc; +CropPicDesc outPicDesc; + + + +uint32_t AlignmentHelper(uint32_t origSize, uint32_t alignment) +{ + if (alignment == 0) { + return 0; + } + uint32_t alignmentH = alignment - 1; + return (origSize + alignmentH) / alignment * alignment; +} + + +void dvpp_crop_release() +{ + aclError ret; + // ret = aclrtSetDevice(deviceId_); + // aclrtSetCurrentContext(context_); + + ret = acldvppDestroyChannel(dvppChannelDesc_); + ret = acldvppDestroyChannelDesc(dvppChannelDesc_); + + if (stream_ != nullptr) { + ret = aclrtDestroyStream(stream_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("destroy stream failed"); + } + stream_ = nullptr; + } + INFO_LOG("end to destroy stream"); + + if (context_ != nullptr) { + ret = aclrtDestroyContext(context_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("destroy context failed"); + } + context_ = nullptr; + } + INFO_LOG("end to destroy context"); + + ret = aclrtResetDevice(deviceId_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("reset device failed"); + } + INFO_LOG("end to reset device is %d", deviceId_); +} + + +int dvpp_crop(acldvppPicDesc *input_pic_desc) +{ + /* 1.ACL initialization */ + // aclInit(nullptr); + + /* 2.Run the management resource application, including Device, Context, Stream */ + aclrtSetDevice(deviceId_); + aclrtCreateContext(&context_, deviceId_); + aclrtCreateStream(&stream_); + aclrtGetRunMode(&runMode); + + /* 3.Initialization parameters: width and height of the original image, crop width and height. + * Initialize folder: Output folder */ + + outPicDesc={"output.jpg", 100, 100, 300, 300}; + + const int orimodelInputWidth = outPicDesc.width; // cur model shape is 224 * 224 + const int orimodelInputHeight = outPicDesc.height; + const int modelInputLeft = outPicDesc.left; // cur model shape is 224 * 224 + const int modelInputTop = outPicDesc.top; + + /* 4. Channel description information when creating image data processing channels, + * dvppChannelDesc_ is acldvppChannelDesc type */ + dvppChannelDesc_ = acldvppCreateChannelDesc(); + + /* 5. Create the image data processing channel. */ + acldvppCreateChannel(dvppChannelDesc_); + + // GetPicDevBuffer4JpegD + int modelInputWidth = (orimodelInputWidth + 15) / 16 * 16; + int modelInputHeight = (orimodelInputHeight + 1) / 2 * 2; + + uint32_t oddNum = 1; + uint32_t cropSizeWidth = modelInputWidth; + uint32_t cropSizeHeight = modelInputHeight; + uint32_t cropLeftOffset = modelInputLeft; // must even + uint32_t cropRightOffset = cropLeftOffset + cropSizeWidth - oddNum; // must odd + uint32_t cropTopOffset = modelInputTop; // must even + uint32_t cropBottomOffset = cropTopOffset + cropSizeHeight - oddNum; // must odd + acldvppRoiConfig *cropArea_ = acldvppCreateRoiConfig(cropLeftOffset, cropRightOffset, cropTopOffset, cropBottomOffset); + + /* processdecode */ + uint32_t vpcOutBufferSize_ = modelInputWidth * modelInputHeight * 3 / 2; + void *vpcOutBufferDev_ = nullptr; + acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_); + acldvppPicDesc *vpcOutputDesc_ = acldvppCreatePicDesc(); + acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_); + acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + acldvppSetPicDescWidth(vpcOutputDesc_, modelInputWidth); + acldvppSetPicDescHeight(vpcOutputDesc_, modelInputHeight); + acldvppSetPicDescWidthStride(vpcOutputDesc_, modelInputWidth); + acldvppSetPicDescHeightStride(vpcOutputDesc_, modelInputHeight); + acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_); + + int ret = acldvppVpcCropAsync(dvppChannelDesc_, input_pic_desc, vpcOutputDesc_, cropArea_, stream_); + + ret = aclrtSynchronizeStream(stream_); + + DVPP_UTIL::dvpp_jpeg_encode(vpcOutputDesc_, "output.jpg"); + + /* DestroycropResource */ + (void)acldvppDestroyRoiConfig(cropArea_); + cropArea_ = nullptr; + (void)acldvppDestroyPicDesc(vpcOutputDesc_); + vpcOutputDesc_ = nullptr; + + if (vpcOutBufferDev_ != nullptr) { + (void)acldvppFree(vpcOutBufferDev_); + vpcOutBufferDev_ = nullptr; + } + + return SUCCESS; +} + +int dvpp_crop_init(int32_t devId){ + deviceId_ = devId; + + aclError ret; + /* 2.Run the management resource application, including Device, Context, Stream */ + aclrtSetDevice(deviceId_); + aclrtCreateContext(&context_, deviceId_); + aclrtCreateStream(&stream_); + aclrtGetRunMode(&runMode); + + // channel 准备 + dvppChannelDesc_ = acldvppCreateChannelDesc(); + ret = acldvppCreateChannel(dvppChannelDesc_); + +} + +void check_coordinate(uint32_t& cropLeftOffset, uint32_t& cropRightOffset, uint32_t& cropTopOffset, uint32_t& cropBottomOffset, uint32_t width, uint32_t height){ + if (cropLeftOffset < 0){ + cropLeftOffset = 0; + } + if (cropTopOffset < 0){ + cropTopOffset = 0; + } + if(cropRightOffset > width){ + cropRightOffset = width; + } + if(cropBottomOffset > height){ + cropBottomOffset = height; + } + +} + +vector dvpp_crop_batch(DeviceMemory *devMem, vector objs){ + + vector vec_img_info; + + /* 1.ACL initialization */ + // aclInit(nullptr); + aclError ret; + aclrtSetDevice(deviceId_); + ret = aclrtSetCurrentContext(context_); + + // 输入 + acldvppBatchPicDesc *vpcInputBatchDesc_ = acldvppCreateBatchPicDesc(1); + acldvppPicDesc *vpcInputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, 0); + acldvppSetPicDescData(vpcInputDesc_, devMem->getMem()); + acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + acldvppSetPicDescWidth(vpcInputDesc_, devMem->getWidth()); + acldvppSetPicDescHeight(vpcInputDesc_, devMem->getHeight()); + acldvppSetPicDescWidthStride(vpcInputDesc_, devMem->getWidthStride()); + acldvppSetPicDescHeightStride(vpcInputDesc_, devMem->getHeightStride()); + acldvppSetPicDescSize(vpcInputDesc_, devMem->getSize()); + + const uint32_t outputBatchSize_ = objs.size(); + // 输出 + acldvppBatchPicDesc *outputBatchPicDesc_ = acldvppCreateBatchPicDesc(outputBatchSize_); + if (outputBatchPicDesc_ == nullptr) { + ERROR_LOG("acldvppCreatePicDesc outBatchPicDesc failed"); + return vec_img_info; + } + vector vecOutPtr_; + acldvppPicDesc *vpcOutputDesc = nullptr; + // acldvppRoiConfig cropAreas[outputBatchSize_]; + // std::unique_ptr + // cropAreas(new(std::nothrow) acldvppRoiConfig *[outputBatchSize_ * sizeof(acldvppRoiConfig *)]); + acldvppRoiConfig *cropAreas[outputBatchSize_]; + for (uint32_t i = 0; i < outputBatchSize_; i++) { + video_object_info obj = objs[i]; + + int orimodelInputWidth = obj.right - obj.left; + int orimodelInputHeight = obj.bottom - obj.top; + // GetPicDevBuffer4JpegD + int modelInputWidth = (orimodelInputWidth + 15) / 16 * 16; + int modelInputHeight = (orimodelInputHeight + 1) / 2 * 2; + + uint32_t oddNum = 1; + uint32_t cropSizeWidth = modelInputWidth; + uint32_t cropSizeHeight = modelInputHeight; + uint32_t cropLeftOffset = obj.left; // must even + uint32_t cropRightOffset = obj.right;//cropLeftOffset + cropSizeWidth - oddNum; // must odd + uint32_t cropTopOffset = obj.top; // must even + uint32_t cropBottomOffset = obj.bottom;//cropTopOffset + cropSizeHeight - oddNum; // must odd + + check_coordinate(cropLeftOffset, cropRightOffset, cropTopOffset, cropBottomOffset, devMem->getWidth(), devMem->getHeight()); + + cropAreas[i] = acldvppCreateRoiConfig(cropLeftOffset, cropRightOffset, cropTopOffset, cropBottomOffset); + + uint32_t vpcOutBufferSize_ = modelInputWidth * modelInputHeight * 3 / 2; + void *vpcBatchOutputBufferDev = nullptr; + auto ret = acldvppMalloc(&vpcBatchOutputBufferDev, vpcOutBufferSize_); + if (ret != ACL_SUCCESS) { + ERROR_LOG("acldvppMalloc failed, size = %u, errorCode = %d.", vpcOutBufferSize_, static_cast(ret)); + // 释放之前成功的部分 再退出 + for(int i = 0; i < vecOutPtr_.size(); i++){ + if (vecOutPtr_[i] != nullptr){ + acldvppFree(vecOutPtr_[i]); + } + } + return vec_img_info; + } + vecOutPtr_.push_back(vpcBatchOutputBufferDev); + vpcOutputDesc = acldvppGetPicDesc(outputBatchPicDesc_, i); + (void)acldvppSetPicDescData(vpcOutputDesc, vpcBatchOutputBufferDev); + (void)acldvppSetPicDescFormat(vpcOutputDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + (void)acldvppSetPicDescWidth(vpcOutputDesc, modelInputWidth); + (void)acldvppSetPicDescHeight(vpcOutputDesc, modelInputHeight); + (void)acldvppSetPicDescWidthStride(vpcOutputDesc, modelInputWidth); + (void)acldvppSetPicDescHeightStride(vpcOutputDesc, modelInputHeight); + (void)acldvppSetPicDescSize(vpcOutputDesc, vpcOutBufferSize_); + } + + uint32_t roiNums[] = { outputBatchSize_ }; + ret = acldvppVpcBatchCropAsync(dvppChannelDesc_, vpcInputBatchDesc_, roiNums, 1, outputBatchPicDesc_, cropAreas, stream_); + ret = aclrtSynchronizeStream(stream_); + + for (uint32_t i = 0; i < outputBatchSize_; i++) { + video_object_info obj = objs[i]; + + vpcOutputDesc = acldvppGetPicDesc(outputBatchPicDesc_, i); + void *outputDataDev = acldvppGetPicDescData(vpcOutputDesc); + uint32_t outputSize = acldvppGetPicDescSize(vpcOutputDesc); + uint32_t width = acldvppGetPicDescWidth(vpcOutputDesc); + uint32_t width_stride = acldvppGetPicDescWidthStride(vpcOutputDesc); + uint32_t height = acldvppGetPicDescHeight(vpcOutputDesc); + uint32_t height_stride = acldvppGetPicDescHeightStride(vpcOutputDesc); + acldvppPixelFormat fmt = acldvppGetPicDescFormat(vpcOutputDesc); + + acldvppPicDesc *vpcInputDesc_= acldvppCreatePicDesc(); + acldvppSetPicDescData(vpcInputDesc_, vecOutPtr_[i]); + acldvppSetPicDescFormat(vpcInputDesc_, fmt); + acldvppSetPicDescWidth(vpcInputDesc_, width); + acldvppSetPicDescHeight(vpcInputDesc_, height); + acldvppSetPicDescWidthStride(vpcInputDesc_, width_stride); + acldvppSetPicDescHeightStride(vpcInputDesc_, height_stride); + acldvppSetPicDescSize(vpcInputDesc_, outputSize); + + vpc_img_info img_info ; + img_info.pic_desc = vpcInputDesc_; + img_info.object_id = obj.object_id; + img_info.task_id = obj.task_id; //该物体属于的任务ID号 + img_info.task_frame_count = obj.task_frame_count; //该物体当前出现的帧号 + img_info.index = obj.index; //该物体所属类别的编号 + img_info.confidence = obj.confidence; //该物体的置信度 + vec_img_info.push_back(img_info); + // vpcOutputDesc = acldvppGetPicDesc(outputBatchPicDesc_, i); + // string file_name = "output"; + // file_name = file_name + to_string(i) + ".jpg"; + // dvpp_jpeg_encode(vpcOutputDesc, file_name); + } + + aclrtSetCurrentContext(context_); + + if (vpcInputBatchDesc_ != nullptr) { + (void)acldvppDestroyBatchPicDesc(vpcInputBatchDesc_); + vpcInputBatchDesc_ = nullptr; + } + + // for(int i = 0; i < vecOutPtr_.size(); i++){ + // if (vecOutPtr_[i] != nullptr){ + // acldvppFree(vecOutPtr_[i]); + // } + // } + + if (outputBatchPicDesc_ != nullptr) { + (void)acldvppDestroyBatchPicDesc(outputBatchPicDesc_); + outputBatchPicDesc_ = nullptr; + } + + // for (size_t i = 0; i < vec_img_info.size(); i++) + // { + // if(vec_img_info[i].pic_desc != nullptr){ + // void *outputDataDev = acldvppGetPicDescData(vec_img_info[i].pic_desc); + // acldvppFree(outputDataDev); + // acldvppDestroyPicDesc(vec_img_info[i].pic_desc); + // } + // } + + + for (uint32_t i = 0; i < outputBatchSize_; i++) { + if (cropAreas[i] != nullptr) { + (void)acldvppDestroyRoiConfig(cropAreas[i]); + cropAreas[i] = nullptr; + } + } + + return vec_img_info; +} + +vpc_img_info dvpp_devMem2vpcImg(DeviceMemory *devMem){ + vpc_img_info img_info ; + + int nBufferSize = devMem->getSize(); + + void *devBuffer = nullptr; + auto ret = acldvppMalloc(&devBuffer, nBufferSize); + if (ret != ACL_SUCCESS) { + ERROR_LOG("acldvppMalloc failed, size = %u, errorCode = %d.", nBufferSize, static_cast(ret)); + // 这里应释放之前成功的部分 再退出 + return img_info; + } + + aclrtMemcpy(devBuffer, nBufferSize, devMem->getMem(), nBufferSize, ACL_MEMCPY_DEVICE_TO_DEVICE); + + acldvppPicDesc *vpcInputDesc_= acldvppCreatePicDesc(); + acldvppSetPicDescData(vpcInputDesc_, devBuffer); + acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + acldvppSetPicDescWidth(vpcInputDesc_, devMem->getWidth()); + acldvppSetPicDescHeight(vpcInputDesc_, devMem->getHeight()); + acldvppSetPicDescWidthStride(vpcInputDesc_, devMem->getWidthStride()); + acldvppSetPicDescHeightStride(vpcInputDesc_, devMem->getHeightStride()); + acldvppSetPicDescSize(vpcInputDesc_, devMem->getSize()); + + img_info.pic_desc = vpcInputDesc_; + img_info.object_id = -1; + img_info.task_id = devMem->getId(); //该物体属于的任务ID号 + img_info.index = -1; //该物体所属类别的编号 + img_info.confidence = 0.0; //该物体的置信度 + + return img_info; +} + +void dvpp_img_release(vpc_img_info img_info){ + if(img_info.pic_desc != nullptr){ + void *outputDataDev = acldvppGetPicDescData(img_info.pic_desc); + acldvppFree(outputDataDev); + acldvppDestroyPicDesc(img_info.pic_desc); + } +} + +void dvpp_imgList_release(vector& imgList){ + for(int i=0; i < imgList.size(); i++){ + dvpp_img_release(imgList[i]); + } + imgList.clear(); +} \ No newline at end of file diff --git a/src/util/vpc_util.h b/src/util/vpc_util.h new file mode 100644 index 0000000..7019425 --- /dev/null +++ b/src/util/vpc_util.h @@ -0,0 +1,38 @@ +#ifndef ___VPC_UTIL_H__ +#define ___VPC_UTIL_H__ + +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" +#include "acl/dvpp/hi_dvpp.h" +#include "../ai_platform/header.h" + +#include +#include + +using namespace std; + +struct vpc_img_info{ + acldvppPicDesc* pic_desc{nullptr}; + string task_id; //该物体属于的任务ID号 + int task_frame_count; //该物体当前出现的帧号 + int object_id; //该物体的ID号 + int index; //该物体所属类别的编号 + double confidence; //该物体的置信度 +}; + +class DeviceMemory; + +int dvpp_crop(acldvppPicDesc *input_pic_desc); + +int dvpp_crop_init(int32_t devId); + +vector dvpp_crop_batch(DeviceMemory *devMem, vector objs); + +void dvpp_img_release(vpc_img_info ); +void dvpp_imgList_release(vector& ); + +void dvpp_crop_release(); + +vpc_img_info dvpp_devMem2vpcImg(DeviceMemory *devMem); + +#endif //___VPC_UTIL_H__ \ No newline at end of file