使用NVIDIA显卡GPU进行视频编码时,如果同时进行多路转码,在某些显卡上会报错: Out of Memory,一般就是调用nvEncOpenEncodeSessionEx函数出错,返回的错误码是10(NV_ENC_ERR_OUT_OF_MEMORY),NVENC并发的Session数目超过了限制,具体信息可以去官网查一下。
Video Encode and Decode GPU Support Matrix
很奇怪NVIDIA会做如此的限制,因为并不是GPU能力不够。就我的电脑来说,NVIDIA显卡型号是GeForce GTX 1650,NVENC的并发最大数目是2,为了查找在哪里进行了限制,我写了如下代码:
cuInit(0);
CUdevice cuDevice = 0;
cuDeviceGet(&cuDevice, 0);
CUcontext cuContext = NULL;
cuCtxCreate(&cuContext, CU_CTX_SCHED_BLOCKING_SYNC, cuDevice);
NV_ENCODE_API_FUNCTION_LIST nvenc = { NV_ENCODE_API_FUNCTION_LIST_VER };
NVENCSTATUS nvStatus = NvEncodeAPICreateInstance(&nvenc);
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS encodeSessionExParams = {
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER };
encodeSessionExParams.device = cuContext;
encodeSessionExParams.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
encodeSessionExParams.apiVersion = NVENCAPI_VERSION;
printf("OpenEncodeSesionEx #1\n");
void *hEncoder1 = NULL;
nvStatus = nvenc.nvEncOpenEncodeSessionEx(&encodeSessionExParams, &hEncoder1);
printf("OpenEncodeSesionEx #2\n");
void *hEncoder2 = NULL;
nvStatus = nvenc.nvEncOpenEncodeSessionEx(&encodeSessionExParams, &hEncoder2);
printf("OpenEncodeSesionEx #3\n");
void *hEncoder3 = NULL;
nvStatus = nvenc.nvEncOpenEncodeSessionEx(&encodeSessionExParams, &hEncoder3);
最后在Open第3个Session时返回了NV_ENC_ERR_OUT_OF_MEMORY,之后我使用x64dbg对代码进行了跟踪调试,原来限制的模块并不是在驱动层,而是在应用层,动态库文件是nvcuvid.dll,汇编代码大概如下:
.text:00000001800E7FAF FF 90+ call qword ptr [rax+90h] ; 调用这个函数检查数目是否超过限制
.text:00000001800E7FB5 84 C0 test al, al
.text:00000001800E7FB7 74 08 jz short loc_1800E7FC1
.text:00000001800E7FB9 C6 43+ mov byte ptr [rbx+38h], 1
.text:00000001800E7FBD 33 C0 xor eax, eax
.text:00000001800E7FBF EB 05 jmp short loc_1800E7FC6
.text:00000001800E7FC1 loc_1800E7FC1:
.text:00000001800E7FC1 B8 0A+ mov eax, 0Ah ; 超过限制就设置返回值为10
找到了位置,然后就简单了,只需要把jz short loc_1800E7FC1 这个判断跳转nop掉即可
.text:00000001800E7FAF FF 90+ call qword ptr [rax+90h]
.text:00000001800E7FB5 84 C0 test al, al
.text:00000001800E7FB7 90 nop ;这里nop掉之后,就不会跳转到loc_1800E7FC1
.text:00000001800E7FB8 90 nop
.text:00000001800E7FB9 C6 43+ mov byte ptr [rbx+38h], 1
.text:00000001800E7FBD 33 C0 xor eax, eax
.text:00000001800E7FBF EB 05 jmp short loc_1800E7FC6
.text:00000001800E7FC1 loc_1800E7FC1:
.text:00000001800E7FC1 B8 0A+ mov eax, 0Ah
汇编修改之后对nvcuvid.dll打patch,替换掉系统目录下的文件,然后再运行测试程序,开十几路同时编码也没问题了,没限制的感觉太香了!哈哈...
附版本441.66的补丁: 下载
2020-04-07更新了版本442.19的补丁: 下载