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