突破NVIDIA NVENC并发Session数目限制

使用NVIDIA显卡GPU进行视频编码时,如果同时进行多路转码,在某些显卡上会报错: Out of Memory,一般就是调用nvEncOpenEncodeSessionEx函数出错,返回的错误码是10(NV_ENC_ERR_OUT_OF_MEMORY),NVENC并发的Session数目超过了限制,具体信息可以去官网查一下。
Video Encode and Decode GPU Support Matrix

3423648703.pnguploading.4e448015.gif转存失败重新上传取消2020-01-03_15-21-19.png
2020-01-03_15-21-35.png

很奇怪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的补丁: 下载

  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值