diff --git a/src/decoder/dvpp/DvppDecoder.cpp b/src/decoder/dvpp/DvppDecoder.cpp index 940f378..cf14bc8 100644 --- a/src/decoder/dvpp/DvppDecoder.cpp +++ b/src/decoder/dvpp/DvppDecoder.cpp @@ -56,6 +56,22 @@ static void VdecCallback(acldvppStreamDesc *input, acldvppPicDesc *output, void } } +static int AVInterruptCallBackFun(void *param) +{ + DvppDecoder *pDecoder = (DvppDecoder*)param; + if (nullptr == pDecoder) return 0; + + long long cur_ts = get_cur_time_ms(); + long time_gap = cur_ts - pDecoder->get_last_read_ts(); + if (time_gap > 1000*30) { + LOG_WARN("摄像头异常,释放阻塞"); + //通知FFMpeg可以从阻塞工作线程中释放操作 + return 1; + } else { + //通知FFMpeg继续阻塞工作 + return 0; + } +} DvppDecoder::DvppDecoder(){ m_read_thread = nullptr; @@ -114,9 +130,11 @@ AVCodecContext* DvppDecoder::init_FFmpeg(FFDecConfig config){ 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 ); // 单位为 百万分之一秒 + av_dict_set( &options, "max_delay", "500000", 0); //设置最大时延 do{ fmt_ctx = avformat_alloc_context(); + // fmt_ctx->flags |= AVFMT_FLAG_NONBLOCK; if (avformat_open_input(&fmt_ctx, input_file, nullptr, &options) != 0) { LOG_ERROR("[{}]- Cannot open input file: {}", m_dec_name, input_file); break; @@ -135,6 +153,10 @@ AVCodecContext* DvppDecoder::init_FFmpeg(FFDecConfig config){ m_bReal = false; } else { m_bReal = true; + + fmt_ctx->interrupt_callback.callback = AVInterruptCallBackFun; + fmt_ctx->interrupt_callback.opaque = this; + m_last_read_ts = get_cur_time_ms(); } } @@ -203,6 +225,12 @@ AVCodecContext* DvppDecoder::init_FFmpeg(FFDecConfig config){ m_vdec_out_size = frame_width * frame_height * 3 / 2; + if (avctx->gop_size > 0) { + m_cache_gop = avctx->gop_size + 1; + } else { + m_cache_gop = 20; + } + #ifdef USE_VILLAGE bool bRet = m_recoderManager.init2(frame_width, frame_height, m_fps, avctx->bit_rate); if (!bRet){ @@ -403,6 +431,10 @@ float DvppDecoder::fps(){ return m_fps; } +long long DvppDecoder::get_last_read_ts() { + return m_last_read_ts; +} + static int snap_count = 0; DeviceMemory* DvppDecoder::snapshot(){ @@ -532,15 +564,15 @@ void DvppDecoder::read_thread() { } m_decoded_data_queue_mtx.unlock(); - if(m_DvppCacheCounter.load() > 20) { + if(m_DvppCacheCounter.load() > m_cache_gop) { // 解码器解码不过来 std::this_thread::sleep_for(std::chrono::milliseconds(10)); continue; } + } else { + m_last_read_ts = get_cur_time_ms(); } - // LOG_DEBUG("[{}]- read in", m_dec_name); - int result = av_read_frame(fmt_ctx, pkt); if (result == AVERROR_EOF || result < 0){ av_packet_unref(pkt); @@ -548,9 +580,7 @@ void DvppDecoder::read_thread() { break; } - // LOG_DEBUG("[{}]- read out", m_dec_name); - - if (m_bReal && m_DvppCacheCounter.load() > 20){ + if (m_bReal && m_DvppCacheCounter.load() > m_cache_gop){ // 解码器解码不过来。实时流在此处的处理会导致花屏,这是由于解码器性能问题导致,无法避免 // 实时流在这里处理是为了避免长时间不读取数据导致数据中断 std::this_thread::sleep_for(std::chrono::milliseconds(10)); @@ -564,8 +594,6 @@ void DvppDecoder::read_thread() { if (video_index == pkt->stream_index){ - LOG_DEBUG("[{}]- av_bsf_send_packet", m_dec_name); - ret = av_bsf_send_packet(h264bsfc, pkt); if(ret < 0) { LOG_ERROR("[{}]- av_bsf_send_packet error!", m_dec_name); diff --git a/src/decoder/dvpp/DvppDecoder.h b/src/decoder/dvpp/DvppDecoder.h index 4a75329..d65c4f0 100644 --- a/src/decoder/dvpp/DvppDecoder.h +++ b/src/decoder/dvpp/DvppDecoder.h @@ -65,6 +65,7 @@ public: public: void doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData); void doProcessReport(); + long long get_last_read_ts(); private: AVCodecContext* init_FFmpeg(FFDecConfig config); @@ -133,12 +134,15 @@ private: long long last_ts {0}; + long long m_last_read_ts {0}; + uint64_t m_in_count {0}; uint64_t m_out_count {0}; int m_frameSkip {1}; std::atomic m_DvppCacheCounter{0}; + int m_cache_gop{0}; VpcUtils m_vpcUtils; }; \ No newline at end of file