//#include "LOG_manager.h" #include #include "DvppGB28181Decoder.h" extern "C" { #include "libavutil/avstring.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" } #include"RTPTcpReceiver.h" #include"RTPUdpReceiver.h" #include #include "common_header.h" // #include "../nvdec/FFCuContextManager.h" // #include "../nvdec/GpuRgbMemory.hpp" // #include "../nvdec/cuda_kernels.h" #define ECLOSED 0 #define ECLOSING 1 #define ERUNNING 2 #define EPAUSE 3 static void RTP_Stream_CallBack(void* userdata, int videoType, char* data, int len, int isKey, uint64_t pts, uint64_t localPts) { DvppGB28181Decoder* decoder = (DvppGB28181Decoder*)userdata; decoder->stream_callback(videoType, data, len, isKey, pts, localPts); } static void RTP_Stream_End_CallBack(void* userdata) { DvppGB28181Decoder* decoder = (DvppGB28181Decoder*)userdata; decoder->stream_end_callback(); } DvppGB28181Decoder::DvppGB28181Decoder() { m_frameSkip = 1; m_dec_keyframe = false; m_post_decode_thread = 0; } DvppGB28181Decoder::~DvppGB28181Decoder() { close(); if (m_pAVCodecCtx) { avcodec_close(m_pAVCodecCtx); avcodec_free_context(&m_pAVCodecCtx); } m_dec_keyframe = false; LOG_INFO("destroy OK--{}", m_dec_name); } void DvppGB28181Decoder::close(){ if (m_status == ECLOSED || m_status == ECLOSING) return ; m_status = ECLOSING; LOG_DEBUG("real decode thread exit success 1--{}", m_dec_name); if(nullptr != m_rtpPtr){ if (m_rtpPtr->IsOpened()) { m_rtpPtr->Close(); LOG_DEBUG("real decode thread exit success 2--{}", m_dec_name); } delete m_rtpPtr; m_rtpPtr = nullptr; } if (gpu_options) av_dict_free(&gpu_options); if (m_post_decode_thread != 0) { pthread_join(m_post_decode_thread,0); } while(mFrameQueue.size() > 0){ AVFrame * gpuFrame = mFrameQueue.front(); av_frame_free(&gpuFrame); mFrameQueue.pop(); } m_status = ECLOSED; LOG_INFO("解码器关闭成功 --{}", m_dec_name); } bool DvppGB28181Decoder::init(FFDecConfig& cfg){ if(cfg.force_tcp){ m_rtpPtr = new RTPTcpReceiver(); }else{ m_rtpPtr = new RTPUdpReceiver(); } if(nullptr == m_rtpPtr){ return false; } m_dec_name = cfg.uri; m_frameSkip = cfg.skip_frame; if (m_frameSkip < 1) m_frameSkip = 1; m_gpuid = atoi(cfg.gpuid.c_str()); m_rtpPtr->SetOutputCallback(RTP_Stream_CallBack, this); m_rtpPtr->SetVodEndCallback(RTP_Stream_End_CallBack, this); post_decoded_cbk = cfg.post_decoded_cbk; decode_finished_cbk = cfg.decode_finished_cbk; if (!streamDecoder.Init(cfg)) { return false; } m_cfg = cfg; LOG_INFO("init - {} ", m_dec_name); return true; } bool DvppGB28181Decoder::start() { m_status = ERUNNING; bool bRet = m_rtpPtr->Open(m_dec_name); if(bRet){ pthread_create(&m_post_decode_thread,0, [](void* arg) { DvppGB28181Decoder* a=(DvppGB28181Decoder*)arg; a->display_thread(); return (void*)0; } ,this); } LOG_ERROR("[{}] - rtp receiver open failed !", m_dec_name); return bRet; } void DvppGB28181Decoder::setDecKeyframe(bool bKeyframe){ m_dec_keyframe = bKeyframe; } void DvppGB28181Decoder::stream_callback(int videoType, char* data, int len, int isKey, uint64_t pts, uint64_t localPts) { if (m_status == EPAUSE) return; // 若设置为关键帧解码,非关键帧数据直接返回 if(m_dec_keyframe && !isKey) return; if (len <= 0) { if (data == nullptr && pts == -1) { LOG_INFO("frame callback EOF!"); post_decoded_cbk(m_postDecArg, nullptr); return ; } LOG_INFO("frame data is zero --{}", m_dec_name); return; } streamDecoder.SendData(videoType, data, len, isKey, pts); // AVPacket* pkt = av_packet_alloc(); // av_init_packet(pkt); // pkt->size = len; // pkt->data = (uint8_t*)data; // // ffmpeg 解码 // ff_decode(videoType, pkt); // av_packet_free(&pkt); // pkt = nullptr; } int DvppGB28181Decoder::ff_decode(int videoType, AVPacket* pkt) { if (m_pAVCodecCtx == nullptr) { LOG_INFO("frame data is zero --{}", m_dec_name); if (VIDEO_TYPE_H264 == videoType) { if (m_gpuid >= 0){ m_pAVCodec = avcodec_find_decoder_by_name("h264_cuvid"); } else{ m_pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H264); } LOG_INFO("m_avCodecName is H264"); } else if (VIDEO_TYPE_H265 == videoType) { if (m_gpuid >= 0){ m_pAVCodec = avcodec_find_decoder_by_name("hevc_cuvid"); } else{ m_pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H265); } LOG_INFO("m_avCodecName is H265"); } else{ LOG_INFO("m_avCodecName is unknown, videoType is {}", videoType); } if (!m_pAVCodec) { LOG_ERROR("frameCallback frame decode error, ERROR_DECODER_NOT_FOUND"); return; } m_pAVCodecCtx = avcodec_alloc_context3(m_pAVCodec); if (m_gpuid >= 0) { char gpui[8] = { 0 }; sprintf(gpui, "%d", m_gpuid); av_dict_set(&gpu_options, "gpu", gpui, 0); m_pAVCodecCtx->get_format = get_hw_format; FFCuContextManager* pCtxMgr = FFCuContextManager::getInstance(); m_pAVCodecCtx->hw_device_ctx = av_buffer_ref(pCtxMgr->getCuCtx(gpui)); if (nullptr == m_pAVCodecCtx->hw_device_ctx){ // TODO 这里应该抛出错误 return ; } } if (avcodec_open2(m_pAVCodecCtx, m_pAVCodec, &gpu_options) < 0) return; } //开始解码 int ret = avcodec_send_packet(m_pAVCodecCtx, pkt); if (ret < 0) { //send_exception(RunMessageType::E2002, e_msg); LOG_ERROR("Real stream视频解码失败,请检查视频设备{}: avcodec_send_packet failed. ret={}", m_dec_name, ret); return; } if (frameW < 1) { frameW = m_pAVCodecCtx->width; frameH = m_pAVCodecCtx->height; if (frameW <= 0 || frameH <= 0) { LOG_ERROR("[{}] frame W or H is error! ({},{})", m_dec_name, frameW, frameH); return; } } m_fps = av_q2d(m_pAVCodecCtx->framerate); AVFrame* gpuFrame = av_frame_alloc(); ret = avcodec_receive_frame(m_pAVCodecCtx, gpuFrame); if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){ LOG_ERROR("{} - Failed to receive frame: {}", m_dec_name, ret); av_frame_free(&gpuFrame); gpuFrame = nullptr; return; } if (gpuFrame->width != frameW || gpuFrame->height != frameH){ LOG_INFO("AVFrame is inconsistent: width is {}, height is {}; original frameW is {}, frameH is {}--{}", gpuFrame->width, gpuFrame->height, frameW, frameH , m_dec_name); av_frame_free(&gpuFrame); gpuFrame = nullptr; return; } av_frame_free(&gpuFrame); gpuFrame = nullptr; } void DvppGB28181Decoder::display_thread(){ int index = 0; while (isRunning()) { auto mem = streamDecoder.GetFrame(); if(mem) { if ((m_frameSkip == 1 || index % m_frameSkip == 0) && post_decoded_cbk){ post_decoded_cbk(m_postDecArg, mem); } index++; if(index >= 100000){ index = 0; } } else { delete mem; mem = nullptr; } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } LOG_INFO("display thread exited."); } void DvppGB28181Decoder::stream_end_callback() { LOG_INFO("send_video_eof--{}", m_dec_name); decode_finished_cbk(m_finishedDecArg); return; } void DvppGB28181Decoder::setPostDecArg(const void* postDecArg){ m_postDecArg = postDecArg; } void DvppGB28181Decoder::setFinishedDecArg(const void* finishedDecArg){ m_finishedDecArg = finishedDecArg; } void DvppGB28181Decoder::pause() { m_status = EPAUSE; LOG_INFO("pause --{}", m_dec_name); } void DvppGB28181Decoder::resume() { m_status = ERUNNING; LOG_INFO("resume --{}", m_dec_name); } bool DvppGB28181Decoder::isRunning(){ if (m_status == ECLOSED || m_status == ECLOSING){ return false; } return true; } bool DvppGB28181Decoder::isFinished(){ if (m_status == ECLOSED || m_status == ECLOSING){ return true; } return false; } bool DvppGB28181Decoder::isPausing(){ if (m_status == EPAUSE){ return true; } return false; } bool DvppGB28181Decoder::getResolution( int &width, int &height ){ width = frameW; height = frameH; return true; } float DvppGB28181Decoder::fps() { return m_fps; } bool DvppGB28181Decoder::isSurport(FFDecConfig& cfg){ // 由于是否支持需要在拿到数据后才能断定,无法事先判断,所以这个地方默认返回true return true; } int DvppGB28181Decoder::getCachedQueueLength(){ return m_rtpPtr->GetPsFrameListSize(); }