官网下载的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替换为udp
av_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(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(frame, [](AVFrame* p) {av_frame_free(&p); });
}
if (!(pCodecCtx = avcodec_alloc_context3(pCodec)))
{
return -1;
}
m_spCodecContext = std::shared_ptr(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 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(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