yolobs-studio/plugins/obs-ffmpeg/jim-nvenc-helpers.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

189 lines
4.6 KiB
C
Raw Permalink Normal View History

2019-07-27 12:47:10 +00:00
#include "jim-nvenc.h"
#include <util/platform.h>
#include <util/threading.h>
2020-05-27 20:57:19 +00:00
#include <util/dstr.h>
2019-07-27 12:47:10 +00:00
static void *nvenc_lib = NULL;
static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
NV_ENCODE_API_FUNCTION_LIST nv = {NV_ENCODE_API_FUNCTION_LIST_VER};
NV_CREATE_INSTANCE_FUNC nv_create_instance = NULL;
2019-09-22 21:19:10 +00:00
#define error(format, ...) blog(LOG_ERROR, "[jim-nvenc] " format, ##__VA_ARGS__)
2019-07-27 12:47:10 +00:00
2020-05-27 20:57:19 +00:00
bool nv_failed(obs_encoder_t *encoder, NVENCSTATUS err, const char *func,
const char *call)
2019-07-27 12:47:10 +00:00
{
2020-05-27 20:57:19 +00:00
struct dstr error_message = {0};
switch (err) {
case NV_ENC_SUCCESS:
2019-07-27 12:47:10 +00:00
return false;
2020-05-27 20:57:19 +00:00
case NV_ENC_ERR_OUT_OF_MEMORY:
obs_encoder_set_last_error(
encoder, obs_module_text("NVENC.TooManySessions"));
break;
case NV_ENC_ERR_UNSUPPORTED_DEVICE:
obs_encoder_set_last_error(
encoder, obs_module_text("NVENC.UnsupportedDevice"));
break;
2020-10-01 20:15:25 +00:00
case NV_ENC_ERR_INVALID_VERSION:
obs_encoder_set_last_error(
encoder, obs_module_text("NVENC.OutdatedDriver"));
break;
2020-05-27 20:57:19 +00:00
default:
dstr_printf(&error_message,
"NVENC Error: %s: %s failed: %d (%s)", func, call,
(int)err, nv_error_name(err));
obs_encoder_set_last_error(encoder, error_message.array);
dstr_free(&error_message);
break;
}
2019-07-27 12:47:10 +00:00
error("%s: %s failed: %d (%s)", func, call, (int)err,
2019-09-22 21:19:10 +00:00
nv_error_name(err));
2019-07-27 12:47:10 +00:00
return true;
}
2020-05-27 20:57:19 +00:00
#define NV_FAILED(e, x) nv_failed(e, x, __FUNCTION__, #x)
2019-07-27 12:47:10 +00:00
bool load_nvenc_lib(void)
{
2019-09-22 21:19:10 +00:00
if (sizeof(void *) == 8) {
2019-07-27 12:47:10 +00:00
nvenc_lib = os_dlopen("nvEncodeAPI64.dll");
} else {
nvenc_lib = os_dlopen("nvEncodeAPI.dll");
}
return !!nvenc_lib;
}
static void *load_nv_func(const char *func)
{
void *func_ptr = os_dlsym(nvenc_lib, func);
if (!func_ptr) {
error("Could not load function: %s", func);
}
return func_ptr;
}
2019-09-22 21:19:10 +00:00
typedef NVENCSTATUS(NVENCAPI *NV_MAX_VER_FUNC)(uint32_t *);
2019-07-27 12:47:10 +00:00
const char *nv_error_name(NVENCSTATUS err)
{
#define RETURN_CASE(x) \
2019-09-22 21:19:10 +00:00
case x: \
return #x
2019-07-27 12:47:10 +00:00
switch (err) {
2019-09-22 21:19:10 +00:00
RETURN_CASE(NV_ENC_SUCCESS);
RETURN_CASE(NV_ENC_ERR_NO_ENCODE_DEVICE);
RETURN_CASE(NV_ENC_ERR_UNSUPPORTED_DEVICE);
RETURN_CASE(NV_ENC_ERR_INVALID_ENCODERDEVICE);
RETURN_CASE(NV_ENC_ERR_INVALID_DEVICE);
RETURN_CASE(NV_ENC_ERR_DEVICE_NOT_EXIST);
RETURN_CASE(NV_ENC_ERR_INVALID_PTR);
RETURN_CASE(NV_ENC_ERR_INVALID_EVENT);
RETURN_CASE(NV_ENC_ERR_INVALID_PARAM);
RETURN_CASE(NV_ENC_ERR_INVALID_CALL);
RETURN_CASE(NV_ENC_ERR_OUT_OF_MEMORY);
RETURN_CASE(NV_ENC_ERR_ENCODER_NOT_INITIALIZED);
RETURN_CASE(NV_ENC_ERR_UNSUPPORTED_PARAM);
RETURN_CASE(NV_ENC_ERR_LOCK_BUSY);
RETURN_CASE(NV_ENC_ERR_NOT_ENOUGH_BUFFER);
RETURN_CASE(NV_ENC_ERR_INVALID_VERSION);
RETURN_CASE(NV_ENC_ERR_MAP_FAILED);
RETURN_CASE(NV_ENC_ERR_NEED_MORE_INPUT);
RETURN_CASE(NV_ENC_ERR_ENCODER_BUSY);
RETURN_CASE(NV_ENC_ERR_EVENT_NOT_REGISTERD);
RETURN_CASE(NV_ENC_ERR_GENERIC);
RETURN_CASE(NV_ENC_ERR_INCOMPATIBLE_CLIENT_KEY);
RETURN_CASE(NV_ENC_ERR_UNIMPLEMENTED);
RETURN_CASE(NV_ENC_ERR_RESOURCE_REGISTER_FAILED);
RETURN_CASE(NV_ENC_ERR_RESOURCE_NOT_REGISTERED);
RETURN_CASE(NV_ENC_ERR_RESOURCE_NOT_MAPPED);
2019-07-27 12:47:10 +00:00
}
#undef RETURN_CASE
return "Unknown Error";
}
2020-05-27 20:57:19 +00:00
static inline bool init_nvenc_internal(obs_encoder_t *encoder)
2019-07-27 12:47:10 +00:00
{
static bool initialized = false;
static bool success = false;
if (initialized)
return success;
initialized = true;
2019-09-22 21:19:10 +00:00
NV_MAX_VER_FUNC nv_max_ver = (NV_MAX_VER_FUNC)load_nv_func(
"NvEncodeAPIGetMaxSupportedVersion");
2019-07-27 12:47:10 +00:00
if (!nv_max_ver) {
2020-05-27 20:57:19 +00:00
obs_encoder_set_last_error(
encoder,
"Missing NvEncodeAPIGetMaxSupportedVersion, check "
"your video card drivers are up to date.");
2019-07-27 12:47:10 +00:00
return false;
}
uint32_t ver = 0;
2020-05-27 20:57:19 +00:00
if (NV_FAILED(encoder, nv_max_ver(&ver))) {
2019-07-27 12:47:10 +00:00
return false;
}
2019-09-22 21:19:10 +00:00
uint32_t cur_ver = (NVENCAPI_MAJOR_VERSION << 4) |
NVENCAPI_MINOR_VERSION;
2019-07-27 12:47:10 +00:00
if (cur_ver > ver) {
2020-05-27 20:57:19 +00:00
obs_encoder_set_last_error(
encoder, obs_module_text("NVENC.OutdatedDriver"));
2019-07-27 12:47:10 +00:00
error("Current driver version does not support this NVENC "
2019-09-22 21:19:10 +00:00
"version, please upgrade your driver");
2019-07-27 12:47:10 +00:00
return false;
}
2019-09-22 21:19:10 +00:00
nv_create_instance = (NV_CREATE_INSTANCE_FUNC)load_nv_func(
"NvEncodeAPICreateInstance");
2019-07-27 12:47:10 +00:00
if (!nv_create_instance) {
2020-05-27 20:57:19 +00:00
obs_encoder_set_last_error(
encoder, "Missing NvEncodeAPICreateInstance, check "
"your video card drivers are up to date.");
2019-07-27 12:47:10 +00:00
return false;
}
2020-05-27 20:57:19 +00:00
if (NV_FAILED(encoder, nv_create_instance(&nv))) {
2019-07-27 12:47:10 +00:00
return false;
}
success = true;
return true;
}
2020-05-27 20:57:19 +00:00
bool init_nvenc(obs_encoder_t *encoder)
2019-07-27 12:47:10 +00:00
{
bool success;
pthread_mutex_lock(&init_mutex);
2020-05-27 20:57:19 +00:00
success = init_nvenc_internal(encoder);
2019-07-27 12:47:10 +00:00
pthread_mutex_unlock(&init_mutex);
return success;
}
extern struct obs_encoder_info nvenc_info;
void jim_nvenc_load(void)
{
pthread_mutex_init(&init_mutex, NULL);
obs_register_encoder(&nvenc_info);
}
void jim_nvenc_unload(void)
{
pthread_mutex_destroy(&init_mutex);
}