From 069b42f6dbdd65ee1409d0a0315d39d83759e16f Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Wed, 16 Feb 2022 10:37:02 -0300
Subject: [PATCH 01/18] avcodec/libsvtav1: add a svtav1-params option to pass a
 list of key=value parameters

Signed-off-by: James Almer <jamrial@gmail.com>
---
 doc/encoders.texi      |  4 ++++
 libavcodec/libsvtav1.c | 52 ++++++++++++++++++++++++++++++------------
 2 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/doc/encoders.texi b/doc/encoders.texi
index e3b61de5a1..096ee8625b 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -1816,6 +1816,10 @@ Set log2 of the number of rows of tiles to use (0-6).
 @item tile_columns
 Set log2 of the number of columns of tiles to use (0-4).
 
+@item svtav1-params
+Set SVT-AV1 options using a list of @var{key}=@var{value} pairs separated
+by ":". See the SVT-AV1 encoder user guide for a list of accepted parameters.
+
 @end table
 
 @section libkvazaar
diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c
index 6196da25e6..ce3b0ba7ac 100644
--- a/libavcodec/libsvtav1.c
+++ b/libavcodec/libsvtav1.c
@@ -60,6 +60,7 @@ typedef struct SvtContext {
     EOS_STATUS eos_flag;
 
     // User options.
+    AVDictionary *svtav1_opts;
     int hierarchical_level;
     int la_depth;
     int enc_mode;
@@ -151,6 +152,41 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param,
 {
     SvtContext *svt_enc = avctx->priv_data;
     const AVPixFmtDescriptor *desc;
+    AVDictionaryEntry *en = NULL;
+
+    // Update param from options
+    param->hierarchical_levels      = svt_enc->hierarchical_level;
+    param->enc_mode                 = svt_enc->enc_mode;
+    param->tier                     = svt_enc->tier;
+    param->rate_control_mode        = svt_enc->rc_mode;
+    param->scene_change_detection   = svt_enc->scd;
+    param->qp                       = svt_enc->qp;
+
+    if (svt_enc->la_depth >= 0)
+        param->look_ahead_distance  = svt_enc->la_depth;
+
+    param->tile_columns = svt_enc->tile_columns;
+    param->tile_rows    = svt_enc->tile_rows;
+
+#if SVT_AV1_CHECK_VERSION(0, 9, 1)
+    while ((en = av_dict_get(svt_enc->svtav1_opts, "", en, AV_DICT_IGNORE_SUFFIX))) {
+        EbErrorType ret = svt_av1_enc_parse_parameter(param, en->key, en->value);
+        if (ret != EB_ErrorNone) {
+            int level = (avctx->err_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING;
+            av_log(avctx, level, "Error parsing option %s: %s.\n", en->key, en->value);
+            if (avctx->err_recognition & AV_EF_EXPLODE)
+                return AVERROR(EINVAL);
+        }
+    }
+#else
+    if ((en = av_dict_get(svt_enc->svtav1_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
+        int level = (avctx->err_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING;
+        av_log(avctx, level, "svt-params needs libavcodec to be compiled with SVT-AV1 "
+                             "headers >= 0.9.1.\n");
+        if (avctx->err_recognition & AV_EF_EXPLODE)
+            return AVERROR(ENOSYS);
+    }
+#endif
 
     param->source_width     = avctx->width;
     param->source_height    = avctx->height;
@@ -184,14 +220,6 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param,
         param->profile = FF_PROFILE_AV1_HIGH;
     }
 
-    // Update param from options
-    param->hierarchical_levels      = svt_enc->hierarchical_level;
-    param->enc_mode                 = svt_enc->enc_mode;
-    param->tier                     = svt_enc->tier;
-    param->rate_control_mode        = svt_enc->rc_mode;
-    param->scene_change_detection   = svt_enc->scd;
-    param->qp                       = svt_enc->qp;
-
     param->target_bit_rate          = avctx->bit_rate;
 
     if (avctx->gop_size > 0)
@@ -214,12 +242,6 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param,
     /* 2 = IDR, closed GOP, 1 = CRA, open GOP */
     param->intra_refresh_type = avctx->flags & AV_CODEC_FLAG_CLOSED_GOP ? 2 : 1;
 
-    if (svt_enc->la_depth >= 0)
-        param->look_ahead_distance  = svt_enc->la_depth;
-
-    param->tile_columns = svt_enc->tile_columns;
-    param->tile_rows    = svt_enc->tile_rows;
-
     return 0;
 }
 
@@ -535,6 +557,8 @@ static const AVOption options[] = {
     { "tile_columns", "Log2 of number of tile columns to use", OFFSET(tile_columns), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, VE},
     { "tile_rows", "Log2 of number of tile rows to use", OFFSET(tile_rows), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 6, VE},
 
+    { "svtav1-params", "Set the SVT-AV1 configuration using a :-separated list of key=value parameters", OFFSET(svtav1_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE },
+
     {NULL},
 };
 
-- 
2.40.1

