On 15.07.2020 16:34, wangbin wrote:
From: wang-bin <wbse...@gmail.com>

There are reserved bit fields in nvEncoderAPI.h structs, so driver's abi
is stable. Requesting runtime version of these structs should work. I've
compared 7.0~9.x headers, and confirmed on some devices.
---
  libavcodec/nvenc.c | 72 ++++++++++++++++++++++++++--------------------
  libavcodec/nvenc.h |  3 ++
  2 files changed, 44 insertions(+), 31 deletions(-)

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index c6740c1842..ac35cb9f48 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -193,14 +193,26 @@ static void nvenc_print_driver_requirement(AVCodecContext 
*avctx, int level)
      av_log(avctx, level, "The minimum required Nvidia driver for nvenc is %s or 
newer\n", minver);
  }
+static inline uint32_t struct_ver_rt(NvencContext* ctx, uint32_t struct_ver)
+{
+    return ((uint32_t)ctx->apiver_rt | ((struct_ver)<<16) | (0x7 << 28));
+}

I'm really not a fan of hard-coding magic numbers, that can change in the future, into the ffmpeg implementation.

+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)
          return ret;
@@ -214,19 +226,17 @@ 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");
+    nvenc_max_major = nvenc_max_ver >> 4;
+    nvenc_max_minor = nvenc_max_ver & 0xf;
+    av_log(avctx, AV_LOG_VERBOSE, "nvenc build version: %d.%d, runtime version: 
%d.%d\n", NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION, nvenc_max_major, 
nvenc_max_minor);
- av_log(avctx, AV_LOG_VERBOSE, "Loaded Nvenc version %d.%d\n", nvenc_max_ver >> 4, nvenc_max_ver & 0xf);
-
-    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. "
-               "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);
-    }
+    ctx->apiver_rt = api_ver(nvenc_max_major, nvenc_max_minor); /* 
NVENCAPI_VERSION */
+    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);
- 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)
@@ -267,8 +277,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); // 
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER
+    params.apiVersion = ctx->apiver_rt;
      if (ctx->d3d11_device) {
          params.device     = ctx->d3d11_device;
          params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
@@ -329,7 +339,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, &params, &val);
@@ -688,7 +698,7 @@ static av_cold void set_constqp(AVCodecContext *avctx)
      NV_ENC_RC_PARAMS *rc = &ctx->encode_config.rcParams;
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) {
@@ -1221,8 +1231,8 @@ 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;

More magic numbers.

ctx->init_encode_params.encodeHeight = avctx->height;
      ctx->init_encode_params.encodeWidth = avctx->width;
@@ -1231,8 +1241,8 @@ static av_cold int nvenc_setup_encoder(AVCodecContext 
*avctx)
nvenc_map_preset(ctx); - 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;

Yet more of them.

+    preset_config.presetCfg.version = ctx->config_ver_rt;//NV_ENC_CONFIG_VER;
if (IS_SDK10_PRESET(ctx->preset)) {
  #ifdef NVENC_HAVE_NEW_PRESETS
@@ -1260,7 +1270,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;
@@ -1404,7 +1414,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();
@@ -1420,7 +1430,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;
@@ -1503,7 +1513,7 @@ static av_cold int nvenc_setup_extradata(AVCodecContext 
*avctx)
      uint32_t outSize = 0;
      char tmpHeader[256];
      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);
@@ -1535,7 +1545,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),
                                              .encodePicFlags = 
NV_ENC_PIC_FLAG_EOS };

Same here

          res = nvenc_push_context(avctx);
@@ -1747,7 +1757,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];
@@ -1802,7 +1812,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) {
@@ -1822,7 +1832,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);
@@ -1936,7 +1946,7 @@ static int process_output_surface(AVCodecContext *avctx, 
AVPacket *pkt, NvencSur
          goto error;
      }
- 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;
@@ -2054,7 +2064,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);
@@ -2148,7 +2158,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 fb3820f7cf..6a39391276 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -146,6 +146,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;


What is the logic behind picking those numbers? What happens if a struct gets updated, and ffmpeg wants to use the new fields when available, like happened plenty of times?
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to