使用 NVENC 硬编码视频
简介NVENC 是 NVIDIA 视频编解码器中的编码部分,使用硬件加速视频编码,官方参考文档。
测试编码能力
H264 编码最大分辨率为 4096 x 4096。
H265 编码最大分辨率为 8192 x 8192。
NVENC NV12 编码视频 H264,不支持推流到 RTMP。
NVENC NV12 编码视频 H265,不支持推流到 RTSP、RTMP、UDP,所以选用推流到 TCP,使用 TCP 转发到 RTSP 的方式。
构建代码构建环境
Windows 10
Visual Studio 2019
CUDA Toolkit 10.2
CMake 3.17.2
构建步骤
下载 NVIDIA VIDEO CODEC SDK
使用 CMake 构建项目 ./Video_Codec_SDK_12.0.16/Samples
启动构建好的 NvCodec.sln
本文基于工程中 AppEncCuda 项目开发
配置参数编码数据类型设置编码输入格式,指编码数据的类型。
1234567typedef enum _NV_ENC_BUFFER_FORMAT{ // NVDEC 解码默认格式,介绍说存储格式与 YUV420P 相同,但是测试 UV 分量偏移。 NV_ENC_BUFFER_FORMAT_IYUV, // YUV NV12 格式,可以使用 FFmpeg CUDA 硬解码直接使用。 NV_ENC_BUFFER_FORMAT_NV12} NV_ENC_BUFFER_FORMAT;
编码器类型预设参数设置编码器类型与预设参数,修改 NvEncoderCLIOptions.h 文件,在 NvEncoderInitParam 构造函数中增加配置。
编码器类型支持 H264 或 H265。
编码器预设参数,从 P1 到 P7,性能下降,质量提高。默认情况下,H264 的预设 P3 至 P7 和 HEVC 的预设 P2 至 P7。12345NvEncoderInitParam(const char* szParam = "", std::function
代码初始化 NVENC123456789///
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566NV_ENC_BUFFER_FORMAT eFormat = NV_ENC_BUFFER_FORMAT_NV12;int iGpu = 0;NvEncoderInitParam encodeCLIOptions = NvEncoderInitParam("", NULL, true);ck(cuInit(0));int nGpu = 0;ck(cuDeviceGetCount(&nGpu));if (iGpu < 0 || iGpu >= nGpu){ cout << "GPU ordinal out of range. Should be within [" << 0 << ", " << nGpu - 1 << "]" << endl; return;}CUdevice cuDevice = 0;ck(cuDeviceGet(&cuDevice, iGpu));char szDeviceName[80];ck(cuDeviceGetName(szDeviceName, sizeof(szDeviceName), cuDevice));cout << "GPU in use: " << szDeviceName << endl;ck(cuCtxCreate(&cuContext_, 0, cuDevice));pEnc_ = unique_ptr
编码视频12345678910111213141516171819// 原图像数据指针 YUV NV12void* pSrcFrame;// 表示源图像帧中每行像素(以字节为单位)的跨度uint32_t nSrcPitch;// 编码视频,格式为 vector
处理编码视频保存为本地文件12345678910111213string szOutFilePath = "FilePath";std::ofstream fpOut(szOutFilePath, std::ios::out | std::ios::binary);if (!fpOut){ std::ostringstream err; err << "Unable to open output file: " << szOutFilePath << std::endl; throw std::invalid_argument(err.str());}for (std::vector
使用 FFmpeg 推流视频12345678910111213141516171819///
1234567891011121314151617181920// 在外部初始化 FFmpeg 推流配置for (auto& packet : vPacket) { AVPacket avPacket; av_init_packet(&avPacket); avPacket.size = packet.size(); avPacket.data = packet.data(); // 设置 pts 推流视频 avPacket.pts = av_rescale_q(pts_++, { 1, control_fps_ }, time_base_); ret = av_interleaved_write_frame(outputContext_, &avPacket); if (ret < 0) { av_packet_unref(&avPacket); printf("Push stream failed, unable to connect to streaming server!\n"); return; } av_packet_unref(&avPacket);}
释放内存12// 释放 CUDA 上下文cuCtxDestroy(cuContext_);
注意事项由于驱动版本导致的异常NvEncodeAPIGetMaxSupportedVersion(&version) 报错 192>117:Current Driver Version does not support this NvEncodeAPI version, please upgrade driver显卡驱动程序包含的 CUDA 版本号,可以从 nvidia-smi 中查看,NvEncodeAPI 12.0 要求 cuda 版本 12.0,22年12月
编码会话数限制消除 Nvidia 对消费级 GPU 施加的最大同时 NVENC 视频编码会话数限制
FFmpeg 推流 TCP 转发到 RTSP推流到 TCP 需要先使用命令启动服务
123456:: 使用默认编码器ffmpeg -listen 1 -i tcp://0.0.0.0:1234 -f rtsp rtsp://localhost:8554/main:: 使用 libx264 编码器ffmpeg -listen 1 -i tcp://0.0.0.0:1234 -c:v libx264 -f rtsp rtsp://localhost:8554/main:: 使用 libx265 编码器ffmpeg -listen 1 -i tcp://0.0.0.0:1234 -c:v libx265 -f rtsp rtsp://localhost:8554/main