New upstream version 24.0.1+dfsg1

This commit is contained in:
Sebastian Ramacher 2019-09-22 23:19:10 +02:00
parent b14f9eae6d
commit 5a730d6ec3
842 changed files with 42245 additions and 33385 deletions

View file

@ -12,17 +12,16 @@
#define EXTRA_BUFFERS 5
#define do_log(level, format, ...) \
#define do_log(level, format, ...) \
blog(level, "[jim-nvenc: '%s'] " format, \
obs_encoder_get_name(enc->encoder), ##__VA_ARGS__)
obs_encoder_get_name(enc->encoder), ##__VA_ARGS__)
#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
#define error_hr(msg) \
error("%s: %s: 0x%08lX", __FUNCTION__, msg, (uint32_t)hr);
#define error_hr(msg) error("%s: %s: 0x%08lX", __FUNCTION__, msg, (uint32_t)hr);
struct nv_bitstream;
struct nv_texture;
@ -39,57 +38,57 @@ struct handle_tex {
struct nvenc_data {
obs_encoder_t *encoder;
void *session;
void *session;
NV_ENC_INITIALIZE_PARAMS params;
NV_ENC_CONFIG config;
size_t buf_count;
size_t output_delay;
size_t buffers_queued;
size_t next_bitstream;
size_t cur_bitstream;
bool encode_started;
bool first_packet;
bool can_change_bitrate;
bool bframes;
NV_ENC_CONFIG config;
size_t buf_count;
size_t output_delay;
size_t buffers_queued;
size_t next_bitstream;
size_t cur_bitstream;
bool encode_started;
bool first_packet;
bool can_change_bitrate;
bool bframes;
DARRAY(struct nv_bitstream) bitstreams;
DARRAY(struct nv_texture) textures;
DARRAY(struct handle_tex) input_textures;
struct circlebuf dts_list;
DARRAY(struct nv_texture) textures;
DARRAY(struct handle_tex) input_textures;
struct circlebuf dts_list;
DARRAY(uint8_t) packet_data;
int64_t packet_pts;
bool packet_keyframe;
int64_t packet_pts;
bool packet_keyframe;
ID3D11Device *device;
ID3D11Device *device;
ID3D11DeviceContext *context;
uint32_t cx;
uint32_t cy;
uint8_t *header;
size_t header_size;
size_t header_size;
uint8_t *sei;
size_t sei_size;
size_t sei_size;
};
/* ------------------------------------------------------------------------- */
/* Bitstream Buffer */
struct nv_bitstream {
void *ptr;
void *ptr;
HANDLE event;
};
static inline bool nv_failed(struct nvenc_data *enc, NVENCSTATUS err,
const char *func, const char *call)
const char *func, const char *call)
{
if (err == NV_ENC_SUCCESS)
return false;
error("%s: %s failed: %d (%s)", func, call, (int)err,
nv_error_name(err));
nv_error_name(err));
return true;
}
@ -97,7 +96,8 @@ static inline bool nv_failed(struct nvenc_data *enc, NVENCSTATUS err,
static bool nv_bitstream_init(struct nvenc_data *enc, struct nv_bitstream *bs)
{
NV_ENC_CREATE_BITSTREAM_BUFFER buf = {NV_ENC_CREATE_BITSTREAM_BUFFER_VER};
NV_ENC_CREATE_BITSTREAM_BUFFER buf = {
NV_ENC_CREATE_BITSTREAM_BUFFER_VER};
NV_ENC_EVENT_PARAMS params = {NV_ENC_EVENT_PARAMS_VER};
HANDLE event = NULL;
@ -126,7 +126,7 @@ fail:
}
if (buf.bitstreamBuffer) {
nv.nvEncDestroyBitstreamBuffer(enc->session,
buf.bitstreamBuffer);
buf.bitstreamBuffer);
}
return false;
}
@ -147,9 +147,9 @@ static void nv_bitstream_free(struct nvenc_data *enc, struct nv_bitstream *bs)
/* Texture Resource */
struct nv_texture {
void *res;
void *res;
ID3D11Texture2D *tex;
void *mapped_res;
void *mapped_res;
};
static bool nv_texture_init(struct nvenc_data *enc, struct nv_texture *nvtex)
@ -159,13 +159,13 @@ static bool nv_texture_init(struct nvenc_data *enc, struct nv_texture *nvtex)
HRESULT hr;
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = enc->cx;
desc.Height = enc->cy;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_NV12;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
desc.Width = enc->cx;
desc.Height = enc->cy;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_NV12;
desc.SampleDesc.Count = 1;
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
hr = device->lpVtbl->CreateTexture2D(device, &desc, NULL, &tex);
if (FAILED(hr)) {
@ -176,11 +176,11 @@ static bool nv_texture_init(struct nvenc_data *enc, struct nv_texture *nvtex)
tex->lpVtbl->SetEvictionPriority(tex, DXGI_RESOURCE_PRIORITY_MAXIMUM);
NV_ENC_REGISTER_RESOURCE res = {NV_ENC_REGISTER_RESOURCE_VER};
res.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX;
res.resourceToRegister = tex;
res.width = enc->cx;
res.height = enc->cy;
res.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12;
res.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX;
res.resourceToRegister = tex;
res.width = enc->cx;
res.height = enc->cy;
res.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12;
if (NV_FAILED(nv.nvEncRegisterResource(enc->session, &res))) {
tex->lpVtbl->Release(tex);
@ -197,7 +197,7 @@ static void nv_texture_free(struct nvenc_data *enc, struct nv_texture *nvtex)
if (nvtex->res) {
if (nvtex->mapped_res) {
nv.nvEncUnmapInputResource(enc->session,
nvtex->mapped_res);
nvtex->mapped_res);
}
nv.nvEncUnregisterResource(enc->session, nvtex->res);
nvtex->tex->lpVtbl->Release(nvtex->tex);
@ -235,13 +235,16 @@ static bool nvenc_update(void *data, obs_data_t *settings)
int bitrate = (int)obs_data_get_int(settings, "bitrate");
enc->config.rcParams.averageBitRate = bitrate * 1000;
enc->config.rcParams.maxBitRate = bitrate * 1000;
enc->config.rcParams.maxBitRate = bitrate * 1000;
NV_ENC_RECONFIGURE_PARAMS params = {0};
params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
params.reInitEncodeParams = enc->params;
params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
params.reInitEncodeParams = enc->params;
params.resetEncoder = 1;
params.forceIDR = 1;
if (FAILED(nv.nvEncReconfigureEncoder(enc->session, &params))) {
if (NV_FAILED(nv.nvEncReconfigureEncoder(enc->session,
&params))) {
return false;
}
}
@ -261,28 +264,28 @@ static HANDLE get_lib(struct nvenc_data *enc, const char *lib)
return mod;
}
typedef HRESULT (WINAPI *CREATEDXGIFACTORY1PROC)(REFIID, void **);
typedef HRESULT(WINAPI *CREATEDXGIFACTORY1PROC)(REFIID, void **);
static bool init_d3d11(struct nvenc_data *enc, obs_data_t *settings)
{
HMODULE dxgi = get_lib(enc, "DXGI.dll");
HMODULE d3d11 = get_lib(enc, "D3D11.dll");
CREATEDXGIFACTORY1PROC create_dxgi;
HMODULE dxgi = get_lib(enc, "DXGI.dll");
HMODULE d3d11 = get_lib(enc, "D3D11.dll");
CREATEDXGIFACTORY1PROC create_dxgi;
PFN_D3D11_CREATE_DEVICE create_device;
IDXGIFactory1 *factory;
IDXGIAdapter *adapter;
ID3D11Device *device;
ID3D11DeviceContext *context;
HRESULT hr;
IDXGIFactory1 *factory;
IDXGIAdapter *adapter;
ID3D11Device *device;
ID3D11DeviceContext *context;
HRESULT hr;
if (!dxgi || !d3d11) {
return false;
}
create_dxgi = (CREATEDXGIFACTORY1PROC)GetProcAddress(dxgi,
"CreateDXGIFactory1");
create_device = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d11,
"D3D11CreateDevice");
create_dxgi = (CREATEDXGIFACTORY1PROC)GetProcAddress(
dxgi, "CreateDXGIFactory1");
create_device = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(
d3d11, "D3D11CreateDevice");
if (!create_dxgi || !create_device) {
error("Failed to load D3D11/DXGI procedures");
@ -302,8 +305,8 @@ static bool init_d3d11(struct nvenc_data *enc, obs_data_t *settings)
return false;
}
hr = create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0,
NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context);
hr = create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0,
D3D11_SDK_VERSION, &device, NULL, &context);
adapter->lpVtbl->Release(adapter);
if (FAILED(hr)) {
error_hr("D3D11CreateDevice failed");
@ -317,8 +320,8 @@ static bool init_d3d11(struct nvenc_data *enc, obs_data_t *settings)
static bool init_session(struct nvenc_data *enc)
{
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params =
{NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER};
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = {
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER};
params.device = enc->device;
params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
params.apiVersion = NVENCAPI_VERSION;
@ -384,19 +387,19 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
}
if (astrcmpi(rc, "lossless") == 0) {
nv_preset = hp
? NV_ENC_PRESET_LOSSLESS_HP_GUID
: NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
nv_preset = hp ? NV_ENC_PRESET_LOSSLESS_HP_GUID
: NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
}
/* -------------------------- */
/* get preset default config */
NV_ENC_PRESET_CONFIG preset_config =
{NV_ENC_PRESET_CONFIG_VER, {NV_ENC_CONFIG_VER}};
NV_ENC_PRESET_CONFIG preset_config = {NV_ENC_PRESET_CONFIG_VER,
{NV_ENC_CONFIG_VER}};
err = nv.nvEncGetEncodePresetConfig(enc->session,
NV_ENC_CODEC_H264_GUID, nv_preset, &preset_config);
NV_ENC_CODEC_H264_GUID, nv_preset,
&preset_config);
if (nv_failed(enc, err, __FUNCTION__, "nvEncGetEncodePresetConfig")) {
return false;
}
@ -406,9 +409,8 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
enc->config = preset_config.presetCfg;
uint32_t gop_size = (keyint_sec)
? keyint_sec * voi->fps_num / voi->fps_den
: 250;
uint32_t gop_size =
(keyint_sec) ? keyint_sec * voi->fps_num / voi->fps_den : 250;
NV_ENC_INITIALIZE_PARAMS *params = &enc->params;
NV_ENC_CONFIG *config = &enc->config;
@ -461,9 +463,8 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
enc->can_change_bitrate =
nv_get_cap(enc, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE);
config->rcParams.rateControlMode = twopass
? NV_ENC_PARAMS_RC_VBR_HQ
: NV_ENC_PARAMS_RC_VBR;
config->rcParams.rateControlMode = twopass ? NV_ENC_PARAMS_RC_VBR_HQ
: NV_ENC_PARAMS_RC_VBR;
if (astrcmpi(rc, "cqp") == 0 || astrcmpi(rc, "lossless") == 0) {
if (astrcmpi(rc, "lossless") == 0)
@ -480,9 +481,9 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
} else if (astrcmpi(rc, "vbr") != 0) { /* CBR by default */
h264_config->outputBufferingPeriodSEI = 1;
config->rcParams.rateControlMode = twopass
? NV_ENC_PARAMS_RC_2_PASS_QUALITY
: NV_ENC_PARAMS_RC_CBR;
config->rcParams.rateControlMode =
twopass ? NV_ENC_PARAMS_RC_2_PASS_QUALITY
: NV_ENC_PARAMS_RC_CBR;
}
h264_config->outputPictureTimingSEI = 1;
@ -508,7 +509,7 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
}
enc->buf_count = config->frameIntervalP +
config->rcParams.lookaheadDepth + EXTRA_BUFFERS;
config->rcParams.lookaheadDepth + EXTRA_BUFFERS;
enc->output_delay = enc->buf_count - 1;
info("settings:\n"
@ -524,12 +525,8 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
"\tb-frames: %d\n"
"\tlookahead: %s\n"
"\tpsycho_aq: %s\n",
rc, bitrate, cqp, gop_size,
preset, profile,
enc->cx, enc->cy,
twopass ? "true" : "false",
bf,
lookahead ? "true" : "false",
rc, bitrate, cqp, gop_size, preset, profile, enc->cx, enc->cy,
twopass ? "true" : "false", bf, lookahead ? "true" : "false",
psycho_aq ? "true" : "false");
return true;
@ -662,12 +659,13 @@ static void nvenc_destroy(void *data)
}
static ID3D11Texture2D *get_tex_from_handle(struct nvenc_data *enc,
uint32_t handle, IDXGIKeyedMutex **km_out)
uint32_t handle,
IDXGIKeyedMutex **km_out)
{
ID3D11Device *device = enc->device;
ID3D11Device *device = enc->device;
IDXGIKeyedMutex *km;
ID3D11Texture2D *input_tex;
HRESULT hr;
HRESULT hr;
for (size_t i = 0; i < enc->input_textures.num; i++) {
struct handle_tex *ht = &enc->input_textures.array[i];
@ -678,15 +676,16 @@ static ID3D11Texture2D *get_tex_from_handle(struct nvenc_data *enc,
}
hr = device->lpVtbl->OpenSharedResource(device,
(HANDLE)(uintptr_t)handle,
&IID_ID3D11Texture2D, &input_tex);
(HANDLE)(uintptr_t)handle,
&IID_ID3D11Texture2D,
&input_tex);
if (FAILED(hr)) {
error_hr("OpenSharedResource failed");
return NULL;
}
hr = input_tex->lpVtbl->QueryInterface(input_tex, &IID_IDXGIKeyedMutex,
&km);
&km);
if (FAILED(hr)) {
error_hr("QueryInterface(IDXGIKeyedMutex) failed");
input_tex->lpVtbl->Release(input_tex);
@ -694,7 +693,7 @@ static ID3D11Texture2D *get_tex_from_handle(struct nvenc_data *enc,
}
input_tex->lpVtbl->SetEvictionPriority(input_tex,
DXGI_RESOURCE_PRIORITY_MAXIMUM);
DXGI_RESOURCE_PRIORITY_MAXIMUM);
*km_out = km;
@ -717,15 +716,15 @@ static bool get_encoded_packet(struct nvenc_data *enc, bool finalize)
size_t count = finalize ? enc->buffers_queued : 1;
for (size_t i = 0; i < count; i++) {
size_t cur_bs_idx = enc->cur_bitstream;
struct nv_bitstream *bs = &enc->bitstreams.array[cur_bs_idx];
struct nv_texture *nvtex = &enc->textures.array[cur_bs_idx];
size_t cur_bs_idx = enc->cur_bitstream;
struct nv_bitstream *bs = &enc->bitstreams.array[cur_bs_idx];
struct nv_texture *nvtex = &enc->textures.array[cur_bs_idx];
/* ---------------- */
NV_ENC_LOCK_BITSTREAM lock = {NV_ENC_LOCK_BITSTREAM_VER};
lock.outputBitstream = bs->ptr;
lock.doNotWait = false;
lock.outputBitstream = bs->ptr;
lock.doNotWait = false;
if (NV_FAILED(nv.nvEncLockBitstream(s, &lock))) {
return false;
@ -736,19 +735,17 @@ static bool get_encoded_packet(struct nvenc_data *enc, bool finalize)
size_t size;
enc->first_packet = false;
obs_extract_avc_headers(
lock.bitstreamBufferPtr,
lock.bitstreamSizeInBytes,
&new_packet, &size,
&enc->header, &enc->header_size,
&enc->sei, &enc->sei_size);
obs_extract_avc_headers(lock.bitstreamBufferPtr,
lock.bitstreamSizeInBytes,
&new_packet, &size,
&enc->header, &enc->header_size,
&enc->sei, &enc->sei_size);
da_copy_array(enc->packet_data, new_packet, size);
bfree(new_packet);
} else {
da_copy_array(enc->packet_data,
lock.bitstreamBufferPtr,
lock.bitstreamSizeInBytes);
da_copy_array(enc->packet_data, lock.bitstreamBufferPtr,
lock.bitstreamSizeInBytes);
}
enc->packet_pts = (int64_t)lock.outputTimeStamp;
@ -781,18 +778,19 @@ static bool get_encoded_packet(struct nvenc_data *enc, bool finalize)
}
static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
uint64_t lock_key, uint64_t *next_key,
struct encoder_packet *packet, bool *received_packet)
uint64_t lock_key, uint64_t *next_key,
struct encoder_packet *packet,
bool *received_packet)
{
struct nvenc_data *enc = data;
ID3D11Device *device = enc->device;
struct nvenc_data *enc = data;
ID3D11Device *device = enc->device;
ID3D11DeviceContext *context = enc->context;
ID3D11Texture2D *input_tex;
ID3D11Texture2D *output_tex;
IDXGIKeyedMutex *km;
struct nv_texture *nvtex;
ID3D11Texture2D *input_tex;
ID3D11Texture2D *output_tex;
IDXGIKeyedMutex *km;
struct nv_texture *nvtex;
struct nv_bitstream *bs;
NVENCSTATUS err;
NVENCSTATUS err;
if (handle == GS_INVALID_HANDLE) {
error("Encode failed: bad texture handle");
@ -800,10 +798,10 @@ static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
return false;
}
bs = &enc->bitstreams.array[enc->next_bitstream];
bs = &enc->bitstreams.array[enc->next_bitstream];
nvtex = &enc->textures.array[enc->next_bitstream];
input_tex = get_tex_from_handle(enc, handle, &km);
input_tex = get_tex_from_handle(enc, handle, &km);
output_tex = nvtex->tex;
if (!input_tex) {
@ -823,9 +821,8 @@ static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
km->lpVtbl->AcquireSync(km, lock_key, INFINITE);
context->lpVtbl->CopyResource(context,
(ID3D11Resource *)output_tex,
(ID3D11Resource *)input_tex);
context->lpVtbl->CopyResource(context, (ID3D11Resource *)output_tex,
(ID3D11Resource *)input_tex);
km->lpVtbl->ReleaseSync(km, *next_key);
@ -833,7 +830,7 @@ static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
/* map output tex so nvenc can use it */
NV_ENC_MAP_INPUT_RESOURCE map = {NV_ENC_MAP_INPUT_RESOURCE_VER};
map.registeredResource = nvtex->res;
map.registeredResource = nvtex->res;
if (NV_FAILED(nv.nvEncMapInputResource(enc->session, &map))) {
return false;
}
@ -844,15 +841,15 @@ static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
/* do actual encode call */
NV_ENC_PIC_PARAMS params = {0};
params.version = NV_ENC_PIC_PARAMS_VER;
params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
params.inputBuffer = nvtex->mapped_res;
params.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12;
params.inputTimeStamp = (uint64_t)pts;
params.inputWidth = enc->cx;
params.inputHeight = enc->cy;
params.outputBitstream = bs->ptr;
params.completionEvent = bs->event;
params.version = NV_ENC_PIC_PARAMS_VER;
params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
params.inputBuffer = nvtex->mapped_res;
params.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12;
params.inputTimeStamp = (uint64_t)pts;
params.inputWidth = enc->cx;
params.inputHeight = enc->cy;
params.outputBitstream = bs->ptr;
params.completionEvent = bs->event;
err = nv.nvEncEncodePicture(enc->session, &params);
if (err != NV_ENC_SUCCESS && err != NV_ENC_ERR_NEED_MORE_INPUT) {
@ -886,11 +883,11 @@ static bool nvenc_encode_tex(void *data, uint32_t handle, int64_t pts,
dts -= packet->timebase_num;
*received_packet = true;
packet->data = enc->packet_data.array;
packet->size = enc->packet_data.num;
packet->type = OBS_ENCODER_VIDEO;
packet->pts = enc->packet_pts;
packet->dts = dts;
packet->data = enc->packet_data.array;
packet->size = enc->packet_data.num;
packet->type = OBS_ENCODER_VIDEO;
packet->pts = enc->packet_pts;
packet->dts = dts;
packet->keyframe = enc->packet_keyframe;
} else {
*received_packet = false;
@ -911,7 +908,7 @@ static bool nvenc_extra_data(void *data, uint8_t **header, size_t *size)
}
*header = enc->header;
*size = enc->header_size;
*size = enc->header_size;
return true;
}
@ -923,23 +920,23 @@ static bool nvenc_sei_data(void *data, uint8_t **sei, size_t *size)
return false;
}
*sei = enc->sei;
*sei = enc->sei;
*size = enc->sei_size;
return true;
}
struct obs_encoder_info nvenc_info = {
.id = "jim_nvenc",
.codec = "h264",
.type = OBS_ENCODER_VIDEO,
.caps = OBS_ENCODER_CAP_PASS_TEXTURE,
.get_name = nvenc_get_name,
.create = nvenc_create,
.destroy = nvenc_destroy,
.update = nvenc_update,
.encode_texture = nvenc_encode_tex,
.get_defaults = nvenc_defaults,
.get_properties = nvenc_properties,
.get_extra_data = nvenc_extra_data,
.get_sei_data = nvenc_sei_data,
.id = "jim_nvenc",
.codec = "h264",
.type = OBS_ENCODER_VIDEO,
.caps = OBS_ENCODER_CAP_PASS_TEXTURE | OBS_ENCODER_CAP_DYN_BITRATE,
.get_name = nvenc_get_name,
.create = nvenc_create,
.destroy = nvenc_destroy,
.update = nvenc_update,
.encode_texture = nvenc_encode_tex,
.get_defaults = nvenc_defaults,
.get_properties = nvenc_properties,
.get_extra_data = nvenc_extra_data,
.get_sei_data = nvenc_sei_data,
};