From c704e3535f866d9f89535b9df59db9ca9811bcf9 Mon Sep 17 00:00:00 2001
From: Oliver Collyer <ovcollyer@mac.com>
Date: Fri, 8 Mar 2019 07:42:41 +0000
Subject: [PATCH 1/1] avcodec/nvenc: Reconfigure resolution on-the-fly

---
 libavcodec/nvenc.c      | 31 ++++++++++++++++++++++++++++---
 libavcodec/nvenc.h      |  3 +++
 libavcodec/nvenc_h264.c |  4 ++++
 libavcodec/nvenc_hevc.c |  4 ++++
 4 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index 304a684e0c..b1d6caf3c6 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -384,6 +384,7 @@ static int nvenc_check_capabilities(AVCodecContext *avctx)
 #endif
 
     ctx->support_dyn_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE);
+    ctx->support_dyn_res = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_RES_CHANGE);
 
     return 0;
 }
@@ -1121,6 +1122,8 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
 
     ctx->init_encode_params.encodeHeight = avctx->height;
     ctx->init_encode_params.encodeWidth = avctx->width;
+    ctx->init_encode_params.maxEncodeHeight = ctx->max_height;
+    ctx->init_encode_params.maxEncodeWidth = ctx->max_width;
 
     ctx->init_encode_params.encodeConfig = &ctx->encode_config;
 
@@ -1276,8 +1279,8 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx)
         }
 
         allocSurf.version = NV_ENC_CREATE_INPUT_BUFFER_VER;
-        allocSurf.width = avctx->width;
-        allocSurf.height = avctx->height;
+        allocSurf.width = FFMAX(ctx->max_width, avctx->width);
+        allocSurf.height = FFMAX(ctx->max_height, avctx->height);
         allocSurf.bufferFmt = ctx->surfaces[idx].format;
 
         nv_status = p_nvenc->nvEncCreateInputBuffer(ctx->nvencoder, &allocSurf);
@@ -1926,7 +1929,7 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
     NV_ENC_RECONFIGURE_PARAMS params = { 0 };
     int needs_reconfig = 0;
     int needs_encode_config = 0;
-    int reconfig_bitrate = 0, reconfig_dar = 0;
+    int reconfig_bitrate = 0, reconfig_dar = 0, reconfig_res = 0;
     int dw, dh;
 
     params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
@@ -1986,6 +1989,24 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
         }
     }
 
+    if (ctx->support_dyn_res && ctx->init_encode_params.maxEncodeWidth && ctx->init_encode_params.maxEncodeHeight) {
+        if (params.reInitEncodeParams.encodeWidth != avctx->width || params.reInitEncodeParams.encodeHeight != avctx->height) {
+            av_log(avctx, AV_LOG_VERBOSE,
+                "resolution change: %d x %d -> %d x %d\n",
+                params.reInitEncodeParams.encodeWidth,
+                params.reInitEncodeParams.encodeHeight,
+                avctx->width,
+                avctx->height);
+
+            params.reInitEncodeParams.encodeWidth = avctx->width;
+            params.reInitEncodeParams.encodeHeight = avctx->height;
+            params.forceIDR = 1;
+
+            needs_reconfig = 1;
+            reconfig_res = 1;
+        }
+    }
+
     if (!needs_encode_config)
         params.reInitEncodeParams.encodeConfig = NULL;
 
@@ -2005,6 +2026,10 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
                 ctx->encode_config.rcParams.vbvBufferSize = params.reInitEncodeParams.encodeConfig->rcParams.vbvBufferSize;
             }
 
+            if (reconfig_res) {
+                ctx->init_encode_params.encodeWidth = params.reInitEncodeParams.encodeWidth;
+                ctx->init_encode_params.encodeHeight = params.reInitEncodeParams.encodeHeight;
+            }
         }
     }
 }
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index ddd6168409..30a3aa6f6f 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -158,6 +158,7 @@ typedef struct NvencContext
     int first_packet_output;
 
     int support_dyn_bitrate;
+    int support_dyn_res;
 
     void *nvencoder;
 
@@ -192,6 +193,8 @@ typedef struct NvencContext
     int coder;
     int b_ref_mode;
     int a53_cc;
+    int max_width;
+    int max_height;
 } NvencContext;
 
 int ff_nvenc_encode_init(AVCodecContext *avctx);
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
index a6623f5f35..9c9a0c7b8d 100644
--- a/libavcodec/nvenc_h264.c
+++ b/libavcodec/nvenc_h264.c
@@ -138,6 +138,10 @@ static const AVOption options[] = {
     { "middle",       "",                                   0,                    AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0,       VE, "b_ref_mode" },
 #endif
     { "a53cc",        "Use A53 Closed Captions (if available)", OFFSET(a53_cc),   AV_OPT_TYPE_BOOL,  { .i64 = 1 }, 0, 1, VE },
+    { "max_width",    "Maximum encode width for dynamic resolution encoding",
+                                                            OFFSET(max_width),    AV_OPT_TYPE_INT,   {.i64 = 0 }, 0, INT_MAX, VE },
+    { "max_height",   "Maximum encode height for dynamic resolution encoding",
+                                                            OFFSET(max_height),   AV_OPT_TYPE_INT,   {.i64 = 0 }, 0, INT_MAX, VE },
     { NULL }
 };
 
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
index d567d960ba..49cb526740 100644
--- a/libavcodec/nvenc_hevc.c
+++ b/libavcodec/nvenc_hevc.c
@@ -127,6 +127,10 @@ static const AVOption options[] = {
     { "each",         "",                                   0,                    AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0,       VE, "b_ref_mode" },
     { "middle",       "",                                   0,                    AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0,       VE, "b_ref_mode" },
 #endif
+    { "max_width",    "Maximum encode width for dynamic resolution encoding",
+                                                            OFFSET(max_width),    AV_OPT_TYPE_INT,   {.i64 = 0 }, 0, INT_MAX, VE },
+    { "max_height",   "Maximum encode height for dynamic resolution encoding",
+                                                            OFFSET(max_height),   AV_OPT_TYPE_INT,   {.i64 = 0 }, 0, INT_MAX, VE },
     { NULL }
 };
 
-- 
2.20.1.windows.1

