From 046f5cb850c45e7b92ba4f6a0d907c4f51d5b480 Mon Sep 17 00:00:00 2001
From: Roman Arzumanyan <rarzumanyan@nvidia.com>
Date: Thu, 26 Sep 2019 14:31:41 +0300
Subject: [PATCH] avcodec/nvenc: adding multiple reference frames

---
 libavcodec/nvenc.c      | 23 +++++++++++++++++++++++
 libavcodec/nvenc.h      |  6 ++++++
 libavcodec/nvenc_h264.c | 11 +++++++++++
 libavcodec/nvenc_hevc.c | 11 +++++++++++
 4 files changed, 51 insertions(+)

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index 316e4a3679..d2d5d35f52 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -403,6 +403,19 @@ static int nvenc_check_capabilities(AVCodecContext *avctx)
     }
 #endif
 
+#ifdef NVENC_HAVE_MULTIPLE_REF_FRAMES
+    ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_MULTIPLE_REF_FRAMES);
+    if(ctx->nb_ref_frames != NV_ENC_NUM_REF_FRAMES_AUTOSELECT && ret <= 0) {
+        av_log(avctx, AV_LOG_VERBOSE, "Given reference frames number is not supported\n");
+        return AVERROR(ENOSYS);
+    }
+#else
+    if(ctx->nb_ref_frames != NV_ENC_NUM_REF_FRAMES_AUTOSELECT){
+        av_log(avctx, AV_LOG_VERBOSE, "Multiple reference frames need SDK 9.1 at build time\n");
+        return AVERROR(ENOSYS);
+    }
+#endif
+
     ctx->support_dyn_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE);
 
     return 0;
@@ -1010,6 +1023,11 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx)
     h264->useBFramesAsRef = ctx->b_ref_mode;
 #endif
 
+#ifdef NVENC_HAVE_MULTIPLE_REF_FRAMES
+    h264->numRefL0 = ctx->nb_ref_frames;
+    h264->numRefL1 = ctx->nb_ref_frames;
+#endif
+
     return 0;
 }
 
@@ -1094,6 +1112,11 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx)
     hevc->useBFramesAsRef = ctx->b_ref_mode;
 #endif
 
+#ifdef NVENC_HAVE_MULTIPLE_REF_FRAMES
+    hevc->numRefL0 = ctx->nb_ref_frames;
+    hevc->numRefL1 = ctx->nb_ref_frames;
+#endif
+
     return 0;
 }
 
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index ddd6168409..d1b7db86c6 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -54,6 +54,11 @@ typedef void ID3D11Device;
 #define NVENC_HAVE_HEVC_BFRAME_REF_MODE
 #endif
 
+// SDK 9.1 compile time feature checks
+#if NVENCAPI_CHECK_VERSION(9, 1)
+#define NVENC_HAVE_MULTIPLE_REF_FRAMES
+#endif
+
 typedef struct NvencSurface
 {
     NV_ENC_INPUT_PTR input_surface;
@@ -192,6 +197,7 @@ typedef struct NvencContext
     int coder;
     int b_ref_mode;
     int a53_cc;
+    int nb_ref_frames;
 } NvencContext;
 
 int ff_nvenc_encode_init(AVCodecContext *avctx);
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
index a6623f5f35..e3eea4f6ae 100644
--- a/libavcodec/nvenc_h264.c
+++ b/libavcodec/nvenc_h264.c
@@ -138,6 +138,17 @@ 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 },
+#ifdef NVENC_HAVE_MULTIPLE_REF_FRAMES  
+    { "nb_ref_frames", 
+                      "Use multiple reference frames: ('auto' to let HW decide, integer number to set by hand",      
+                                                            OFFSET(nb_ref_frames),  
+                                                                                  AV_OPT_TYPE_INT,   { .i64 = NV_ENC_NUM_REF_FRAMES_AUTOSELECT }, NV_ENC_NUM_REF_FRAMES_AUTOSELECT, NV_ENC_NUM_REF_FRAMES_7, VE, "nb_ref_frames" },
+    { "auto",         "Number of reference frames is auto selected by the encoder driver",
+                                                            0,                    AV_OPT_TYPE_CONST, { .i64 = NV_ENC_NUM_REF_FRAMES_AUTOSELECT }, 0,                                0,                       VE, "nb_ref_frames" },
+#else
+    { "nb_ref_frames", "(not supported)",                   OFFSET(nb_ref_frames), AV_OPT_TYPE_INT,   { .i64 = NV_ENC_NUM_REF_FRAMES_AUTOSELECT }, NV_ENC_NUM_REF_FRAMES_AUTOSELECT, NV_ENC_NUM_REF_FRAMES_7, VE, "nb_ref_frames" },
+    { "auto",          "",                                  0,                     AV_OPT_TYPE_CONST, { .i64 = NV_ENC_NUM_REF_FRAMES_AUTOSELECT }, 0,                                0,                       VE, "nb_ref_frames" },
+#endif
     { NULL }
 };
 
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
index d567d960ba..9536f15b1b 100644
--- a/libavcodec/nvenc_hevc.c
+++ b/libavcodec/nvenc_hevc.c
@@ -126,6 +126,17 @@ static const AVOption options[] = {
     { "disabled",     "",                                   0,                    AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0,       VE, "b_ref_mode" },
     { "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
+#ifdef NVENC_HAVE_MULTIPLE_REF_FRAMES  
+    { "nb_ref_frames", 
+                      "Use multiple reference frames: ('auto' to let HW decide, integer number to set by hand",      
+                                                            OFFSET(nb_ref_frames),  
+                                                                                  AV_OPT_TYPE_INT,   { .i64 = NV_ENC_NUM_REF_FRAMES_AUTOSELECT }, NV_ENC_NUM_REF_FRAMES_AUTOSELECT, NV_ENC_NUM_REF_FRAMES_7, VE, "nb_ref_frames" },
+    { "auto",         "Number of reference frames is auto selected by the encoder driver",
+                                                            0,                    AV_OPT_TYPE_CONST, { .i64 = NV_ENC_NUM_REF_FRAMES_AUTOSELECT }, 0,                                0,                       VE, "nb_ref_frames" },
+#else
+    { "nb_ref_frames", "(not supported)",                   OFFSET(nb_ref_frames), AV_OPT_TYPE_INT,   { .i64 = NV_ENC_NUM_REF_FRAMES_AUTOSELECT }, NV_ENC_NUM_REF_FRAMES_AUTOSELECT, NV_ENC_NUM_REF_FRAMES_7, VE, "nb_ref_frames" },
+    { "auto",          "",                                  0,                     AV_OPT_TYPE_CONST, { .i64 = NV_ENC_NUM_REF_FRAMES_AUTOSELECT }, 0,                                0,                       VE, "nb_ref_frames" },
 #endif
     { NULL }
 };
-- 
2.16.1.windows.4

