]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
update vaapi
authoralingherghescu <alin_gherghescu@yahoo.com>
Sat, 7 Jan 2023 02:09:28 +0000 (18:09 -0800)
committerFlole998 <Flole998@users.noreply.github.com>
Tue, 10 Jan 2023 19:18:39 +0000 (20:18 +0100)
- added new settings: platform, bitrate scale factor, low power, loop filter level, loop filter sharpness, async depth
- implemented new (dynamic) settings adjustment (in js)
- added new parameters: b, low_power, loop_filter_level, loop_filter_sharpness, async_depth
- tvhva_context_check_profile() will change TVHVAContext->entrypoint from VAEntrypointEncSlice into VAEntrypointEncSliceLP if VAEntrypointEncSlice is not available for that CODEC (according to VAAPI info)
- moved low_power to tvh_codeo_profile in order to initialize properly the entrypoint
- many error reporting improvements
- separated some bundled conditions

src/transcoding/codec.h
src/transcoding/codec/codecs/libs/vaapi.c
src/transcoding/transcode/hwaccels/hwaccels.c
src/transcoding/transcode/hwaccels/hwaccels.h
src/transcoding/transcode/hwaccels/vaapi.c
src/transcoding/transcode/hwaccels/vaapi.h
src/transcoding/transcode/video.c
src/webui/static/app/codec.js

index 88e85b53b79b4ba406ce3981123dbf116972c01d..3938e8b0e587e7f7bb5ed0164b4620ae7ae5c1eb 100644 (file)
@@ -92,6 +92,7 @@ struct tvh_codec_profile {
     double bit_rate;
     double qscale;
     int profile;
+    int low_power;
     char *device; // for hardware acceleration
     LIST_ENTRY(tvh_codec_profile) link;
 };
index cbcfe9b4797720b0d4193ceab126ce5909a396e3..38e573398f3d0eb2a68447145dfd6a3b9f3f9d62 100644 (file)
 #include <fcntl.h>
 #include <sys/ioctl.h>
 
+#include "idnode.h"
+#include "htsmsg.h"
 
-#define AV_DICT_SET_QP(d, v, a) \
-    AV_DICT_SET_INT((d), "qp", (v) ? (v) : (a), AV_DICT_DONT_OVERWRITE)
+/* hts ==================================================================== */
 
+static htsmsg_t *
+platform_get_list( void *o, const char *lang )
+{
+    static const struct strtab tab[] = {
+        { N_("Unconstrained"),  0 },
+        { N_("Intel"),          1 },
+        { N_("AMD"),            2 },
+    };
+    return strtab2htsmsg(tab, 1, lang);
+}
+
+static htsmsg_t *
+rc_mode_get_list( void *o, const char *lang )
+{
+    static const struct strtab tab[] = {
+        { N_("skip"),  -1 },
+        { N_("auto"),   0 },
+        { N_("CQP"),    1 },
+        { N_("CBR"),    2 },
+        { N_("VBR"),    3 },
+        { N_("ICQ"),    4 },
+        { N_("QVBR"),   5 },
+        { N_("AVBR"),   6 },
+    };
+    return strtab2htsmsg(tab, 1, lang);
+}
 
 /* vaapi ==================================================================== */
 
@@ -33,10 +60,15 @@ typedef struct {
     TVHVideoCodecProfile;
     int qp;
     int quality;
+    int async_depth;
+    double max_bit_rate;
+    double bit_rate_scale_factor;
+    int platform;
+    int loop_filter_level;
+    int loop_filter_sharpness;
     double buff_factor;
     int rc_mode;
     int tier;
-    int ignore_bframe;
 } tvh_codec_profile_vaapi_t;
 
 #if defined(__linux__)
@@ -121,73 +153,117 @@ tvh_codec_profile_vaapi_open(tvh_codec_profile_vaapi_t *self,
     return 0;
 }
 
+// NOTE:
+// the names below are used in codec.js (/src/webui/static/app/codec.js)
 static const codec_profile_class_t codec_profile_vaapi_class = {
     {
         .ic_super      = (idclass_t *)&codec_profile_video_class,
         .ic_class      = "codec_profile_vaapi",
         .ic_caption    = N_("vaapi"),
         .ic_properties = (const property_t[]){
+            {
+                .type     = PT_INT,
+                .id       = "platform",     // Don't change
+                .name     = N_("Platform"),
+                .desc     = N_("Select platform"),
+                .group    = 3,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, platform),
+                .list     = platform_get_list,
+                .def.i    = 0,
+            },
             {
                 .type     = PT_STR,
                 .id       = "device",
                 .name     = N_("Device name"),
-                .desc     = N_("Device name (e.g. /dev/dri/renderD129)."),
+                .desc     = N_("Device name (e.g. /dev/dri/renderD128)."),
                 .group    = 3,
                 .off      = offsetof(tvh_codec_profile_vaapi_t, device),
                 .list     = tvh_codec_profile_vaapi_device_list,
             },
             {
-                .type     = PT_DBL,
-                .id       = "bit_rate",
-                .name     = N_("Bitrate (kb/s) (0=auto)"),
-                .desc     = N_("Target bitrate."),
+                .type     = PT_BOOL,
+                .id       = "low_power",     // Don't change
+                .name     = N_("Low Power"),
+                .desc     = N_("Set low power mode.[if disabled will not send paramter to libav]"),
                 .group    = 3,
+                .opts     = PO_EXPERT,
                 .get_opts = codec_profile_class_get_opts,
-                .off      = offsetof(TVHCodecProfile, bit_rate),
-                .def.d    = 0,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, low_power),
+                .def.i    = 0,
             },
             {
-                .type     = PT_DBL,
-                .id       = "buff_factor",
-                .name     = N_("Buffer factor"),
-                .desc     = N_("Size of transcoding buffer (buffer=bitrate*1000*factor). Good factor is 3."),
+                .type     = PT_INT,
+                .id       = "async_depth",
+                .name     = N_("Maximum processing parallelism"),
+                .desc     = N_("Set maximum process in parallel (0=skip, 2=default).[driver must implement vaSyncBuffer function]"),
                 .group    = 3,
                 .get_opts = codec_profile_class_get_opts,
-                .off      = offsetof(tvh_codec_profile_vaapi_t, buff_factor),
-                .def.d    = 3,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, async_depth),
+                .intextra = INTEXTRA_RANGE(0, 64, 1),
+                .def.i    = 2,
             },
             {
                 .type     = PT_INT,
-                .id       = "rc_mode",
+                .id       = "rc_mode",     // Don't change
                 .name     = N_("Rate control mode"),
-                .desc     = N_("Set rate control mode (from 0 to 6).[0=auto 1=CQP 2=CBR 3=VBR 4=ICQ 5=QVBR 6=AVBR]"),
+                .desc     = N_("Set rate control mode"),
                 .group    = 3,
                 .get_opts = codec_profile_class_get_opts,
                 .off      = offsetof(tvh_codec_profile_vaapi_t, rc_mode),
-                .intextra = INTEXTRA_RANGE(0, 6, 0),
-                .def.d    = 0,
+                .list     = rc_mode_get_list,
+                .def.i    = 0,
             },
             {
                 .type     = PT_INT,
-                .id       = "qp",
-                .name     = N_("Constant QP (0=auto)"),
+                .id       = "qp",     // Don't change
+                .name     = N_("Constant QP"),
                 .group    = 3,
-                .desc     = N_("Fixed QP of P frames [0-52]."),
+                .desc     = N_("Fixed QP of P frames (from 0 to 52, 0=skip).[if disabled will not send paramter to libav]"),
                 .get_opts = codec_profile_class_get_opts,
                 .off      = offsetof(tvh_codec_profile_vaapi_t, qp),
                 .intextra = INTEXTRA_RANGE(0, 52, 1),
                 .def.i    = 0,
             },
             {
-                .type     = PT_INT,
-                .id       = "ignore_bframe",
-                .name     = N_("Ignore B-Frames"),
+                .type     = PT_DBL,
+                .id       = "bit_rate",     // Don't change
+                .name     = N_("Bitrate (kb/s)"),
+                .desc     = N_("Target bitrate (0=skip).[if disabled will not send paramter to libav]"),
                 .group    = 3,
-                .desc     = N_("Some VAAPI drivers cannot handle b-frames (like AMD). [0=use b-frames (default) 1=ignore b-frames]"),
                 .get_opts = codec_profile_class_get_opts,
-                .off      = offsetof(tvh_codec_profile_vaapi_t, ignore_bframe),
-                .intextra = INTEXTRA_RANGE(0, 1, 0),
-                .def.i    = 0,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, bit_rate),
+                .def.d    = 0,
+            },
+            {
+                .type     = PT_DBL,
+                .id       = "max_bit_rate",     // Don't change
+                .name     = N_("Max bitrate (kb/s)"),
+                .desc     = N_("Maximum bitrate (0=skip).[if disabled will not send paramter to libav]"),
+                .group    = 3,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, max_bit_rate),
+                .def.d    = 0,
+            },
+            {
+                .type     = PT_DBL,
+                .id       = "buff_factor",     // Don't change
+                .name     = N_("Buffer size factor"),
+                .desc     = N_("Size of transcoding buffer (buffer=bitrate*2048*factor). Good factor is 3."),
+                .group    = 3,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, buff_factor),
+                .def.d    = 3,
+            },
+            {
+                .type     = PT_DBL,
+                .id       = "bit_rate_scale_factor",     // Don't change
+                .name     = N_("Bitrate scale factor"),
+                .desc     = N_("Bitrate & Max bitrate scaler with resolution (0=no scale; 1=proportional_change). Relative to 480."),
+                .group    = 3,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, bit_rate_scale_factor),
+                .def.d    = 0,
             },
             {}
         }
@@ -209,28 +285,154 @@ static int
 tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
                                   AVDictionary **opts)
 {
-    // bit_rate or qp
-    if (self->bit_rate) {
-        if (self->buff_factor <= 0) {
-            self->buff_factor = 3;
-        }
-        AV_DICT_SET_BIT_RATE(opts, self->bit_rate);
-        AV_DICT_SET_INT(opts, "maxrate", (self->bit_rate) * 1000, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET_INT(opts, "bufsize", ((self->bit_rate) * 1000) * self->buff_factor, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
+    // to avoid issues we have this check:
+    if (self->buff_factor <= 0) {
+        self->buff_factor = 3;
+    }
+    int int_bitrate = (int)((double)(self->bit_rate) * 1024.0 * (1.0 + (self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480.0)));
+    int int_buffer_size = (int)((double)(self->bit_rate) * 2048.0 * self->buff_factor * (1.0 + self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480));
+    int int_max_bitrate = (int)((double)(self->max_bit_rate) * 1024.0 * (1.0 + (self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480.0)));
+    // https://wiki.libav.org/Hardware/vaapi
+    // https://blog.wmspanel.com/2017/03/vaapi-libva-support-nimble-streamer.html
+    // to find available parameters use:
+    // ffmpeg -hide_banner -h encoder=h264_vaapi
+    //-rc_mode         <int>        E..V....... Set rate control mode (from 0 to 6) (default auto)
+    // auto            0            E..V....... Choose mode automatically based on other parameters
+    // CQP             1            E..V....... Constant-quality
+    // CBR             2            E..V....... Constant-bitrate
+    // VBR             3            E..V....... Variable-bitrate
+    // ICQ             4            E..V....... Intelligent constant-quality
+    // QVBR            5            E..V....... Quality-defined variable-bitrate
+    // AVBR            6            E..V....... Average variable-bitrate
+    if (self->rc_mode >= 0) {
         AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
-        if (self->ignore_bframe) {
-            AV_DICT_SET_INT(opts, "bf", 0, 0);
-        }
     }
-    else {
-        AV_DICT_SET_QP(opts, self->qp, 20);
+    switch (self->platform) {
+        case 0:
+            // Uncontrained --> will allow any combination of parameters (valid or invalid)
+            // this mode is usefull fur future platform and for debugging.
+            if (self->bit_rate) {
+                AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->max_bit_rate) {
+                AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->qp) {
+                AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
+        case 1:
+            // Intel
+            switch (self->rc_mode) {
+                case -1:
+                    // same like 0 but is not sending 'rc_mode'
+                case 0:
+                    // for auto --> let the driver decide as requested by documentation
+                    if (self->bit_rate) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    if (self->max_bit_rate) {
+                            AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        }
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 1:
+                case 4:
+                    // for constant quality: CQP and ICQ we use qp
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 2:
+                    // for constant bitrate: CBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 3:
+                    // for variable bitrate: VBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 5:
+                    // for variable bitrate: QVBR we use bitrate + qp
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 6:
+                    // for variable bitrate: AVBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+            }
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
+        case 2:
+            // AMD --> will allow any combination of parameters
+            // I am unable to confirm this platform because I don't have the HW
+            // Is only going to override bf to 0 (as highlited by the previous implementation)
+            if (self->bit_rate) {
+                AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->max_bit_rate) {
+                AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->qp) {
+                AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+            }
+            AV_DICT_SET_INT(opts, "bf", 0, 0);
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
     }
-    AV_DICT_SET_INT(opts, "quality", self->quality, 0);
+    // force keyframe every 3 sec.
+    AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
     return 0;
 }
 
-
+// NOTE:
+// the names below are used in codec.js (/src/webui/static/app/codec.js)
 static const codec_profile_class_t codec_profile_vaapi_h264_class = {
     {
         .ic_super      = (idclass_t *)&codec_profile_vaapi_class,
@@ -239,15 +441,15 @@ static const codec_profile_class_t codec_profile_vaapi_h264_class = {
         .ic_properties = (const property_t[]){
             {
                 .type     = PT_INT,
-                .id       = "quality",
-                .name     = N_("Quality (0=auto)"),
+                .id       = "quality",     // Don't change
+                .name     = N_("Quality"),
                 .desc     = N_("Set encode quality (trades off against speed, "
-                               "higher is faster) [0-8]."),
+                               "higher is faster) [-1=skip 0-7]."),
                 .group    = 5,
                 .opts     = PO_EXPERT,
                 .get_opts = codec_profile_class_get_opts,
                 .off      = offsetof(tvh_codec_profile_vaapi_t, quality),
-                .intextra = INTEXTRA_RANGE(0, 8, 1),
+                .intextra = INTEXTRA_RANGE(-1, 7, 1),
                 .def.i    = 0,
             },
             {}
@@ -280,24 +482,148 @@ static int
 tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
                                   AVDictionary **opts)
 {
-    // bit_rate or qp
-    if (self->bit_rate) {
-        AV_DICT_SET_BIT_RATE(opts, self->bit_rate);
-        if (self->buff_factor <= 0) {
-            self->buff_factor = 3;
-        }
-        AV_DICT_SET_INT(opts, "maxrate", (self->bit_rate) * 1000, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET_INT(opts, "bufsize", ((self->bit_rate) * 1000) * self->buff_factor, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
+    // to avoid issues we have this check:
+    if (self->buff_factor <= 0) {
+        self->buff_factor = 3;
+    }
+    int int_bitrate = (int)((double)(self->bit_rate) * 1024.0 * (1.0 + (self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480.0)));
+    int int_buffer_size = (int)((double)(self->bit_rate) * 2048.0 * self->buff_factor * (1.0 + self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480));
+    int int_max_bitrate = (int)((double)(self->max_bit_rate) * 1024.0 * (1.0 + (self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480.0)));
+    // https://wiki.libav.org/Hardware/vaapi
+    // to find available parameters use:
+    // ffmpeg -hide_banner -h encoder=hevc_vaapi
+    //-rc_mode         <int>        E..V....... Set rate control mode (from 0 to 6) (default auto)
+    // auto            0            E..V....... Choose mode automatically based on other parameters
+    // CQP             1            E..V....... Constant-quality
+    // CBR             2            E..V....... Constant-bitrate
+    // VBR             3            E..V....... Variable-bitrate
+    // ICQ             4            E..V....... Intelligent constant-quality
+    // QVBR            5            E..V....... Quality-defined variable-bitrate
+    // AVBR            6            E..V....... Average variable-bitrate
+    if (self->rc_mode >= 0) {
         AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET_INT(opts, "tier", self->tier, AV_DICT_DONT_OVERWRITE);
-        if (self->ignore_bframe) {
-            AV_DICT_SET_INT(opts, "bf", 0, 0);
-        }
     }
-    else {
-        AV_DICT_SET_QP(opts, self->qp, 25);
+    switch (self->platform) {
+        case 0:
+            // Unconstrained --> will allow any combination of parameters (valid or invalid)
+            // this mode is usefull fur future platform and for debugging.
+            if (self->bit_rate) {
+                AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->max_bit_rate) {
+                AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->qp) {
+                AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->tier >= 0) {
+                AV_DICT_SET_INT(opts, "tier", self->tier, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
+        case 1:
+            // Intel
+            switch (self->rc_mode) {
+                case -1:
+                    // same like 0 but is not sending 'rc_mode'
+                case 0:
+                    // for auto --> let the driver decide as requested by documentation
+                    if (self->bit_rate) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    if (self->max_bit_rate) {
+                            AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        }
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 1:
+                case 4:
+                    // for constant quality: CQP and ICQ we use qp
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 2:
+                    // for constant bitrate: CBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 3:
+                    // for variable bitrate: VBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 5:
+                    // for variable bitrate: QVBR we use bitrate + qp
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 6:
+                    // for variable bitrate: AVBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+            }
+            if (self->tier >= 0) {
+                AV_DICT_SET_INT(opts, "tier", self->tier, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
+        case 2:
+            // AMD --> will allow any combination of parameters
+            // I am unable to confirm this platform because I don't have the HW
+            // Is only going to override bf to 0 (as highlited by the previous implementation)
+            if (self->bit_rate) {
+                AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->max_bit_rate) {
+                AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->qp) {
+                AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+            }
+            AV_DICT_SET_INT(opts, "bf", 0, 0);
+            if (self->tier >= 0) {
+                AV_DICT_SET_INT(opts, "tier", self->tier, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
     }
+    // force keyframe every 3 sec.
+    AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
     return 0;
 }
 
@@ -310,14 +636,14 @@ static const codec_profile_class_t codec_profile_vaapi_hevc_class = {
         .ic_properties = (const property_t[]){
             {
                 .type     = PT_INT,
-                .id       = "tier",
+                .id       = "tier",     // Don't change
                 .name     = N_("Tier"),
-                .desc     = N_("Set tier (general_tier_flag) [0=main 1=high]"),
+                .desc     = N_("Set tier (-1, 0 or 1) [-1=skip 0=main 1=high]"),
                 .group    = 5,
                 .opts     = PO_EXPERT,
                 .get_opts = codec_profile_class_get_opts,
                 .off      = offsetof(tvh_codec_profile_vaapi_t, tier),
-                .intextra = INTEXTRA_RANGE(0, 1, 0),
+                .intextra = INTEXTRA_RANGE(-1, 1, 1),
                 .def.i    = 0,
             },
             {}
@@ -347,22 +673,166 @@ static int
 tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
                                   AVDictionary **opts)
 {
-    // bit_rate or qp
-    if (self->bit_rate) {
-        AV_DICT_SET_BIT_RATE(opts, self->bit_rate);
-        if (self->buff_factor <= 0) {
-            self->buff_factor = 3;
-        }
-        AV_DICT_SET_INT(opts, "maxrate", (self->bit_rate) * 1000, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET_INT(opts, "bufsize", ((self->bit_rate) * 1000) * self->buff_factor, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
+    // to avoid issues we have this check:
+    if (self->buff_factor <= 0) {
+        self->buff_factor = 3;
     }
-    else {
-        AV_DICT_SET_QP(opts, self->qp, 25);
+    int int_bitrate = (int)((double)(self->bit_rate) * 1024.0 * (1.0 + (self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480.0)));
+    int int_buffer_size = (int)((double)(self->bit_rate) * 2048.0 * self->buff_factor * (1.0 + self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480));
+    int int_max_bitrate = (int)((double)(self->max_bit_rate) * 1024.0 * (1.0 + (self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480.0)));
+    // https://wiki.libav.org/Hardware/vaapi
+    // to find available parameters use:
+    // ffmpeg -hide_banner -h encoder=vp8_vaapi
+    //-rc_mode         <int>        E..V....... Set rate control mode (from 0 to 6) (default auto)
+    // auto            0            E..V....... Choose mode automatically based on other parameters
+    // CQP             1            E..V....... Constant-quality
+    // CBR             2            E..V....... Constant-bitrate
+    // VBR             3            E..V....... Variable-bitrate
+    // ICQ             4            E..V....... Intelligent constant-quality
+    // QVBR            5            E..V....... Quality-defined variable-bitrate
+    // AVBR            6            E..V....... Average variable-bitrate
+    if (self->rc_mode >= 0) {
+        AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
     }
-    if (self->ignore_bframe) {
-        AV_DICT_SET_INT(opts, "bf", 0, 0);
+    switch (self->platform) {
+        case 0:
+            // Unconstrained --> will allow any combination of parameters (valid or invalid)
+            // this mode is usefull fur future platform and for debugging.
+            if (self->bit_rate) {
+                AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->max_bit_rate) {
+                AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->qp) {
+                AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_level >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_level", self->loop_filter_level, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_sharpness >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_sharpness", self->loop_filter_sharpness, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
+        case 1:
+            // Intel
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            switch (self->rc_mode) {
+                case -1:
+                    // same like 0 but is not sending 'rc_mode'
+                case 0:
+                    // for auto --> let the driver decide as requested by documentation
+                    if (self->bit_rate) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    if (self->max_bit_rate) {
+                            AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        }
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 1:
+                case 4:
+                    // for constant quality: CQP we use qp
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 2:
+                    // for constant bitrate: CBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 3:
+                    // for variable bitrate: VBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 5:
+                    // for variable bitrate: QVBR we use bitrate + qp
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 6:
+                    // for variable bitrate: AVBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_level >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_level", self->loop_filter_level, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_sharpness >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_sharpness", self->loop_filter_sharpness, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
+        case 2:
+            // AMD --> will allow any combination of parameters
+            // I am unable to confirm this platform because I don't have the HW
+            // Is only going to override bf to 0 (as highlited by the previous implementation)
+            if (self->bit_rate) {
+                AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->max_bit_rate) {
+                AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->qp) {
+                AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+            }
+            AV_DICT_SET_INT(opts, "bf", 0, 0);
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_level >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_level", self->loop_filter_level, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_sharpness >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_sharpness", self->loop_filter_sharpness, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
     }
+    // force keyframe every 3 sec.
+    AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
     return 0;
 }
 
@@ -371,7 +841,46 @@ static const codec_profile_class_t codec_profile_vaapi_vp8_class = {
     {
         .ic_super      = (idclass_t *)&codec_profile_vaapi_class,
         .ic_class      = "codec_profile_vaapi_vp8",
-        .ic_caption    = N_("vaapi_vp8")
+        .ic_caption    = N_("vaapi_vp8"),
+        .ic_properties = (const property_t[]){
+            {
+                .type     = PT_INT,
+                .id       = "quality",     // Don't change
+                .name     = N_("Global Quality"),
+                .desc     = N_("Set encode quality [-1=skip 0-127]."),
+                .group    = 5,
+                .opts     = PO_EXPERT,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, quality),
+                .intextra = INTEXTRA_RANGE(-1, 127, 1),
+                .def.i    = 40,
+            },
+            {
+                .type     = PT_INT,
+                .id       = "loop_filter_level",     // Don't change
+                .name     = N_("Loop filter level"),
+                .desc     = N_("Set Loop filter level (-1=skip from 0 to 63) [default 16]"),
+                .group    = 5,
+                .opts     = PO_EXPERT,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, loop_filter_level),
+                .intextra = INTEXTRA_RANGE(-1, 63, 1),
+                .def.i    = 16,
+            },
+            {
+                .type     = PT_INT,
+                .id       = "loop_filter_sharpness",     // Don't change
+                .name     = N_("Loop filter sharpness"),
+                .desc     = N_("Set Loop filter sharpness (-1=skip from 0 to 15) [default 4]"),
+                .group    = 5,
+                .opts     = PO_EXPERT,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, loop_filter_sharpness),
+                .intextra = INTEXTRA_RANGE(-1, 15, 1),
+                .def.i    = 4,
+            },
+            {}
+        }
     },
     .open = (codec_profile_open_meth)tvh_codec_profile_vaapi_vp8_open,
 };
@@ -389,6 +898,10 @@ TVHVideoCodec tvh_codec_vaapi_vp8 = {
 /* vp9_vaapi =============================================================== */
 
 static const AVProfile vaapi_vp9_profiles[] = {
+    { FF_PROFILE_VP9_0, "Profile0" },
+    { FF_PROFILE_VP9_1, "Profile1" },
+    { FF_PROFILE_VP9_2, "Profile2" },
+    { FF_PROFILE_VP9_3, "Profile3" },
     { FF_PROFILE_UNKNOWN },
 };
 
@@ -396,22 +909,166 @@ static int
 tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
                                   AVDictionary **opts)
 {
-    // bit_rate or qp
-    if (self->bit_rate) {
-        AV_DICT_SET_BIT_RATE(opts, self->bit_rate);
-        if (self->buff_factor <= 0) {
-            self->buff_factor = 3;
-        }
-        AV_DICT_SET_INT(opts, "maxrate", (self->bit_rate) * 1000, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET_INT(opts, "bufsize", ((self->bit_rate) * 1000) * self->buff_factor, AV_DICT_DONT_OVERWRITE);
-        AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
+    // to avoid issues we have this check:
+    if (self->buff_factor <= 0) {
+        self->buff_factor = 3;
     }
-    else {
-        AV_DICT_SET_QP(opts, self->qp, 25);
+    int int_bitrate = (int)((double)(self->bit_rate) * 1024.0 * (1.0 + (self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480.0)));
+    int int_buffer_size = (int)((double)(self->bit_rate) * 2048.0 * self->buff_factor * (1.0 + self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480));
+    int int_max_bitrate = (int)((double)(self->max_bit_rate) * 1024.0 * (1.0 + (self->bit_rate_scale_factor * ((double)(self->size.den) - 480.0) / 480.0)));
+    // https://wiki.libav.org/Hardware/vaapi
+    // to find available parameters use:
+    // ffmpeg -hide_banner -h encoder=vp9_vaapi
+    //-rc_mode         <int>        E..V....... Set rate control mode (from 0 to 6) (default auto)
+    // auto            0            E..V....... Choose mode automatically based on other parameters
+    // CQP             1            E..V....... Constant-quality
+    // CBR             2            E..V....... Constant-bitrate
+    // VBR             3            E..V....... Variable-bitrate
+    // ICQ             4            E..V....... Intelligent constant-quality
+    // QVBR            5            E..V....... Quality-defined variable-bitrate
+    // AVBR            6            E..V....... Average variable-bitrate
+    if (self->rc_mode >= 0) {
+        AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
     }
-    if (self->ignore_bframe) {
-        AV_DICT_SET_INT(opts, "bf", 0, 0);
+    switch (self->platform) {
+        case 0:
+            // Unconstrained --> will allow any combination of parameters (valid or invalid)
+            // this mode is usefull fur future platform and for debugging.
+            if (self->bit_rate) {
+                AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->max_bit_rate) {
+                AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->qp) {
+                AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_level >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_level", self->loop_filter_level, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_sharpness >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_sharpness", self->loop_filter_sharpness, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
+        case 1:
+            // Intel
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            switch (self->rc_mode) {
+                case -1:
+                    // same like 0 but is not sending 'rc_mode'
+                case 0:
+                    // for auto --> let the driver decide as requested by documentation
+                    if (self->bit_rate) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    if (self->max_bit_rate) {
+                            AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        }
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 1:
+                case 4:
+                    // for constant quality: CQP we use qp
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 2:
+                    // for constant bitrate: CBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 3:
+                    // for variable bitrate: VBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 5:
+                    // for variable bitrate: QVBR we use bitrate + qp
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+                    }
+                    if (self->qp) {
+                        AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+                case 6:
+                    // for variable bitrate: AVBR we use bitrate
+                    if (self->bit_rate && self->buff_factor) {
+                        AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                        AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+                    }
+                    break;
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_level >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_level", self->loop_filter_level, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_sharpness >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_sharpness", self->loop_filter_sharpness, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
+        case 2:
+            // AMD --> will allow any combination of parameters
+            // I am unable to confirm this platform because I don't have the HW
+            // Is only going to override bf to 0 (as highlited by the previous implementation)
+            if (self->bit_rate) {
+                AV_DICT_SET_INT(opts, "b", int_bitrate, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->max_bit_rate) {
+                AV_DICT_SET_INT(opts, "maxrate", int_max_bitrate, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->qp) {
+                AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
+            }
+            AV_DICT_SET_INT(opts, "bf", 0, 0);
+            if (self->quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->low_power) {
+                AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_level >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_level", self->loop_filter_level, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->loop_filter_sharpness >= 0) {
+                AV_DICT_SET_INT(opts, "loop_filter_sharpness", self->loop_filter_sharpness, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->async_depth) {
+                AV_DICT_SET_INT(opts, "async_depth", self->async_depth, AV_DICT_DONT_OVERWRITE);
+            }
+            break;
     }
+    // force keyframe every 3 sec.
+    AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
     return 0;
 }
 
@@ -420,7 +1077,46 @@ static const codec_profile_class_t codec_profile_vaapi_vp9_class = {
     {
         .ic_super      = (idclass_t *)&codec_profile_vaapi_class,
         .ic_class      = "codec_profile_vaapi_vp9",
-        .ic_caption    = N_("vaapi_vp9")
+        .ic_caption    = N_("vaapi_vp9"),
+        .ic_properties = (const property_t[]){
+            {
+                .type     = PT_INT,
+                .id       = "quality",     // Don't change
+                .name     = N_("Global Quality"),
+                .desc     = N_("Set encode quality [-1=skip 0-255]."),
+                .group    = 5,
+                .opts     = PO_EXPERT,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, quality),
+                .intextra = INTEXTRA_RANGE(-1, 255, 1),
+                .def.i    = 40,
+            },
+            {
+                .type     = PT_INT,
+                .id       = "loop_filter_level",     // Don't change
+                .name     = N_("Loop filter level"),
+                .desc     = N_("Set Loop filter level (-1=skip from 0 to 63) [default 16]"),
+                .group    = 5,
+                .opts     = PO_EXPERT,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, loop_filter_level),
+                .intextra = INTEXTRA_RANGE(-1, 63, 1),
+                .def.i    = 16,
+            },
+            {
+                .type     = PT_INT,
+                .id       = "loop_filter_sharpness",     // Don't change
+                .name     = N_("Loop filter sharpness"),
+                .desc     = N_("Set Loop filter sharpness (-1=skip from 0 to 15) [default 4]"),
+                .group    = 5,
+                .opts     = PO_EXPERT,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, loop_filter_sharpness),
+                .intextra = INTEXTRA_RANGE(-1, 15, 1),
+                .def.i    = 4,
+            },
+            {}
+        }
     },
     .open = (codec_profile_open_meth)tvh_codec_profile_vaapi_vp9_open,
 };
index 7a79cda181cbd5cc9879d03a42e4c00d5c107137..0130f2af6abdb639ecbdb30530b4ebc42fd97a91 100644 (file)
@@ -177,12 +177,12 @@ hwaccels_get_deint_filter(AVCodecContext *avctx, char *filter, size_t filter_len
 /* encoding ================================================================= */
 
 int
-hwaccels_encode_setup_context(AVCodecContext *avctx)
+hwaccels_encode_setup_context(AVCodecContext *avctx, int low_power)
 {
     switch (avctx->pix_fmt) {
 #if ENABLE_VAAPI
         case AV_PIX_FMT_VAAPI:
-            return vaapi_encode_setup_context(avctx);
+            return vaapi_encode_setup_context(avctx, low_power);
 #endif
         default:
             break;
index 55caad8e60743bdc90810cdf7912076b0fabd735..a14647672ccd8dacb8c124d513fb7c6929a69826 100644 (file)
@@ -47,7 +47,7 @@ hwaccels_get_deint_filter(AVCodecContext *avctx, char *filter, size_t filter_len
 /* encoding ================================================================= */
 
 int
-hwaccels_encode_setup_context(AVCodecContext *avctx);
+hwaccels_encode_setup_context(AVCodecContext *avctx, int low_power);
 
 void
 hwaccels_encode_close_context(AVCodecContext *avctx);
index 3cf784e1c1f8690cbeb2f9595261f8c185b14006..c449060dc2cce653735dd27c5c121d0dd52ab436 100644 (file)
@@ -232,6 +232,9 @@ tvhva_context_profile(TVHVAContext *self, AVCodecContext *avctx)
         for (j = 0; j < profiles_max; j++) {
             profiles[j] = VAProfileNone;
         }
+        if (profiles_max == 0) {
+            tvherror(LS_VAAPI, "%s: vaMaxNumProfiles() returned %d; vaapi doesn't have any profiles available, run: $ vainfo", self->logpref, profiles_max);
+        }
         va_res = vaQueryConfigProfiles(self->display,
                                        profiles, &profiles_len);
         if (va_res == VA_STATUS_SUCCESS) {
@@ -242,6 +245,9 @@ tvhva_context_profile(TVHVAContext *self, AVCodecContext *avctx)
                 }
             }
         }
+        else {
+            tvherror(LS_VAAPI, "%s: va_res != VA_STATUS_SUCCESS; Failed to query profiles: %d (%s), run: $ vainfo", self->logpref, va_res, vaErrorStr(va_res));
+        }
         free(profiles);
     }
 
@@ -256,10 +262,11 @@ tvhva_context_check_profile(TVHVAContext *self, VAProfile profile)
     VAEntrypoint *entrypoints = NULL;
     int res = -1, i, entrypoints_max, entrypoints_len;
 
-    if ((entrypoints_max = vaMaxNumEntrypoints(self->display)) > 0 &&
-        (entrypoints = calloc(entrypoints_max, sizeof(VAEntrypoint)))) {
-        va_res = vaQueryConfigEntrypoints(self->display, profile,
-                                          entrypoints, &entrypoints_len);
+    entrypoints_max = vaMaxNumEntrypoints(self->display);
+
+    if (entrypoints_max > 0) {
+        entrypoints = calloc(entrypoints_max, sizeof(VAEntrypoint));
+        va_res = vaQueryConfigEntrypoints(self->display, profile, entrypoints, &entrypoints_len);
         if (va_res == VA_STATUS_SUCCESS) {
             for (i = 0; i < entrypoints_len; i++) {
                 if (entrypoints[i] == self->entrypoint) {
@@ -268,8 +275,43 @@ tvhva_context_check_profile(TVHVAContext *self, VAProfile profile)
                 }
             }
         }
+        else {
+            tvherror(LS_VAAPI, "%s: va_res != VA_STATUS_SUCCESS; Failed to query entrypoints: %d (%s), run: $ vainfo", self->logpref, va_res, vaErrorStr(va_res));
+        }
+        if (res != 0) {
+            // before giving up we swap VAEntrypointEncSliceLP with VAEntrypointEncSlice or viceversa
+            if (self->entrypoint == VAEntrypointEncSlice) {
+                // we try VAEntrypointEncSliceLP
+                self->entrypoint = VAEntrypointEncSliceLP;
+                va_res = vaQueryConfigEntrypoints(self->display, profile, entrypoints, &entrypoints_len);
+                if (va_res == VA_STATUS_SUCCESS) {
+                    for (i = 0; i < entrypoints_len; i++) {
+                        if (entrypoints[i] == self->entrypoint) {
+                            res = 0;
+                            break;
+                        }
+                    }
+                }
+            }
+            else {
+                // we try VAEntrypointEncSlice
+                self->entrypoint = VAEntrypointEncSlice;
+                va_res = vaQueryConfigEntrypoints(self->display, profile, entrypoints, &entrypoints_len);
+                if (va_res == VA_STATUS_SUCCESS) {
+                    for (i = 0; i < entrypoints_len; i++) {
+                        if (entrypoints[i] == self->entrypoint) {
+                            res = 0;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
         free(entrypoints);
     }
+    else {
+        tvherror(LS_VAAPI, "%s: vaMaxNumEntrypoints() returned %d; vaapi doesn't have any entrypoints available, run: $ vainfo", self->logpref, entrypoints_max);
+    }
     return res;
 }
 
@@ -409,13 +451,20 @@ tvhva_context_setup(TVHVAContext *self, AVCodecContext *avctx)
     }
 
     libav_vaapi_init_context(self->display);
+    // 
+    profile = tvhva_context_profile(self, avctx);
+
+    if (profile == VAProfileNone) {
+        tvherror(LS_VAAPI, "%s: tvhva_context_profile() returned VAProfileNone for %s",
+                 self->logpref,
+                 avctx->codec->name);
+        return -1;
+    }
 
-    if ((profile = tvhva_context_profile(self, avctx)) == VAProfileNone ||
-        tvhva_context_check_profile(self, profile)) {
-        tvherror(LS_VAAPI, "%s: unsupported codec: %s and/or profile: %s",
+    if (tvhva_context_check_profile(self, profile)) {
+        tvherror(LS_VAAPI, "%s: tvhva_context_check_profile() check failed for codec: %s --> codec not available",
                  self->logpref,
-                 avctx->codec->name,
-                 av_get_profile_name(avctx->codec, avctx->profile));
+                 avctx->codec->name);
         return -1;
     }
     if (!(format = tvhva_get_format(self->io_format))) {
@@ -578,13 +627,21 @@ vaapi_get_deint_filter(AVCodecContext *avctx, char *filter, size_t filter_len)
 /* encoding ================================================================= */
 
 int
-vaapi_encode_setup_context(AVCodecContext *avctx)
+vaapi_encode_setup_context(AVCodecContext *avctx, int low_power)
 {
     TVHContext *ctx = avctx->opaque;
     TVHVAContext *hwaccel_context = NULL;
+    VAEntrypoint entrypoint;
+
+    if (low_power) {
+        entrypoint = VAEntrypointEncSliceLP;
+    }
+    else {
+        entrypoint = VAEntrypointEncSlice;
+    }
 
     if (!(hwaccel_context =
-          tvhva_context_create("encode", avctx, VAEntrypointEncSlice))) {
+          tvhva_context_create("encode", avctx, entrypoint))) {
         return -1;
     }
     if (!(ctx->hw_device_octx = av_buffer_ref(hwaccel_context->hw_device_ref))) {
index 9a61a5e24a4d7cae63d97474f9fa2eb6639270ba..3ce9817b9169c5b5f8f2a2cae2be56cded6e04f8 100644 (file)
@@ -45,7 +45,7 @@ vaapi_get_deint_filter(AVCodecContext *avctx, char *filter, size_t filter_len);
 /* encoding ================================================================= */
 
 int
-vaapi_encode_setup_context(AVCodecContext *avctx);
+vaapi_encode_setup_context(AVCodecContext *avctx, int low_power);
 
 void
 vaapi_encode_close_context(AVCodecContext *avctx);
index 4482b5fbab667a0f07e7c3e9d4ca38aa22d9fb24..ac002e13672b13e342f8e5a349b2f99418b9d4c4 100644 (file)
@@ -162,7 +162,7 @@ tvh_video_context_open_encoder(TVHContext *self, AVDictionary **opts)
 #if ENABLE_HWACCELS
     self->oavctx->coded_width = self->oavctx->width;
     self->oavctx->coded_height = self->oavctx->height;
-    if (hwaccels_encode_setup_context(self->oavctx)) {
+    if (hwaccels_encode_setup_context(self->oavctx, self->profile->low_power)) {
         return -1;
     }
 #endif
index dff82db6c6dfa6fc0a79e9287b2c4d8056728f91..6ca5beba01bbfeaf4c1e4234c31e645d5ef53c03 100644 (file)
@@ -229,9 +229,439 @@ var codec_profile_forms = {
         });
     },
 
-    'codec_profile_vaapi_h264': genericCBRvsVBR,
+    'codec_profile_vaapi_h264': function(form) {
+        function updateFilters(form) {
+            var platform_field = form.findField('platform');
+            var rc_mode_field = form.findField('rc_mode');
+            var bit_rate_field = form.findField('bit_rate');
+            var max_bit_rate_field = form.findField('max_bit_rate');
+            var buff_factor_field = form.findField('buff_factor');
+            var bit_rate_scale_factor_field = form.findField('bit_rate_scale_factor');
+            var qp_field = form.findField('qp');
+            var low_power_field = form.findField('low_power');
+
+            var platform = platform_field.getValue();
+            switch (platform) {
+                case 0:
+                    // Unconstrained --> will allow any combination of parameters (valid or invalid)
+                    // this mode is usefull fur future platform and for debugging.
+                    // no filter applied
+                    bit_rate_field.setDisabled(false);
+                    max_bit_rate_field.setDisabled(false);
+                    buff_factor_field.setDisabled(false);
+                    bit_rate_scale_factor_field.setDisabled(false);
+                    qp_field.setDisabled(false);
+                    low_power_field.setDisabled(false);
+                    break;
+                case 1:
+                    // Intel
+                    var rc_mode = rc_mode_field.getValue();
+                    switch (rc_mode) {
+                        case -1:
+                        case 0:
+                            // for auto --> let the driver decide as requested by documentation
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 1:
+                        case 4:
+                            // for constant quality: CQP and ICQ we use qp
+                            bit_rate_field.setDisabled(true);
+                            max_bit_rate_field.setDisabled(true);
+                            buff_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(true);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 2:
+                            // for constant bitrate: CBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(true);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                        case 3:
+                            // for variable bitrate: VBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                        case 5:
+                            // for variable bitrate: QVBR we use bitrate + qp
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 6:
+                            // for variable bitrate: AVBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                    }
+                    low_power_field.setDisabled(false);
+                    break;
+                case 2:
+                    // AMD --> will allow any combination of parameters
+                    // I am unable to confirm this platform because I don't have the HW
+                    // Is only going to override bf to 0 (as highlited by the previous implementation)
+                    bit_rate_field.setDisabled(false);
+                    max_bit_rate_field.setDisabled(false);
+                    buff_factor_field.setDisabled(false);
+                    bit_rate_scale_factor_field.setDisabled(false);
+                    qp_field.setDisabled(false);
+                    break;
+                default:
+            }
+        }
+
+        var platform_field = form.findField('platform');
+        var rc_mode_field = form.findField('rc_mode');
+        // first time we have to call this manually
+        updateFilters(form);
+        
+        // on platform change
+        platform_field.on('select', function(spinner) {
+            updateFilters(form);
+        });
+        // on rc_mode change
+        rc_mode_field.on('select', function(spinner) {
+            updateFilters(form);
+        });
+    },
+
+    'codec_profile_vaapi_hevc': function(form) {
+        function updateFilters(form) {
+            var platform_field = form.findField('platform');
+            var rc_mode_field = form.findField('rc_mode');
+            var bit_rate_field = form.findField('bit_rate');
+            var max_bit_rate_field = form.findField('max_bit_rate');
+            var buff_factor_field = form.findField('buff_factor');
+            var bit_rate_scale_factor_field = form.findField('bit_rate_scale_factor');
+            var qp_field = form.findField('qp');
+            var low_power_field = form.findField('low_power');
+
+            var platform = platform_field.getValue();
+            switch (platform) {
+                case 0:
+                    // Unconstrained --> will allow any combination of parameters (valid or invalid)
+                    // this mode is usefull fur future platform and for debugging.
+                    // no filter applied
+                    bit_rate_field.setDisabled(false);
+                    max_bit_rate_field.setDisabled(false);
+                    buff_factor_field.setDisabled(false);
+                    bit_rate_scale_factor_field.setDisabled(false);
+                    qp_field.setDisabled(false);
+                    low_power_field.setDisabled(false);
+                    break;
+                case 1:
+                    // Intel
+                    var rc_mode = rc_mode_field.getValue();
+                    switch (rc_mode) {
+                        case -1:
+                        case 0:
+                            // for auto --> let the driver decide as requested by documentation
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 1:
+                        case 4:
+                            // for constant quality: CQP and ICQ we use qp
+                            bit_rate_field.setDisabled(true);
+                            max_bit_rate_field.setDisabled(true);
+                            buff_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(true);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 2:
+                            // for constant bitrate: CBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(true);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                        case 3:
+                            // for variable bitrate: VBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                        case 5:
+                            // for variable bitrate: QVBR we use bitrate + qp
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 6:
+                            // for variable bitrate: AVBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(true);
+                            qp_field.setDisabled(true);
+                            break;
+                    }
+                    low_power_field.setDisabled(false);
+                    break;
+                case 2:
+                    // AMD --> will allow any combination of parameters
+                    // I am unable to confirm this platform because I don't have the HW
+                    // Is only going to override bf to 0 (as highlited by the previous implementation)
+                    bit_rate_field.setDisabled(false);
+                    max_bit_rate_field.setDisabled(false);
+                    buff_factor_field.setDisabled(false);
+                    bit_rate_scale_factor_field.setDisabled(false);
+                    qp_field.setDisabled(false);
+                    break;
+                default:
+            }
+        }
+
+        var platform_field = form.findField('platform');
+        var rc_mode_field = form.findField('rc_mode');
+        // first time we have to call this manually
+        updateFilters(form);
+        
+        // on platform change
+        platform_field.on('select', function(spinner) {
+            updateFilters(form);
+        });
+        // on rc_mode change
+        rc_mode_field.on('select', function(spinner) {
+            updateFilters(form);
+        });
+    },
+
+    'codec_profile_vaapi_vp8': function(form) {
+        function updateFilters(form) {
+            var platform_field = form.findField('platform');
+            var rc_mode_field = form.findField('rc_mode');
+            var bit_rate_field = form.findField('bit_rate');
+            var max_bit_rate_field = form.findField('max_bit_rate');
+            var buff_factor_field = form.findField('buff_factor');
+            var bit_rate_scale_factor_field = form.findField('bit_rate_scale_factor');
+            var qp_field = form.findField('qp');
+
+            var platform = platform_field.getValue();
+            switch (platform) {
+                case 0:
+                    // Unconstrained --> will allow any combination of parameters (valid or invalid)
+                    // this mode is usefull fur future platform and for debugging.
+                    // no filter applied
+                    bit_rate_field.setDisabled(false);
+                    max_bit_rate_field.setDisabled(false);
+                    buff_factor_field.setDisabled(false);
+                    bit_rate_scale_factor_field.setDisabled(false);
+                    qp_field.setDisabled(false);
+                    break;
+                case 1:
+                    // Intel
+                    var rc_mode = rc_mode_field.getValue();
+                    switch (rc_mode) {
+                        case -1:
+                        case 0:
+                            // for auto --> let the driver decide as requested by documentation
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 1:
+                        case 4:
+                            // for constant quality: CQP and ICQ we use qp
+                            bit_rate_field.setDisabled(true);
+                            max_bit_rate_field.setDisabled(true);
+                            buff_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(true);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 2:
+                            // for constant bitrate: CBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(true);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                        case 3:
+                            // for variable bitrate: VBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                        case 5:
+                            // for variable bitrate: QVBR we use bitrate + qp
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 6:
+                            // for variable bitrate: AVBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(true);
+                            qp_field.setDisabled(true);
+                            break;
+                    }
+                    break;
+                case 2:
+                    // AMD --> will allow any combination of parameters
+                    // I am unable to confirm this platform because I don't have the HW
+                    // Is only going to override bf to 0 (as highlited by the previous implementation)
+                    bit_rate_field.setDisabled(false);
+                    max_bit_rate_field.setDisabled(false);
+                    buff_factor_field.setDisabled(false);
+                    bit_rate_scale_factor_field.setDisabled(false);
+                    qp_field.setDisabled(false);
+                    break;
+                default:
+            }
+        }
+
+        var platform_field = form.findField('platform');
+        var rc_mode_field = form.findField('rc_mode');
+        // first time we have to call this manually
+        updateFilters(form);
+
+        // on platform change
+        platform_field.on('select', function(spinner) {
+            updateFilters(form);
+        });
+        // on rc_mode change
+        rc_mode_field.on('select', function(spinner) {
+            updateFilters(form);
+        });
+    },
 
-    'codec_profile_vaapi_hevc': genericCBRvsVBR
+    'codec_profile_vaapi_vp9': function(form) {
+        function updateFilters(form) {
+            var platform_field = form.findField('platform');
+            var rc_mode_field = form.findField('rc_mode');
+            var bit_rate_field = form.findField('bit_rate');
+            var max_bit_rate_field = form.findField('max_bit_rate');
+            var buff_factor_field = form.findField('buff_factor');
+            var bit_rate_scale_factor_field = form.findField('bit_rate_scale_factor');
+            var qp_field = form.findField('qp');
+
+            var platform = platform_field.getValue();
+            switch (platform) {
+                case 0:
+                    // Unconstrained --> will allow any combination of parameters (valid or invalid)
+                    // this mode is usefull fur future platform and for debugging.
+                    // no filter applied
+                    bit_rate_field.setDisabled(false);
+                    max_bit_rate_field.setDisabled(false);
+                    buff_factor_field.setDisabled(false);
+                    bit_rate_scale_factor_field.setDisabled(false);
+                    qp_field.setDisabled(false);
+                    break;
+                case 1:
+                    // Intel
+                    var rc_mode = rc_mode_field.getValue();
+                    switch (rc_mode) {
+                        case -1:
+                        case 0:
+                            // for auto --> let the driver decide as requested by documentation
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 1:
+                        case 4:
+                            // for constant quality: CQP and ICQ we use qp
+                            bit_rate_field.setDisabled(true);
+                            max_bit_rate_field.setDisabled(true);
+                            buff_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(true);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 2:
+                            // for constant bitrate: CBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(true);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                        case 3:
+                            // for variable bitrate: VBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(true);
+                            break;
+                        case 5:
+                            // for variable bitrate: QVBR we use bitrate + qp
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(false);
+                            bit_rate_scale_factor_field.setDisabled(false);
+                            qp_field.setDisabled(false);
+                            break;
+                        case 6:
+                            // for variable bitrate: AVBR we use bitrate
+                            bit_rate_field.setDisabled(false);
+                            max_bit_rate_field.setDisabled(false);
+                            buff_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(true);
+                            qp_field.setDisabled(true);
+                            break;
+                    }
+                    break;
+                case 2:
+                    // AMD --> will allow any combination of parameters
+                    // I am unable to confirm this platform because I don't have the HW
+                    // Is only going to override bf to 0 (as highlited by the previous implementation)
+                    bit_rate_field.setDisabled(false);
+                    max_bit_rate_field.setDisabled(false);
+                    buff_factor_field.setDisabled(false);
+                    bit_rate_scale_factor_field.setDisabled(false);
+                    qp_field.setDisabled(false);
+                    break;
+                default:
+            }
+        }
+
+        var platform_field = form.findField('platform');
+        var rc_mode_field = form.findField('rc_mode');
+        // first time we have to call this manually
+        updateFilters(form);
+
+        // on platform change
+        platform_field.on('select', function(spinner) {
+            updateFilters(form);
+        });
+        // on rc_mode change
+        rc_mode_field.on('select', function(spinner) {
+            updateFilters(form);
+        });
+    }
 };