From 77e1339cc5e9a80442364cb93aa76a7283171d45 Mon Sep 17 00:00:00 2001
From: cmhu <2657262686@qq.com>
Date: Thu, 11 Apr 2024 15:26:23 +0800
Subject: [PATCH] GB28181 补充定时抓拍接口,补充保存视频接口
---
bin/sip_server_cfg.xml | 12 ++++++++++++
src/ai_engine_module/pedestrian_vehicle_trespass.cpp | 17 +++++++++++++++++
src/ai_engine_module/pedestrian_vehicle_trespass.h | 6 ++++++
src/ai_platform/MultiSourceProcess.cpp | 129 ++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------
src/ai_platform/MultiSourceProcess.h | 2 --
src/ai_platform/task_param_manager.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ai_platform/task_param_manager.h | 5 +++++
src/decoder/dvpp/DvppStreamDecoder.cpp | 27 ++++++++++++++++++++++++++-
src/decoder/dvpp/DvppStreamDecoder.h | 8 ++++++++
src/decoder/dvpp/FFRecoder2.cpp | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/decoder/dvpp/FFRecoder2.h | 38 ++++++++++++++++++++++++++++++++++++++
src/decoder/dvpp/FFRecoderTaskManager.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/decoder/dvpp/FFRecoderTaskManager.h | 9 +++++++++
src/decoder/gb28181/DvppGB28181Decoder.cpp | 23 ++++++++++++++++++++---
src/decoder/test_28181.cpp | 13 +------------
src/demo/demo.cpp | 8 ++++----
16 files changed, 639 insertions(+), 115 deletions(-)
create mode 100644 bin/sip_server_cfg.xml
create mode 100644 src/decoder/dvpp/FFRecoder2.cpp
create mode 100644 src/decoder/dvpp/FFRecoder2.h
diff --git a/bin/sip_server_cfg.xml b/bin/sip_server_cfg.xml
new file mode 100644
index 0000000..7b3434c
--- /dev/null
+++ b/bin/sip_server_cfg.xml
@@ -0,0 +1,12 @@
+
+
+ SY_Sip_Server
+ 12345678
+ 192.168.60.179
+ 15060
+ 34020000002000000002
+ 3402000000
+ sy123456
+ 1800
+ 3600
+
diff --git a/src/ai_engine_module/pedestrian_vehicle_trespass.cpp b/src/ai_engine_module/pedestrian_vehicle_trespass.cpp
index 3af7142..e2f0e0a 100755
--- a/src/ai_engine_module/pedestrian_vehicle_trespass.cpp
+++ b/src/ai_engine_module/pedestrian_vehicle_trespass.cpp
@@ -150,10 +150,27 @@ bool PedestrianVehicleTrespass::in_rect_analysis(const obj_key_t &id, const box_
}
}
+bool PedestrianVehicleTrespass::isInited(string task_id) {
+ auto it = m_task_inited.find(task_id);
+ if(it == m_task_inited.end()){
+ return false;
+ }
+ return true;
+}
+
+void PedestrianVehicleTrespass::release(string task_id) {
+ auto it = m_task_inited.find(task_id);
+ if(it != m_task_inited.end()){
+ m_task_inited.erase(it);
+ }
+}
+
/* 根据用户输入的点 初始化禁区区域mask */
void PedestrianVehicleTrespass::pedestrianvehicletrespass_init_region(const string &task_id,
const algorithm_type_t algor_type,
const int width, const int height) {
+ m_task_inited[task_id] = true;
+
obj_key_t obj_key = {0, task_id, algor_type};
auto &&algor_type_seq = task_id_to_algorithm_type_seq(task_id, task_param_manager_);
diff --git a/src/ai_engine_module/pedestrian_vehicle_trespass.h b/src/ai_engine_module/pedestrian_vehicle_trespass.h
index fcca210..253857b 100755
--- a/src/ai_engine_module/pedestrian_vehicle_trespass.h
+++ b/src/ai_engine_module/pedestrian_vehicle_trespass.h
@@ -34,6 +34,10 @@ public:
~PedestrianVehicleTrespass();
+ bool isInited(string task_id);
+
+ void release(string task_id);
+
void pedestrianvehicletrespass_init_region(const string &task_id, const algorithm_type_t algor_type, const int width,
const int height);
@@ -55,6 +59,8 @@ private:
std::map > obj_to_alarm_boxes_;
std::map obj_to_position_; // 保存物体上一帧的位置,基于非法闯入判断逻辑,上一帧在框外,下一帧闯入禁区
std::map trespass_regions;
+
+ std::map m_task_inited;
};
} // namespace pedestrian_vehicle_trespass
} // namespace ai_engine_module
diff --git a/src/ai_platform/MultiSourceProcess.cpp b/src/ai_platform/MultiSourceProcess.cpp
index e3c2520..6f58d60 100755
--- a/src/ai_platform/MultiSourceProcess.cpp
+++ b/src/ai_platform/MultiSourceProcess.cpp
@@ -322,7 +322,7 @@ int CMultiSourceProcess::GetTaskStatus(const string taskID) {
bool CMultiSourceProcess::AddTask(task_param _cur_task_param){
DecoderManager* pDecManager = DecoderManager::getInstance();
- const char* task_id = _cur_task_param.task_id;
+ string task_id = _cur_task_param.task_id;
MgrDecConfig config;
config.name = task_id;
@@ -360,7 +360,7 @@ bool CMultiSourceProcess::AddTask(task_param _cur_task_param){
}
decode_cbk_userdata* userPtr = new decode_cbk_userdata;
- userPtr->task_id = string(task_id);
+ userPtr->task_id = task_id;
userPtr->opaque = this;
userPtr->opaque1 = dec;
pDecManager->setPostDecArg(config.name, userPtr);
@@ -372,11 +372,6 @@ bool CMultiSourceProcess::AddTask(task_param _cur_task_param){
// 保存新添加任务的配置参数
m_task_param_manager->add_task_param(task_id, _cur_task_param);
- int input_image_width = 0;
- int input_image_height = 0;
- pDecManager->getOutResolution(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){
@@ -391,12 +386,12 @@ bool CMultiSourceProcess::AddTask(task_param _cur_task_param){
#endif
// 人车物跟踪
- if (task_has_vpt_algor(task_id))
+ if (m_task_param_manager->task_has_vpt_algor(task_id))
vpt_process.addTaskTracker(task_id, 1, 1, skip_frame_);
// 人脸跟踪
#ifdef WITH_FACE_DET_SS
- if (task_has_face_algor(task_id))
+ if (m_task_param_manager->task_has_face_algor(task_id))
m_face_det_ai_engine.add_tracker(task_id, skip_frame_); // 跳帧数暂时写死
#endif
@@ -404,37 +399,9 @@ bool CMultiSourceProcess::AddTask(task_param _cur_task_param){
m_FinishedTaskMap[task_id] = false;
m_FinishedTaskMtx.unlock();
- auto algor_map = m_task_param_manager->get_task_other_param(task_id);
- if (algor_map != nullptr){
- /* 如果开启了行人 机动车非法闯入功能 生成闯入区域mask */
- if (algor_map->find(algorithm_type_t::PEDESTRIAN_TRESPASS) != algor_map->end()) {
- pedestrian_vehicle_trespass_.pedestrianvehicletrespass_init_region(
- task_id, algorithm_type_t::PEDESTRIAN_TRESPASS, input_image_width, input_image_height);
- }
-
- if (algor_map->find(algorithm_type_t::VEHICLE_TRESPASS) != algor_map->end()) {
- pedestrian_vehicle_trespass_.pedestrianvehicletrespass_init_region(
- task_id, algorithm_type_t::VEHICLE_TRESPASS, input_image_width, input_image_height);
- }
-
- // 设置定时截图的时间间隔
- auto algor = algor_map->find(algorithm_type_t::VIDEO_TIMING_SNAPSHOT);
- if(algor != algor_map->end()){
- task_param_manager::algo_param_type_t_* cur_task_params = algor->second;
- if(cur_task_params){
- int frame_stride = ((algor_config_video_timing_snapshot*)cur_task_params->algor_param)->frame_stride;
- LOG_INFO("task {} snap time interval: {} s", config.name, frame_stride);
- // 单位是ms, 乘以 1000 编成s
- dec->setSnapTimeInterval(frame_stride * 1000);
- }
- }
-
- // 测试代码
- // auto algor_face = algor_map->find(algorithm_type_t::FACE_SNAPSHOT);
- // if(algor_face != algor_map->end()){
- // const algor_basic_config_param_t *cur_param = ((algor_init_config_param_t *)(algor_face->second))->basic_param;
- // LOG_INFO("face_snapshot, result_folder: {} result_folder_little: {}", cur_param->result_folder, cur_param->result_folder_little);
- // }
+ int time_interval = m_task_param_manager->get_video_timing_snapshot_interval(task_id);
+ if(time_interval > 0) {
+ dec->setSnapTimeInterval(time_interval);
}
LOG_INFO("started task {} successed!", config.name);
@@ -447,55 +414,6 @@ int CMultiSourceProcess::CountRunningTask() {
return pDecManager->count();
}
-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() ||
- algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_NOHELMET) != algor_map->end() ||
- algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_OVERMAN) != algor_map->end() ||
- algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_USEPHONE) != algor_map->end() ||
- algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_REFIT) != algor_map->end() ||
- algor_map->find(algorithm_type_t::NONMOTOR_RUNNING_REDLIGHTS) != algor_map->end() ||
- algor_map->find(algorithm_type_t::NONMOTOR_CEOSSPARKLINE) != algor_map->end() ||
- algor_map->find(algorithm_type_t::NONMOTOR_IN_VEHICLELANE) != algor_map->end() ||
- algor_map->find(algorithm_type_t::NONMOTOR_WRONGDIRECTION) != algor_map->end() ||
- algor_map->find(algorithm_type_t::PERSON_IN_VEHICLELANE) != algor_map->end() ||
- algor_map->find(algorithm_type_t::PERSON_RUNNING_REDLIGHTS) != algor_map->end() ||
- algor_map->find(algorithm_type_t::PERSON_CROSS) != algor_map->end() ||
- algor_map->find(algorithm_type_t::VEHICLE_WRONGDIRECTION) != algor_map->end() ||
- algor_map->find(algorithm_type_t::VEHICLE_SOLIDLINETURNAROUND) != algor_map->end() ||
- algor_map->find(algorithm_type_t::VEHICLE_NOTGIVEWAY) != algor_map->end() ||
- algor_map->find(algorithm_type_t::VEHICLE_NOTDECELERATION) != algor_map->end() ||
- algor_map->find(algorithm_type_t::TRICYCLE_MANNED) != algor_map->end() ||
- algor_map->find(algorithm_type_t::TRUCK_MANNED) != algor_map->end());
-}
-
-bool CMultiSourceProcess::task_has_face_algor(const std::string &task_id){
- auto algor_map = m_task_param_manager->get_task_other_param(task_id);
- if (nullptr != algor_map){
- return algor_map->find(algorithm_type_t::FACE_SNAPSHOT) != algor_map->end();
- }
-
- return false;
-}
-
void CMultiSourceProcess::decoded_cbk(DeviceMemory* devFrame){
do{
@@ -689,12 +607,13 @@ void CMultiSourceProcess::clear_finished_task(){// 清理已经结束的任务
// 解码器已经结束,且数据队列中没有改任务的数据,则做最后任务清理工作
finish_task(task_id,false);
iter_finished = m_FinishedTaskMap.erase(iter_finished);
+ pedestrian_vehicle_trespass_.release(task_id);
continue;
}
}
++ iter_finished;
- }
+ }
}
bool CMultiSourceProcess::finish_task(const string taskID, const bool delete_snapshot){
@@ -705,7 +624,7 @@ bool CMultiSourceProcess::finish_task(const string taskID, const bool delete_sna
#ifdef WITH_FACE_DET_SS
// 人脸任务结束
- if (task_has_face_algor(taskID))
+ if (m_task_param_manager->task_has_face_algor(taskID))
m_face_det_ai_engine.finish_task(taskID);
#endif
@@ -805,6 +724,30 @@ int CMultiSourceProcess::algorthim_process_thread(){
LOG_WARN("mem is null");
} else {
vec_gpuMem.push_back(gpuMem);
+
+ string task_id = gpuMem->getId();
+ if (!pedestrian_vehicle_trespass_.isInited(task_id)) {
+ auto algor_map = m_task_param_manager->get_task_other_param(task_id);
+ if (algor_map != nullptr) {
+ int input_image_width = gpuMem->getWidth();
+ int input_image_height = gpuMem->getHeight();
+ LOG_INFO("task_id: {} width: {} height:{}", task_id, input_image_width, input_image_height);
+
+ /* 如果开启了行人 机动车非法闯入功能 生成闯入区域mask */
+ if (algor_map->find(algorithm_type_t::PEDESTRIAN_TRESPASS) != algor_map->end()) {
+ pedestrian_vehicle_trespass_.pedestrianvehicletrespass_init_region(
+ task_id, algorithm_type_t::PEDESTRIAN_TRESPASS, input_image_width, input_image_height);
+ }
+
+ if (algor_map->find(algorithm_type_t::VEHICLE_TRESPASS) != algor_map->end()) {
+ pedestrian_vehicle_trespass_.pedestrianvehicletrespass_init_region(
+ task_id, algorithm_type_t::VEHICLE_TRESPASS, input_image_width, input_image_height);
+ }
+ }
+ }
+
+
+
}
m_RgbDataList.pop_front();
@@ -913,7 +856,7 @@ int CMultiSourceProcess::algorthim_vpt(vector vec_gpuMem){
vector vec_vptMem;
for (int i = 0; i < vec_gpuMem.size(); i++) {
DeviceMemory* mem = vec_gpuMem[i];
- if (!task_has_vpt_algor(mem->getId())){
+ if (!m_task_param_manager->task_has_vpt_algor(mem->getId())){
continue;
}
@@ -2100,7 +2043,7 @@ void CMultiSourceProcess::algorthim_face_detect(vector vec_gpuMem
vector vec_vptMem;
for (int i = 0; i < vec_gpuMem.size(); i++) {
DeviceMemory* mem = vec_gpuMem[i];
- if (!task_has_face_algor(mem->getId())){
+ if (!m_task_param_manager->task_has_face_algor(mem->getId())){
continue;
}
diff --git a/src/ai_platform/MultiSourceProcess.h b/src/ai_platform/MultiSourceProcess.h
index 64b920a..18f3f15 100755
--- a/src/ai_platform/MultiSourceProcess.h
+++ b/src/ai_platform/MultiSourceProcess.h
@@ -101,8 +101,6 @@ private:
private:
// 工具处理函数
- bool task_has_vpt_algor(const std::string &task_id);
- bool task_has_face_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);
diff --git a/src/ai_platform/task_param_manager.cpp b/src/ai_platform/task_param_manager.cpp
index dc76bde..41381c7 100755
--- a/src/ai_platform/task_param_manager.cpp
+++ b/src/ai_platform/task_param_manager.cpp
@@ -542,3 +542,78 @@ map task_param_manager::get_task_algor_params()
map> task_param_manager::get_task_other_params() {
return m_task_params;
}
+
+bool task_param_manager::task_has_vpt_algor(const std::string &task_id) {
+ auto algor_map = 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() ||
+ algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_NOHELMET) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_OVERMAN) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_USEPHONE) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::NONMOTOR_VEHICLE_REFIT) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::NONMOTOR_RUNNING_REDLIGHTS) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::NONMOTOR_CEOSSPARKLINE) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::NONMOTOR_IN_VEHICLELANE) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::NONMOTOR_WRONGDIRECTION) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::PERSON_IN_VEHICLELANE) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::PERSON_RUNNING_REDLIGHTS) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::PERSON_CROSS) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::VEHICLE_WRONGDIRECTION) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::VEHICLE_SOLIDLINETURNAROUND) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::VEHICLE_NOTGIVEWAY) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::VEHICLE_NOTDECELERATION) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::TRICYCLE_MANNED) != algor_map->end() ||
+ algor_map->find(algorithm_type_t::TRUCK_MANNED) != algor_map->end());
+}
+
+bool task_param_manager::task_has_face_algor(const std::string &task_id) {
+ auto algor_map = get_task_other_param(task_id);
+ if (nullptr != algor_map){
+ return algor_map->find(algorithm_type_t::FACE_SNAPSHOT) != algor_map->end();
+ }
+
+ return false;
+}
+
+int task_param_manager::get_video_timing_snapshot_interval(std::string& task_id) {
+ auto algor_map = get_task_other_param(task_id);
+ if (algor_map != nullptr) {
+
+ // 设置定时截图的时间间隔
+ auto algor = algor_map->find(algorithm_type_t::VIDEO_TIMING_SNAPSHOT);
+ if(algor != algor_map->end()){
+ task_param_manager::algo_param_type_t_* cur_task_params = algor->second;
+ if(cur_task_params){
+ int frame_stride = ((algor_config_video_timing_snapshot*)cur_task_params->algor_param)->frame_stride;
+ LOG_INFO("task {} snap time interval: {} s", task_id, frame_stride);
+ // 单位是ms, 乘以 1000 编成s
+ return frame_stride * 1000;
+ }
+ }
+
+ // 测试代码
+ // auto algor_face = algor_map->find(algorithm_type_t::FACE_SNAPSHOT);
+ // if(algor_face != algor_map->end()){
+ // const algor_basic_config_param_t *cur_param = ((algor_init_config_param_t *)(algor_face->second))->basic_param;
+ // LOG_INFO("face_snapshot, result_folder: {} result_folder_little: {}", cur_param->result_folder, cur_param->result_folder_little);
+ // }
+ }
+
+ return -1;
+}
\ No newline at end of file
diff --git a/src/ai_platform/task_param_manager.h b/src/ai_platform/task_param_manager.h
index cebb772..4161423 100755
--- a/src/ai_platform/task_param_manager.h
+++ b/src/ai_platform/task_param_manager.h
@@ -43,6 +43,11 @@ public:
map> get_task_other_params();
void task_param_manager_release();
+ bool task_has_vpt_algor(const std::string &task_id);
+ bool task_has_face_algor(const std::string &task_id);
+
+ int get_video_timing_snapshot_interval(std::string& task_id);
+
private:
task_param_manager();
task_param_manager(const task_param_manager& other);
diff --git a/src/decoder/dvpp/DvppStreamDecoder.cpp b/src/decoder/dvpp/DvppStreamDecoder.cpp
index 91f8dde..d0e8a57 100644
--- a/src/decoder/dvpp/DvppStreamDecoder.cpp
+++ b/src/decoder/dvpp/DvppStreamDecoder.cpp
@@ -479,6 +479,10 @@ int DvppStreamDecoder::SendData(int videoType, char* data, int len, int isKey, u
m_frame_nb++;
+ #ifdef USE_VILLAGE
+ m_recoderManager.cache_pkt(pkt, m_frame_nb);
+#endif
+
// dvpp 解码
nSended = sendPkt(vdecChannelDesc, pkt, m_frame_nb, vdec_out_size);
}
@@ -568,7 +572,11 @@ int DvppStreamDecoder::parse_stream_info(int videoType, AVPacket* pkt) {
av_bsf_init(h264bsfc);
}
- m_fps = av_q2d(avctx->framerate);
+ if (avctx->framerate.den) {
+ m_fps = av_q2d(avctx->framerate);
+ } else {
+ m_fps = 0.0;
+ }
AVFrame* frame = av_frame_alloc();
do
@@ -587,6 +595,13 @@ int DvppStreamDecoder::parse_stream_info(int videoType, AVPacket* pkt) {
m_vdec_out_size = frame->width * frame->height * 3 / 2;
} while (0);
+#ifdef USE_VILLAGE
+ bool bRet = m_recoderManager.init2(frame->width, frame->height, m_fps, avctx->bit_rate);
+ if (!bRet){
+ LOG_ERROR("[{}]- m_recoderManager 初始化失败!", m_dec_name);
+ }
+#endif
+
av_frame_free(&frame);
frame = nullptr;
@@ -629,7 +644,17 @@ void DvppStreamDecoder::Close() {
h264bsfc = nullptr;
}
+ m_recoderManager.close();
+
if(decode_finished_cbk) {
decode_finished_cbk(m_finishedDecArg);
}
+}
+
+void DvppStreamDecoder::doRecode(RecoderInfo& recoderInfo) {
+ m_recoderManager.create_recode_task(recoderInfo);
+}
+
+void DvppStreamDecoder::set_mq_callback(mq_callback_t cb) {
+ m_recoderManager.set_mq_callback(cb);
}
\ No newline at end of file
diff --git a/src/decoder/dvpp/DvppStreamDecoder.h b/src/decoder/dvpp/DvppStreamDecoder.h
index 1b3a657..3ff281c 100644
--- a/src/decoder/dvpp/DvppStreamDecoder.h
+++ b/src/decoder/dvpp/DvppStreamDecoder.h
@@ -6,6 +6,8 @@
#include "VpcUtils.h"
+#include "FFRecoderTaskManager.h"
+
using namespace std;
class DvppStreamDecoder
@@ -22,6 +24,10 @@ public:
DvppDataMemory* GetFrame();
+ void doRecode(RecoderInfo& recoderInfo);
+
+ void set_mq_callback(mq_callback_t cb);
+
public:
void doProcessReport();
void doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData);
@@ -73,6 +79,8 @@ private:
uint64_t m_out_count {0};
bool m_bResize {false};
+
+ FFRecoderTaskManager m_recoderManager;
};
diff --git a/src/decoder/dvpp/FFRecoder2.cpp b/src/decoder/dvpp/FFRecoder2.cpp
new file mode 100644
index 0000000..caefb3b
--- /dev/null
+++ b/src/decoder/dvpp/FFRecoder2.cpp
@@ -0,0 +1,261 @@
+// FFRecoder2.cpp
+#include "FFRecoder2.h"
+#include
+#include
+#include
+
+extern "C" {
+#include
+#include
+#include
+#include
+#include
+#include
+}
+
+
+FFRecoder2::FFRecoder2()
+ :width_{},
+ height_{},
+ y_size_{},
+ uv_size_{},
+ pts_{},
+ codec_ctx_{ nullptr },
+ fmt_ctx_{ nullptr },
+ out_stream_{ nullptr },
+ yuv_frame_{ nullptr }
+{
+}
+
+FFRecoder2::~FFRecoder2()
+{
+ uninit();
+}
+
+
+bool FFRecoder2::init(int w, int h, int fps, int bit_rate, const char* outfile_name)
+{
+ uninit();
+
+ width_ = w;
+ height_ = h;
+ y_size_ = w * h;
+ uv_size_ = y_size_ / 4;
+
+ // [1] 创建解码器
+ const AVCodec* encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
+ if (!encoder) {
+ fprintf(stderr, "Find encoder AV_CODEC_ID_H264 failed!\n");
+ return false;
+ }
+ // 获取解码器上下文
+ codec_ctx_ = avcodec_alloc_context3(encoder);
+ if (!codec_ctx_) {
+ fprintf(stderr, "Alloc context for encoder contx failed!\n");
+ return false;
+ }
+ // 设置解码器上下文参数
+ codec_ctx_->bit_rate = bit_rate;
+ codec_ctx_->width = width_;
+ codec_ctx_->height = height_;
+ codec_ctx_->time_base = AVRational{ 1, fps };
+ codec_ctx_->gop_size = 50;
+ codec_ctx_->max_b_frames = 0;
+ codec_ctx_->pix_fmt = AV_PIX_FMT_YUV420P;
+ codec_ctx_->thread_count = 4;
+ codec_ctx_->qmin = 10;
+ codec_ctx_->qmax = 51;
+ codec_ctx_->qcompress = 0.6f;
+ codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+
+ //av_opt_set(codec_ctx_->priv_data, "preset", "ultrafast", 0);
+ av_opt_set(codec_ctx_->priv_data, "tune", "zerolatency", 0);
+
+ // 打开解码器
+ if (avcodec_open2(codec_ctx_, encoder, nullptr) < 0) {
+ fprintf(stderr, "Open encoder failed!\n");
+ return false;
+ }
+
+ // [2] 创建输出上下文
+ avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr, outfile_name);
+
+ // [3] 添加输出视频流
+ out_stream_ = avformat_new_stream(fmt_ctx_, nullptr);
+ out_stream_->id = 0;
+ out_stream_->codecpar->codec_tag = 0;
+ avcodec_parameters_from_context(out_stream_->codecpar, codec_ctx_);
+
+ av_dump_format(fmt_ctx_, out_stream_->id, outfile_name, 1);
+
+ // 创建YUV格式帧
+ yuv_frame_ = av_frame_alloc();
+ yuv_frame_->format = AV_PIX_FMT_YUV420P;
+ yuv_frame_->width = width_;
+ yuv_frame_->height = height_;
+ // 为创建的YUV帧分配内存
+ if (av_frame_get_buffer(yuv_frame_, 0) < 0) {
+ av_frame_free(&yuv_frame_);
+ yuv_frame_ = nullptr;
+ fprintf(stderr, "Frame get buffer failed!\n");
+ return false;
+ }
+
+ // [5] 打开输出视频文件并写入视频头信息
+ if (avio_open(&fmt_ctx_->pb, outfile_name, AVIO_FLAG_WRITE) < 0) {
+ fprintf(stderr, "avio_open failed!\n");
+ return false;
+ }
+ if (avformat_write_header(fmt_ctx_, nullptr) < 0) {
+ fprintf(stderr, "Write header failed!\n");
+ return false;
+ }
+
+ return true;
+}
+
+void FFRecoder2::uninit()
+{
+ if (fmt_ctx_) {
+ av_write_trailer(fmt_ctx_);
+ avio_close(fmt_ctx_->pb);
+ avformat_free_context(fmt_ctx_);
+ fmt_ctx_ = nullptr;
+ }
+
+ if (codec_ctx_) {
+ avcodec_close(codec_ctx_);
+ avcodec_free_context(&codec_ctx_);
+ codec_ctx_ = nullptr;
+ }
+
+ if (yuv_frame_) {
+ av_frame_free(&yuv_frame_);
+ yuv_frame_ = nullptr;
+ }
+
+ width_ = 0;
+ height_ = 0;
+ y_size_ = 0;
+ uv_size_ = 0;
+ pts_ = 0;
+}
+
+bool FFRecoder2::write_image(const uint8_t* bgr)
+{
+ // 分配YUV格式数据的内存
+ thread_local std::vector yuv_data;
+ if (yuv_data.size() != y_size_ * 3 / 2) {
+ yuv_data.resize(y_size_ * 3 / 2);
+ }
+ // BGR格式转YUV格式
+ bgr_to_yuv420p(bgr, yuv_data.data());
+
+ return write_yuv(yuv_data.data());
+}
+
+bool FFRecoder2::write_yuv(const uint8_t* yuv_data)
+{
+ //拷贝YUV数据到帧,由于帧数据存在内存对齐,故需逐行拷贝
+ for (int i = 0; i < height_; i++) {
+ memcpy(yuv_frame_->data[0] + i * yuv_frame_->linesize[0], yuv_data + width_ * i, width_);
+ }
+ const int uv_stride = width_ / 2;
+ for (int i = 0; i < height_ / 2; i++) {
+ memcpy(yuv_frame_->data[1] + i * yuv_frame_->linesize[1], yuv_data + y_size_ + uv_stride * i, uv_stride);
+ memcpy(yuv_frame_->data[2] + i * yuv_frame_->linesize[2], yuv_data + y_size_ + uv_size_ + uv_stride * i, uv_stride);
+ }
+
+ yuv_frame_->pts = pts_++;
+
+ return write_frame(yuv_frame_);
+}
+
+bool FFRecoder2::write_frame(const AVFrame* frame)
+{
+ char errbuf[64]{ 0 };
+ // 将帧数据发送到编码器
+ int ret = avcodec_send_frame(codec_ctx_, frame);
+ if (ret < 0) {
+ fprintf(stderr, "Error sending a frame to the encoder: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret));
+ return false;
+ }
+
+ while (true) {
+ AVPacket pkt{ 0 };
+ // 获取编码后的数据
+ ret = avcodec_receive_packet(codec_ctx_, &pkt);
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ return true;
+ else if (ret < 0) {
+ fprintf(stderr, "Error encoding a frame: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret));
+ return false;
+ }
+ // 将pts缩放到输出流的time_base上
+ av_packet_rescale_ts(&pkt, codec_ctx_->time_base, out_stream_->time_base);
+ pkt.stream_index = out_stream_->index;
+ // 将数据写入到输出流
+ ret = av_interleaved_write_frame(fmt_ctx_, &pkt);
+ av_packet_unref(&pkt);
+ if (ret < 0) {
+ fprintf(stderr, "Error while writing output packet: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool FFRecoder2::write_pkt(AVPacket* pkt) {
+ // 将pts缩放到输出流的time_base上
+ av_packet_rescale_ts(pkt, codec_ctx_->time_base, out_stream_->time_base);
+ pkt->stream_index = out_stream_->index;
+ // 将数据写入到输出流
+ int ret = av_interleaved_write_frame(fmt_ctx_, pkt);
+
+ char errbuf[64]{ 0 };
+ if (ret < 0) {
+ fprintf(stderr, "Error while writing output packet: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret));
+ return false;
+ }
+
+ return true;
+}
+
+bool FFRecoder2::flush()
+{
+ return write_frame(nullptr);
+}
+
+bool FFRecoder2::bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_420p)
+{
+ // 分配转换上下文
+ thread_local std::tuple params{ 0, 0, 0 };
+ thread_local std::unique_ptr sws_context{ nullptr, &sws_freeContext };
+
+ std::tuple new_params{ width_, height_, av_image_get_linesize(AV_PIX_FMT_YUV420P, width_, 0) };
+ if (!sws_context || params != new_params)
+ {
+ sws_context.reset(sws_getContext(width_, height_, AV_PIX_FMT_BGR24, width_, height_,
+ AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr));
+ params = new_params;
+ }
+
+ // 转换格式
+ const int stride = std::get<2>(params);//Y平面一行的数据长度
+ const int ret = sws_scale(sws_context.get(),
+ &buf_bgr,/* bgr数据只有一个平面 */
+ std::array {width_ * 3}.data(),/* BGR所以图像宽度*3 */
+ 0, height_,
+ std::array{ buf_420p, buf_420p + y_size_, buf_420p + y_size_ + uv_size_ }.data(),/* YUV三个平面的起始地址 */
+ std::array{ stride, stride / 2, stride / 2 }.data()
+ );/* YUV每个平面中一行的宽度 */
+
+ return ret >= 0;
+}
+
+bool FFRecoder2::close()
+{
+ flush();
+ uninit();
+}
\ No newline at end of file
diff --git a/src/decoder/dvpp/FFRecoder2.h b/src/decoder/dvpp/FFRecoder2.h
new file mode 100644
index 0000000..2ac361c
--- /dev/null
+++ b/src/decoder/dvpp/FFRecoder2.h
@@ -0,0 +1,38 @@
+#pragma once
+#include
+
+class AVFrame;
+class AVStream;
+class AVCodecContext;
+class AVFormatContext;
+class AVPacket;
+
+class FFRecoder2
+{
+public:
+ FFRecoder2();
+ ~FFRecoder2();
+
+ bool init(int w, int h, int fps, int bit_rate, const char* outfile_name);
+ void uninit();
+ bool write_image(const uint8_t* bgr);
+ bool write_yuv(const uint8_t* yuv_data);
+ bool write_frame(const AVFrame* frame);
+ bool write_pkt(AVPacket* pkt);
+ bool flush();
+ bool close();
+
+private:
+ bool bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_420p);
+
+private:
+ int width_;
+ int height_;
+ int y_size_;
+ int uv_size_;
+ int pts_;
+ AVCodecContext* codec_ctx_;
+ AVFormatContext* fmt_ctx_;
+ AVStream* out_stream_;
+ AVFrame* yuv_frame_;
+};
\ No newline at end of file
diff --git a/src/decoder/dvpp/FFRecoderTaskManager.cpp b/src/decoder/dvpp/FFRecoderTaskManager.cpp
index 3c35f9a..e6fd545 100644
--- a/src/decoder/dvpp/FFRecoderTaskManager.cpp
+++ b/src/decoder/dvpp/FFRecoderTaskManager.cpp
@@ -60,6 +60,31 @@ bool FFRecoderTaskManager::init(AVStream* stream, AVCodecContext* avctx){
return true;
}
+bool FFRecoderTaskManager::init2(int w, int h, int fps, int bit_rate) {
+ m_width = w;
+ m_height = h;
+ m_bit_rate = bit_rate;
+
+ if (fps > 1) {
+ m_fps = fps;
+ } else {
+ m_fps = 25;
+ }
+
+ m_recoder_thread = new std::thread(
+ [](void* arg) {
+ FFRecoderTaskManager* _this=(FFRecoderTaskManager*)arg;
+ if(_this != nullptr) {
+ _this->recode_thread2();
+ }else{
+ LOG_ERROR("recode 线程启动失败 !");
+ }
+ return (void*)0;
+ }, this);
+
+ return true;
+}
+
static AVPacket* packet_clone(AVPacket* pkt) {
AVPacket *new_pkt = av_packet_alloc();
av_init_packet( new_pkt );
@@ -259,6 +284,102 @@ void FFRecoderTaskManager::recode_thread() {
LOG_INFO("recode_thread end.");
}
+
+void FFRecoderTaskManager::recode_thread2() {
+ LOG_INFO("recode_thread2 start...");
+ while(true) {
+ if(m_bExit) {
+ break;
+ }
+
+ m_recoderinfo_list_mtx.lock();
+ if(m_recoderinfo_list.size() <= 0){
+ m_recoderinfo_list_mtx.unlock();
+ std::this_thread::sleep_for(std::chrono::milliseconds(3));
+ continue;
+ }
+
+ auto it_param = m_recoderinfo_list.begin();
+ RecoderInfo recoderinfo = *it_param;
+ m_recoderinfo_list_mtx.unlock();
+
+ do
+ {
+ auto it_data = getStartIterator(recoderinfo.frame_nb);
+ if(it_data == m_pkt_list.end()) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(3));
+ break;
+ }
+
+ LOG_INFO("start frame_nb: {}", (*it_data)->frame_nb);
+
+ m_pkt_list_mtx.lock();
+ auto it = m_pkt_list.begin();
+ while (it != it_data) {
+ DataPacket* dataPkt = m_pkt_list.front();
+ delete dataPkt;
+ dataPkt = nullptr;
+ m_pkt_list.pop_front();
+ it = m_pkt_list.begin();
+ }
+ m_pkt_list_mtx.unlock();
+
+ string file_name = recoderinfo.recoderPath;
+
+ FFRecoder2 ffrecoder;
+ bool bInit = ffrecoder.init(m_width, m_height, m_fps, m_bit_rate, file_name.c_str());
+ if (!bInit) {
+ LOG_ERROR("ffrecoder init error : {} {} {}", recoderinfo.task_id, recoderinfo.object_id, recoderinfo.frame_nb);
+ ffrecoder.uninit();
+ break;
+ }
+ LOG_DEBUG("record start, pkt_list size: {} task_id: {} object_id:{} frame_nb: {}", m_pkt_list.size(), recoderinfo.task_id, recoderinfo.object_id, recoderinfo.frame_nb);
+
+ int count = 0;
+ auto it_save = it_data;
+ unsigned long long start_frame_nb = (*it_data)->frame_nb;
+ unsigned long long end_frame_nb = (*it_data)->frame_nb;
+ for (; it_save != m_pkt_list.end() && count < 500; ++it_save) {
+ DataPacket* dataPkt = *it_save;
+ if(dataPkt->frame_nb > recoderinfo.frame_nb) {
+ break;
+ }
+ AVPacket* pkt = dataPkt->pkt;
+ if(pkt == nullptr) {
+ LOG_ERROR("{} pkt is nullptr", recoderinfo.task_id);
+ continue;
+ } else if (pkt->data == nullptr || pkt->size <= 0){
+ LOG_ERROR("{} pkt data is nullptr", recoderinfo.task_id);
+ continue;
+ }
+
+ ffrecoder.write_pkt(pkt);
+ count++;
+ end_frame_nb = (*it_save)->frame_nb;
+ }
+
+ ffrecoder.flush();
+ ffrecoder.uninit();
+
+ // 发送mq消息
+ if(mq_publish_func && recoderinfo.mq_info.length() > 0) {
+ mq_publish_func(recoderinfo.mq_info.c_str());
+ // LOG_INFO("record save: {}", recoderinfo.mq_info.c_str());
+ }
+
+ LOG_INFO("record end, total save: {} start_frame_nb: {} end_frame_nb: {} file_path: {}", count, start_frame_nb, end_frame_nb, file_name);
+ } while (0);
+
+ // m_recoderinfo_list 为空会触发 m_pkt_list size 大于1000时的删除操作,
+ // 因此应当在本次m_pkt_list操作都完成之后再pop,避免这边在用m_pkt_list, 另一边在删除,从而导致崩溃
+ m_recoderinfo_list_mtx.lock();
+ m_recoderinfo_list.pop_front();
+ m_recoderinfo_list_mtx.unlock();
+ }
+
+ LOG_INFO("recode_thread end.");
+}
+
void FFRecoderTaskManager::close() {
m_bExit = true;
diff --git a/src/decoder/dvpp/FFRecoderTaskManager.h b/src/decoder/dvpp/FFRecoderTaskManager.h
index 44c8f3d..32fa621 100644
--- a/src/decoder/dvpp/FFRecoderTaskManager.h
+++ b/src/decoder/dvpp/FFRecoderTaskManager.h
@@ -1,4 +1,5 @@
#include "FFRecoder.h"
+#include "FFRecoder2.h"
#include "../../ai_platform/common_header.h"
#include "depend_headers.h"
@@ -28,6 +29,7 @@ public:
void cache_pkt(AVPacket* pkt, long long frame_nb);
bool init(AVStream* stream, AVCodecContext* avctx);
+ bool init2(int w, int h, int fps, int bit_rate);
void create_recode_task(RecoderInfo& recoderInfo);
void close();
@@ -36,6 +38,7 @@ public:
public:
void recode_thread();
+ void recode_thread2();
private:
void save_intask_recoderinfo(RecoderInfo info);
@@ -59,4 +62,10 @@ private:
thread* m_recoder_thread{nullptr};
mq_callback_t mq_publish_func;
+
+ // FFRecoder2
+ int m_width;
+ int m_height;
+ int m_fps;
+ int m_bit_rate;
};
\ No newline at end of file
diff --git a/src/decoder/gb28181/DvppGB28181Decoder.cpp b/src/decoder/gb28181/DvppGB28181Decoder.cpp
index 4d1942a..abe357c 100644
--- a/src/decoder/gb28181/DvppGB28181Decoder.cpp
+++ b/src/decoder/gb28181/DvppGB28181Decoder.cpp
@@ -374,13 +374,30 @@ int DvppGB28181Decoder::getCachedQueueLength(){
}
DeviceMemory* DvppGB28181Decoder::snapshot() {
- return nullptr;
+
+ DeviceMemory* snapshot_mem = nullptr;
+ int loop_times = 0;
+ while (isRunning()) {
+ snapshot_mem = streamDecoder.GetFrame();
+ if (snapshot_mem) {
+ break;
+ }
+
+ loop_times++;
+ if(loop_times > 100) {
+ // 1s都没截取到图,退出
+ break;
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+
+ return snapshot_mem;
}
void DvppGB28181Decoder::doRecode(RecoderInfo& recoderInfo) {
-
+ return streamDecoder.doRecode(recoderInfo);
}
void DvppGB28181Decoder::set_mq_callback(std::function mq_publish) {
-
+ streamDecoder.set_mq_callback(mq_publish);
}
\ No newline at end of file
diff --git a/src/decoder/test_28181.cpp b/src/decoder/test_28181.cpp
index f275d52..a0d16ef 100644
--- a/src/decoder/test_28181.cpp
+++ b/src/decoder/test_28181.cpp
@@ -142,19 +142,8 @@ int main(){
printf("start... \n");
- ServerInfo info(
- "SY_Sip_Server",
- "12345678",
- "192.168.60.179",
- 15060,
- "34020000002000000002",
- "3402000000",
- "sy123456",
- 1800,
- 3600);
-
SipServer* pSipServer = SipServer::getInstance();
- pSipServer->Init(info);
+ pSipServer->Init(nullptr);
DecoderManager* pDecManager = DecoderManager::getInstance();
diff --git a/src/demo/demo.cpp b/src/demo/demo.cpp
index 8ea4b8e..3b65471 100755
--- a/src/demo/demo.cpp
+++ b/src/demo/demo.cpp
@@ -1125,7 +1125,7 @@ string createTask_dvpp28181(void *handle, std::vector algor_ve
algor_init_config_param_t* config_param = tparam.algor_config_params[idx].algor_init_config_param;
delete config_param;
- }else if(tparam.algor_config_params[idx].algor_type == algorithm_type_t::VEHICLE_SOLIDLINETURNAROUND) {
+ } else if(tparam.algor_config_params[idx].algor_type == algorithm_type_t::VEHICLE_SOLIDLINETURNAROUND) {
algor_config_param_manned_incident* algor_param = (algor_config_param_manned_incident*)tparam.algor_config_params[idx].algor_init_config_param->algor_param;
delete algor_param;
algor_basic_config_param_t* basic_param = (algor_basic_config_param_t*)tparam.algor_config_params[idx].algor_init_config_param->basic_param;
@@ -1326,13 +1326,13 @@ while (ch != 'q') {
switch (ch)
{
case '0':
- createTask_dvpp28181(handle, algor_vec2, 0, false);
+ createTask_dvpp28181(handle, algor_vec, 0, false);
break;
case '1':
- createTask_dvpp28181(handle, algor_vec2, 1, false);
+ createTask_dvpp28181(handle, algor_vec, 1, false);
break;
case '2':
- createTask_dvpp28181(handle, algor_vec2, 2, false);
+ createTask_dvpp28181(handle, algor_vec, 2, false);
break;
case 'c':
close_all_task(handle);
--
libgit2 0.21.4