From b83a105d49a954f143cd659f1b3298bef123f35a Mon Sep 17 00:00:00 2001 From: cmhu <2657262686@qq.com> Date: Tue, 12 Sep 2023 09:03:22 +0000 Subject: [PATCH] 1. 修正是否实时流判断错误的问题; 2.添加display线程,以实现解码后跳帧,避免解码后的处理操作耗时过长阻塞读取数据包从而导致花屏 3. 优化解码失败可能造成的显存泄漏问题 --- src/decoder/dvpp/DvppDecoder.cpp | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------- src/decoder/dvpp/DvppDecoder.h | 8 +++++++- 2 files changed, 111 insertions(+), 74 deletions(-) diff --git a/src/decoder/dvpp/DvppDecoder.cpp b/src/decoder/dvpp/DvppDecoder.cpp index ae782bd..8b21660 100755 --- a/src/decoder/dvpp/DvppDecoder.cpp +++ b/src/decoder/dvpp/DvppDecoder.cpp @@ -17,7 +17,6 @@ struct Vdec_CallBack_UserData { DvppDecoder::DvppDecoder(){ m_read_thread = 0; - m_decode_thread = 0; m_cached_mem = nullptr; fmt_ctx = nullptr; @@ -76,8 +75,9 @@ AVCodecContext* DvppDecoder::init_FFmpeg(FFDecConfig config){ avformat_network_init(); const char* uri = config.uri.c_str(); - fstream infile(uri); - if (infile.is_open()){ + fstream infile; + infile.open(uri, ios::in); + if (!infile.fail()){ m_bReal = false; infile.close(); } else { @@ -335,6 +335,7 @@ void DvppDecoder::read_thread() { int frame_count = 0; int ret = -1; + pthread_t m_decode_thread; pthread_create(&m_decode_thread,0, [](void* arg) { @@ -393,7 +394,7 @@ void DvppDecoder::read_thread() { bool bPushed = false; while ((ret = av_bsf_receive_packet(h264bsfc, pkt)) == 0) { if(pkt->size > g_pkt_size){ - LOG_ERROR("[{}]- pkt size 大于最大预设值, 为 {}!", m_dec_name, pkt->size); + LOG_ERROR("[{}]- pkt size 大于最大预设值!", m_dec_name); break; } @@ -412,13 +413,12 @@ void DvppDecoder::read_thread() { data_pkt->frame_nb = frame_nb; m_pktQueue.push(data_pkt); m_pktQueue_mutex.unlock(); - bPushed = true; + bPushed = true; frame_count++; } - if(!bPushed) - { + if(!bPushed){ av_packet_free(&pkt); pkt = nullptr; } @@ -509,6 +509,13 @@ static void VdecCallback(acldvppStreamDesc *input, acldvppPicDesc *output, void } } + +static long get_cur_time_ms() { + chrono::time_point tpMicro + = chrono::time_point_cast(chrono::system_clock::now()); + return tpMicro.time_since_epoch().count(); +} + void DvppDecoder::doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output, unsigned long long frame_nb){ m_vdecQueue_mutex.lock(); @@ -539,71 +546,58 @@ void DvppDecoder::doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *o break; } - if(width > 0 && height > 0 && outputSize > 0){ - DvppDataMemory* mem = new DvppDataMemory(width, width_stride, height, height_stride, outputSize, m_dec_name, to_string(m_dvpp_deviceId), false, frame_nb, (unsigned char *)outputDataDev); - if(mem){ - if(post_decoded_cbk) { - post_decoded_cbk(m_postDecArg, mem); - } else { - delete mem; - mem = nullptr; - } + bool bCached = false; - if(m_bSnapShoting){ - // 缓存snapshot - std::unique_lock locker(m_cached_mutex); - - m_cached_mem = new DvppDataMemory(-1, width, width_stride, height, height_stride, outputSize, m_dec_name, to_string(m_dvpp_deviceId), false, 0); - if(m_cached_mem != nullptr){ - aclrtMemcpy(m_cached_mem->getMem(), outputSize, (unsigned char *)outputDataDev, outputSize, ACL_MEMCPY_DEVICE_TO_DEVICE); + if(width > 0 && height > 0 && outputSize > 0){ + if (!m_bReal) { + while(m_bRunning) { + // 非实时流,即为文件情形,因为不存在花屏问题,为保证不丢帧,这里做个循环等待 + m_decoded_data_queue_mtx.lock(); + if(m_decoded_data_queue.size() > 5){ + m_decoded_data_queue_mtx.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + continue; } - - locker.unlock(); - m_cached_cond.notify_one(); - m_bSnapShoting = false; + m_decoded_data_queue_mtx.unlock(); + break; } - } else { - LOG_ERROR("[{}]- DvppDataMemory 创建失败! ", m_dec_name, ret); - acldvppFree(outputDataDev); - outputDataDev = nullptr; } - } else { + // cout << m_dec_name << " 解码时间间隔: " << get_cur_time_ms() - last_ts << endl; + // last_ts = get_cur_time_ms(); + + // 换成解码后数据, 这里这样做的是为了保证解码一直持续进行,避免后续操作阻碍文件读取和解码从而导致花屏 + m_decoded_data_queue_mtx.lock(); + if(m_decoded_data_queue.size() <= 5) { + DvppDataMemory* mem = new DvppDataMemory(width, width_stride, height, height_stride, outputSize, m_dec_name, to_string(m_dvpp_deviceId), false, frame_nb, (unsigned char *)outputDataDev); + if(mem){ + m_decoded_data_queue.push(mem); + bCached = true; + } + } + m_decoded_data_queue_mtx.unlock(); + + if(m_bSnapShoting){ + // 缓存snapshot + std::unique_lock locker(m_cached_mutex); + + m_cached_mem = new DvppDataMemory(-1, width, width_stride, height, height_stride, outputSize, m_dec_name, to_string(m_dvpp_deviceId), false, 0); + if(m_cached_mem != nullptr){ + aclrtMemcpy(m_cached_mem->getMem(), outputSize, (unsigned char *)outputDataDev, outputSize, ACL_MEMCPY_DEVICE_TO_DEVICE); + } + + locker.unlock(); + m_cached_cond.notify_one(); + m_bSnapShoting = false; + } + + } + + if(!bCached) { LOG_WARN("[{}]- decode result error, width:{} width_stride:{} height:{} height_stride:{} size:{}", m_dec_name, width, width_stride, height, height_stride, outputSize); acldvppFree(outputDataDev); outputDataDev = nullptr; } - - // 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); - // } }while(0); CHECK_AND_RETURN_NOVALUE(acldvppDestroyStreamDesc(input), "acldvppDestroyStreamDesc failed"); @@ -624,6 +618,16 @@ void DvppDecoder::decode_thread(){ return; } + pthread_t display_thread; + pthread_create(&display_thread,0, + [](void* arg) + { + DvppDecoder* a=(DvppDecoder*)arg; + a->display_thread(); + return (void*)0; + } + ,this); + aclrtSetDevice(m_dvpp_deviceId); aclrtContext ctx; ret = aclrtCreateContext(&ctx, m_dvpp_deviceId); @@ -651,8 +655,7 @@ void DvppDecoder::decode_thread(){ uint64_t frame_count = 0; bool bBreak = false; - while (m_bRunning) - { + while (m_bRunning) { if (m_bPause){ std::this_thread::sleep_for(std::chrono::milliseconds(3)); continue; @@ -662,10 +665,9 @@ void DvppDecoder::decode_thread(){ bBreak = true; break; }else if(ret == 1){ - std::this_thread::sleep_for(std::chrono::milliseconds(3)); continue; } - + frame_count++; } @@ -699,6 +701,7 @@ void DvppDecoder::decode_thread(){ m_bRunning = false; m_bExitReportThd = true; CHECK_NOT_RETURN(pthread_join(report_thread, nullptr), "pthread_join failed"); + CHECK_NOT_RETURN(pthread_join(display_thread, nullptr), "pthread_join failed"); // 最后清理一遍未解码的数据 m_vdecQueue_mutex.lock(); @@ -741,7 +744,7 @@ int DvppDecoder::sentFrame(aclvdecChannelDesc *vdecChannelDesc, uint64_t frame_c data_pkt = m_pktQueue.front(); m_pktQueue.pop(); m_pktQueue_mutex.unlock(); - + // 解码 void *vdecInputbuf = nullptr; int ret = acldvppMalloc((void **)&vdecInputbuf, g_pkt_size); @@ -770,7 +773,6 @@ int DvppDecoder::sentFrame(aclvdecChannelDesc *vdecChannelDesc, uint64_t frame_c return 2; } - bool bRet = false; acldvppStreamDesc *input_stream_desc = nullptr; acldvppPicDesc *output_pic_desc = nullptr; do{ @@ -808,12 +810,10 @@ int DvppDecoder::sentFrame(aclvdecChannelDesc *vdecChannelDesc, uint64_t frame_c user_data = nullptr; break; } - + m_vdecQueue.push(vdecInputbuf); m_vdecQueue_mutex.unlock(); - bRet = true; - return 0; }while (0); @@ -822,7 +822,7 @@ int DvppDecoder::sentFrame(aclvdecChannelDesc *vdecChannelDesc, uint64_t frame_c data_pkt = nullptr; } - if (!bRet){ + if (vdecInputbuf){ acldvppFree(vdecInputbuf); vdecInputbuf = nullptr; } @@ -870,6 +870,37 @@ bool DvppDecoder::sendVdecEos(aclvdecChannelDesc *vdecChannelDesc) { return true; } +void DvppDecoder::display_thread(){ + LOG_INFO("[{}]- display_thread start...", m_dec_name); + while(m_bRunning) { + m_decoded_data_queue_mtx.lock(); + if(m_decoded_data_queue.size() <= 0) { + m_decoded_data_queue_mtx.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + continue; + } + DvppDataMemory* mem = m_decoded_data_queue.front(); + m_decoded_data_queue.pop(); + m_decoded_data_queue_mtx.unlock(); + + if(post_decoded_cbk) { + post_decoded_cbk(m_postDecArg, mem); + } else { + delete mem; + mem = nullptr; + } + } + + while (m_decoded_data_queue.size() > 0){ + DvppDataMemory* mem = m_decoded_data_queue.front(); + m_decoded_data_queue.pop(); + delete mem; + mem = nullptr; + } + + LOG_INFO("[{}]- display_thread end.", m_dec_name); +} + void DvppDecoder::release_dvpp(){ if(m_context){ aclError ret = aclrtDestroyContext(m_context); diff --git a/src/decoder/dvpp/DvppDecoder.h b/src/decoder/dvpp/DvppDecoder.h index 8d9f33f..6a3e7c8 100755 --- a/src/decoder/dvpp/DvppDecoder.h +++ b/src/decoder/dvpp/DvppDecoder.h @@ -71,6 +71,8 @@ private: bool sendVdecEos(aclvdecChannelDesc *vdecChannelDesc); void release_dvpp(); + void display_thread(); + private: FFDecConfig m_cfg; string m_dec_name; @@ -109,7 +111,6 @@ private: aclrtContext m_context{nullptr}; acldvppStreamFormat enType; - pthread_t m_decode_thread{0}; mutex m_vdecQueue_mutex; queue m_vdecQueue; @@ -125,4 +126,9 @@ private: condition_variable m_cached_cond; FFRecoderTaskManager m_recoderManager; + + queue m_decoded_data_queue; + mutex m_decoded_data_queue_mtx; + + long long last_ts {0}; }; \ No newline at end of file -- libgit2 0.21.4