官网下载的ffmpeg目前只能下载到X64版本的库,具体编译请参考windows编译ffmpeg源码(32位库)_windows 32位ffmpeg动态库-CSDN博客
直接上代码
int VideoDecodeModule::Open(std::string strUrl)
{AVFormatContext *pFormatCtx = nullptr;AVCodec *pCodec = nullptr;AVCodecContext* pCodecCtx = nullptr;AVDictionary *opt = nullptr;std::string decodeName = "";AVBufferRef* pBufferRef = nullptr;int ret = 0;int videoStream = -1;char errorbuf[1024] = { 0 };av_dict_set(&opt, "buffer_size", "1024000", 0); // 缓冲区大小 单位字节 解决高画质模糊的问题av_dict_set(&opt, "max_delay", "100", 0); // 最大延时 单位微妙av_dict_set(&opt, "stimeout", "3000000", 0); // 设置超时断开连接时间 3s 单位微妙av_dict_set(&opt, "rtsp_transport", "tcp", 0); // 以tcp方式打开,如果以udp方式打开将tcp替换为udpav_dict_set(&opt, "fflags", "nobuffer", 0);av_dict_set(&opt, "rtbufsize", "6", 0);av_dict_set(&opt, "start_time_realtime", 0, 0);if ((ret = avformat_open_input(&pFormatCtx, strUrl.data(), nullptr, &opt)) != 0){av_strerror(ret, errorbuf, sizeof(errorbuf));return -1;}m_spFormatContext = std::shared_ptr<AVFormatContext>(pFormatCtx, [](AVFormatContext* ctx){avformat_close_input(&ctx);});if ((ret = avformat_find_stream_info(pFormatCtx, nullptr)) < 0){av_strerror(ret, errorbuf, sizeof(errorbuf));return -1;}if ((ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &pCodec, 0)) < 0){av_strerror(ret, errorbuf, sizeof(errorbuf));return -1;}videoStream = ret;m_video = pFormatCtx->streams[videoStream];if (m_decodeType == DT_CPU){if (!(pCodec = avcodec_find_decoder(m_video->codecpar->codec_id))){int error = AVERROR(ENOMEM);return -1;}}else if (m_decodeType == DT_INTER_QSV){decodeName = GetCodeName(m_video->codecpar->codec_id, DT_INTER_QSV);if (av_hwdevice_ctx_create(&pBufferRef, AV_HWDEVICE_TYPE_QSV, "auto", nullptr, 0) != 0){return -1;}if (!(pCodec = avcodec_find_decoder_by_name(decodeName.data()))){int error = AVERROR(ENOMEM);return -1;}}else if (m_decodeType == DT_NVIDIA_CUDA){decodeName = GetCodeName(m_video->codecpar->codec_id, DT_NVIDIA_CUDA);if (av_hwdevice_ctx_create(&pBufferRef, AV_HWDEVICE_TYPE_CUDA, "auto", nullptr, 0) != 0){return -1;}if (!(pCodec = avcodec_find_decoder_by_name(decodeName.data()))){int error = AVERROR(ENOMEM);return -1;}}if (auto frame = av_frame_alloc()){m_spSwFrame = std::shared_ptr<AVFrame>(frame, [](AVFrame* p) {av_frame_free(&p); });}if (!(pCodecCtx = avcodec_alloc_context3(pCodec))){return -1;}m_spCodecContext = std::shared_ptr<AVCodecContext>(pCodecCtx, [](AVCodecContext* ctx){avcodec_free_context(&ctx);});m_spCodecContext->codec_id = m_video->codecpar->codec_id;if (m_video->codecpar->extradata_size){m_spCodecContext->extradata = (uint8_t*)av_mallocz(m_video->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);if (!m_spCodecContext->extradata){return -1;}memcpy(m_spCodecContext->extradata, m_video->codecpar->extradata, m_video->codecpar->extradata_size);m_spCodecContext->extradata_size = m_video->codecpar->extradata_size;}m_spCodecContext->flags2 |= AV_CODEC_FLAG2_FAST; // 允许不符合规范的加速技巧。m_spCodecContext->thread_count = 8; // 使用8线程解码if ((ret = avcodec_parameters_to_context(m_spCodecContext.get(), m_video->codecpar)) < 0){av_strerror(ret, errorbuf, sizeof(errorbuf));return -1;}if (m_decodeType == DT_INTER_QSV){m_spCodecContext->opaque = pBufferRef;m_spCodecContext->get_format = GetHWQsvFormat;}else if (m_decodeType == DT_NVIDIA_CUDA){m_spCodecContext->hw_device_ctx = av_buffer_ref(pBufferRef);m_spCodecContext->opaque = this;m_spCodecContext->get_format = GetHWCudaFormat;}if ((ret = avcodec_open2(m_spCodecContext.get(), pCodec, nullptr)) < 0){av_strerror(ret, errorbuf, sizeof(errorbuf));return -1;}m_isConnect = true;return ret;
}
if (!spFrame)return;/// 解码的图片宽int width = spFrame->width;/// 解码的图片高int height = spFrame->height;// 计算转码后的图片裸数据需要的大小int nSrcbuffSize = av_image_get_buffer_size(m_pixelFormat, width, height, 1);if (nSrcbuffSize > m_dstBuffer.size()){m_dstBuffer.resize(nSrcbuffSize, '\0');}std::shared_ptr<SwsContext> spSwsContext = nullptr;/// 判断是否需要格式转换if (m_pixelFormat != (AVPixelFormat)spFrame->format){AVPixelFormat srcFmt = (AVPixelFormat)spFrame->format;SwsContext* image_sws_ctx = sws_getContext(width, height, srcFmt,width, height, m_pixelFormat, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);spSwsContext = std::shared_ptr<SwsContext>(image_sws_ctx, [](SwsContext* p) {sws_freeContext(p); });uint8_t* data[4] = { nullptr };int linesize[4] = { 0 };av_image_fill_arrays(data, linesize, m_dstBuffer.data(), m_pixelFormat, width, height, 1);int ret = sws_scale(spSwsContext.get(), (uint8_t const* const*)spFrame->data, spFrame->linesize, 0, height, data, linesize);if (ret < 0)return;}if (m_pFrameDataCallBack){FrameInfo info;info.format = GetVideoFormatByAVPixelFormat(m_pixelFormat);info.width = width;info.height = height;info.pts = spFrame->pts / 1000;m_pFrameDataCallBack->cbFrameDataCallBack(m_dstBuffer.data(), m_dstBuffer.size(), info, m_pFrameDataCallBack->pUser);}
解码显示效果图
英伟达显卡播放效果因本人没有显卡不在这里展示,可以看出通过硬解降低将近一半的cpu。
代码参考 https://download.csdn.net/download/weixin_38887743/88748651