jim-nvenc-helpers.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include "jim-nvenc.h"
  2. #include <util/platform.h>
  3. #include <util/threading.h>
  4. #include <util/dstr.h>
  5. static void *nvenc_lib = NULL;
  6. static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
  7. NV_ENCODE_API_FUNCTION_LIST nv = {NV_ENCODE_API_FUNCTION_LIST_VER};
  8. NV_CREATE_INSTANCE_FUNC nv_create_instance = NULL;
  9. #define error(format, ...) blog(LOG_ERROR, "[jim-nvenc] " format, ##__VA_ARGS__)
  10. bool nv_failed(obs_encoder_t *encoder, NVENCSTATUS err, const char *func,
  11. const char *call)
  12. {
  13. struct dstr error_message = {0};
  14. switch (err) {
  15. case NV_ENC_SUCCESS:
  16. return false;
  17. case NV_ENC_ERR_OUT_OF_MEMORY:
  18. obs_encoder_set_last_error(
  19. encoder,
  20. "NVENC Error: Too many concurrent sessions. "
  21. "Try closing other recording software which might "
  22. "be using NVENC such as Windows 10 Game DVR.");
  23. break;
  24. case NV_ENC_ERR_UNSUPPORTED_DEVICE:
  25. obs_encoder_set_last_error(
  26. encoder,
  27. "NVENC Error: Unsupported device. Check your "
  28. "video card supports NVENC and that the drivers are "
  29. "up to date.");
  30. break;
  31. default:
  32. dstr_printf(&error_message,
  33. "NVENC Error: %s: %s failed: %d (%s)", func, call,
  34. (int)err, nv_error_name(err));
  35. obs_encoder_set_last_error(encoder, error_message.array);
  36. dstr_free(&error_message);
  37. break;
  38. }
  39. error("%s: %s failed: %d (%s)", func, call, (int)err,
  40. nv_error_name(err));
  41. return true;
  42. }
  43. #define NV_FAILED(e, x) nv_failed(e, x, __FUNCTION__, #x)
  44. bool load_nvenc_lib(void)
  45. {
  46. if (sizeof(void *) == 8) {
  47. nvenc_lib = os_dlopen("nvEncodeAPI64.dll");
  48. } else {
  49. nvenc_lib = os_dlopen("nvEncodeAPI.dll");
  50. }
  51. return !!nvenc_lib;
  52. }
  53. static void *load_nv_func(const char *func)
  54. {
  55. void *func_ptr = os_dlsym(nvenc_lib, func);
  56. if (!func_ptr) {
  57. error("Could not load function: %s", func);
  58. }
  59. return func_ptr;
  60. }
  61. typedef NVENCSTATUS(NVENCAPI *NV_MAX_VER_FUNC)(uint32_t *);
  62. const char *nv_error_name(NVENCSTATUS err)
  63. {
  64. #define RETURN_CASE(x) \
  65. case x: \
  66. return #x
  67. switch (err) {
  68. RETURN_CASE(NV_ENC_SUCCESS);
  69. RETURN_CASE(NV_ENC_ERR_NO_ENCODE_DEVICE);
  70. RETURN_CASE(NV_ENC_ERR_UNSUPPORTED_DEVICE);
  71. RETURN_CASE(NV_ENC_ERR_INVALID_ENCODERDEVICE);
  72. RETURN_CASE(NV_ENC_ERR_INVALID_DEVICE);
  73. RETURN_CASE(NV_ENC_ERR_DEVICE_NOT_EXIST);
  74. RETURN_CASE(NV_ENC_ERR_INVALID_PTR);
  75. RETURN_CASE(NV_ENC_ERR_INVALID_EVENT);
  76. RETURN_CASE(NV_ENC_ERR_INVALID_PARAM);
  77. RETURN_CASE(NV_ENC_ERR_INVALID_CALL);
  78. RETURN_CASE(NV_ENC_ERR_OUT_OF_MEMORY);
  79. RETURN_CASE(NV_ENC_ERR_ENCODER_NOT_INITIALIZED);
  80. RETURN_CASE(NV_ENC_ERR_UNSUPPORTED_PARAM);
  81. RETURN_CASE(NV_ENC_ERR_LOCK_BUSY);
  82. RETURN_CASE(NV_ENC_ERR_NOT_ENOUGH_BUFFER);
  83. RETURN_CASE(NV_ENC_ERR_INVALID_VERSION);
  84. RETURN_CASE(NV_ENC_ERR_MAP_FAILED);
  85. RETURN_CASE(NV_ENC_ERR_NEED_MORE_INPUT);
  86. RETURN_CASE(NV_ENC_ERR_ENCODER_BUSY);
  87. RETURN_CASE(NV_ENC_ERR_EVENT_NOT_REGISTERD);
  88. RETURN_CASE(NV_ENC_ERR_GENERIC);
  89. RETURN_CASE(NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY);
  90. RETURN_CASE(NV_ENC_ERR_UNIMPLEMENTED);
  91. RETURN_CASE(NV_ENC_ERR_RESOURCE_REGISTER_FAILED);
  92. RETURN_CASE(NV_ENC_ERR_RESOURCE_NOT_REGISTERED);
  93. RETURN_CASE(NV_ENC_ERR_RESOURCE_NOT_MAPPED);
  94. }
  95. #undef RETURN_CASE
  96. return "Unknown Error";
  97. }
  98. static inline bool init_nvenc_internal(obs_encoder_t *encoder)
  99. {
  100. static bool initialized = false;
  101. static bool success = false;
  102. if (initialized)
  103. return success;
  104. initialized = true;
  105. NV_MAX_VER_FUNC nv_max_ver = (NV_MAX_VER_FUNC)load_nv_func(
  106. "NvEncodeAPIGetMaxSupportedVersion");
  107. if (!nv_max_ver) {
  108. obs_encoder_set_last_error(
  109. encoder,
  110. "Missing NvEncodeAPIGetMaxSupportedVersion, check "
  111. "your video card drivers are up to date.");
  112. return false;
  113. }
  114. uint32_t ver = 0;
  115. if (NV_FAILED(encoder, nv_max_ver(&ver))) {
  116. return false;
  117. }
  118. uint32_t cur_ver = (NVENCAPI_MAJOR_VERSION << 4) |
  119. NVENCAPI_MINOR_VERSION;
  120. if (cur_ver > ver) {
  121. obs_encoder_set_last_error(
  122. encoder,
  123. "Your current video card driver does not support "
  124. "this NVENC version, please update your drivers.");
  125. error("Current driver version does not support this NVENC "
  126. "version, please upgrade your driver");
  127. return false;
  128. }
  129. nv_create_instance = (NV_CREATE_INSTANCE_FUNC)load_nv_func(
  130. "NvEncodeAPICreateInstance");
  131. if (!nv_create_instance) {
  132. obs_encoder_set_last_error(
  133. encoder, "Missing NvEncodeAPICreateInstance, check "
  134. "your video card drivers are up to date.");
  135. return false;
  136. }
  137. if (NV_FAILED(encoder, nv_create_instance(&nv))) {
  138. return false;
  139. }
  140. success = true;
  141. return true;
  142. }
  143. bool init_nvenc(obs_encoder_t *encoder)
  144. {
  145. bool success;
  146. pthread_mutex_lock(&init_mutex);
  147. success = init_nvenc_internal(encoder);
  148. pthread_mutex_unlock(&init_mutex);
  149. return success;
  150. }
  151. extern struct obs_encoder_info nvenc_info;
  152. void jim_nvenc_load(void)
  153. {
  154. pthread_mutex_init(&init_mutex, NULL);
  155. obs_register_encoder(&nvenc_info);
  156. }
  157. void jim_nvenc_unload(void)
  158. {
  159. pthread_mutex_destroy(&init_mutex);
  160. }