From c027963f5bf730c6ca10c85b5af7e84cc09d4c9d Mon Sep 17 00:00:00 2001 From: Hu Chunming <2657262686@qq.com> Date: Mon, 29 Jul 2024 18:21:51 +0800 Subject: [PATCH] ffmpeg6.1.1版本的接收rtp --- src/decoder/dvpp/DvppDecoder.cpp | 6 +----- src/decoder/dvpp/DvppDecoder.h | 2 -- src/decoder/dvpp/DvppDecoderApi.cpp | 7 ------- src/decoder/dvpp/DvppDecoderApi.h | 2 -- src/decoder/dvpp/DvppRtpDecoder.cpp | 885 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/dvpp/DvppRtpDecoder.h | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/dvpp/DvppStreamDecoder.cpp | 10 ++++++++++ src/decoder/dvpp/FFRecoder.cpp | 18 ++++++++++++------ src/decoder/dvpp/depend_headers.h | 7 ++++--- src/decoder/gb28181/DvppGB28181Decoder.cpp | 407 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- src/decoder/gb28181/DvppGB28181Decoder.cpp0 | 403 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/gb28181/DvppGB28181Decoder.h | 2 -- src/decoder/gb28181/DvppGB28181Decoder2.cpp | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/gb28181/DvppGB28181Decoder2.h | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/gb28181/rtp/FFRtpParser.cpp | 127 ------------------------------------------------------------------------------------------------------------------------------- src/decoder/gb28181/rtp/FFRtpParser.h | 46 ---------------------------------------------- src/decoder/gb28181/rtp/RTPReceiver2.cpp | 287 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- src/decoder/gb28181/rtp/RTPReceiver2.h | 39 --------------------------------------- src/decoder/gb28181/rtp/Rtp.cpp | 49 ------------------------------------------------- src/decoder/gb28181/rtp/Rtp.h | 69 --------------------------------------------------------------------- src/decoder/gb28181/rtp2/RTPReceiver2.cpp | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/gb28181/rtp2/RTPReceiver2.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/gb28181/rtp2/Rtp.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/gb28181/rtp2/Rtp.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder/gb28181/websocket/WebsocketClient.cpp | 6 +++--- src/decoder/gb28181/websocket/WebsocketClient.h | 10 +++++----- src/decoder/interface/AbstractDecoder.h | 2 -- src/decoder/interface/DecoderManager.cpp | 21 ++------------------- src/decoder/interface/DecoderManager.h | 9 --------- src/decoder/interface/VideoTools.cpp | 160 ---------------------------------------------------------------------------------------------------------------------------------------------------------------- src/decoder/interface/VideoTools.h | 25 ------------------------- 31 files changed, 2386 insertions(+), 1274 deletions(-) create mode 100644 src/decoder/dvpp/DvppRtpDecoder.cpp create mode 100644 src/decoder/dvpp/DvppRtpDecoder.h delete mode 100644 src/decoder/gb28181/DvppGB28181Decoder.cpp create mode 100644 src/decoder/gb28181/DvppGB28181Decoder.cpp0 create mode 100644 src/decoder/gb28181/DvppGB28181Decoder2.cpp create mode 100644 src/decoder/gb28181/DvppGB28181Decoder2.h delete mode 100644 src/decoder/gb28181/rtp/FFRtpParser.cpp delete mode 100644 src/decoder/gb28181/rtp/FFRtpParser.h delete mode 100644 src/decoder/gb28181/rtp/RTPReceiver2.cpp delete mode 100644 src/decoder/gb28181/rtp/RTPReceiver2.h delete mode 100644 src/decoder/gb28181/rtp/Rtp.cpp delete mode 100644 src/decoder/gb28181/rtp/Rtp.h create mode 100644 src/decoder/gb28181/rtp2/RTPReceiver2.cpp create mode 100644 src/decoder/gb28181/rtp2/RTPReceiver2.h create mode 100644 src/decoder/gb28181/rtp2/Rtp.cpp create mode 100644 src/decoder/gb28181/rtp2/Rtp.h delete mode 100644 src/decoder/interface/VideoTools.cpp delete mode 100644 src/decoder/interface/VideoTools.h diff --git a/src/decoder/dvpp/DvppDecoder.cpp b/src/decoder/dvpp/DvppDecoder.cpp index f4a5f78..6cf41d4 100644 --- a/src/decoder/dvpp/DvppDecoder.cpp +++ b/src/decoder/dvpp/DvppDecoder.cpp @@ -174,7 +174,7 @@ AVCodecContext* DvppDecoder::init_FFmpeg(FFDecConfig config){ } // 查找视频流信息 - AVCodec *decoder = nullptr; + const AVCodec *decoder = nullptr; video_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); if (video_index < 0) { LOG_ERROR("[{}]- Cannot find a video stream in the input file!", m_dec_name); @@ -480,10 +480,6 @@ DeviceMemory* DvppDecoder::snapshot(){ return snapshot_mem; } -int DvppDecoder::getCachedQueueLength(){ - return 0; -} - void DvppDecoder::release_ffmpeg() { m_dec_keyframe = false; if(h264bsfc){ diff --git a/src/decoder/dvpp/DvppDecoder.h b/src/decoder/dvpp/DvppDecoder.h index d65c4f0..35ce529 100644 --- a/src/decoder/dvpp/DvppDecoder.h +++ b/src/decoder/dvpp/DvppDecoder.h @@ -56,8 +56,6 @@ public: void setPostDecArg(const void* postDecArg); void setFinishedDecArg(const void* finishedDecArg); - int getCachedQueueLength(); - void doRecode(RecoderInfo& recoderInfo); void set_mq_callback(mq_callback_t cb); diff --git a/src/decoder/dvpp/DvppDecoderApi.cpp b/src/decoder/dvpp/DvppDecoderApi.cpp index a2e3d81..45627dd 100644 --- a/src/decoder/dvpp/DvppDecoderApi.cpp +++ b/src/decoder/dvpp/DvppDecoderApi.cpp @@ -100,13 +100,6 @@ float DvppDecoderApi::fps(){ return 0.0; } -int DvppDecoderApi::getCachedQueueLength(){ - if(m_pDecoder != nullptr){ - return m_pDecoder->getCachedQueueLength(); - } - return 0; -} - void DvppDecoderApi::setName(string nm){ if(m_pDecoder != nullptr){ return m_pDecoder->setName(nm); diff --git a/src/decoder/dvpp/DvppDecoderApi.h b/src/decoder/dvpp/DvppDecoderApi.h index 445ddba..071a8ea 100644 --- a/src/decoder/dvpp/DvppDecoderApi.h +++ b/src/decoder/dvpp/DvppDecoderApi.h @@ -28,8 +28,6 @@ public: bool isSurport(FFDecConfig& cfg); - int getCachedQueueLength(); - float fps(); DeviceMemory* snapshot(); diff --git a/src/decoder/dvpp/DvppRtpDecoder.cpp b/src/decoder/dvpp/DvppRtpDecoder.cpp new file mode 100644 index 0000000..842a502 --- /dev/null +++ b/src/decoder/dvpp/DvppRtpDecoder.cpp @@ -0,0 +1,885 @@ +#include "DvppRtpDecoder.h" + +#include "DvppSourceManager.h" +#include "../gb28181/rtp2/Rtp.h" + + +#define CHECK_AND_RETURN(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); return ret;} +#define CHECK_NOT_RETURN(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message);} +#define CHECK_AND_RETURN_NOVALUE(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); return;} +#define CHECK_AND_BREAK(ret, message) \ + if(ret != 0) {LOG_ERROR("[{}]- {}", m_dec_name, message); break;} + + + + +struct Vdec_CallBack_UserData { + uint64_t frameId; + uint64_t frame_nb; + long startTime; + long sendTime; + DvppRtpDecoder* self; + + Vdec_CallBack_UserData() { + frameId = 0; + frame_nb = 0; + } +}; + + +static long get_cur_time_ms() { + chrono::time_point tpMicro + = chrono::time_point_cast(chrono::system_clock::now()); + return tpMicro.time_since_epoch().count(); +} + +static void *ReportThd(void *arg) +{ + DvppRtpDecoder *self = (DvppRtpDecoder *)arg; + if(nullptr != self){ + self->doProcessReport(); + } + return (void *)0; +} + +static void VdecCallback(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData) +{ + Vdec_CallBack_UserData *userData = (Vdec_CallBack_UserData *) pUserData; + if(nullptr != userData){ + DvppRtpDecoder* self = userData->self; + if(self != nullptr){ + self->doVdppVdecCallBack(input, output, userData); + } + delete userData; + userData = nullptr; + } +} + +static int avio_read_packet(void* opaque, uint8_t* buf, int buffsize){ + DvppRtpDecoder* rtpDecoder = (DvppRtpDecoder*)opaque; + if(rtpDecoder) { + return rtpDecoder->ReadBuffer(buf, buffsize); + } + + LOG_ERROR("rtpDecoder is null"); + + return 0; +} + +DvppRtpDecoder::DvppRtpDecoder(){ + m_read_thread = nullptr; + + fmt_ctx = nullptr; + m_bRunning = false; + + mVideoIndex = -1; + pix_fmt = AV_PIX_FMT_NONE; + m_dec_name = ""; + + m_bPause = false; + + m_bFinished = false; + m_dec_keyframe = false; + m_fps = 0.0; +} + +DvppRtpDecoder::~DvppRtpDecoder() { + Close(); + + LOG_DEBUG("[{}]- ~DvppRtpDecoder() in_count:{} out_count:{}", m_dec_name, m_in_count, m_out_count); +} + +bool DvppRtpDecoder::Init(FFDecConfig cfg) { + + m_dec_name = cfg.dec_name; + m_frameSkip = cfg.skip_frame; + + m_cfg = cfg; + + m_bResize = m_cfg.resize; + + decode_finished_cbk = cfg.decode_finished_cbk; + + bool bRet = init_dvpp(cfg); + if(!bRet){ + return false; + } + + m_bFinished = false; + + return true; +} + +void DvppRtpDecoder::calcOutResolution(int width, int height) { + if(m_bResize) { + float srcRatio = width / (float)height; + float stdRatio = 1920.0 / 1080.0f ; + int outWidth = 1920; + int outHeight = 1080; + if (srcRatio > stdRatio) { + outHeight = static_cast(outWidth * (float)height / width) ; + if (outHeight % 2 == 1) { + outHeight += 1; + } + } else if (srcRatio < stdRatio) { + outWidth = static_cast(outHeight * (float)width / height) ; + if (outWidth % 2 == 1) { + outWidth += 1; + } + } + + out_frame_width = outWidth; + out_frame_height = outHeight; + } else { + out_frame_width = width; + out_frame_height = height; + } +} + +int DvppRtpDecoder::getVdecType(int videoType, int profile) +{ + int streamFormat = H264_MAIN_LEVEL; + + // VDEC only support H265 main level,264 baseline level,main level,high level + if (videoType == AV_CODEC_ID_HEVC) { + streamFormat = H265_MAIN_LEVEL; + } else if (videoType == AV_CODEC_ID_H264) { + switch (profile) { + case FF_PROFILE_H264_BASELINE: + streamFormat = H264_BASELINE_LEVEL; + break; + case FF_PROFILE_H264_MAIN: + streamFormat = H264_MAIN_LEVEL; + break; + case FF_PROFILE_H264_HIGH: + case FF_PROFILE_H264_HIGH_10: + case FF_PROFILE_H264_HIGH_10_INTRA: + case FF_PROFILE_H264_MULTIVIEW_HIGH: + case FF_PROFILE_H264_HIGH_422: + case FF_PROFILE_H264_HIGH_422_INTRA: + case FF_PROFILE_H264_STEREO_HIGH: + case FF_PROFILE_H264_HIGH_444: + case FF_PROFILE_H264_HIGH_444_PREDICTIVE: + case FF_PROFILE_H264_HIGH_444_INTRA: + streamFormat = H264_HIGH_LEVEL; + break; + default: + LOG_INFO("Not support h264 profile {}, use as mp", profile); + streamFormat = H264_MAIN_LEVEL; + break; + } + } else { + streamFormat = -1; + LOG_ERROR("Not support stream, type {}, profile {}", videoType, profile); + } + + return streamFormat; +} + + bool DvppRtpDecoder::init_dvpp(FFDecConfig cfg) { + + LOG_INFO("[{}]- Init device start...", m_dec_name); + + m_dvpp_deviceId = atoi(cfg.gpuid.c_str()); + + post_decoded_cbk = cfg.post_decoded_cbk; + + do{ + aclError ret = aclrtSetDevice(m_dvpp_deviceId); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]-aclrtSetDevice failed !", m_dec_name); + break; + } + + ret = aclrtCreateContext(&m_context, m_dvpp_deviceId); + if (ret != ACL_ERROR_NONE) { + LOG_ERROR("[{}]-aclrtCreateContext failed !", m_dec_name); + break; + } + + // DvppSourceManager 创建时包含 aclInit,析构时包含 aclFinalize + DvppSourceManager* pSrcMgr = DvppSourceManager::getInstance(); + m_dvpp_channel = pSrcMgr->getChannel(m_dvpp_deviceId); + if(m_dvpp_channel < 0){ + LOG_ERROR("[{}]-该设备channel已经用完了!", m_dec_name); + break; + } + + m_vpcUtils.init(m_dvpp_deviceId); + + LOG_INFO("[{}]- init vdpp success! device:{} channel:{}", m_dec_name, m_dvpp_deviceId, m_dvpp_channel); + return true; + }while(0); + + release_dvpp(); + + return false; +} + +bool DvppRtpDecoder::isSurport(FFDecConfig& cfg){ + return true; +} + +bool DvppRtpDecoder::start(){ + + if(!probe()) { + return false; + } + + m_bRunning = true; + + m_read_thread = new std::thread([](void* arg) + { + DvppRtpDecoder* a=(DvppRtpDecoder*)arg; + a->read_thread(); + return (void*)0; + }, this); + + return true; +} + +void DvppRtpDecoder::Close(){ + m_bRunning=false; + + if(m_read_thread != nullptr){ + m_read_thread->join(); + delete m_read_thread; + m_read_thread = nullptr; + } + + m_recoderManager.close(); + + release_ffmpeg(); + release_dvpp(); +} + +void DvppRtpDecoder::setPostDecArg(const void* postDecArg){ + m_postDecArg = postDecArg; +} + +void DvppRtpDecoder::setFinishedDecArg(const void* finishedDecArg){ + m_finishedDecArg = finishedDecArg; +} + +void DvppRtpDecoder::pause(){ + m_bPause = true; +} + +void DvppRtpDecoder::resume(){ + m_bPause = false; +} + +void DvppRtpDecoder::setDecKeyframe(bool bKeyframe){ + m_dec_keyframe = bKeyframe; +} + +bool DvppRtpDecoder::isRunning(){ + return m_bRunning; +} + +bool DvppRtpDecoder::isFinished(){ + return m_bFinished; +} + +bool DvppRtpDecoder::isPausing(){ + return m_bPause; +} + +bool DvppRtpDecoder::getResolution(int &width, int &height){ + width = frame_width; + height = frame_height; + return true; +} + +bool DvppRtpDecoder::getOutResolution( int &width, int &height ) { + width = out_frame_width; + height = out_frame_height; + return true; +} + +float DvppRtpDecoder::fps(){ + return m_fps; +} + +static int snap_count = 0; + +DeviceMemory* DvppRtpDecoder::snapshot(){ + + int ret = aclrtSetCurrentContext(m_context); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- aclrtSetCurrentContext failed", m_dec_name); + return nullptr; + } + + // 注意有锁 + DeviceMemory* snapshot_mem = nullptr; + int loop_times = 0; + while(m_bRunning) { + m_decoded_data_queue_mtx.lock(); + if(m_decoded_data_queue.size() <= 0) { + m_decoded_data_queue_mtx.unlock(); + loop_times++; + if(loop_times > 100) { + // 1s都没截取到图,退出 + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + + DvppDataMemory* mem = m_decoded_data_queue.front(); + snapshot_mem = new DvppDataMemory(mem); + m_decoded_data_queue_mtx.unlock(); + + // snap_count++; + // LOG_INFO("[{}]- snap_count:{} ", m_dec_name, snap_count); + break; + } + + return snapshot_mem; +} + +void DvppRtpDecoder::release_ffmpeg() { + m_dec_keyframe = false; + if(h264bsfc){ + av_bsf_free(&h264bsfc); + h264bsfc = nullptr; + } + if(avctx){ + avcodec_free_context(&avctx); + avctx = nullptr; + } + if (fmt_ctx){ + avformat_close_input(&fmt_ctx); + fmt_ctx = nullptr; + } + + LOG_DEBUG("[{}]- release_ffmpeg", m_dec_name); +} + +void DvppRtpDecoder::CacheBuffer(uint8_t* recvBuf, int recvBufSize) { + if ((m_bufferSize + recvBufSize - RTP_HEADER_SIZE) < MAX_RTP_BUFFER_SIZE) { + memcpy(m_buffer + m_bufferSize, recvBuf + RTP_HEADER_SIZE, recvBufSize - RTP_HEADER_SIZE); + m_bufferSize += recvBufSize - RTP_HEADER_SIZE; + } else { + LOG_WARN("recvBufSize = {} over MAX_RTP_BUFFER_SIZE ", recvBufSize); + } +} + +int DvppRtpDecoder::ReadBuffer(uint8_t* buf, int buffsize) { + int ret = 0; + if (m_bufferSize >= buffsize) { + memcpy(buf, m_buffer, buffsize); + m_bufferSize = m_bufferSize - buffsize; + memmove(m_buffer, m_buffer + buffsize, m_bufferSize); + ret = buffsize; + + LOG_DEBUG("avio_read_packet={}", buffsize); + } + + return ret; +} + +bool DvppRtpDecoder::probe() { + // todo: 此处可能有泄露 + unsigned char* avioBuff = (unsigned char*)av_malloc(7680 * 4320); + ioCtx = avio_alloc_context(avioBuff, sizeof(avioBuff), 0, this, avio_read_packet, NULL, NULL); + //探测流(获取码流格式) + const AVInputFormat* inputFmt; + int ret = av_probe_input_buffer2(ioCtx, &inputFmt, "", NULL, 0, 0); + if (ret < 0){ + LOG_ERROR("av_probe_input_buffer2 error: {}", ret); + return false; + } + + do{ + fmt_ctx = avformat_alloc_context(); + fmt_ctx->pb = ioCtx; + + + AVDictionary* net_options{nullptr};//网络连接参数 + + //配置流参数 + //av_dict_set(&net_options, "fflags", "nobuffer", 0); //不缓存直接解码 + + //打开流 + ret = avformat_open_input(&fmt_ctx, "", inputFmt, &net_options); + if (ret != 0) + { + LOG_ERROR("avformat_open_input error: {}", ret); + break; + } + //获取流信息 + if (avformat_find_stream_info(fmt_ctx, NULL) < 0)//? + { + LOG_ERROR("avformat_find_stream_info error"); + break; + } + //获取视频流 + mVideoIndex = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + if (mVideoIndex < 0) + { + LOG_ERROR("av_find_best_stream error"); + break; + } + //获取解码信息 + AVStream* stream = fmt_ctx->streams[mVideoIndex]; + AVCodecParameters *codecpar = stream->codecpar; + const AVCodec* videoCodec = avcodec_find_decoder(codecpar->codec_id); + if (!videoCodec){ + LOG_ERROR("avcodec_find_decoder error"); + break; + } + avctx = avcodec_alloc_context3(videoCodec); + + //codecpar为解码器上下文赋值 + if (avcodec_parameters_to_context(avctx, codecpar) != 0) + { + LOG_ERROR("avcodec_parameters_to_context error"); + break; + } + + int enType = getVdecType(codecpar->codec_id, codecpar->profile); + if(-1 == enType) { + break; + } + m_enType = static_cast(enType); + + const AVBitStreamFilter * filter = nullptr; + if(codecpar->codec_id == AV_CODEC_ID_H264){ + filter = av_bsf_get_by_name("h264_mp4toannexb"); + }else if(codecpar->codec_id == AV_CODEC_ID_HEVC){ + filter = av_bsf_get_by_name("hevc_mp4toannexb"); + }else { + LOG_ERROR("[{}]- codec_id is not supported!", m_dec_name); + break; + } + + ret = av_bsf_alloc(filter, &h264bsfc); + if (ret < 0){ + break; + } + + avcodec_parameters_copy(h264bsfc->par_in, codecpar); + av_bsf_init(h264bsfc); + + frame_width = codecpar->width; + frame_height = codecpar->height; + pix_fmt = (AVPixelFormat)codecpar->format; + + calcOutResolution(frame_width, frame_height); + + if (stream->avg_frame_rate.den) { + m_fps = av_q2d(stream ->avg_frame_rate); + } else { + m_fps = 0.0; + } + + 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.init(frame_width, frame_height, m_fps, avctx->bit_rate); + if (!bRet){ + LOG_ERROR("[{}]- m_recoderManager 初始化失败!", m_dec_name); + } + #endif + + LOG_INFO("[{}]- init ffmpeg success! src:({}, {}) out:({}, {}) fps:{} ", m_dec_name, frame_width, frame_height, out_frame_width, out_frame_height, m_fps); + + return true; + } while(0); + + release_ffmpeg(); + + return false; +} + +void DvppRtpDecoder::read_thread() { + + int ret = -1; + + m_bExitReportThd = false; + pthread_t report_thread; + ret = pthread_create(&report_thread, nullptr, ReportThd, (void *)this); + if(ret != 0){ + LOG_ERROR("[{}]- pthread_create failed", m_dec_name); + return; + } + + aclrtContext ctx = nullptr; + aclvdecChannelDesc *vdecChannelDesc = nullptr; + + do { + CHECK_AND_BREAK(aclrtSetDevice(m_dvpp_deviceId), "aclrtSetDevice failed"); + int ret = aclrtSetCurrentContext(m_context); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- aclrtSetCurrentContext failed", m_dec_name); + break; + } + + vdecChannelDesc = aclvdecCreateChannelDesc(); + if (vdecChannelDesc == nullptr) { + LOG_ERROR("[{}]- aclvdecCreateChannelDesc failed", m_dec_name); + break; + } + + // 创建 channel dec结构体 + // 通道ID在dvpp层面为0~31 + CHECK_AND_BREAK(aclvdecSetChannelDescChannelId(vdecChannelDesc, m_dvpp_channel), "aclvdecSetChannelDescChannelId failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescThreadId(vdecChannelDesc, report_thread), "aclvdecSetChannelDescThreadId failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescCallback(vdecChannelDesc, VdecCallback), "aclvdecSetChannelDescCallback failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescEnType(vdecChannelDesc, m_enType), "aclvdecSetChannelDescEnType failed"); + CHECK_AND_BREAK(aclvdecSetChannelDescOutPicFormat(vdecChannelDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420), "aclvdecSetChannelDescOutPicFormat failed"); + CHECK_AND_BREAK(aclvdecCreateChannel(vdecChannelDesc), "aclvdecCreateChannel failed"); + + unsigned long long frame_nb = 0; + while (m_bRunning){ + + AVPacket* pkt = av_packet_alloc(); + av_init_packet( pkt ); + int result = av_read_frame(fmt_ctx, pkt); + if (result == AVERROR_EOF || result < 0){ + av_packet_free(&pkt); + pkt = nullptr; + LOG_WARN("[{}]- Failed to read frame!", m_dec_name); + break; + } + + if (m_DvppCacheCounter.load() > m_cache_gop){ + // 解码器解码不过来。实时流在此处的处理会导致花屏,这是由于解码器性能问题导致,无法避免 + // 实时流在这里处理是为了避免长时间不读取数据导致数据中断 + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + + if (m_dec_keyframe && !(pkt->flags & AV_PKT_FLAG_KEY)) { + av_packet_free(&pkt); + pkt = nullptr; + continue; + } + + if (mVideoIndex == pkt->stream_index){ + + ret = av_bsf_send_packet(h264bsfc, pkt); + if(ret < 0) { + LOG_ERROR("[{}]- av_bsf_send_packet error!", m_dec_name); + av_packet_free(&pkt); + pkt = nullptr; + continue; + } + + frame_nb++; + int nSended = -1; + while ((ret = av_bsf_receive_packet(h264bsfc, pkt)) == 0) { + if(!m_bRunning){ + break; + } + nSended = sendPkt(vdecChannelDesc, pkt, frame_nb); + } + + if(nSended < 0) { + // 执行出错,强行结束整个任务 + m_bRunning=false; + break; + } + + #ifdef USE_VILLAGE + m_recoderManager.cache_pkt(pkt, frame_nb, m_dec_name); + #endif + } else { + av_packet_free(&pkt); + pkt = nullptr; + } + } + + if (vdecChannelDesc) { + sendVdecEos(vdecChannelDesc); + } + + while(m_bRunning && m_decoded_data_queue.size() > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + } while (0); + + if (vdecChannelDesc) { + CHECK_NOT_RETURN(aclvdecDestroyChannel(vdecChannelDesc), "aclvdecDestroyChannel failed"); + CHECK_NOT_RETURN(aclvdecDestroyChannelDesc(vdecChannelDesc), "aclvdecDestroyChannelDesc failed"); + vdecChannelDesc = nullptr; + } + + m_bRunning=false; + + m_bExitReportThd = true; + CHECK_NOT_RETURN(pthread_join(report_thread, nullptr), "report_thread join failed"); + + m_bFinished = true; + + LOG_INFO("[{}]- read thread exit.", m_dec_name); + + if(decode_finished_cbk) { + decode_finished_cbk(m_finishedDecArg); + } +} + +int DvppRtpDecoder::sendPkt(aclvdecChannelDesc *vdecChannelDesc, AVPacket* pkt, unsigned long long frame_nb){ + + void *vdecInputbuf = nullptr; + void *vdecOutputBuf = nullptr; + acldvppStreamDesc *input_stream_desc = nullptr; + acldvppPicDesc *output_pic_desc = nullptr; + do{ + int ret = acldvppMalloc((void **)&vdecInputbuf, pkt->size); + if(ACL_ERROR_NONE != ret){ + LOG_ERROR("[{}]- acldvppMalloc failed!, ret:{}", m_dec_name, ret); + break; + } + + ret = aclrtMemcpy(vdecInputbuf, pkt->size, pkt->data, pkt->size, ACL_MEMCPY_HOST_TO_DEVICE); + if(ACL_ERROR_NONE != ret){ + LOG_ERROR("[{}]- aclrtMemcpy failed", m_dec_name); + break; + } + + ret = acldvppMalloc((void **)&vdecOutputBuf, m_vdec_out_size); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- acldvppMalloc failed", m_dec_name); + break; + } + + input_stream_desc = acldvppCreateStreamDesc(); + if (input_stream_desc == nullptr) { + LOG_ERROR("[{}]- acldvppCreateStreamDesc failed", m_dec_name); + break; + } + output_pic_desc = acldvppCreatePicDesc(); + if (output_pic_desc == nullptr) { + LOG_ERROR("[{}]- acldvppCreatePicDesc failed", m_dec_name); + break; + } + CHECK_AND_BREAK(acldvppSetStreamDescData(input_stream_desc, vdecInputbuf), "acldvppSetStreamDescData failed"); + CHECK_AND_BREAK(acldvppSetStreamDescSize(input_stream_desc, pkt->size), "acldvppSetStreamDescSize failed"); + CHECK_AND_BREAK(acldvppSetPicDescData(output_pic_desc, vdecOutputBuf), "acldvppSetPicDescData failed"); + CHECK_AND_BREAK(acldvppSetPicDescSize(output_pic_desc, m_vdec_out_size), "acldvppSetPicDescSize failed"); + + Vdec_CallBack_UserData *user_data = NULL; + user_data = new Vdec_CallBack_UserData; + user_data->frameId = frame_nb; + user_data->frame_nb = frame_nb; + // user_data->startTime = startTime; + user_data->sendTime = UtilTools::get_cur_time_ms(); + user_data->self = this; + + m_in_count++; + + // 内部缓存计数加1 + m_DvppCacheCounter++; + ret = aclvdecSendFrame(vdecChannelDesc, input_stream_desc, output_pic_desc, nullptr, reinterpret_cast(user_data)); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- aclvdecSendFrame failed", m_dec_name); + delete user_data; + user_data = nullptr; + return -2; + } + + return 0; + }while (0); + + if (vdecInputbuf){ + acldvppFree(vdecInputbuf); + vdecInputbuf = nullptr; + } + + // 报错情形 + if(input_stream_desc){ + CHECK_NOT_RETURN(acldvppDestroyStreamDesc(input_stream_desc), "acldvppDestroyStreamDesc failed"); + } + + if (vdecOutputBuf){ + acldvppFree(vdecOutputBuf); + vdecOutputBuf = nullptr; + } + + if(output_pic_desc){ + CHECK_NOT_RETURN(acldvppDestroyPicDesc(output_pic_desc), "acldvppDestroyPicDesc failed"); + } + + return -1; +} + +void DvppRtpDecoder::doProcessReport(){ + + aclError ret = aclrtSetDevice(m_dvpp_deviceId); + if(ret != ACL_ERROR_NONE){ + // cout << "aclrtSetDevice failed" << endl; + LOG_ERROR("aclrtSetDevice failed !"); + return ; + } + + aclrtContext ctx; + ret = aclrtCreateContext(&ctx, m_dvpp_deviceId); + if (ret != ACL_ERROR_NONE) { + // cout << "aclrtCreateContext failed " << endl; + LOG_ERROR("aclrtCreateContext failed !"); + return ; + } + + while (!m_bExitReportThd) { + aclrtProcessReport(1000); + } + + ret = aclrtDestroyContext(ctx); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("aclrtDestroyContext failed !"); + } + LOG_INFO("doProcessReport exit."); +} + +void DvppRtpDecoder::doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData){ + + // 内部缓存计数减1 + m_DvppCacheCounter--; + + if(nullptr == pUserData){ + return; + } + + Vdec_CallBack_UserData *userData = (Vdec_CallBack_UserData *) pUserData; + uint64_t frame_nb = userData->frame_nb; + + m_out_count++; + + CHECK_AND_RETURN_NOVALUE(aclrtSetCurrentContext(m_context), "aclrtSetCurrentContext failed"); + + void *inputDataDev = acldvppGetStreamDescData(input); + acldvppFree(inputDataDev); + inputDataDev = nullptr; + + void *outputDataDev = acldvppGetPicDescData(output); + uint32_t outputSize = acldvppGetPicDescSize(output); + uint32_t width = acldvppGetPicDescWidth(output); + uint32_t width_stride = acldvppGetPicDescWidthStride(output); + uint32_t height = acldvppGetPicDescHeight(output); + uint32_t height_stride = acldvppGetPicDescHeightStride(output); + + do{ + int ret = acldvppGetPicDescRetCode(output); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- decode result error, retCode:{} ", m_dec_name, ret); + acldvppFree(outputDataDev); + outputDataDev = nullptr; + break; + } + + bool bCached = false; + if(width > 0 && height > 0 && outputSize > 0){ + + // cout << m_dec_name << " 解码时间间隔: " << get_cur_time_ms() - last_ts << endl; + // last_ts = get_cur_time_ms(); + + // 换成解码后数据, 这里这样做的是为了保证解码一直持续进行,避免后续操作阻碍文件读取和解码从而导致花屏 + DvppDataMemory* mem = nullptr; + if (m_bResize && (width > 1920 || height > 1080)) { + + mem = m_vpcUtils.resize(output, out_frame_width, out_frame_height); + if (mem) { + acldvppFree(outputDataDev); + outputDataDev = nullptr; + + mem->setDeviceId(to_string(m_dvpp_deviceId)); + mem->setId(m_dec_name); + mem->setFrameNb(frame_nb); + } + } else { + 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_mtx.lock(); + m_decoded_data_queue.push(mem); + m_decoded_data_queue_mtx.unlock(); + bCached = true; + } + } + + if(!bCached) { + LOG_WARN("[{}]- decode result warning, width:{} width_stride:{} height:{} height_stride:{} size:{}", m_dec_name, width, width_stride, height, height_stride, outputSize); + acldvppFree(outputDataDev); + outputDataDev = nullptr; + } + }while(0); + + CHECK_AND_RETURN_NOVALUE(acldvppDestroyStreamDesc(input), "acldvppDestroyStreamDesc failed"); + CHECK_AND_RETURN_NOVALUE(acldvppDestroyPicDesc(output), "acldvppDestroyPicDesc failed"); +} + +bool DvppRtpDecoder::sendVdecEos(aclvdecChannelDesc *vdecChannelDesc) { + // create stream desc + acldvppStreamDesc *streamInputDesc = acldvppCreateStreamDesc(); + if (streamInputDesc == nullptr) { + LOG_ERROR("[{}]- fail to create input stream desc", m_dec_name); + return false; + } + aclError ret = acldvppSetStreamDescEos(streamInputDesc, 1); + if (ret != ACL_SUCCESS) { + LOG_ERROR("[{}]- fail to set eos for stream desc, errorCode = {}", m_dec_name, static_cast(ret)); + (void)acldvppDestroyStreamDesc(streamInputDesc); + return false; + } + + // send vdec eos frame. when all vdec callback are completed, aclvdecSendFrame can be returned. + LOG_INFO("[{}]- send eos", m_dec_name); + ret = aclvdecSendFrame(vdecChannelDesc, streamInputDesc, nullptr, nullptr, nullptr); + (void)acldvppDestroyStreamDesc(streamInputDesc); + if (ret != ACL_SUCCESS) { + LOG_ERROR("[{}]- fail to send eos frame, ret={}", m_dec_name, ret); + return false; + } + + return true; +} + +DvppDataMemory* DvppRtpDecoder::GetFrame() { + DvppDataMemory* mem = nullptr; + m_decoded_data_queue_mtx.lock(); + if (m_decoded_data_queue.size() > 0) { + mem = m_decoded_data_queue.front(); + m_decoded_data_queue.pop(); + } + m_decoded_data_queue_mtx.unlock(); + + return mem; +} + +void DvppRtpDecoder::release_dvpp(){ + if(m_context){ + aclError ret = aclrtDestroyContext(m_context); + if(ret != ACL_ERROR_NONE){ + LOG_ERROR("[{}]- aclrtDestroyContext failed !", m_dec_name); + } + m_context = nullptr; + } + + if(m_dvpp_channel >= 0){ + DvppSourceManager* pSrcMgr = DvppSourceManager::getInstance(); + pSrcMgr->releaseChannel(m_dvpp_deviceId, m_dvpp_channel); + m_dvpp_channel = -1; + } +} + +void DvppRtpDecoder::doRecode(RecoderInfo& recoderInfo) { + m_recoderManager.create_recode_task(recoderInfo); +} + +void DvppRtpDecoder::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/DvppRtpDecoder.h b/src/decoder/dvpp/DvppRtpDecoder.h new file mode 100644 index 0000000..8473c56 --- /dev/null +++ b/src/decoder/dvpp/DvppRtpDecoder.h @@ -0,0 +1,157 @@ +#ifndef __DVPP_RTP_DECODER_H__ +#define __DVPP_RTP_DECODER_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include "depend_headers.h" +#include "dvpp_headers.h" +#include "DvppDataMemory.hpp" + +#include "FFRecoderTaskManager.h" + +#include "VpcUtils.h" + +using namespace std; + +#define MAX_RTP_BUFFER_SIZE 4194304 // 4M = 4 * 1024 * 1024 = 4194304 字节 + +class DvppRtpDecoder +{ +public: + DvppRtpDecoder(); + ~DvppRtpDecoder(); + +public: + std::atomic m_buffer[MAX_RTP_BUFFER_SIZE]; + std::atomic_int m_bufferSize {0}; + +public: + bool Init(FFDecConfig cfg); + void Close(); + bool start(); + void pause(); + void resume(); + + void setDecKeyframe(bool bKeyframe); + + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + bool getOutResolution( int &width, int &height ); + + bool isSurport(FFDecConfig& cfg); + + float fps(); + + void setName(string nm){ + m_dec_name = nm; + } + + string getName(){ + return m_dec_name; + } + + DeviceMemory* snapshot(); + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); + + DvppDataMemory* GetFrame(); + + void doRecode(RecoderInfo& recoderInfo); + + void set_mq_callback(mq_callback_t cb); + + void CacheBuffer(uint8_t* buf, int buf_size); + + int ReadBuffer(uint8_t* buf, int buffsize); + +public: + void doVdppVdecCallBack(acldvppStreamDesc *input, acldvppPicDesc *output, void *pUserData); + void doProcessReport(); + +private: + bool init_dvpp(FFDecConfig cfg); + void release_ffmpeg(); + void read_thread(); + bool probe();//阻塞式探测国标流并获取解码参数 + + int sendPkt(aclvdecChannelDesc *vdecChannelDesc, AVPacket* pkt, unsigned long long frame_nb); + bool sendVdecEos(aclvdecChannelDesc *vdecChannelDesc); + void release_dvpp(); + + int getVdecType(int videoType, int profile); + + void calcOutResolution(int w, int h); + +private: + FFDecConfig m_cfg; + string m_dec_name; + + const void * m_finishedDecArg {nullptr}; + DECODE_FINISHED_CALLBACK decode_finished_cbk {nullptr}; + + bool m_bFinished{false}; + bool m_bRunning{false}; + bool m_bPause{false}; + + bool m_bExitReportThd{false}; + + // 读取数据 + AVFormatContext *fmt_ctx{nullptr}; + AVIOContext * ioCtx{nullptr}; + int mVideoIndex {-1}; + AVPixelFormat pix_fmt; + AVCodecContext *avctx{nullptr}; + AVBSFContext * h264bsfc{nullptr}; + + int frame_width{0}; + int frame_height{0}; + int out_frame_width{0}; + int out_frame_height{0}; + float m_fps{0.0}; + + std::thread* m_read_thread{nullptr}; + + bool m_dec_keyframe {false}; + bool m_bResize {false}; + + // 解码 + int m_dvpp_deviceId {-1}; + int m_dvpp_channel {-1}; + aclrtContext m_context{nullptr}; + acldvppStreamFormat m_enType; + + const void * m_postDecArg {nullptr}; + POST_DECODE_CALLBACK post_decoded_cbk {nullptr}; + + int m_vdec_out_size {-1}; + + FFRecoderTaskManager m_recoderManager; + + queue m_decoded_data_queue; + mutex m_decoded_data_queue_mtx; + + 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; + +}; +#endif //__DVPP_RTP_DECODER_H__ \ No newline at end of file diff --git a/src/decoder/dvpp/DvppStreamDecoder.cpp b/src/decoder/dvpp/DvppStreamDecoder.cpp index 5b00f77..387c521 100644 --- a/src/decoder/dvpp/DvppStreamDecoder.cpp +++ b/src/decoder/dvpp/DvppStreamDecoder.cpp @@ -668,6 +668,16 @@ void DvppStreamDecoder::Close() { decode_finished_cbk(m_finishedDecArg); decode_finished_cbk = nullptr; } + + DvppDataMemory* mem = nullptr; + m_decoded_data_queue_mtx.lock(); + while (m_decoded_data_queue.size() > 0) { + mem = m_decoded_data_queue.front(); + delete mem; + mem = nullptr; + m_decoded_data_queue.pop(); + } + m_decoded_data_queue_mtx.unlock(); } void DvppStreamDecoder::doRecode(RecoderInfo& recoderInfo) { diff --git a/src/decoder/dvpp/FFRecoder.cpp b/src/decoder/dvpp/FFRecoder.cpp index 8a4c1ce..a8c1370 100644 --- a/src/decoder/dvpp/FFRecoder.cpp +++ b/src/decoder/dvpp/FFRecoder.cpp @@ -134,10 +134,17 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil return false; } - avcodec_copy_context(codec_ctx_, avctx); - codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; m_inStream = stream; + int ret = avcodec_parameters_to_context(codec_ctx_, m_inStream->codecpar); + if (ret < 0) { + printf("Failed to copy in_stream codecpar to codec context\n"); + return false; + } + + // avcodec_copy_context(codec_ctx_, avctx); + codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + // [2] 创建输出上下文 avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr, outfile_name); @@ -154,8 +161,8 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil codec_ctx_->time_base = out_stream_->time_base; - av_opt_set(out_stream_->codec->priv_data, "preset", "ultrafast", 0); - av_opt_set(out_stream_->codec->priv_data, "tune", "zerolatency", 0); + av_opt_set(out_stream_->priv_data, "preset", "ultrafast", 0); + av_opt_set(out_stream_->priv_data, "tune", "zerolatency", 0); // av_dump_format(fmt_ctx_, out_stream_->id, outfile_name, 1); @@ -175,8 +182,7 @@ bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfil void FFRecoder::release() { av_write_trailer(fmt_ctx_); - avcodec_close(fmt_ctx_->streams[0]->codec); - av_freep(&fmt_ctx_->streams[0]->codec); + avcodec_parameters_free(&fmt_ctx_->streams[0]->codecpar); av_freep(&fmt_ctx_->streams[0]); avio_close(fmt_ctx_->pb); diff --git a/src/decoder/dvpp/depend_headers.h b/src/decoder/dvpp/depend_headers.h index bfb25be..0c1c7ea 100644 --- a/src/decoder/dvpp/depend_headers.h +++ b/src/decoder/dvpp/depend_headers.h @@ -27,9 +27,10 @@ extern "C" { #include "libavutil/samplefmt.h" #include "libavformat/avformat.h" #include "libavcodec/avcodec.h" - #include - #include - #include + #include "libavcodec/bsf.h" + #include "libavutil/opt.h" + #include "libavutil/timestamp.h" + #include "libswscale/swscale.h" } diff --git a/src/decoder/gb28181/DvppGB28181Decoder.cpp b/src/decoder/gb28181/DvppGB28181Decoder.cpp deleted file mode 100644 index cdd0850..0000000 --- a/src/decoder/gb28181/DvppGB28181Decoder.cpp +++ /dev/null @@ -1,407 +0,0 @@ -//#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 "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 -#define EINITED 4 - -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) 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); - m_post_decode_thread = 0; - } - - streamDecoder.Close(); - - 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.dec_name; - 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); - - m_status = EINITED; - - return true; -} - -bool DvppGB28181Decoder::start() { - - m_status = ERUNNING; - - bool bRet = m_rtpPtr->Open(m_cfg.uri); - if(bRet){ - pthread_create(&m_post_decode_thread,0, - [](void* arg) - { - DvppGB28181Decoder* a=(DvppGB28181Decoder*)arg; - a->display_thread(); - return (void*)0; - } - ,this); - - return true; - } - - close(); - - 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 {}--{}", m_dec_name, gpuFrame->width, gpuFrame->height, frameW, frameH); - // 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); - } else { - delete mem; - mem = nullptr; - } - - index++; - if(index >= 100000){ - index = 0; - } - } - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - LOG_INFO("[{}] - display thread exited.", m_dec_name); -} - -void DvppGB28181Decoder::stream_end_callback() -{ - LOG_INFO("[{}] - send_video_eof", m_dec_name); - - m_status = ECLOSING; - - 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; -} - -bool DvppGB28181Decoder::getOutResolution( 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(); -} - -DeviceMemory* DvppGB28181Decoder::snapshot() { - - 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/gb28181/DvppGB28181Decoder.cpp0 b/src/decoder/gb28181/DvppGB28181Decoder.cpp0 new file mode 100644 index 0000000..8d644f4 --- /dev/null +++ b/src/decoder/gb28181/DvppGB28181Decoder.cpp0 @@ -0,0 +1,403 @@ +//#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 "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 +#define EINITED 4 + +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) 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); + m_post_decode_thread = 0; + } + + streamDecoder.Close(); + + 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.dec_name; + 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); + + m_status = EINITED; + + return true; +} + +bool DvppGB28181Decoder::start() { + + m_status = ERUNNING; + + bool bRet = m_rtpPtr->Open(m_cfg.uri); + if(bRet){ + pthread_create(&m_post_decode_thread,0, + [](void* arg) + { + DvppGB28181Decoder* a=(DvppGB28181Decoder*)arg; + a->display_thread(); + return (void*)0; + } + ,this); + + return true; + } + + close(); + + 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 {}--{}", m_dec_name, gpuFrame->width, gpuFrame->height, frameW, frameH); + // 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); + } else { + delete mem; + mem = nullptr; + } + + index++; + if(index >= 100000){ + index = 0; + } + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + LOG_INFO("[{}] - display thread exited.", m_dec_name); +} + +void DvppGB28181Decoder::stream_end_callback() +{ + LOG_INFO("[{}] - send_video_eof", m_dec_name); + + m_status = ECLOSING; + + 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; +} + +bool DvppGB28181Decoder::getOutResolution( int &width, int &height ) { + width = frameW; + height = frameH; + return true; +} + +float DvppGB28181Decoder::fps() { + return m_fps; +} + +bool DvppGB28181Decoder::isSurport(FFDecConfig& cfg){ + // 由于是否支持需要在拿到数据后才能断定,无法事先判断,所以这个地方默认返回true + return true; +} + +DeviceMemory* DvppGB28181Decoder::snapshot() { + + 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/gb28181/DvppGB28181Decoder.h b/src/decoder/gb28181/DvppGB28181Decoder.h index b42ee95..c578b18 100644 --- a/src/decoder/gb28181/DvppGB28181Decoder.h +++ b/src/decoder/gb28181/DvppGB28181Decoder.h @@ -42,8 +42,6 @@ public: bool isSurport(FFDecConfig& cfg); - int getCachedQueueLength(); - float fps(); DECODER_TYPE getDecoderType(){ return DECODER_TYPE_DVPP_GB28181; } diff --git a/src/decoder/gb28181/DvppGB28181Decoder2.cpp b/src/decoder/gb28181/DvppGB28181Decoder2.cpp new file mode 100644 index 0000000..37ada89 --- /dev/null +++ b/src/decoder/gb28181/DvppGB28181Decoder2.cpp @@ -0,0 +1,264 @@ +//#include "LOG_manager.h" +#include +#include "DvppGB28181Decoder2.h" +#include "common_header.h" + + +#define ECLOSED 0 +#define ECLOSING 1 +#define ERUNNING 2 +#define EPAUSE 3 +#define EINITED 4 + +static void RTP_Stream_CallBack(void* userdata, uint8_t* buf, int buf_size, uint64_t pts) +{ + DvppGB28181Decoder2* decoder = (DvppGB28181Decoder2*)userdata; + decoder->stream_callback(buf, buf_size, pts); +} + +static void RTP_Stream_End_CallBack(void* userdata) +{ + DvppGB28181Decoder2* decoder = (DvppGB28181Decoder2*)userdata; + decoder->stream_end_callback(); +} + +DvppGB28181Decoder2::DvppGB28181Decoder2() { + m_frameSkip = 1; + m_dec_keyframe = false; + m_post_decode_thread = 0; +} + +DvppGB28181Decoder2::~DvppGB28181Decoder2() +{ + close(); + + m_dec_keyframe = false; + + LOG_INFO("destroy OK--{}", m_dec_name); +} + +void DvppGB28181Decoder2::close(){ + + if (m_status == ECLOSED) 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 (m_post_decode_thread != 0) { + pthread_join(m_post_decode_thread,0); + m_post_decode_thread = 0; + } + + rtpDecoder.Close(); + + m_status = ECLOSED; + + LOG_INFO("解码器关闭成功 --{}", m_dec_name); +} + +bool DvppGB28181Decoder2::init(FFDecConfig& cfg){ + + m_rtpPtr = new RTPReceiver2(); + if(nullptr == m_rtpPtr){ + return false; + } + + m_dec_name = cfg.dec_name; + 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 (!rtpDecoder.Init(cfg)) { + return false; + } + + m_cfg = cfg; + + LOG_INFO("init - {} ", m_dec_name); + + m_status = EINITED; + + return true; +} + +bool DvppGB28181Decoder2::start() { + + m_status = ERUNNING; + + bool bRet = m_rtpPtr->Open(m_cfg.uri, !m_cfg.force_tcp); + if(bRet && rtpDecoder.start()) { + pthread_create(&m_post_decode_thread,0, + [](void* arg) + { + DvppGB28181Decoder2* a=(DvppGB28181Decoder2*)arg; + a->display_thread(); + return (void*)0; + } + ,this); + + return true; + } + + close(); + + LOG_ERROR("[{}] - rtp receiver open failed !", m_dec_name); + + return false; +} + +void DvppGB28181Decoder2::setDecKeyframe(bool bKeyframe){ + m_dec_keyframe = bKeyframe; +} + +void DvppGB28181Decoder2::stream_callback(uint8_t* buf, int buf_size, uint64_t pts) { + if (m_status == EPAUSE) return; + + // 若设置为关键帧解码,非关键帧数据直接返回 + // if(m_dec_keyframe && !isKey) return; + + rtpDecoder.CacheBuffer(buf, buf_size); +} + +void DvppGB28181Decoder2::display_thread(){ + + int index = 0; + while (isRunning()) + { + auto mem = rtpDecoder.GetFrame(); + if(mem) { + if ((m_frameSkip == 1 || index % m_frameSkip == 0) && post_decoded_cbk){ + post_decoded_cbk(m_postDecArg, mem); + } else { + delete mem; + mem = nullptr; + } + + index++; + if(index >= 100000){ + index = 0; + } + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + LOG_INFO("[{}] - display thread exited.", m_dec_name); +} + +void DvppGB28181Decoder2::stream_end_callback() +{ + LOG_INFO("[{}] - stream end.", m_dec_name); + + m_status = ECLOSING; + + decode_finished_cbk(m_finishedDecArg); + + return; +} + +void DvppGB28181Decoder2::setPostDecArg(const void* postDecArg){ + m_postDecArg = postDecArg; +} + +void DvppGB28181Decoder2::setFinishedDecArg(const void* finishedDecArg){ + m_finishedDecArg = finishedDecArg; +} + +void DvppGB28181Decoder2::pause() { + m_status = EPAUSE; + LOG_INFO("[{}] - pause", m_dec_name); +} + +void DvppGB28181Decoder2::resume() { + m_status = ERUNNING; + LOG_INFO("[{}] - resume", m_dec_name); +} + +bool DvppGB28181Decoder2::isRunning(){ + if (m_status == ECLOSED || m_status == ECLOSING){ + return false; + } + return true; +} + +bool DvppGB28181Decoder2::isFinished(){ + if (m_status == ECLOSED || m_status == ECLOSING){ + return true; + } + return false; +} + +bool DvppGB28181Decoder2::isPausing(){ + if (m_status == EPAUSE){ + return true; + } + return false; +} + +bool DvppGB28181Decoder2::getResolution( int &width, int &height ){ + width = frameW; + height = frameH; + return true; +} + +bool DvppGB28181Decoder2::getOutResolution( int &width, int &height ) { + width = frameW; + height = frameH; + return true; +} + +float DvppGB28181Decoder2::fps() { + return m_fps; +} + +bool DvppGB28181Decoder2::isSurport(FFDecConfig& cfg){ + // 由于是否支持需要在拿到数据后才能断定,无法事先判断,所以这个地方默认返回true + return true; +} + +DeviceMemory* DvppGB28181Decoder2::snapshot() { + + DeviceMemory* snapshot_mem = nullptr; + int loop_times = 0; + while (isRunning()) { + snapshot_mem = rtpDecoder.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 DvppGB28181Decoder2::doRecode(RecoderInfo& recoderInfo) { + return rtpDecoder.doRecode(recoderInfo); +} + +void DvppGB28181Decoder2::set_mq_callback(std::function mq_publish) { + rtpDecoder.set_mq_callback(mq_publish); +} \ No newline at end of file diff --git a/src/decoder/gb28181/DvppGB28181Decoder2.h b/src/decoder/gb28181/DvppGB28181Decoder2.h new file mode 100644 index 0000000..bf792b3 --- /dev/null +++ b/src/decoder/gb28181/DvppGB28181Decoder2.h @@ -0,0 +1,100 @@ +#ifndef _GB28181_DECODER_H_ +#define _GB28181_DECODER_H_ + +#include +#include + +#include "./rtp2/RTPReceiver2.h" +#include "../dvpp/DvppRtpDecoder.h" + +#include "common_header.h" +#include "../interface/AbstractDecoder.h" + +using namespace std; + +class DvppGB28181Decoder2: public AbstractDecoder +{ +public: + DvppGB28181Decoder2(); + ~DvppGB28181Decoder2(); + + bool init(FFDecConfig& cfg); + void close(); + bool start(); + void pause(); + void resume(); + + void setDecKeyframe(bool bKeyframe); + + bool isRunning(); + bool isFinished(); + bool isPausing(); + bool getResolution( int &width, int &height ); + bool getOutResolution( int &width, int &height ); + + bool isSurport(FFDecConfig& cfg); + + float fps(); + + DECODER_TYPE getDecoderType(){ return DECODER_TYPE_DVPP_GB28181; } + + DeviceMemory* snapshot(); + + void setName(string nm){ + m_dec_name = nm; + } + + string getName(){ + return m_dec_name; + } + + void setPostDecArg(const void* postDecArg); + void setFinishedDecArg(const void* finishedDecArg); + + void doRecode(RecoderInfo& recoderInfo); + + void set_mq_callback(std::function mq_publish); + +public: + void stream_callback(uint8_t* buf, int buf_size, uint64_t pts); + void stream_end_callback(); + void display_thread(); + +private: + string m_dec_name; // 必须为28181编码 + FFDecConfig m_cfg; + + RTPReceiver2* m_rtpPtr {nullptr}; + + uint64_t m_startPts {}; + uint64_t m_lastPts {}; //上一次pts的值 + uint64_t m_curPts {}; //当前的pts值 + uint64_t m_diffPts {}; + + uint32_t frameW {}, frameH {}; + float m_fps {}; + int m_frameSkip {}; + + int log_count {}; + + std::atomic_int m_status {}; + + pthread_t m_post_decode_thread; + const void * m_postDecArg; + POST_DECODE_CALLBACK post_decoded_cbk; // 解码数据回调接口 + + const void * m_finishedDecArg; + DECODE_FINISHED_CALLBACK decode_finished_cbk; + + queue mFrameQueue; + mutex m_queue_mutex; + mutex m_snapshot_mutex; + + bool m_dec_keyframe; + + DvppRtpDecoder rtpDecoder; + + int m_gpuid {0}; +}; + +#endif // _GB28181_DECODER_H_ diff --git a/src/decoder/gb28181/rtp/FFRtpParser.cpp b/src/decoder/gb28181/rtp/FFRtpParser.cpp deleted file mode 100644 index 694e511..0000000 --- a/src/decoder/gb28181/rtp/FFRtpParser.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// -// Created by bxc on 2023/4/18. -// 作者:北小菜 -// 邮箱:bilibili_bxc@126.com -// 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 -// 哔哩哔哩主页:https://space.bilibili.com/487906612/ -// - -#include "FFRtpParser.h" -#include "Utils.h" -#include - -int avio_read_packet(void* opaque, uint8_t* buf, int buffsize){ - FFRtpParser* player = (FFRtpParser*)opaque; - - int ret = 0; - if (player->bufferSize >= buffsize) - { - memcpy(buf, player->buffer, buffsize); - player->bufferSize = player->bufferSize - buffsize; - memmove(player->buffer, player->buffer + buffsize, player->bufferSize); - ret = buffsize; - - LOG_INFO("avio_read_packet=%d", buffsize); - } - return ret; -} - -FFRtpParser::FFRtpParser() -{ -} - -FFRtpParser::~FFRtpParser() -{ - if (mVideoCodecPar) { - avcodec_parameters_free(&mVideoCodecPar); - } - if (mVideoCodecCtx) { - avcodec_close(mVideoCodecCtx); - mVideoCodecCtx = nullptr; - } - - if (mFmtCtx) { - avformat_close_input(&mFmtCtx); - mFmtCtx = nullptr; - } -} - -bool FFRtpParser::probe() -{ - mFmtCtx = avformat_alloc_context(); - - unsigned char* avioBuff = (unsigned char*)av_malloc(1920 * 1080); - mAvioCtx = avio_alloc_context(avioBuff, sizeof(avioBuff), 0, this, avio_read_packet, NULL, NULL); - //探测流(获取码流格式) - if (av_probe_input_buffer2(mAvioCtx, (const AVInputFormat**)&mInputFmt, "", NULL, 0, 0) < 0){ - LOG_ERROR("av_probe_input_buffer2 error"); - return false; - } - mFmtCtx->pb = mAvioCtx; - - //配置流参数 - //av_dict_set(&options, "fflags", "nobuffer", 0); //不缓存直接解码 - - //打开流 - if (avformat_open_input(&mFmtCtx, "", mInputFmt, &net_options) != 0) - { - LOG_ERROR("avformat_open_input error"); - return false; - } - //获取流信息 - if (avformat_find_stream_info(mFmtCtx, NULL) < 0)//? - { - LOG_ERROR("avformat_find_stream_info error"); - return false; - } - //获取视频流 - mVideoStream = av_find_best_stream(mFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); - if (mVideoStream < 0) - { - LOG_ERROR("av_find_best_stream error"); - return false; - } - //获取解码信息 - mVideoCodecPar = mFmtCtx->streams[mVideoStream]->codecpar; - const AVCodec* videoCodec = avcodec_find_decoder(mVideoCodecPar->codec_id); - if (!videoCodec){ - LOG_ERROR("avcodec_find_decoder error"); - return false; - } - mVideoCodecCtx = avcodec_alloc_context3(videoCodec); - - //codecpar为解码器上下文赋值 - if (avcodec_parameters_to_context(mVideoCodecCtx, mVideoCodecPar) != 0) - { - LOG_ERROR("avcodec_parameters_to_context error"); - return false; - } - - //设置解码器参数 - //av_dict_set(&codec_options, "tune", "zero-latency", 0);//设置零延迟 - //av_dict_set(&codec_options, "preset", "ultrafast", 0);//设置最模糊但是最快的解码方式 - //av_dict_set(&codec_options, "x265-params", "qp=20", 0);//设置265量化参数 - //量化参数:控制了视频帧中每一个宏区块(Macroblock)的压缩量。较大的数值,量化值更高,意味着更多的压缩,更低的质量,较小的数值代表相反的含义。 - - //打开解码器 - if (avcodec_open2(mVideoCodecCtx, videoCodec, &codec_options) < 0) - { - LOG_ERROR("avcodec_open2 error"); - return false; - } - LOG_INFO("mVideoCodecCtx->width=%d,mVideoCodecCtx->height=%d", mVideoCodecCtx->width, mVideoCodecCtx->height); - return true; -} - -void FFRtpParser::play(){ - LOG_INFO("start"); - - AVPacket pkt; - while (av_read_frame(mFmtCtx, &pkt) >= 0) { - if (pkt.stream_index == mVideoStream){ - - } - av_packet_unref(&pkt); - } - LOG_INFO("end"); -} \ No newline at end of file diff --git a/src/decoder/gb28181/rtp/FFRtpParser.h b/src/decoder/gb28181/rtp/FFRtpParser.h deleted file mode 100644 index afa27b9..0000000 --- a/src/decoder/gb28181/rtp/FFRtpParser.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// Created by bxc on 2023/4/18. -// 作者:北小菜 -// 邮箱:bilibili_bxc@126.com -// 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 -// 哔哩哔哩主页:https://space.bilibili.com/487906612/ -// - -#ifndef GB28181_RTP_FFRTPPARSER_H -#define GB28181_RTP_FFRTPPARSER_H - -#include - -extern "C" -{ - #include - #include - #include -} - -#define RtpParser_buffer_max_size 4194304 // 4M = 4 * 1024 * 1024 = 4194304 字节 - -class FFRtpParser -{ -public: - FFRtpParser(); - ~FFRtpParser(); -public: - bool probe();//阻塞式探测国标流并获取解码参数 - void play();//在探测国标流成功以后,解码并渲染国标视频流 -public: - std::atomic buffer[RtpParser_buffer_max_size]; - std::atomic_int bufferSize {0}; -private: - AVFormatContext * mFmtCtx; - AVIOContext * mAvioCtx; - const AVInputFormat* mInputFmt; - int mVideoStream = -1; - AVCodecParameters * mVideoCodecPar; - AVCodecContext * mVideoCodecCtx; - - AVDictionary* net_options;//网络连接参数 - AVDictionary* codec_options;//编码参数 - -}; -#endif //GB28181_RTP_FFRTPPARSER_H \ No newline at end of file diff --git a/src/decoder/gb28181/rtp/RTPReceiver2.cpp b/src/decoder/gb28181/rtp/RTPReceiver2.cpp deleted file mode 100644 index dbe9a87..0000000 --- a/src/decoder/gb28181/rtp/RTPReceiver2.cpp +++ /dev/null @@ -1,287 +0,0 @@ -#include "RTPReceiver2.h" -#include "rtppacket.h" -#include - -#include "../common_header.h" -#include "../websocket/WebsocketClient.h" - -#ifdef __linux__ -#include "arpa/inet.h" -#endif - -#include "Rtp.h" - -const int MAX_RTP_BUFFER_SIZE = 1024*1024*10; - -#define Server_cache_max_size 4194304 // 1M = 1 * 1024 * 1024 = 1048576 字节 -#define Server_rtp_max_size 1800 - - -RTPReceiver2::RTPReceiver2() -{ - mRecvCache = (uint8_t*)malloc(Server_cache_max_size); - mRecvRtpBuffer = (uint8_t*)malloc(Server_rtp_max_size); -} - -RTPReceiver2::~RTPReceiver2(){ - if (mRecvCache) { - free(mRecvCache); - mRecvCache = nullptr; - } - - if (mRecvRtpBuffer) { - free(mRecvRtpBuffer); - mRecvRtpBuffer = nullptr; - } -} - -int RTPReceiver2::init(const char* ip, uint16_t port, bool isUdp) { - if (!isUdp) { - LOG_INFO("tcp://%s:%d", ip, port); - startTcpServer(ip, port); - } - else { - LOG_INFO("udp://%s:%d", ip, port); - startUdpServer(ip, port); - } -} - -int RTPReceiver2::startUdpServer(const char* ip, uint16_t port) { - - int server_fd, ret; - struct sockaddr_in ser_addr; - - server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP - if(server_fd < 0) - { - printf("create socket fail!\n"); - return -1; - } - - memset(&ser_addr, 0, sizeof(ser_addr)); - ser_addr.sin_family = AF_INET; - ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址 - ser_addr.sin_port = htons(port); //端口号,需要网络序转换 - - ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr)); - if(ret < 0) - { - printf("socket bind fail!\n"); - return -1; - } - - - char recvBuf[10000]; - int recvBufSize; - - socklen_t len; - struct sockaddr_in clent_addr; //clent_addr用于记录发送方的地址信息 - while(!m_bRtpExit) - { - memset(recvBuf, 0, sizeof(recvBuf)); - len = sizeof(clent_addr); - recvBufSize = recvfrom(server_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr*)&clent_addr, &len); //recvfrom是拥塞函数,没有数据就一直拥塞 - if(recvBufSize <= 0) { - printf("recieve data fail!\n"); - break; - } - - if ((mPlayer->bufferSize + recvBufSize - RTP_HEADER_SIZE) < MAX_RTP_BUFFER_SIZE) { - memcpy(mPlayer->buffer + mPlayer->bufferSize, recvBuf + RTP_HEADER_SIZE, recvBufSize - RTP_HEADER_SIZE); - mPlayer->bufferSize += recvBufSize - RTP_HEADER_SIZE; - } else { - LOG_ERROR("recvBufSize = {} over GB28181Player_buffer_max_size ", recvBufSize); - } - } - - close(server_fd); - - return 0; -} - -int RTPReceiver2::startTcpServer(const char* ip, uint16_t port) { - - int listenfd, connfd; - struct sockaddr_in servaddr; - char buff[4096]; - int n; - - if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){ - printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); - return 0; - } - - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr.sin_port = htons(port); - - if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ - printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); - return 0; - } - - if( listen(listenfd, 10) == -1){ - printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); - return 0; - } - - - char recvBuf[10000]; - int recvBufSize = 0; - - while (!m_bRtpExit) - { - LOG_INFO("阻塞监听新连接..."); - // 阻塞接收请求 start - - int clientFd = accept(listenfd, (struct sockaddr*)NULL, NULL); - if (clientFd < 0) { - LOG_ERROR("accept connection error"); - continue; - } - // 阻塞接收请求 end - LOG_INFO("发现新连接:clientFd=%d", clientFd); - - while (!m_bRtpExit) { - recvBufSize = recv(clientFd, recvBuf, sizeof(recvBuf), 0); - if (recvBufSize <= 0) { - LOG_ERROR("::recv error: clientFd={},recvBufSize={}", clientFd, recvBufSize); - break; - } - - parseTcpData(recvBuf, recvBufSize); - } - - close(clientFd); - LOG_INFO("关闭连接 clientFd={}", clientFd); - - } - - close(listenfd); - return 0; -} - -void RTPReceiver2::parseTcpData(char* recvBuf, int recvBufSize) { - - if ((mRecvCacheSize + recvBufSize) > Server_cache_max_size) { - LOG_ERROR("超过缓冲容量上限,忽略本次读取的数据。mRecvCacheSize=%d,recvBufSize=%d",mRecvCacheSize, recvBufSize); - - } - else { - memcpy(mRecvCache + mRecvCacheSize, recvBuf, recvBufSize); - mRecvCacheSize += recvBufSize; - } - //LOGI("cacheSize=%d,开始进入解析 ... ...", cacheSize); - - while (true) { - - if (mRecvCacheSize > 2) { - - bool success = false; - - if (mRecvCacheSize > 2) { - mRecvRtpBufferSize = ntohs(*(int16_t*)(mRecvCache)); - if ((mRecvCacheSize - 2) >= mRecvRtpBufferSize) { - success = true; - } - } - - if (success) { - mRecvCacheSize -= 2; - mRecvCacheSize -= mRecvRtpBufferSize; - - // 提取RTP - memcpy(mRecvRtpBuffer, mRecvCache + 2, mRecvRtpBufferSize); - memmove(mRecvCache, mRecvCache + 2 + mRecvRtpBufferSize, mRecvCacheSize); - - // RTP - RtpHeader rtpHeader; - parseRtpHeader(mRecvRtpBuffer, &rtpHeader); - printf("get a rtp seq=%d,RtpBufferSize=%d,mRecvCacheSize=%d,marker=%d,timestamp=%d\n", - rtpHeader.seq, - mRecvRtpBufferSize, - mRecvCacheSize,rtpHeader.marker, rtpHeader.timestamp); - - - // 将从mRecvCache提取出来的rtp字节流 mRecvRtpBuffer去掉RTP_HEADER_SIZE,存储到播放器缓存中 - if ((mPlayer->bufferSize + mRecvRtpBufferSize - RTP_HEADER_SIZE) < MAX_RTP_BUFFER_SIZE) { - memcpy(mPlayer->buffer + mPlayer->bufferSize, mRecvRtpBuffer + RTP_HEADER_SIZE, mRecvRtpBufferSize - RTP_HEADER_SIZE); - mPlayer->bufferSize += mRecvRtpBufferSize - RTP_HEADER_SIZE; - } - else { - LOG_ERROR("recvBufSize = %d over MAX_RTP_BUFFER_SIZE ", recvBufSize); - } - - } - else { - //LOGI("跳出解析:cacheSize=%d,pktSize=%d", cacheSize, pktSize); - break; - } - } - else { - //LOGI("跳出解析:缓冲数据未发现完整数据包"); - break; - } - } -} - -int RTPReceiver2::allocRtpPort() { - - WebsocketClient* pServer = WebsocketClient::getInstance(); - int MIN_RTP_PORT = pServer->GetMinRtpPort() ; - int MAX_RTP_PORT = pServer->GetMaxRtpPort(); - - int s_rtpPort = MIN_RTP_PORT; - - srand((unsigned int)time(NULL)); - s_rtpPort = MIN_RTP_PORT + (rand() % MIN_RTP_PORT); - - if (s_rtpPort % 2) - ++s_rtpPort; - - int count = 0; - - while (true) - { - if (s_rtpPort >= MAX_RTP_PORT) { - s_rtpPort = MIN_RTP_PORT; - count ++; - if (count > 1) { - LOG_ERROR("[{}] - 范围内没有可用的port", m_SipChannelId); - } - } - - int i = 0; - for (; i < 2; i++) { - sockaddr_in sRecvAddr; - int s = socket(AF_INET, SOCK_DGRAM, 0); - - sRecvAddr.sin_family = AF_INET; - sRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); - sRecvAddr.sin_port = htons(s_rtpPort + i); - - int nResult = bind(s, (sockaddr *)&sRecvAddr, sizeof(sRecvAddr)); - if (nResult != 0) { - break; - } - - nResult = close(s); - if (nResult != 0) { - LOG_ERROR("[{}] - closesocket failed : {}", m_SipChannelId, nResult); - break; - } - } - - if (i == 2) - break; - - s_rtpPort += 2; - } - - return s_rtpPort; -} - -void RTPReceiver2::RequestStreamFailed() { - m_bRtpExit = true; -} \ No newline at end of file diff --git a/src/decoder/gb28181/rtp/RTPReceiver2.h b/src/decoder/gb28181/rtp/RTPReceiver2.h deleted file mode 100644 index 4d247bf..0000000 --- a/src/decoder/gb28181/rtp/RTPReceiver2.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _RTP_RECEIVER_H_ -#define _RTP_RECEIVER_H_ - -#include -#include -#include - -using namespace std; - - -class RTPReceiver2{ - -public: - RTPReceiver2(); - virtual ~RTPReceiver2(); - - int init(const char* ip, uint16_t port, bool isUdp); - - void RequestStreamFailed(); - - int allocRtpPort(); - -private: - int startUdpServer(const char* ip, uint16_t port); - int startTcpServer(const char* ip, uint16_t port); - - void parseTcpData(char* recvBuf, int recvBufSize); - -public: - uint8_t* mRecvCache {nullptr}; - uint64_t mRecvCacheSize {0}; - - uint8_t* mRecvRtpBuffer {nullptr}; // 从mRecvCache提取出来的rtp字节流 - int16_t mRecvRtpBufferSize {0};// 从mRecvCache提取出来的rtp字节流总长度 (rtpHeader+rtpBody) - - bool m_bRtpExit {false}; -}; - -#endif // _RTP_RECEIVER_H_ \ No newline at end of file diff --git a/src/decoder/gb28181/rtp/Rtp.cpp b/src/decoder/gb28181/rtp/Rtp.cpp deleted file mode 100644 index 03e2a8a..0000000 --- a/src/decoder/gb28181/rtp/Rtp.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Created by bxc on 2023/4/18. -// 作者:北小菜 -// 邮箱:bilibili_bxc@126.com -// 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 -// 哔哩哔哩主页:https://space.bilibili.com/487906612/ -// - -#include "Rtp.h" -#include -#include - -void rtpHeaderInit(struct RtpPacket* rtpPacket, uint8_t csrcLen, uint8_t extension, - uint8_t padding, uint8_t version, uint8_t payloadType, uint8_t marker, - uint16_t seq, uint32_t timestamp, uint32_t ssrc){ - rtpPacket->rtpHeader.csrcLen = csrcLen; - rtpPacket->rtpHeader.extension = extension; - rtpPacket->rtpHeader.padding = padding; - rtpPacket->rtpHeader.version = version; - rtpPacket->rtpHeader.payloadType = payloadType; - rtpPacket->rtpHeader.marker = marker; - rtpPacket->rtpHeader.seq = seq; - rtpPacket->rtpHeader.timestamp = timestamp; - rtpPacket->rtpHeader.ssrc = ssrc; -} -int parseRtpHeader(uint8_t* headerBuf, struct RtpHeader* rtpHeader){ - memset(rtpHeader,0,sizeof(*rtpHeader)); - /* byte 0 */ - rtpHeader->version = (headerBuf[0] & 0xC0) >> 6; - rtpHeader->padding = (headerBuf[0] & 0x20) >> 5; - rtpHeader->extension = (headerBuf[0] & 0x10) >> 4; - rtpHeader->csrcLen = (headerBuf[0] & 0x0F); - /* byte 1 */ - rtpHeader->marker = (headerBuf[1] & 0x80) >> 7; - rtpHeader->payloadType = (headerBuf[1] & 0x7F); - /* bytes 2,3 */ - rtpHeader->seq = ((headerBuf[2] & 0xFF) << 8) | (headerBuf[3] & 0xFF); - /* bytes 4-7 */ - rtpHeader->timestamp = ((headerBuf[4] & 0xFF) << 24) | ((headerBuf[5] & 0xFF) << 16) - | ((headerBuf[6] & 0xFF) << 8) - | ((headerBuf[7] & 0xFF)); - /* bytes 8-11 */ - rtpHeader->ssrc = ((headerBuf[8] & 0xFF) << 24) | ((headerBuf[9] & 0xFF) << 16) - | ((headerBuf[10] & 0xFF) << 8) - | ((headerBuf[11] & 0xFF)); - - return 0; -} - diff --git a/src/decoder/gb28181/rtp/Rtp.h b/src/decoder/gb28181/rtp/Rtp.h deleted file mode 100644 index f672ea4..0000000 --- a/src/decoder/gb28181/rtp/Rtp.h +++ /dev/null @@ -1,69 +0,0 @@ -// -// Created by bxc on 2023/4/18. -// 作者:北小菜 -// 邮箱:bilibili_bxc@126.com -// 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 -// 哔哩哔哩主页:https://space.bilibili.com/487906612/ -// - -#ifndef GB28181PLAYER_RTP_H -#define GB28181PLAYER_RTP_H - -#include - -#define RTP_VESION 2 -#define RTP_PAYLOAD_TYPE_H264 96 -#define RTP_PAYLOAD_TYPE_AAC 97 - -#define RTP_HEADER_SIZE 12 -#define RTP_MAX_SIZE 1400 - -/* - * - * 0 1 2 3 - * 7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |V=2|P|X| CC |M| PT | sequence number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | timestamp | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | synchronization source (SSRC) identifier | - * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ - * | contributing source (CSRC) identifiers | - * : .... : - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - */ -struct RtpHeader{ - /* byte 0 */ - uint8_t csrcLen:4; - uint8_t extension:1; - uint8_t padding:1; - uint8_t version:2; // 最高2位 - - /* byte 1 */ - uint8_t payloadType:7; - uint8_t marker:1; - - /* bytes 2,3 */ - uint16_t seq; - - /* bytes 4-7 */ - uint32_t timestamp; - - /* bytes 8-11 */ - uint32_t ssrc; -}; -struct RtpPacket{ - struct RtpHeader rtpHeader; - uint8_t payload[0]; -}; - -void rtpHeaderInit(struct RtpPacket* rtpPacket, uint8_t csrcLen, uint8_t extension, - uint8_t padding, uint8_t version, uint8_t payloadType, uint8_t marker, - uint16_t seq, uint32_t timestamp, uint32_t ssrc); - -int parseRtpHeader(uint8_t* headerBuf, struct RtpHeader* rtpHeader); - -#endif //GB28181PLAYER_RTP_H - diff --git a/src/decoder/gb28181/rtp2/RTPReceiver2.cpp b/src/decoder/gb28181/rtp2/RTPReceiver2.cpp new file mode 100644 index 0000000..5134e58 --- /dev/null +++ b/src/decoder/gb28181/rtp2/RTPReceiver2.cpp @@ -0,0 +1,357 @@ +#include "RTPReceiver2.h" +#include "rtppacket.h" +#include + +#include "../common_header.h" +#include "../websocket/WebsocketClient.h" + +#ifdef __linux__ +#include "arpa/inet.h" +#endif + +#include "Rtp.h" + +const int MAX_RTP_BUFFER_SIZE = 1024*1024*10; + +#define Server_cache_max_size 4194304 // 1M = 1 * 1024 * 1024 = 1048576 字节 +#define Server_rtp_max_size 1800 + + +RTPReceiver2::RTPReceiver2() +{ + mRecvCache = (uint8_t*)malloc(Server_cache_max_size); + mRecvRtpBuffer = (uint8_t*)malloc(Server_rtp_max_size); +} + +RTPReceiver2::~RTPReceiver2(){ + if (mRecvCache) { + free(mRecvCache); + mRecvCache = nullptr; + } + + if (mRecvRtpBuffer) { + free(mRecvRtpBuffer); + mRecvRtpBuffer = nullptr; + } +} + +void RTPReceiver2::SetOutputCallback(CallBack_Stream cb, void* param) +{ + m_buffer_cbk = cb; + m_bufferParam = param; +} + +void RTPReceiver2::SetVodEndCallback(CallBack_VodFileEnd cb, void* param) +{ + m_finish_cbk = cb; + m_finishParam = param; +} + +bool RTPReceiver2::Open(string channel_id, bool isUdp) { + m_SipChannelId = channel_id; + + m_rtp_port = allocRtpPort(); + if (m_rtp_port < 0) { + return false; + } + + bool bReq = start_server(channel_id, m_rtp_port, isUdp); + if (!bReq) { + LOG_INFO("[{}] start_server failed !", m_SipChannelId); + Close(); + return false; + } + + m_bOpened = true; + + LOG_INFO("[{}] started.", m_SipChannelId); + + return true; +} + +bool RTPReceiver2::IsOpened(){ + LOG_INFO("[{}] isopen:{} ", m_SipChannelId, m_bOpened); + return m_bOpened; +} + +void RTPReceiver2::Close(){ + m_bRtpExit = true; + + WebsocketClient* pServer = WebsocketClient::getInstance(); + if (pServer){ + pServer->ByeInvite(m_SipChannelId, m_rtp_port); + } + + if(m_server_thread) { + m_server_thread->join(); + delete m_server_thread; + m_server_thread = nullptr; + } +} + +bool RTPReceiver2::start_server(string channel_id, int port, bool isUdp) { + WebsocketClient* pClient = WebsocketClient::getInstance(); + if (pClient){ + + if (isUdp) { + m_server_thread = new std::thread([](void* arg) { + RTPReceiver2* a=(RTPReceiver2*)arg; + a->udp_server(); + return (void*)0; + }, this); + + if (pClient->InviteUdp(channel_id, port, this) < 0) { + return false; + } + + } else { + m_server_thread = new std::thread([](void* arg) { + RTPReceiver2* a=(RTPReceiver2*)arg; + a->tcp_server(); + return (void*)0; + }, this); + + if (pClient->InviteTcp(channel_id, port, this) < 0) { + return false; + } + } + } + + return true; +} + +int RTPReceiver2::udp_server() { + + uint16_t port = m_rtp_port; + + LOG_INFO("udp {}",port); + + int server_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //AF_INET:IPV4;SOCK_DGRAM:UDP + if(server_fd < 0) + { + printf("create socket fail!\n"); + return -1; + } + + struct sockaddr_in ser_addr; + memset(&ser_addr, 0, sizeof(ser_addr)); + ser_addr.sin_family = AF_INET; + ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址 + ser_addr.sin_port = htons(port); //端口号,需要网络序转换 + + int ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr)); + if(ret < 0) { + printf("socket bind fail!\n"); + return -1; + } + + uint8_t recvBuf[10000]; + int recvBufSize; + + socklen_t len; + struct sockaddr_in clent_addr; //clent_addr用于记录发送方的地址信息 + while(!m_bRtpExit) + { + memset(recvBuf, 0, sizeof(recvBuf)); + len = sizeof(clent_addr); + recvBufSize = recvfrom(server_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr*)&clent_addr, &len); //recvfrom是拥塞函数,没有数据就一直拥塞 + if(recvBufSize <= 0) { + LOG_ERROR("recieve data fail!"); + break; + } + + // buffer 抛出 + m_buffer_cbk(m_bufferParam, recvBuf, recvBufSize, 0); + } + + close(server_fd); + + m_finish_cbk(m_finishParam); + + LOG_INFO("udp server exit."); + + return 0; +} + +int RTPReceiver2::tcp_server() { + + uint16_t port = m_rtp_port; + + LOG_INFO("tcp {}", port); + + int listenfd, connfd; + struct sockaddr_in servaddr; + char buff[4096]; + int n; + + if( (listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ){ + printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); + return 0; + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(port); + + if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ + printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); + return 0; + } + + if( listen(listenfd, SOMAXCONN) == -1){ + printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); + return 0; + } + + char recvBuf[10000]; + int recvBufSize = 0; + + while (!m_bRtpExit) + { + LOG_INFO("阻塞监听新连接..."); + // 阻塞接收请求 start + socklen_t len = sizeof(sockaddr); + sockaddr_in accept_addr; + int clientFd = accept(listenfd, (struct sockaddr*)&accept_addr, &len); + if (clientFd < 0) { + LOG_WARN("accept connection error"); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + continue; + } + // 阻塞接收请求 end + LOG_INFO("发现新连接:clientFd={}", clientFd); + + while (!m_bRtpExit) { + recvBufSize = recv(clientFd, recvBuf, sizeof(recvBuf), 0); + if (recvBufSize <= 0) { + LOG_ERROR("::recv error: clientFd={},recvBufSize={}", clientFd, recvBufSize); + break; + } + + parseTcpData(recvBuf, recvBufSize); + } + + close(clientFd); + LOG_WARN("关闭连接 clientFd={}", clientFd); + } + + close(listenfd); + + m_finish_cbk(m_finishParam); + + LOG_INFO("tcp server exit."); + return 0; +} + +void RTPReceiver2::parseTcpData(char* recvBuf, int recvBufSize) { + + if ((mRecvCacheSize + recvBufSize) > Server_cache_max_size) { + LOG_ERROR("超过缓冲容量上限,忽略本次读取的数据。mRecvCacheSize=%d,recvBufSize=%d",mRecvCacheSize, recvBufSize); + } else { + memcpy(mRecvCache + mRecvCacheSize, recvBuf, recvBufSize); + mRecvCacheSize += recvBufSize; + } + //LOGI("cacheSize=%d,开始进入解析 ... ...", cacheSize); + + while (true) { + + if (mRecvCacheSize > 2) { + + bool success = false; + + if (mRecvCacheSize > 2) { + mRecvRtpBufferSize = ntohs(*(int16_t*)(mRecvCache)); + if ((mRecvCacheSize - 2) >= mRecvRtpBufferSize) { + success = true; + } + } + + if (success) { + mRecvCacheSize -= 2; + mRecvCacheSize -= mRecvRtpBufferSize; + + // 提取RTP + memcpy(mRecvRtpBuffer, mRecvCache + 2, mRecvRtpBufferSize); + memmove(mRecvCache, mRecvCache + 2 + mRecvRtpBufferSize, mRecvCacheSize); + + struct RtpHeader rtpHeader; + parseRtpHeader(mRecvRtpBuffer, &rtpHeader); + printf("get a rtp seq=%d,RtpBufferSize=%d,mRecvCacheSize=%d,marker=%d,timestamp=%d\n", + rtpHeader.seq, + mRecvRtpBufferSize, + mRecvCacheSize,rtpHeader.marker, rtpHeader.timestamp); + + // buffer 抛出 + m_buffer_cbk(m_bufferParam, mRecvRtpBuffer, mRecvRtpBufferSize, rtpHeader.timestamp); + + } else { + //LOGI("跳出解析:cacheSize=%d,pktSize=%d", cacheSize, pktSize); + break; + } + } else { + //LOGI("跳出解析:缓冲数据未发现完整数据包"); + break; + } + } +} + +int RTPReceiver2::allocRtpPort() { + + WebsocketClient* pServer = WebsocketClient::getInstance(); + int MIN_RTP_PORT = pServer->GetMinRtpPort() ; + int MAX_RTP_PORT = pServer->GetMaxRtpPort(); + + int s_rtpPort = MIN_RTP_PORT; + + srand((unsigned int)time(NULL)); + s_rtpPort = MIN_RTP_PORT + (rand() % MIN_RTP_PORT); + + if (s_rtpPort % 2) + ++s_rtpPort; + + int count = 0; + + while (true) + { + if (s_rtpPort >= MAX_RTP_PORT) { + s_rtpPort = MIN_RTP_PORT; + count ++; + if (count > 1) { + LOG_ERROR("[{}] - 范围内没有可用的port", m_SipChannelId); + } + } + + int i = 0; + for (; i < 2; i++) { + sockaddr_in sRecvAddr; + int s = socket(AF_INET, SOCK_DGRAM, 0); + + sRecvAddr.sin_family = AF_INET; + sRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + sRecvAddr.sin_port = htons(s_rtpPort + i); + + int nResult = bind(s, (sockaddr *)&sRecvAddr, sizeof(sRecvAddr)); + if (nResult != 0) { + break; + } + + nResult = close(s); + if (nResult != 0) { + LOG_ERROR("[{}] - closesocket failed : {}", m_SipChannelId, nResult); + break; + } + } + + if (i == 2) + break; + + s_rtpPort += 2; + } + + return s_rtpPort; +} + +void RTPReceiver2::RequestStreamFailed() { + m_bRtpExit = true; +} \ No newline at end of file diff --git a/src/decoder/gb28181/rtp2/RTPReceiver2.h b/src/decoder/gb28181/rtp2/RTPReceiver2.h new file mode 100644 index 0000000..eecc410 --- /dev/null +++ b/src/decoder/gb28181/rtp2/RTPReceiver2.h @@ -0,0 +1,66 @@ +#ifndef _RTP_RECEIVER_H_ +#define _RTP_RECEIVER_H_ + +#include +#include +#include + +using namespace std; + +typedef void(*CallBack_Stream)(void* userdata, uint8_t* buf, int buf_size, uint64_t pts); + +typedef void(*CallBack_VodFileEnd)(void* userdata); + + +class RTPReceiver2 { + +public: + RTPReceiver2(); + virtual ~RTPReceiver2(); + + bool Open(string channel_id, bool isUdp); + bool IsOpened(); + void Close(); + + void SetVodEndCallback(CallBack_VodFileEnd cb, void* param); + + void SetOutputCallback(CallBack_Stream cb, void* param); + + void RequestStreamFailed(); + + int allocRtpPort(); + +public: + int udp_server(); + int tcp_server(); + +private: + bool start_server(string channel_id, int port, bool isUdp); + void parseTcpData(char* recvBuf, int recvBufSize); + +public: + uint8_t* mRecvCache {nullptr}; + uint64_t mRecvCacheSize {0}; + + uint8_t* mRecvRtpBuffer {nullptr}; // 从mRecvCache提取出来的rtp字节流 + int16_t mRecvRtpBufferSize {0}; // 从mRecvCache提取出来的rtp字节流总长度 (rtpHeader+rtpBody) + + bool m_bRtpExit {false}; + + string m_SipChannelId; + int m_rtp_port{-1}; + + std::atomic_bool m_bOpened; + std::atomic_bool m_bAccepted; + std::atomic_bool m_bClosing; + + std::thread* m_server_thread{nullptr}; + + void* m_bufferParam; + CallBack_Stream m_buffer_cbk; // 视频流回调 + + void* m_finishParam; + CallBack_VodFileEnd m_finish_cbk; // 录像流结束回调 +}; + +#endif // _RTP_RECEIVER_H_ \ No newline at end of file diff --git a/src/decoder/gb28181/rtp2/Rtp.cpp b/src/decoder/gb28181/rtp2/Rtp.cpp new file mode 100644 index 0000000..03e2a8a --- /dev/null +++ b/src/decoder/gb28181/rtp2/Rtp.cpp @@ -0,0 +1,49 @@ +// +// Created by bxc on 2023/4/18. +// 作者:北小菜 +// 邮箱:bilibili_bxc@126.com +// 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 +// 哔哩哔哩主页:https://space.bilibili.com/487906612/ +// + +#include "Rtp.h" +#include +#include + +void rtpHeaderInit(struct RtpPacket* rtpPacket, uint8_t csrcLen, uint8_t extension, + uint8_t padding, uint8_t version, uint8_t payloadType, uint8_t marker, + uint16_t seq, uint32_t timestamp, uint32_t ssrc){ + rtpPacket->rtpHeader.csrcLen = csrcLen; + rtpPacket->rtpHeader.extension = extension; + rtpPacket->rtpHeader.padding = padding; + rtpPacket->rtpHeader.version = version; + rtpPacket->rtpHeader.payloadType = payloadType; + rtpPacket->rtpHeader.marker = marker; + rtpPacket->rtpHeader.seq = seq; + rtpPacket->rtpHeader.timestamp = timestamp; + rtpPacket->rtpHeader.ssrc = ssrc; +} +int parseRtpHeader(uint8_t* headerBuf, struct RtpHeader* rtpHeader){ + memset(rtpHeader,0,sizeof(*rtpHeader)); + /* byte 0 */ + rtpHeader->version = (headerBuf[0] & 0xC0) >> 6; + rtpHeader->padding = (headerBuf[0] & 0x20) >> 5; + rtpHeader->extension = (headerBuf[0] & 0x10) >> 4; + rtpHeader->csrcLen = (headerBuf[0] & 0x0F); + /* byte 1 */ + rtpHeader->marker = (headerBuf[1] & 0x80) >> 7; + rtpHeader->payloadType = (headerBuf[1] & 0x7F); + /* bytes 2,3 */ + rtpHeader->seq = ((headerBuf[2] & 0xFF) << 8) | (headerBuf[3] & 0xFF); + /* bytes 4-7 */ + rtpHeader->timestamp = ((headerBuf[4] & 0xFF) << 24) | ((headerBuf[5] & 0xFF) << 16) + | ((headerBuf[6] & 0xFF) << 8) + | ((headerBuf[7] & 0xFF)); + /* bytes 8-11 */ + rtpHeader->ssrc = ((headerBuf[8] & 0xFF) << 24) | ((headerBuf[9] & 0xFF) << 16) + | ((headerBuf[10] & 0xFF) << 8) + | ((headerBuf[11] & 0xFF)); + + return 0; +} + diff --git a/src/decoder/gb28181/rtp2/Rtp.h b/src/decoder/gb28181/rtp2/Rtp.h new file mode 100644 index 0000000..8950163 --- /dev/null +++ b/src/decoder/gb28181/rtp2/Rtp.h @@ -0,0 +1,68 @@ +// +// Created by bxc on 2023/4/18. +// 作者:北小菜 +// 邮箱:bilibili_bxc@126.com +// 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 +// 哔哩哔哩主页:https://space.bilibili.com/487906612/ +// + +#ifndef GB28181PLAYER_RTP_H +#define GB28181PLAYER_RTP_H + +#include + +#define RTP_VESION 2 +#define RTP_PAYLOAD_TYPE_H264 96 +#define RTP_PAYLOAD_TYPE_AAC 97 + +#define RTP_HEADER_SIZE 12 + +/* + * + * 0 1 2 3 + * 7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |V=2|P|X| CC |M| PT | sequence number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | timestamp | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | synchronization source (SSRC) identifier | + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * | contributing source (CSRC) identifiers | + * : .... : + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +struct RtpHeader{ + /* byte 0 */ + uint8_t csrcLen:4; + uint8_t extension:1; + uint8_t padding:1; + uint8_t version:2; // 最高2位 + + /* byte 1 */ + uint8_t payloadType:7; + uint8_t marker:1; + + /* bytes 2,3 */ + uint16_t seq; + + /* bytes 4-7 */ + uint32_t timestamp; + + /* bytes 8-11 */ + uint32_t ssrc; +}; +struct RtpPacket{ + struct RtpHeader rtpHeader; + uint8_t payload[0]; +}; + +void rtpHeaderInit(struct RtpPacket* rtpPacket, uint8_t csrcLen, uint8_t extension, + uint8_t padding, uint8_t version, uint8_t payloadType, uint8_t marker, + uint16_t seq, uint32_t timestamp, uint32_t ssrc); + +int parseRtpHeader(uint8_t* headerBuf, struct RtpHeader* rtpHeader); + +#endif //GB28181PLAYER_RTP_H + diff --git a/src/decoder/gb28181/websocket/WebsocketClient.cpp b/src/decoder/gb28181/websocket/WebsocketClient.cpp index 6b0cea5..d00896b 100644 --- a/src/decoder/gb28181/websocket/WebsocketClient.cpp +++ b/src/decoder/gb28181/websocket/WebsocketClient.cpp @@ -191,7 +191,7 @@ int WebsocketClient::GetMaxRtpPort(){ return mInfo.getMaxRtpPort(); } -int WebsocketClient::InviteUdp(std::string sip_channel_id, int rtp_port, RTPReceiver* r) { +int WebsocketClient::InviteUdp(std::string sip_channel_id, int rtp_port, RTPReceiver2* r) { if (check_connect() < 0) { return -1; } @@ -204,7 +204,7 @@ int WebsocketClient::InviteUdp(std::string sip_channel_id, int rtp_port, RTPRece return 0; } -int WebsocketClient::InviteTcp(std::string sip_channel_id, int rtp_port, RTPReceiver* r) { +int WebsocketClient::InviteTcp(std::string sip_channel_id, int rtp_port, RTPReceiver2* r) { if (check_connect() < 0) { return -1; } @@ -228,7 +228,7 @@ int WebsocketClient::ByeInvite(std::string sip_channel_id, int rtp_port) { return 0; } -void WebsocketClient::cache_receiver(std::string sip_channel_id, int rtp_port, RTPReceiver* r) { +void WebsocketClient::cache_receiver(std::string sip_channel_id, int rtp_port, RTPReceiver2* r) { std::lock_guard l(m_receiver_map_mtx); string rKey = sip_channel_id + "_" + to_string(rtp_port); m_receiver_map[rKey] = r; diff --git a/src/decoder/gb28181/websocket/WebsocketClient.h b/src/decoder/gb28181/websocket/WebsocketClient.h index e9266ec..19069e5 100644 --- a/src/decoder/gb28181/websocket/WebsocketClient.h +++ b/src/decoder/gb28181/websocket/WebsocketClient.h @@ -6,7 +6,7 @@ #include "Message/CatalogParser.h" -#include "../rtp/RTPReceiver.h" +#include "../rtp2/RTPReceiver2.h" typedef websocketpp::client client; typedef websocketpp::config::asio_client::message_type::ptr message_ptr; @@ -32,8 +32,8 @@ public: int GetMinRtpPort(); int GetMaxRtpPort(); - int InviteUdp(std::string sip_channel_id, int rtp_port, RTPReceiver* r); - int InviteTcp(std::string sip_channel_id, int rtp_port, RTPReceiver* r); + int InviteUdp(std::string sip_channel_id, int rtp_port, RTPReceiver2* r); + int InviteTcp(std::string sip_channel_id, int rtp_port, RTPReceiver2* r); int ByeInvite(std::string sip_channel_id, int rtp_port); @@ -56,7 +56,7 @@ private: int msg_parser(websocketpp::connection_hdl hdl, string msg); - void cache_receiver(std::string sip_channel_id, int rtp_port, RTPReceiver* r); + void cache_receiver(std::string sip_channel_id, int rtp_port, RTPReceiver2* r); void response_invite_failed(std::string rKey); @@ -70,6 +70,6 @@ private: bool mbClosed{false}; - std::map m_receiver_map; + std::map m_receiver_map; std::mutex m_receiver_map_mtx; }; \ No newline at end of file diff --git a/src/decoder/interface/AbstractDecoder.h b/src/decoder/interface/AbstractDecoder.h index c2c5615..4401706 100644 --- a/src/decoder/interface/AbstractDecoder.h +++ b/src/decoder/interface/AbstractDecoder.h @@ -27,8 +27,6 @@ public: virtual bool getOutResolution( int &width, int &height ) = 0; virtual bool isSurport(FFDecConfig& cfg) = 0; - - virtual int getCachedQueueLength() = 0; virtual float fps() = 0; diff --git a/src/decoder/interface/DecoderManager.cpp b/src/decoder/interface/DecoderManager.cpp index ad76ffe..0bc2baf 100644 --- a/src/decoder/interface/DecoderManager.cpp +++ b/src/decoder/interface/DecoderManager.cpp @@ -7,7 +7,7 @@ #ifdef USE_DVPP #include "../dvpp/DvppDecoderApi.h" -#include "../gb28181/DvppGB28181Decoder.h" +#include "../gb28181/DvppGB28181Decoder2.h" #endif #include "logger.hpp" @@ -61,7 +61,7 @@ AbstractDecoder* DecoderManager::createDecoder(MgrDecConfig config){ if(DECODER_TYPE_DVPP == config.dec_type){ dec = new DvppDecoderApi(); } else if(DECODER_TYPE_DVPP_GB28181 == config.dec_type){ - dec = new DvppGB28181Decoder(); + dec = new DvppGB28181Decoder2(); } #endif @@ -470,23 +470,6 @@ vector DecoderManager::getAllDecodeName(){ return decode_names; } -int DecoderManager::getCachedQueueLength(const string name){ - if (name.empty()){ - LOG_ERROR("name 为空!"); - return -1; - } - - std::lock_guard l(m_mutex); - - auto dec = decoderMap.find(name); - if (dec != decoderMap.end()){ - return dec->second->getCachedQueueLength(); - } - - LOG_ERROR("没有找到name为{}的解码器",name); - return -1; -} - void DecoderManager::releaseDeviceMemory(DeviceMemory* info){ if(nullptr != info){ delete info; diff --git a/src/decoder/interface/DecoderManager.h b/src/decoder/interface/DecoderManager.h index cd10e16..dbf1554 100644 --- a/src/decoder/interface/DecoderManager.h +++ b/src/decoder/interface/DecoderManager.h @@ -230,15 +230,6 @@ public: vector getAllDecodeName(); /************************************************** - * 接口:getCachedQueueLength - * 功能:获取解码缓冲队列当前长度 - * 参数:const string name 解码器名称 - * 返回:int 解码缓冲队列当前长度 - * 备注: - **************************************************/ - int getCachedQueueLength(const string name); - - /************************************************** * 接口:releaseDeviceMemory * 功能:释放视频快照信息 * 参数:DeviceMemory* info 视频快照信息 diff --git a/src/decoder/interface/VideoTools.cpp b/src/decoder/interface/VideoTools.cpp deleted file mode 100644 index ae7d47f..0000000 --- a/src/decoder/interface/VideoTools.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include "VideoTools.h" -#include "logger.hpp" - -extern "C" { - #include - #include - #include - #include - #include - #include - #include - #include -} - -namespace VideoTools { - -FFImgInfo* snapshot(const string& uri){ - if (uri.empty()){ - return nullptr; - } - - AVFormatContext* ifmt_ctx = nullptr; - AVCodecContext* codec_ctx = nullptr; - AVCodec* codec = nullptr; - AVPacket* pkt = nullptr; - AVFrame *frame = nullptr; - AVFrame *pFrameRGB = nullptr; - int video_index = -1; - AVStream* st = nullptr; - SwsContext *img_convert_ctx = nullptr; - uint8_t *buffer = nullptr; - int numBytes = 0; - int index = 0; - - FFImgInfo* imgInfo = nullptr; - - //av_register_all(); - avformat_network_init(); - - // 参数设置 - AVDictionary *options = nullptr; - av_dict_set( &options, "bufsize", "655360", 0 ); - av_dict_set( &options, "rtsp_transport", "tcp", 0 ); - av_dict_set( &options, "stimeout", "30000000", 0 ); // 单位为 百万分之一秒 - - ///打开输入的流 - int ret = avformat_open_input(&ifmt_ctx, uri.c_str(), nullptr, &options); - if (ret != 0){ - printf("Couldn't open input stream.\n"); - goto end_flag ; - } - - //查找流信息 - if (avformat_find_stream_info(ifmt_ctx, nullptr) < 0){ - printf("Couldn't find stream information.\n"); - goto end_flag ; - } - - //找到视频流索引 - video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); - - st = ifmt_ctx->streams[video_index]; - - //找到解码器 - codec = avcodec_find_decoder(st->codecpar->codec_id); - if (!codec){ - fprintf(stderr, "Codec not found\n"); - goto end_flag ; - } - - //申请AVCodecContext - codec_ctx = avcodec_alloc_context3(codec); - if (!codec_ctx){ - goto end_flag ; - } - - avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[video_index]->codecpar); - - //打开解码器 - if ((ret = avcodec_open2(codec_ctx, codec, nullptr) < 0)){ - goto end_flag ; - } - - // 计算解码后原始数据所需缓冲区大小,并分配内存空间 Determine required buffer size and allocate buffer - numBytes = av_image_get_buffer_size(AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height, 1); - buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); - - pFrameRGB = av_frame_alloc(); - av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_BGR24, codec_ctx->width, codec_ctx->height, 1); - - img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height,codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_BGR24, - SWS_BICUBIC, nullptr, nullptr, nullptr); - - pkt = av_packet_alloc(); - frame = av_frame_alloc(); - while (av_read_frame(ifmt_ctx, pkt) >= 0){ - if (pkt->stream_index == video_index){ - int ret = avcodec_send_packet(codec_ctx, pkt); - if (ret >= 0){ - ret = avcodec_receive_frame(codec_ctx, frame); - if ((ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) || ret < 0){ - LOG_ERROR("Failed to receive frame: {}",ret); - continue; - } - - index ++ ; - - if (index >= 5){ - // 取解码出来的第三帧,应该可以一定程度优化花屏问题 - sws_scale(img_convert_ctx, (const unsigned char* const*)frame->data, frame->linesize, 0, codec_ctx->height, pFrameRGB->data, pFrameRGB->linesize); - - imgInfo = new FFImgInfo(); - imgInfo->pData = buffer; - imgInfo->height = codec_ctx->height; - imgInfo->width = codec_ctx->width; - - break; - } - } - } - av_packet_unref(pkt); - } - -end_flag: - if (codec_ctx != nullptr){ - avcodec_close(codec_ctx); - avcodec_free_context(&codec_ctx); - } - - if (ifmt_ctx != nullptr){ - avformat_close_input(&ifmt_ctx); - } - - if (frame != nullptr){ - av_frame_free(&frame); - } - - if (pFrameRGB != nullptr){ - av_frame_free(&pFrameRGB); - } - - if (pkt != nullptr){ - av_packet_free(&pkt); - } - - return imgInfo; -} - -void releaseFFImgInfo(FFImgInfo* info) { - if(nullptr != info){ - if(info->pData != nullptr){ - av_free(info->pData); - info->pData = nullptr; - } - delete info; - info = nullptr; - } -} - -} // namespace \ No newline at end of file diff --git a/src/decoder/interface/VideoTools.h b/src/decoder/interface/VideoTools.h deleted file mode 100644 index 64ecb1a..0000000 --- a/src/decoder/interface/VideoTools.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __VIDEO_TOOLS_H__ -#define __VIDEO_TOOLS_H__ - -#include - -using namespace std; - -struct FFImgInfo{ - string dec_name; - int width; - int height; - unsigned char * pData; - long timestamp; - long index; -}; - -namespace VideoTools { - - FFImgInfo* snapshot(const string& uri); - - void releaseFFImgInfo(FFImgInfo* info); -} - - -#endif // __VIDEO_TOOLS_H__ \ No newline at end of file -- libgit2 0.21.4