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

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,替换掉系统目录下的文件,然后再运行测试程序,开十几路同时编码也没问题了,没限制的感觉太香了!哈哈...

2020-01-02更新版本441.66的补丁: 下载
2020-04-07更新版本442.19的补丁: 下载
2020-07-28更新版本451.77的补丁: 下载
2020-09-23更新版本451.82的补丁: 下载

标签: cuda, nvenc, nvidia

已有 13 条评论

  1. hooli hooli

    请问这个nvcuid.dll能下载吗,谢谢?

  2. hooli hooli

    大神

  3. end end

    同求Ubuntu的libnvcuvid.so

  4. 三十多 三十多

    谢谢分享!!!!

  5. 谢晟 谢晟

    我在ubuntu上尝试了好几次还是不行,求ubuntu上修改方法或者帮我改个so的版本可以吗,能邮件发我联系方式吗

  6. 谢晟 谢晟

    同问,有ubuntu修改教程吗,或者ubuntu能用的包

  7. Songjinxue Songjinxue

    我也遇到这个问题了,可以发给我一个打上patch后的nvcuvid.dll吗?十分感谢

    1. K K

      有没有linux下的补丁?跪求

      1. 谢晟 谢晟

        请问您现在搞定了吗

  8. 同求patch 同求patch

    我在做视频硬编码时候也遇到这个问题了,跪求

  9. chenjinyun chenjinyun

    能否发一个打上patch后的nvcuvid.dll给我,非常感谢。

    1. 求打上path后的nvcuvid.dl 求打上path后的nvcuvid.dl

      大神求发一个打上patch后的nvcuvid.dll,万分感谢。

      1. 阿牛 阿牛

        我需要支持2080ti的最新显卡驱动的 nvcuvid.dll

添加新评论