PR #22657 opened by wangbin URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22657 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22657.patch
highest version of current environment is used by default. -api option can test a lower version. requires multiple copies of nv-codec-headers to build. >From fe4dcb8a7982ea6efcd56d4c304ac3ce95aae130 Mon Sep 17 00:00:00 2001 From: wang-bin <[email protected]> Date: Wed, 12 Jun 2019 10:43:50 +0800 Subject: [PATCH 1/5] nvenc: use runtime api version to work with old drivers the document recommends to use build version, so using latest nvenc headers requires latest driver version. But api and abi change rarely, so requesting runtime version should work, and does work for my tests. --- libavcodec/nvenc.c | 79 +++++++++++++++++++++++++++++----------------- libavcodec/nvenc.h | 3 ++ 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 392230526d..858c79250a 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -347,20 +347,35 @@ static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) #define to_nv_color_trc(n) (uint32_t)(n) #endif +static inline uint32_t struct_ver_rt(NvencContext* ctx, uint32_t struct_ver) +{ + return ((uint32_t)ctx->apiver_rt | ((struct_ver)<<16) | (0x7 << 28)); +} + +static inline uint32_t api_ver(uint32_t major_ver, uint32_t minor_ver) +{ + return major_ver | (minor_ver << 24); +} + static av_cold int nvenc_load_libraries(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; NVENCSTATUS err; uint32_t nvenc_max_ver; + uint32_t nvenc_max_major; + uint32_t nvenc_max_minor; + uint32_t func_ver = NV_ENCODE_API_FUNCTION_LIST_VER; int ret; - ret = cuda_load_functions(&dl_fn->cuda_dl, avctx); - if (ret < 0) + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "cuda_load_functions error"); return ret; + } ret = nvenc_load_functions(&dl_fn->nvenc_dl, avctx); if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "nvenc_load_functions error"); nvenc_print_driver_requirement(avctx, AV_LOG_ERROR); return ret; } @@ -368,19 +383,25 @@ static av_cold int nvenc_load_libraries(AVCodecContext *avctx) err = dl_fn->nvenc_dl->NvEncodeAPIGetMaxSupportedVersion(&nvenc_max_ver); if (err != NV_ENC_SUCCESS) return nvenc_print_error(avctx, err, "Failed to query nvenc max version"); - - av_log(avctx, AV_LOG_VERBOSE, "Loaded Nvenc version %d.%d\n", nvenc_max_ver >> 4, nvenc_max_ver & 0xf); + nvenc_max_major = nvenc_max_ver >> 4; + nvenc_max_minor = nvenc_max_ver & 0xf; + //ctx->apiver_rt = NVENCAPI_VERSION; + ctx->apiver_rt = api_ver(nvenc_max_major, nvenc_max_minor); + ctx->config_ver_rt = struct_ver_rt(ctx, 7) | (1<<31); /*NV_ENC_CONFIG_VER */ + if (ctx->apiver_rt < api_ver(8, 1)) + ctx->config_ver_rt = struct_ver_rt(ctx, 6) | (1<<31); + func_ver = struct_ver_rt(ctx, 2); + av_log(avctx, AV_LOG_INFO, "Loaded Nvenc version %d.%d\n", nvenc_max_major, nvenc_max_minor); if ((NVENCAPI_MAJOR_VERSION << 4 | NVENCAPI_MINOR_VERSION) > nvenc_max_ver) { - av_log(avctx, AV_LOG_ERROR, "Driver does not support the required nvenc API version. " + av_log(avctx, AV_LOG_WARNING, "Driver does not support the required nvenc API version. " "Required: %d.%d Found: %d.%d\n", NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION, - nvenc_max_ver >> 4, nvenc_max_ver & 0xf); - nvenc_print_driver_requirement(avctx, AV_LOG_ERROR); - return AVERROR(ENOSYS); + nvenc_max_major, nvenc_max_minor); + nvenc_print_driver_requirement(avctx, AV_LOG_WARNING); + //return AVERROR(ENOSYS); } - - dl_fn->nvenc_funcs.version = NV_ENCODE_API_FUNCTION_LIST_VER; + dl_fn->nvenc_funcs.version = func_ver; err = dl_fn->nvenc_dl->NvEncodeAPICreateInstance(&dl_fn->nvenc_funcs); if (err != NV_ENC_SUCCESS) @@ -421,8 +442,8 @@ static av_cold int nvenc_open_session(AVCodecContext *avctx) NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &ctx->nvenc_dload_funcs.nvenc_funcs; NVENCSTATUS ret; - params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER; - params.apiVersion = NVENCAPI_VERSION; + params.version = struct_ver_rt(ctx, 1); + params.apiVersion = ctx->apiver_rt; if (ctx->d3d11_device) { params.device = ctx->d3d11_device; params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX; @@ -483,7 +504,7 @@ static int nvenc_check_cap(AVCodecContext *avctx, NV_ENC_CAPS cap) NV_ENC_CAPS_PARAM params = { 0 }; int ret, val = 0; - params.version = NV_ENC_CAPS_PARAM_VER; + params.version = struct_ver_rt(ctx, 1);//NV_ENC_CAPS_PARAM_VER; params.capsToQuery = cap; ret = p_nvenc->nvEncGetEncodeCaps(ctx->nvencoder, ctx->init_encode_params.encodeGUID, ¶ms, &val); @@ -891,7 +912,7 @@ static av_cold void set_constqp(AVCodecContext *avctx) #endif rc->rateControlMode = NV_ENC_PARAMS_RC_CONSTQP; - + /*rc->reservedBitField1 = 0;*/ if (ctx->init_qp_p >= 0) { rc->constQP.qpInterP = ctx->init_qp_p; if (ctx->init_qp_i >= 0 && ctx->init_qp_b >= 0) { @@ -1829,16 +1850,16 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) int res = 0; int dw, dh; - ctx->encode_config.version = NV_ENC_CONFIG_VER; - ctx->init_encode_params.version = NV_ENC_INITIALIZE_PARAMS_VER; + ctx->encode_config.version = ctx->config_ver_rt;//NV_ENC_CONFIG_VER; + ctx->init_encode_params.version = struct_ver_rt(ctx, 5) | (1<<31);//NV_ENC_INITIALIZE_PARAMS_VER; ctx->init_encode_params.encodeHeight = avctx->height; ctx->init_encode_params.encodeWidth = avctx->width; ctx->init_encode_params.encodeConfig = &ctx->encode_config; - preset_config.version = NV_ENC_PRESET_CONFIG_VER; - preset_config.presetCfg.version = NV_ENC_CONFIG_VER; + preset_config.version = struct_ver_rt(ctx, 4) | (1<<31);// NV_ENC_PRESET_CONFIG_VER; + preset_config.presetCfg.version = ctx->config_ver_rt;//NV_ENC_CONFIG_VER; #ifdef NVENC_HAVE_NEW_PRESETS ctx->init_encode_params.tuningInfo = ctx->tuning_info; @@ -1864,7 +1885,7 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) memcpy(&ctx->encode_config, &preset_config.presetCfg, sizeof(ctx->encode_config)); - ctx->encode_config.version = NV_ENC_CONFIG_VER; + ctx->encode_config.version = ctx->config_ver_rt;//NV_ENC_CONFIG_VER; compute_dar(avctx, &dw, &dh); ctx->init_encode_params.darHeight = dh; @@ -2042,7 +2063,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) NVENCSTATUS nv_status; NV_ENC_CREATE_BITSTREAM_BUFFER allocOut = { 0 }; - allocOut.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER; + allocOut.version = struct_ver_rt(ctx, 1);//NV_ENC_CREATE_BITSTREAM_BUFFER_VER; if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { ctx->surfaces[idx].in_ref = av_frame_alloc(); @@ -2058,7 +2079,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) return AVERROR(EINVAL); } - allocSurf.version = NV_ENC_CREATE_INPUT_BUFFER_VER; + allocSurf.version = struct_ver_rt(ctx, 1);//NV_ENC_CREATE_INPUT_BUFFER_VER; allocSurf.width = avctx->width; allocSurf.height = avctx->height; allocSurf.bufferFmt = ctx->surfaces[idx].format; @@ -2146,7 +2167,7 @@ static av_cold int nvenc_setup_extradata(AVCodecContext *avctx) char tmpHeader[NV_MAX_SEQ_HDR_LEN]; NV_ENC_SEQUENCE_PARAM_PAYLOAD payload = { 0 }; - payload.version = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER; + payload.version = struct_ver_rt(ctx, 1);//NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER; payload.spsppsBuffer = tmpHeader; payload.inBufferSize = sizeof(tmpHeader); @@ -2178,7 +2199,7 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) /* the encoder has to be flushed before it can be closed */ if (ctx->nvencoder) { - NV_ENC_PIC_PARAMS params = { .version = NV_ENC_PIC_PARAMS_VER, + NV_ENC_PIC_PARAMS params = { .version = struct_ver_rt(ctx, 4) | (1<<31),// NV_ENC_PIC_PARAMS_VER, .encodePicFlags = NV_ENC_PIC_FLAG_EOS }; res = nvenc_push_context(avctx); @@ -2402,7 +2423,7 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) if (idx < 0) return idx; - reg.version = NV_ENC_REGISTER_RESOURCE_VER; + reg.version = struct_ver_rt(ctx, 3);// NV_ENC_REGISTER_RESOURCE_VER; reg.width = frames_ctx->width; reg.height = frames_ctx->height; reg.pitch = frame->linesize[0]; @@ -2457,7 +2478,7 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, return res; if (!ctx->registered_frames[reg_idx].mapped) { - ctx->registered_frames[reg_idx].in_map.version = NV_ENC_MAP_INPUT_RESOURCE_VER; + ctx->registered_frames[reg_idx].in_map.version = struct_ver_rt(ctx, 4);// NV_ENC_MAP_INPUT_RESOURCE_VER; ctx->registered_frames[reg_idx].in_map.registeredResource = ctx->registered_frames[reg_idx].regptr; nv_status = p_nvenc->nvEncMapInputResource(ctx->nvencoder, &ctx->registered_frames[reg_idx].in_map); if (nv_status != NV_ENC_SUCCESS) { @@ -2477,7 +2498,7 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, } else { NV_ENC_LOCK_INPUT_BUFFER lockBufferParams = { 0 }; - lockBufferParams.version = NV_ENC_LOCK_INPUT_BUFFER_VER; + lockBufferParams.version = struct_ver_rt(ctx, 1);//NV_ENC_LOCK_INPUT_BUFFER_VER; lockBufferParams.inputBuffer = nvenc_frame->input_surface; nv_status = p_nvenc->nvEncLockInputBuffer(ctx->nvencoder, &lockBufferParams); @@ -2731,7 +2752,7 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur enum AVPictureType pict_type; - lock_params.version = NV_ENC_LOCK_BITSTREAM_VER; + lock_params.version = struct_ver_rt(ctx, 1);//NV_ENC_LOCK_BITSTREAM_VER; lock_params.doNotWait = 0; lock_params.outputBitstream = tmpoutsurf->output_surface; @@ -2954,7 +2975,7 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame) int reconfig_bitrate = 0, reconfig_dar = 0; int dw, dh; - params.version = NV_ENC_RECONFIGURE_PARAMS_VER; + params.version = struct_ver_rt(ctx, 1) | (1<<31);//NV_ENC_RECONFIGURE_PARAMS_VER; params.reInitEncodeParams = ctx->init_encode_params; compute_dar(avctx, &dw, &dh); @@ -3126,7 +3147,7 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; NV_ENC_PIC_PARAMS pic_params = { 0 }; - pic_params.version = NV_ENC_PIC_PARAMS_VER; + pic_params.version = struct_ver_rt(ctx, 4) | (1<<31);//NV_ENC_PIC_PARAMS_VER; if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder) return AVERROR(EINVAL); diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index 069ba82bc9..577a69fe9f 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -213,6 +213,9 @@ typedef struct NvencContext { AVClass *avclass; + uint32_t apiver_rt; + uint32_t config_ver_rt; + NvencDynLoadFunctions nvenc_dload_funcs; NV_ENC_INITIALIZE_PARAMS init_encode_params; -- 2.52.0 >From 6bb50b1e14b3c1bf9b685c217fccb030331c1b2e Mon Sep 17 00:00:00 2001 From: wang-bin <[email protected]> Date: Fri, 5 Jun 2020 14:05:42 +0800 Subject: [PATCH 2/5] nvenc: check runtime 9.1 function ptrs before use --- libavcodec/nvenc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 858c79250a..f1645ba83e 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -188,7 +188,7 @@ static int nvenc_print_error(AVCodecContext *avctx, NVENCSTATUS err, NvencContext *ctx = avctx->priv_data; NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &ctx->nvenc_dload_funcs.nvenc_funcs; - if (p_nvenc && ctx->nvencoder) + if (p_nvenc && ctx->nvencoder && p_nvenc->nvEncGetLastErrorString) details = p_nvenc->nvEncGetLastErrorString(ctx->nvencoder); #endif @@ -1985,7 +1985,7 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) } #ifdef NVENC_HAVE_CUSTREAM_PTR - if (ctx->cu_context) { + if (ctx->cu_context && p_nvenc->nvEncSetIOCudaStreams) { nv_status = p_nvenc->nvEncSetIOCudaStreams(ctx->nvencoder, &ctx->cu_stream, &ctx->cu_stream); if (nv_status != NV_ENC_SUCCESS) { nvenc_pop_context(avctx); -- 2.52.0 >From a5504b47993a7f32298fe6e54b4b1319f49fffbf Mon Sep 17 00:00:00 2001 From: wang-bin <[email protected]> Date: Fri, 3 Jul 2020 14:09:54 +0800 Subject: [PATCH 3/5] nvenc: check sdk 10.0 ptrs at runtime --- libavcodec/nvenc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index f1645ba83e..2ae86a1388 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -1869,17 +1869,18 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) else if (ctx->flags & NVENC_LOWLATENCY) ctx->init_encode_params.tuningInfo = NV_ENC_TUNING_INFO_LOW_LATENCY; + if (p_nvenc->nvEncGetEncodePresetConfigEx) nv_status = p_nvenc->nvEncGetEncodePresetConfigEx(ctx->nvencoder, ctx->init_encode_params.encodeGUID, ctx->init_encode_params.presetGUID, ctx->init_encode_params.tuningInfo, &preset_config); -#else + else +#endif nv_status = p_nvenc->nvEncGetEncodePresetConfig(ctx->nvencoder, ctx->init_encode_params.encodeGUID, ctx->init_encode_params.presetGUID, &preset_config); -#endif if (nv_status != NV_ENC_SUCCESS) return nvenc_print_error(avctx, nv_status, "Cannot get the preset configuration"); -- 2.52.0 >From 2ab6851bcde202862e55524b71295b66bb38bf06 Mon Sep 17 00:00:00 2001 From: wangbin <[email protected]> Date: Mon, 25 Aug 2025 11:03:56 +0800 Subject: [PATCH 4/5] nvenc: support api version 12.0+ & api option --- libavcodec/nvenc.c | 85 +++++++++++++++++++++++++++++++++++------ libavcodec/nvenc.h | 1 + libavcodec/nvenc_av1.c | 1 + libavcodec/nvenc_h264.c | 1 + libavcodec/nvenc_hevc.c | 1 + 5 files changed, 78 insertions(+), 11 deletions(-) diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 2ae86a1388..619a4ddd9c 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -357,6 +357,16 @@ static inline uint32_t api_ver(uint32_t major_ver, uint32_t minor_ver) return major_ver | (minor_ver << 24); } +static inline int api_ver_ge(NvencContext* ctx, uint32_t major_ver, uint32_t minor_ver) +{ + const uint32_t v[2] = { ctx->apiver_rt & 0xff, (ctx->apiver_rt >> 24) & 0xff }; + if (v[0] > major_ver) + return 1; + else if (v[0] < major_ver) + return 0; + return v[1] >= minor_ver; +} + static av_cold int nvenc_load_libraries(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; @@ -386,12 +396,38 @@ static av_cold int nvenc_load_libraries(AVCodecContext *avctx) nvenc_max_major = nvenc_max_ver >> 4; nvenc_max_minor = nvenc_max_ver & 0xf; //ctx->apiver_rt = NVENCAPI_VERSION; - ctx->apiver_rt = api_ver(nvenc_max_major, nvenc_max_minor); - ctx->config_ver_rt = struct_ver_rt(ctx, 7) | (1<<31); /*NV_ENC_CONFIG_VER */ - if (ctx->apiver_rt < api_ver(8, 1)) - ctx->config_ver_rt = struct_ver_rt(ctx, 6) | (1<<31); +// if build and max version < 12.0, no abi break, then max version is desired, lower versions are also ok +// if build version < 12.0 but max > 12.0, use build version or 11.1(highest version w/o abi break) or user option +// if build version >= 12.0, abi breaks too often, so max >= build version is required, and build version is better if high version drivers support lower api versions + uint32_t major = NVENCAPI_MAJOR_VERSION; + uint32_t minor = NVENCAPI_MINOR_VERSION; + if (NVENCAPI_MAJOR_VERSION < 12) { + if (nvenc_max_major < 12) { + major = nvenc_max_major; + minor = nvenc_max_minor; + } else { + major = NVENCAPI_MAJOR_VERSION; + minor = NVENCAPI_MINOR_VERSION; + } + } + if (ctx->apiver_req > 0) { + major = (uint32_t)ctx->apiver_req; + minor = (uint32_t)(ctx->apiver_req * 10.0f) % 10; + } + ctx->apiver_rt = api_ver(major, minor); + uint32_t config_ver = 7; + if (api_ver_ge(ctx, 12, 2)) { + config_ver = 9; + } else if (api_ver_ge(ctx, 12, 0)) { + config_ver = 8; + } else if (api_ver_ge(ctx, 8, 1)) { + config_ver = 7; + } else { + config_ver = 6; + } + ctx->config_ver_rt = struct_ver_rt(ctx, config_ver) | (1u<<31); /*NV_ENC_CONFIG_VER */ func_ver = struct_ver_rt(ctx, 2); - av_log(avctx, AV_LOG_INFO, "Loaded Nvenc version %d.%d\n", nvenc_max_major, nvenc_max_minor); + av_log(avctx, AV_LOG_INFO, "Loaded Nvenc version %u.%u, max: %u.%u, build api: %u.%u. config_ver: %u\n", ctx->apiver_rt & 0xff, (ctx->apiver_rt >> 24) & 0xff, nvenc_max_major, nvenc_max_minor, NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION, config_ver); if ((NVENCAPI_MAJOR_VERSION << 4 | NVENCAPI_MINOR_VERSION) > nvenc_max_ver) { av_log(avctx, AV_LOG_WARNING, "Driver does not support the required nvenc API version. " @@ -1851,14 +1887,20 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) int dw, dh; ctx->encode_config.version = ctx->config_ver_rt;//NV_ENC_CONFIG_VER; - ctx->init_encode_params.version = struct_ver_rt(ctx, 5) | (1<<31);//NV_ENC_INITIALIZE_PARAMS_VER; + ctx->init_encode_params.version = struct_ver_rt(ctx, 5) | (1u<<31);//NV_ENC_INITIALIZE_PARAMS_VER; + if (api_ver_ge(ctx, 12, 2)) + ctx->init_encode_params.version = struct_ver_rt(ctx, 7) | (1u<<31); + else if (api_ver_ge(ctx, 12, 1)) + ctx->init_encode_params.version = struct_ver_rt(ctx, 6) | (1u<<31); ctx->init_encode_params.encodeHeight = avctx->height; ctx->init_encode_params.encodeWidth = avctx->width; ctx->init_encode_params.encodeConfig = &ctx->encode_config; - preset_config.version = struct_ver_rt(ctx, 4) | (1<<31);// NV_ENC_PRESET_CONFIG_VER; + preset_config.version = struct_ver_rt(ctx, 4) | (1u<<31);// NV_ENC_PRESET_CONFIG_VER; + if (api_ver_ge(ctx, 12, 2)) + preset_config.version = struct_ver_rt(ctx, 5) | (1u<<31); preset_config.presetCfg.version = ctx->config_ver_rt;//NV_ENC_CONFIG_VER; #ifdef NVENC_HAVE_NEW_PRESETS @@ -2081,6 +2123,8 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) } allocSurf.version = struct_ver_rt(ctx, 1);//NV_ENC_CREATE_INPUT_BUFFER_VER; + if (api_ver_ge(ctx, 12, 2)) + allocSurf.version = struct_ver_rt(ctx, 2); allocSurf.width = avctx->width; allocSurf.height = avctx->height; allocSurf.bufferFmt = ctx->surfaces[idx].format; @@ -2200,9 +2244,12 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) /* the encoder has to be flushed before it can be closed */ if (ctx->nvencoder) { - NV_ENC_PIC_PARAMS params = { .version = struct_ver_rt(ctx, 4) | (1<<31),// NV_ENC_PIC_PARAMS_VER, + NV_ENC_PIC_PARAMS params = { .version = struct_ver_rt(ctx, 4) | (1u<<31),// NV_ENC_PIC_PARAMS_VER, .encodePicFlags = NV_ENC_PIC_FLAG_EOS }; - + if (api_ver_ge(ctx, 12, 2)) + params.version = struct_ver_rt(ctx, 7) | (1u<<31); + else if (api_ver_ge(ctx, 12, 0)) + params.version = struct_ver_rt(ctx, 6) | (1u<<31); res = nvenc_push_context(avctx); if (res < 0) return res; @@ -2425,6 +2472,10 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) return idx; reg.version = struct_ver_rt(ctx, 3);// NV_ENC_REGISTER_RESOURCE_VER; + if (api_ver_ge(ctx, 12, 2)) + reg.version = struct_ver_rt(ctx, 5); + else if (api_ver_ge(ctx, 12, 0)) + reg.version = struct_ver_rt(ctx, 4); reg.width = frames_ctx->width; reg.height = frames_ctx->height; reg.pitch = frame->linesize[0]; @@ -2754,6 +2805,12 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur enum AVPictureType pict_type; lock_params.version = struct_ver_rt(ctx, 1);//NV_ENC_LOCK_BITSTREAM_VER; + if (api_ver_ge(ctx, 12, 2)) + lock_params.version = struct_ver_rt(ctx, 2) | (1u<<31); + else if (api_ver_ge(ctx, 12, 1)) + lock_params.version = struct_ver_rt(ctx, 1) | (1u<<31); + else if (api_ver_ge(ctx, 12, 0)) + lock_params.version = struct_ver_rt(ctx, 2); lock_params.doNotWait = 0; lock_params.outputBitstream = tmpoutsurf->output_surface; @@ -2976,7 +3033,9 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame) int reconfig_bitrate = 0, reconfig_dar = 0; int dw, dh; - params.version = struct_ver_rt(ctx, 1) | (1<<31);//NV_ENC_RECONFIGURE_PARAMS_VER; + params.version = struct_ver_rt(ctx, 1) | (1u<<31);//NV_ENC_RECONFIGURE_PARAMS_VER; + if (api_ver_ge(ctx, 12, 2)) + params.version = struct_ver_rt(ctx, 2) | (1u<<31); params.reInitEncodeParams = ctx->init_encode_params; compute_dar(avctx, &dw, &dh); @@ -3148,7 +3207,11 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; NV_ENC_PIC_PARAMS pic_params = { 0 }; - pic_params.version = struct_ver_rt(ctx, 4) | (1<<31);//NV_ENC_PIC_PARAMS_VER; + pic_params.version = struct_ver_rt(ctx, 4) | (1u<<31);//NV_ENC_PIC_PARAMS_VER; + if (api_ver_ge(ctx, 12, 2)) + pic_params.version = struct_ver_rt(ctx, 7) | (1u<<31); + else if (api_ver_ge(ctx, 12, 0)) + pic_params.version = struct_ver_rt(ctx, 6) | (1u<<31); if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder) return AVERROR(EINVAL); diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index 577a69fe9f..bbcb9b89a5 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -265,6 +265,7 @@ typedef struct NvencContext uint32_t frame_idx_counter; uint32_t next_view_id; + float apiver_req; // for testing int preset; int profile; int level; diff --git a/libavcodec/nvenc_av1.c b/libavcodec/nvenc_av1.c index 98fcc76e39..784c859c82 100644 --- a/libavcodec/nvenc_av1.c +++ b/libavcodec/nvenc_av1.c @@ -26,6 +26,7 @@ #define OFFSET(x) offsetof(NvencContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { + { "api", "Set the API version", OFFSET(apiver_req), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, 100, VE }, { "preset", "Set the encoding preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = PRESET_P4 }, PRESET_DEFAULT, PRESET_P7, VE, .unit = "preset" }, { "default", "", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_DEFAULT }, 0, 0, VE, .unit = "preset" }, { "slow", "hq 2 passes", 0, AV_OPT_TYPE_CONST, { .i64 = PRESET_SLOW }, 0, 0, VE, .unit = "preset" }, diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c index 2fbd1cad87..fb12e0d01c 100644 --- a/libavcodec/nvenc_h264.c +++ b/libavcodec/nvenc_h264.c @@ -26,6 +26,7 @@ #define OFFSET(x) offsetof(NvencContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { + { "api", "Set the API version", OFFSET(apiver_req), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, 100, VE }, #ifdef NVENC_HAVE_NEW_PRESETS { "preset", "Set the encoding preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = PRESET_P4 }, PRESET_DEFAULT, PRESET_P7, VE, .unit = "preset" }, #else diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c index 31624f45b1..7ec69b0a95 100644 --- a/libavcodec/nvenc_hevc.c +++ b/libavcodec/nvenc_hevc.c @@ -26,6 +26,7 @@ #define OFFSET(x) offsetof(NvencContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { + { "api", "Set the API version", OFFSET(apiver_req), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, 100, VE }, #ifdef NVENC_HAVE_NEW_PRESETS { "preset", "Set the encoding preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = PRESET_P4 }, PRESET_DEFAULT, PRESET_P7, VE, .unit = "preset" }, #else -- 2.52.0 >From 3050797549f3e68b7a7e3cb39f56775788d10040 Mon Sep 17 00:00:00 2001 From: wangbin <[email protected]> Date: Wed, 27 Aug 2025 11:16:40 +0800 Subject: [PATCH 5/5] nvenc: support all versions in 1 build some options have version dependent values, e.g. rc and preset --- libavcodec/Makefile | 1 + libavcodec/nvenc.c | 22 +++- libavcodec/nvenc.h | 5 +- libavcodec/nvenc_111.c | 27 +++++ libavcodec/nvenc_120.c | 27 +++++ libavcodec/nvenc_121.c | 27 +++++ libavcodec/nvenc_91.c | 27 +++++ libavcodec/nvenc_dispatch.c | 214 ++++++++++++++++++++++++++++++++++++ 8 files changed, 343 insertions(+), 7 deletions(-) create mode 100644 libavcodec/nvenc_111.c create mode 100644 libavcodec/nvenc_120.c create mode 100644 libavcodec/nvenc_121.c create mode 100644 libavcodec/nvenc_91.c create mode 100644 libavcodec/nvenc_dispatch.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 687121e337..d1d2b9be54 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -278,6 +278,7 @@ OBJS-$(CONFIG_AV1_D3D12VA_ENCODER) += d3d12va_encode_av1.o av1_levels.o OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_AV1_MEDIACODEC_ENCODER) += mediacodecenc.o OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_av1.o nvenc.o +OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_dispatch.o nvenc_91.o nvenc_111.o nvenc_120.o nvenc_121.o OBJS-$(CONFIG_AV1_QSV_ENCODER) += qsvenc_av1.o OBJS-$(CONFIG_AV1_VAAPI_ENCODER) += vaapi_encode_av1.o av1_levels.o OBJS-$(CONFIG_AV1_VULKAN_ENCODER) += vulkan_encode.o vulkan_encode_av1.o \ diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 619a4ddd9c..333e428441 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -44,6 +44,10 @@ #include "encode.h" #include "internal.h" +#undef CONFIG_AV1_NVENC_ENCODER +#define CONFIG_AV1_NVENC_ENCODER (NVENCAPI_MAJOR_VERSION >= 12) +#define FF_NVENC(f) AV_JOIN(f, AV_JOIN(NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION)) + #define CHECK_CU(x) FF_CUDA_CHECK_DL(avctx, dl_fn->cuda_dl, x) #define NVENC_CAP 0x30 @@ -56,6 +60,7 @@ #define IS_CBR(rc) (rc == NV_ENC_PARAMS_RC_CBR) #endif +#ifndef FF_NVENC_DUP const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12, @@ -94,6 +99,7 @@ const AVCodecHWConfigInternal *const ff_nvenc_hw_configs[] = { #endif NULL, }; +#endif // FF_NVENC_DUP #define IS_10BIT(pix_fmt) (pix_fmt == AV_PIX_FMT_P010 || \ pix_fmt == AV_PIX_FMT_P016 || \ @@ -429,14 +435,16 @@ static av_cold int nvenc_load_libraries(AVCodecContext *avctx) func_ver = struct_ver_rt(ctx, 2); av_log(avctx, AV_LOG_INFO, "Loaded Nvenc version %u.%u, max: %u.%u, build api: %u.%u. config_ver: %u\n", ctx->apiver_rt & 0xff, (ctx->apiver_rt >> 24) & 0xff, nvenc_max_major, nvenc_max_minor, NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION, config_ver); +#if 0 if ((NVENCAPI_MAJOR_VERSION << 4 | NVENCAPI_MINOR_VERSION) > nvenc_max_ver) { av_log(avctx, AV_LOG_WARNING, "Driver does not support the required nvenc API version. " "Required: %d.%d Found: %d.%d\n", NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION, nvenc_max_major, nvenc_max_minor); nvenc_print_driver_requirement(avctx, AV_LOG_WARNING); - //return AVERROR(ENOSYS); + return AVERROR(ENOSYS); } +#endif dl_fn->nvenc_funcs.version = func_ver; err = dl_fn->nvenc_dl->NvEncodeAPICreateInstance(&dl_fn->nvenc_funcs); @@ -2235,7 +2243,8 @@ static av_cold int nvenc_setup_extradata(AVCodecContext *avctx) return 0; } -av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) +int FF_NVENC(ff_nvenc_encode_close)(AVCodecContext *avctx); +av_cold int FF_NVENC(ff_nvenc_encode_close)(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; @@ -2323,7 +2332,8 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) return 0; } -av_cold int ff_nvenc_encode_init(AVCodecContext *avctx) +int FF_NVENC(ff_nvenc_encode_init)(AVCodecContext *avctx); +av_cold int FF_NVENC(ff_nvenc_encode_init)(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; int ret; @@ -3364,7 +3374,8 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) return 0; } -int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt) +int FF_NVENC(ff_nvenc_receive_packet)(AVCodecContext *avctx, AVPacket *pkt); +int FF_NVENC(ff_nvenc_receive_packet)(AVCodecContext *avctx, AVPacket *pkt) { NvencSurface *tmp_out_surf; int res, res2; @@ -3415,7 +3426,8 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt) return 0; } -av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx) +void FF_NVENC(ff_nvenc_encode_flush)(AVCodecContext *avctx); +av_cold void FF_NVENC(ff_nvenc_encode_flush)(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index bbcb9b89a5..ab3fd5d1ed 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -218,8 +218,6 @@ typedef struct NvencContext NvencDynLoadFunctions nvenc_dload_funcs; - NV_ENC_INITIALIZE_PARAMS init_encode_params; - NV_ENC_CONFIG encode_config; CUcontext cu_context; CUcontext cu_context_internal; CUstream cu_stream; @@ -325,6 +323,9 @@ typedef struct NvencContext int cbr_padding; int multiview, multiview_supported; int display_sei_sent; + + NV_ENC_CONFIG encode_config; // size: 3584 + NV_ENC_INITIALIZE_PARAMS init_encode_params; // size: 1800 for 12.2+, 1808 otherwise } NvencContext; int ff_nvenc_encode_init(AVCodecContext *avctx); diff --git a/libavcodec/nvenc_111.c b/libavcodec/nvenc_111.c new file mode 100644 index 0000000000..8dbbca420a --- /dev/null +++ b/libavcodec/nvenc_111.c @@ -0,0 +1,27 @@ +/* + * H.264/HEVC/AV1 hardware encoding using nvidia nvenc + * Copyright (c) 2025 Wang Bin <wbsecg1 at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// include a desired version of nvEncodeAPI.h first, so nvEncodeAPI.h included in nvenc.h will be ignored +#define FF_NVENC_DUP 1 +#if __has_include(<nv-codec-headers-11.1/include/ffnvcodec/nvEncodeAPI.h>) +#include <nv-codec-headers-11.1/include/ffnvcodec/nvEncodeAPI.h> +#include "nvenc.c" +#endif \ No newline at end of file diff --git a/libavcodec/nvenc_120.c b/libavcodec/nvenc_120.c new file mode 100644 index 0000000000..5f582ee627 --- /dev/null +++ b/libavcodec/nvenc_120.c @@ -0,0 +1,27 @@ +/* + * H.264/HEVC/AV1 hardware encoding using nvidia nvenc + * Copyright (c) 2025 Wang Bin <wbsecg1 at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// include a desired version of nvEncodeAPI.h first, so nvEncodeAPI.h included in nvenc.h will be ignored +#define FF_NVENC_DUP 1 +#if __has_include(<nv-codec-headers-12.0/include/ffnvcodec/nvEncodeAPI.h>) +#include <nv-codec-headers-12.0/include/ffnvcodec/nvEncodeAPI.h> +#include "nvenc.c" +#endif \ No newline at end of file diff --git a/libavcodec/nvenc_121.c b/libavcodec/nvenc_121.c new file mode 100644 index 0000000000..4f622b536f --- /dev/null +++ b/libavcodec/nvenc_121.c @@ -0,0 +1,27 @@ +/* + * H.264/HEVC/AV1 hardware encoding using nvidia nvenc + * Copyright (c) 2025 Wang Bin <wbsecg1 at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// include a desired version of nvEncodeAPI.h first, so nvEncodeAPI.h included in nvenc.h will be ignored +#define FF_NVENC_DUP 1 +#if __has_include(<nv-codec-headers-12.1/include/ffnvcodec/nvEncodeAPI.h>) +#include <nv-codec-headers-12.1/include/ffnvcodec/nvEncodeAPI.h> +#include "nvenc.c" +#endif \ No newline at end of file diff --git a/libavcodec/nvenc_91.c b/libavcodec/nvenc_91.c new file mode 100644 index 0000000000..b25faef45e --- /dev/null +++ b/libavcodec/nvenc_91.c @@ -0,0 +1,27 @@ +/* + * H.264/HEVC/AV1 hardware encoding using nvidia nvenc + * Copyright (c) 2025 Wang Bin <wbsecg1 at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// include a desired version of nvEncodeAPI.h first, so nvEncodeAPI.h included in nvenc.h will be ignored +#define FF_NVENC_DUP 1 +#if __has_include(<nv-codec-headers-9.1/include/ffnvcodec/nvEncodeAPI.h>) +#include <nv-codec-headers-9.1/include/ffnvcodec/nvEncodeAPI.h> +#include "nvenc.c" +#endif \ No newline at end of file diff --git a/libavcodec/nvenc_dispatch.c b/libavcodec/nvenc_dispatch.c new file mode 100644 index 0000000000..9143753dce --- /dev/null +++ b/libavcodec/nvenc_dispatch.c @@ -0,0 +1,214 @@ +/* + * H.264/HEVC/AV1 hardware encoding using nvidia nvenc + * Copyright (c) 2025 Wang Bin <wbsecg1 at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "nvenc.h" + +/* + To support all version of nvEncodeAPI.h with minimal changes, we need to dispatch ff_nvenc_* to versioned functions. + nvenc.c is built against the latest version(13.0). + nvenc_111.c is built against version 11.1, which is the highest version that abi compatible with all lower versions + To use nvEncodeAPI.h of a lower version, e.g. 11.1, we need a copy of the header, additional cflags, and include the header + + #include <nv-codec-headers11.1/include/ffnvcodec/nvEncodeAPI.h> + + before nvenc.c, thus <ffnvcodec/nvEncodeAPI.h> in nvenc.h will be ignored and only the lower version will be used. + + 10.0 defines a different set of preset guids, so building against 9.1 header is required. + preset option default value in nvenc_$codec.c is version dependent but only they are built only once, so manually setting preset + for version < 10.0 is required. + TODO: This dispatch file(at least version suffix) and other versioned nvenc_*.c should be generated by a script. +*/ +int ff_nvenc_encode_init130(AVCodecContext *avctx); +int ff_nvenc_encode_close130(AVCodecContext *avctx); +int ff_nvenc_receive_packet130(AVCodecContext *avctx, AVPacket *pkt); +void ff_nvenc_encode_flush130(AVCodecContext *avctx); + +int ff_nvenc_encode_init121(AVCodecContext *avctx); +int ff_nvenc_encode_close121(AVCodecContext *avctx); +int ff_nvenc_receive_packet121(AVCodecContext *avctx, AVPacket *pkt); +void ff_nvenc_encode_flush121(AVCodecContext *avctx); + +int ff_nvenc_encode_init120(AVCodecContext *avctx); +int ff_nvenc_encode_close120(AVCodecContext *avctx); +int ff_nvenc_receive_packet120(AVCodecContext *avctx, AVPacket *pkt); +void ff_nvenc_encode_flush120(AVCodecContext *avctx); + +int ff_nvenc_encode_init111(AVCodecContext *avctx); +int ff_nvenc_encode_close111(AVCodecContext *avctx); +int ff_nvenc_receive_packet111(AVCodecContext *avctx, AVPacket *pkt); +void ff_nvenc_encode_flush111(AVCodecContext *avctx); + +int ff_nvenc_encode_init91(AVCodecContext *avctx); +int ff_nvenc_encode_close91(AVCodecContext *avctx); +int ff_nvenc_receive_packet91(AVCodecContext *avctx, AVPacket *pkt); +void ff_nvenc_encode_flush91(AVCodecContext *avctx); + +#if !__has_include(<nv-codec-headers-12.1/include/ffnvcodec/nvEncodeAPI.h>) +av_cold int ff_nvenc_encode_init121(AVCodecContext *avctx) { return AVERROR_EXTERNAL; } +av_cold int ff_nvenc_encode_close121(AVCodecContext *avctx) { return AVERROR_EXTERNAL; } +int ff_nvenc_receive_packet121(AVCodecContext *avctx, AVPacket *pkt) { return AVERROR_EXTERNAL; } +av_cold void ff_nvenc_encode_flush121(AVCodecContext *avctx) {} +#endif + +#if !__has_include(<nv-codec-headers-12.0/include/ffnvcodec/nvEncodeAPI.h>) +av_cold int ff_nvenc_encode_init120(AVCodecContext *avctx) { return AVERROR_EXTERNAL; } +av_cold int ff_nvenc_encode_close120(AVCodecContext *avctx) { return AVERROR_EXTERNAL; } +int ff_nvenc_receive_packet120(AVCodecContext *avctx, AVPacket *pkt) { return AVERROR_EXTERNAL; } +av_cold void ff_nvenc_encode_flush120(AVCodecContext *avctx) {} +#endif + +#if !__has_include(<nv-codec-headers-11.1/include/ffnvcodec/nvEncodeAPI.h>) +av_cold int ff_nvenc_encode_init111(AVCodecContext *avctx) { return AVERROR_EXTERNAL; } +av_cold int ff_nvenc_encode_close111(AVCodecContext *avctx) { return AVERROR_EXTERNAL; } +int ff_nvenc_receive_packet111(AVCodecContext *avctx, AVPacket *pkt) { return AVERROR_EXTERNAL; } +av_cold void ff_nvenc_encode_flush111(AVCodecContext *avctx) {} +#endif + +#if !__has_include(<nv-codec-headers-9.1/include/ffnvcodec/nvEncodeAPI.h>) +av_cold int ff_nvenc_encode_init91(AVCodecContext *avctx) { return AVERROR_EXTERNAL; } +av_cold int ff_nvenc_encode_close91(AVCodecContext *avctx) { return AVERROR_EXTERNAL; } +int ff_nvenc_receive_packet91(AVCodecContext *avctx, AVPacket *pkt) { return AVERROR_EXTERNAL; } +av_cold void ff_nvenc_encode_flush91(AVCodecContext *avctx) {} +#endif + +static const char* nvenc_driver_requirement(float api) +{ + const struct { + float api; + const char* win; + const char* linux; + } requirements[] = { + {13.1f, "(unknown)", "(unknown)"}, + {13.0f, "570.0", "570.0"}, + {12.2f, "551.76", "550.54.14"}, + {12.1f, "531.61", "530.41.03"}, + {12.0f, "522.25", "520.56.06"}, + {11.1f, "471.41", "470.57.02"}, + {11.0f, "456.71", "455.28"}, + {10.0f, "450.51", "445.87"}, + {9.1f, "436.15", "435.21"}, + {9.0f, "418.81", "418.30"}, + {8.2f, "397.93", "396.24"}, + {8.1f, "390.77", "390.25"}, + {8.0f, "378.66", "378.13"}, + }; + + for (int i = 0; i < FF_ARRAY_ELEMS(requirements); i++) { + if (requirements[i].api <= api) { +#if defined(_WIN32) || defined(__CYGWIN__) + return requirements[i].win; +#else + return requirements[i].linux; +#endif + } + } + return "(unknown)"; +} + +static av_cold int nvenc_load_api(AVCodecContext *avctx) +{ + NvencContext *ctx = avctx->priv_data; + NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; + NVENCSTATUS err; + uint32_t nvenc_max_ver; + uint32_t nvenc_max_major; + uint32_t nvenc_max_minor; + int ret; + ret = nvenc_load_functions(&dl_fn->nvenc_dl, avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "nvenc_load_functions error\n"); + return ret; + } + + err = dl_fn->nvenc_dl->NvEncodeAPIGetMaxSupportedVersion(&nvenc_max_ver); + if (err != NV_ENC_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query nvenc max version\n"); + return AVERROR_UNKNOWN; + } + nvenc_max_major = nvenc_max_ver >> 4; + nvenc_max_minor = nvenc_max_ver & 0xf; + + if (ctx->apiver_req <= 0) { + ctx->apiver_req = nvenc_max_major + nvenc_max_minor / 10.0f; + } + if (ctx->apiver_req > nvenc_max_major + nvenc_max_minor / 10.0f) { + av_log(avctx, AV_LOG_ERROR, "Requested nvenc API version %.1f is not supported, the minimum required Nvidia driver is %s\n", ctx->apiver_req, nvenc_driver_requirement(ctx->apiver_req)); + return AVERROR(ENOSYS); + } + return 0; +} + +av_cold int ff_nvenc_encode_init(AVCodecContext *avctx) +{ + nvenc_load_api(avctx); // don't return error, a future version may be supported + NvencContext *ctx = avctx->priv_data; + if (ctx->apiver_req >= 12.2f) + return ff_nvenc_encode_init130(avctx); + if (ctx->apiver_req >= 12.1f) + return ff_nvenc_encode_init121(avctx); + if (ctx->apiver_req >= 12.0f) + return ff_nvenc_encode_init120(avctx); + if (ctx->apiver_req >= 10.0f) // preset changes + return ff_nvenc_encode_init111(avctx); + return ff_nvenc_encode_init91(avctx); +} + +av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) +{ + NvencContext *ctx = avctx->priv_data; + if (ctx->apiver_req >= 12.2f) + return ff_nvenc_encode_close130(avctx); + if (ctx->apiver_req >= 12.1f) + return ff_nvenc_encode_close121(avctx); + if (ctx->apiver_req >= 12.0f) + return ff_nvenc_encode_close120(avctx); + if (ctx->apiver_req >= 10.0f) // preset changes + return ff_nvenc_encode_close111(avctx); + return ff_nvenc_encode_close91(avctx); +} + +int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt) +{ + NvencContext *ctx = avctx->priv_data; + if (ctx->apiver_req >= 12.2f) + return ff_nvenc_receive_packet130(avctx, pkt); + if (ctx->apiver_req >= 12.1f) + return ff_nvenc_receive_packet121(avctx, pkt); + if (ctx->apiver_req >= 12.0f) + return ff_nvenc_receive_packet120(avctx, pkt); + if (ctx->apiver_req >= 10.0f) // preset changes + return ff_nvenc_receive_packet111(avctx, pkt); + return ff_nvenc_receive_packet91(avctx, pkt); +} + +av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx) +{ + NvencContext *ctx = avctx->priv_data; + if (ctx->apiver_req >= 12.2f) + return ff_nvenc_encode_flush130(avctx); + if (ctx->apiver_req >= 12.1f) + return ff_nvenc_encode_flush121(avctx); + if (ctx->apiver_req >= 12.0f) + return ff_nvenc_encode_flush120(avctx); + if (ctx->apiver_req >= 10.0f) // preset changes + return ff_nvenc_encode_flush111(avctx); + ff_nvenc_encode_flush91(avctx); +} \ No newline at end of file -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
