From a05003106905c035255921c9f7b3c9be5e058eab Mon Sep 17 00:00:00 2001
From: Yogender Kumar Gupta <yogender.gupta@gmail.com>
Date: Wed, 14 Sep 2016 22:20:24 +0530
Subject: [PATCH] SDK 7.0 Support for NVENC

---
 libavcodec/nvenc.c      | 56 ++++++++++++++++++++++++++++++++++++++++++++++---
 libavcodec/nvenc.h      |  9 ++++++++
 libavcodec/nvenc_h264.c |  9 ++++++++
 libavcodec/nvenc_hevc.c |  7 +++++++
 4 files changed, 78 insertions(+), 3 deletions(-)

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index e3edd74..d98d70b 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -356,6 +356,12 @@ static int nvenc_check_capabilities(AVCodecContext *avctx)
         return AVERROR(ENOSYS);
     }
 
+    ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ);
+    if (ret <= 0 && ctx->temporalAQ ) {
+        av_log(avctx, AV_LOG_VERBOSE, "temporalAQ is not supported\n");
+        return AVERROR(ENOSYS);
+    }
+
     return 0;
 }
 
@@ -701,6 +707,11 @@ static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx)
         }
     }
 
+    if (ctx->targetQuality) {
+        ctx->encode_config.rcParams.targetQuality = av_clip(ctx->targetQuality, 1, 51);
+        av_log(avctx, AV_LOG_INFO, "Const Quality mode enabled with targetQuality %d\n", ctx->encode_config.rcParams.targetQuality);
+    }
+
     if (ctx->flags & NVENC_LOSSLESS) {
         set_lossless(avctx);
     } else if (ctx->rc >= 0) {
@@ -716,9 +727,42 @@ static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx)
         ctx->encode_config.rcParams.vbvBufferSize = 2 * ctx->encode_config.rcParams.averageBitRate;
     }
 
-    if (ctx->rc_lookahead > 0) {
-        ctx->encode_config.rcParams.enableLookahead = 1;
-        ctx->encode_config.rcParams.lookaheadDepth = FFMIN(ctx->rc_lookahead, 32);
+    if (ctx->aq)
+    {
+        ctx->encode_config.rcParams.enableAQ = 1;
+        ctx->encode_config.rcParams.aqStrength = ctx->aqStrength;
+        av_log(avctx, AV_LOG_INFO, "AQ Enabled\n");
+    }
+
+    if (ctx->temporalAQ)
+    {
+        ctx->encode_config.rcParams.enableTemporalAQ = 1;
+        av_log(avctx, AV_LOG_INFO, "Temporal AQ Enabled\n");
+    }
+
+    if (ctx->rc_lookahead)
+    {
+        int lkd_bound = FFMIN(ctx->nb_surfaces, ctx->async_depth) - ctx->encode_config.frameIntervalP - 4;
+
+        if (lkd_bound < 0)
+        {
+            av_log(avctx, AV_LOG_WARNING, "Lookahead Not Enabled. Increase Buffer Delay (-delay) \n");
+        }
+        else {
+            ctx->encode_config.rcParams.enableLookahead = 1;
+            ctx->encode_config.rcParams.lookaheadDepth = av_clip(ctx->rc_lookahead, 0, lkd_bound);
+            ctx->encode_config.rcParams.disableIadapt = ctx->no_scenecut;
+            ctx->encode_config.rcParams.disableBadapt = !ctx->b_adapt;
+            av_log(avctx, AV_LOG_INFO, "Lookahead Enabled with depth %d, Scenecut %s, B-Adapt %s\n",
+                ctx->encode_config.rcParams.lookaheadDepth, ctx->encode_config.rcParams.disableIadapt ? "Disabled" : "Enabled",
+                ctx->encode_config.rcParams.disableBadapt ? "Disabled" : "Enabled");
+        }
+    }
+
+    if (ctx->strictGOPTarget)
+    {
+        ctx->encode_config.rcParams.strictGOPTarget = 1;
+        av_log(avctx, AV_LOG_INFO, "Strict GOP Target Enabled\n");
     }
 }
 
@@ -852,6 +896,7 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx)
         cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID;
         avctx->profile = FF_PROFILE_HEVC_MAIN;
         break;
+
     case NV_ENC_HEVC_PROFILE_MAIN_10:
         cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID;
         avctx->profile = FF_PROFILE_HEVC_MAIN_10;
@@ -972,6 +1017,11 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
 
     nvenc_setup_rate_control(avctx);
 
+    if (ctx->aq && ctx->temporalAQ)
+    {
+        av_log(avctx, AV_LOG_ERROR, "AQ and Temporal AQ are not supported together\n");
+    }
+
     if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) {
         ctx->encode_config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
     } else {
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index 521902c..8e26919 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -182,6 +182,15 @@ typedef struct NvencContext
     int flags;
     int async_depth;
     int rc_lookahead;
+    int aq;
+    int no_scenecut;
+    int b_adapt;
+    int temporalAQ;
+    int zeroReorderDelay;
+    int enableNonRefP;
+    int strictGOPTarget;
+    int aqStrength;
+    int targetQuality;
 } NvencContext;
 
 int ff_nvenc_encode_init(AVCodecContext *avctx);
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
index 4ef9836..f304b51 100644
--- a/libavcodec/nvenc_h264.c
+++ b/libavcodec/nvenc_h264.c
@@ -84,6 +84,15 @@ static const AVOption options[] = {
     { "any",      "Pick the first device available",      0,                   AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "gpu" },
     { "list",     "List the available devices",           0,                   AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "gpu" },
     { "delay",    "Delay frame output by the given amount of frames", OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE },
+    { "no-scenecut", "When lookahead is enabled, set this to 1 to disable adaptive I-frame insertion at scene cuts", OFFSET(no_scenecut), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "b-adapt", "When lookahead is enabled, set this to 0 to disable adaptive B-frame decision", OFFSET(b_adapt), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE },
+    { "enableaq", "set to 1 to enable AQ (Spatial) ", OFFSET(aq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "temporalAQ", "set to 1 to enable Temporal AQ",     OFFSET(temporalAQ),  AV_OPT_TYPE_BOOL,   { .i64 = 0                       }, 0, 1, VE        },
+    { "zeroReorderDelay", "Set 1 to indicate zero latency operation (no reordering delay)", OFFSET(zeroReorderDelay), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "enableNonRefP", "Set this to 1 to enable automatic insertion of non-reference P-frames", OFFSET(enableNonRefP), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "strictGOPTarget", "Set 1 to minimize GOP-to-GOP rate fluctuations", OFFSET(strictGOPTarget), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "aq-strength", "When AQ (Spatial) is enabled, this field is used to specify AQ strength. AQ strength scale is from 1 (low) - 15 (aggressive)", OFFSET(aqStrength), AV_OPT_TYPE_INT, { .i64 = 8 }, 1, 15, VE },
+    { "cq", "Set target quality level (0 to 51, 0-automatic) for constant quality mode in VBR rate control", OFFSET(targetQuality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 51, VE },
     { NULL }
 };
 
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
index e875772..f764d74 100644
--- a/libavcodec/nvenc_hevc.c
+++ b/libavcodec/nvenc_hevc.c
@@ -82,6 +82,13 @@ static const AVOption options[] = {
     { "any",      "Pick the first device available",      0,                   AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "device" },
     { "list",     "List the available devices",           0,                   AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "device" },
     { "delay",    "Delay frame output by the given amount of frames", OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE },
+    { "no-scenecut", "When lookahead is enabled, set this to 1 to disable adaptive I-frame insertion at scene cuts", OFFSET(no_scenecut), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "enableaq", "set to 1 to enable AQ (Spatial) ", OFFSET(aq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "zeroReorderDelay", "Set 1 to indicate zero latency operation (no reordering delay)", OFFSET(zeroReorderDelay), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "enableNonRefP", "Set this to 1 to enable automatic insertion of non-reference P-frames", OFFSET(enableNonRefP), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "strictGOPTarget", "Set 1 to minimize GOP-to-GOP rate fluctuations", OFFSET(strictGOPTarget), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "aq-strength", "When AQ (Spatial) is enabled, this field is used to specify AQ strength. AQ strength scale is from 1 (low) - 15 (aggressive)", OFFSET(aqStrength), AV_OPT_TYPE_INT, { .i64 = 8 }, 1, 15, VE },
+    { "cq", "Set target quality level (0 to 51, 0-automatic) for constant quality mode in VBR rate control", OFFSET(targetQuality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 51, VE },
     { NULL }
 };
 
-- 
2.9.0.windows.1

