jim-nvenc-helpers.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include "jim-nvenc.h"
  2. #include <util/platform.h>
  3. #include <util/threading.h>
  4. static void *nvenc_lib = NULL;
  5. static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
  6. NV_ENCODE_API_FUNCTION_LIST nv = {NV_ENCODE_API_FUNCTION_LIST_VER};
  7. NV_CREATE_INSTANCE_FUNC nv_create_instance = NULL;
  8. #define error(format, ...) blog(LOG_ERROR, "[jim-nvenc] " format, ##__VA_ARGS__)
  9. static inline bool nv_failed(NVENCSTATUS err, const char *func,
  10. const char *call)
  11. {
  12. if (err == NV_ENC_SUCCESS)
  13. return false;
  14. error("%s: %s failed: %d (%s)", func, call, (int)err,
  15. nv_error_name(err));
  16. return true;
  17. }
  18. #define NV_FAILED(x) nv_failed(x, __FUNCTION__, #x)
  19. bool load_nvenc_lib(void)
  20. {
  21. if (sizeof(void *) == 8) {
  22. nvenc_lib = os_dlopen("nvEncodeAPI64.dll");
  23. } else {
  24. nvenc_lib = os_dlopen("nvEncodeAPI.dll");
  25. }
  26. return !!nvenc_lib;
  27. }
  28. static void *load_nv_func(const char *func)
  29. {
  30. void *func_ptr = os_dlsym(nvenc_lib, func);
  31. if (!func_ptr) {
  32. error("Could not load function: %s", func);
  33. }
  34. return func_ptr;
  35. }
  36. typedef NVENCSTATUS(NVENCAPI *NV_MAX_VER_FUNC)(uint32_t *);
  37. const char *nv_error_name(NVENCSTATUS err)
  38. {
  39. #define RETURN_CASE(x) \
  40. case x: \
  41. return #x
  42. switch (err) {
  43. RETURN_CASE(NV_ENC_SUCCESS);
  44. RETURN_CASE(NV_ENC_ERR_NO_ENCODE_DEVICE);
  45. RETURN_CASE(NV_ENC_ERR_UNSUPPORTED_DEVICE);
  46. RETURN_CASE(NV_ENC_ERR_INVALID_ENCODERDEVICE);
  47. RETURN_CASE(NV_ENC_ERR_INVALID_DEVICE);
  48. RETURN_CASE(NV_ENC_ERR_DEVICE_NOT_EXIST);
  49. RETURN_CASE(NV_ENC_ERR_INVALID_PTR);
  50. RETURN_CASE(NV_ENC_ERR_INVALID_EVENT);
  51. RETURN_CASE(NV_ENC_ERR_INVALID_PARAM);
  52. RETURN_CASE(NV_ENC_ERR_INVALID_CALL);
  53. RETURN_CASE(NV_ENC_ERR_OUT_OF_MEMORY);
  54. RETURN_CASE(NV_ENC_ERR_ENCODER_NOT_INITIALIZED);
  55. RETURN_CASE(NV_ENC_ERR_UNSUPPORTED_PARAM);
  56. RETURN_CASE(NV_ENC_ERR_LOCK_BUSY);
  57. RETURN_CASE(NV_ENC_ERR_NOT_ENOUGH_BUFFER);
  58. RETURN_CASE(NV_ENC_ERR_INVALID_VERSION);
  59. RETURN_CASE(NV_ENC_ERR_MAP_FAILED);
  60. RETURN_CASE(NV_ENC_ERR_NEED_MORE_INPUT);
  61. RETURN_CASE(NV_ENC_ERR_ENCODER_BUSY);
  62. RETURN_CASE(NV_ENC_ERR_EVENT_NOT_REGISTERD);
  63. RETURN_CASE(NV_ENC_ERR_GENERIC);
  64. RETURN_CASE(NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY);
  65. RETURN_CASE(NV_ENC_ERR_UNIMPLEMENTED);
  66. RETURN_CASE(NV_ENC_ERR_RESOURCE_REGISTER_FAILED);
  67. RETURN_CASE(NV_ENC_ERR_RESOURCE_NOT_REGISTERED);
  68. RETURN_CASE(NV_ENC_ERR_RESOURCE_NOT_MAPPED);
  69. }
  70. #undef RETURN_CASE
  71. return "Unknown Error";
  72. }
  73. static inline bool init_nvenc_internal(void)
  74. {
  75. static bool initialized = false;
  76. static bool success = false;
  77. if (initialized)
  78. return success;
  79. initialized = true;
  80. NV_MAX_VER_FUNC nv_max_ver = (NV_MAX_VER_FUNC)load_nv_func(
  81. "NvEncodeAPIGetMaxSupportedVersion");
  82. if (!nv_max_ver) {
  83. return false;
  84. }
  85. uint32_t ver = 0;
  86. if (NV_FAILED(nv_max_ver(&ver))) {
  87. return false;
  88. }
  89. uint32_t cur_ver = (NVENCAPI_MAJOR_VERSION << 4) |
  90. NVENCAPI_MINOR_VERSION;
  91. if (cur_ver > ver) {
  92. error("Current driver version does not support this NVENC "
  93. "version, please upgrade your driver");
  94. return false;
  95. }
  96. nv_create_instance = (NV_CREATE_INSTANCE_FUNC)load_nv_func(
  97. "NvEncodeAPICreateInstance");
  98. if (!nv_create_instance) {
  99. return false;
  100. }
  101. if (NV_FAILED(nv_create_instance(&nv))) {
  102. return false;
  103. }
  104. success = true;
  105. return true;
  106. }
  107. bool init_nvenc(void)
  108. {
  109. bool success;
  110. pthread_mutex_lock(&init_mutex);
  111. success = init_nvenc_internal();
  112. pthread_mutex_unlock(&init_mutex);
  113. return success;
  114. }
  115. extern struct obs_encoder_info nvenc_info;
  116. void jim_nvenc_load(void)
  117. {
  118. pthread_mutex_init(&init_mutex, NULL);
  119. obs_register_encoder(&nvenc_info);
  120. }
  121. void jim_nvenc_unload(void)
  122. {
  123. pthread_mutex_destroy(&init_mutex);
  124. }