]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
update vaapi - vainfo
authoruknunknown <alin_gherghescu@yahoo.com>
Tue, 23 May 2023 02:48:04 +0000 (19:48 -0700)
committerFlole <Flole998@users.noreply.github.com>
Mon, 12 Aug 2024 20:17:48 +0000 (22:17 +0200)
- add enable vainfo detection checkbox in config
- defined PT_DYN_INT to load integer field from function
- PT_DYN_INT must be paired with dyn_i
- show only VAAPI codecs advertised by vainfo
- defined two invisible fields: ui and uilp used for UI enable/disable features
- check if bitrate is greater than max_bitrate (fix to avoid tvh crash)
- vp8, vp9 separate Global Quality from Quality
- load quality and max B frames filters from vainfo
- UI has several constrains or warnings implemented using vainfo
- separated 'b_depth' from 'bf'

17 files changed:
src/config.c
src/config.h
src/idnode.c
src/main.c
src/prop.c
src/prop.h
src/transcoding/codec.h
src/transcoding/codec/codec.c
src/transcoding/codec/codecs/libs/vaapi.c
src/transcoding/codec/internals.h
src/transcoding/codec/module.c
src/transcoding/codec/profile_video_class.c
src/transcoding/codec/vainfo.c [new file with mode: 0644]
src/transcoding/codec/vainfo.h [new file with mode: 0644]
src/tvhlog.c
src/tvhlog.h
src/webui/static/app/codec.js

index d5926df64aa824e7619eba89fa6aa89203ad0d40..c5bd4ef4dbd86d060b810e91e1f0707680cb803e 100644 (file)
@@ -56,6 +56,9 @@ struct config config;
 static char config_lock[PATH_MAX];
 static int config_lock_fd;
 static int config_scanfile_ok;
+#if ENABLE_VAAPI
+int vainfo_probe_enabled;
+#endif
 
 /* *************************************************************************
  * Config migration
@@ -1896,6 +1899,9 @@ config_init ( int backup )
     if (config_migrate(backup))
       config_check();
   }
+#if ENABLE_VAAPI
+  vainfo_probe_enabled = config.enable_vainfo;
+#endif
   tvhinfo(LS_CONFIG, "loaded");
 }
 
@@ -2754,6 +2760,19 @@ const idclass_t config_class = {
       .opts   = PO_EXPERT,
       .group  = 7,
     },
+#if ENABLE_VAAPI
+    {
+      .type   = PT_BOOL,
+      .id     = "enable_vainfo",
+      .name   = N_("Enable vainfo detection"),
+      .desc   = N_("Enable vainfo detection in order to show only "
+                   "encoders that are advertised by VAAPI driver.\n"
+                   "NOTE: After save, Tvheadend restart is required!"),
+      .off    = offsetof(config_t, enable_vainfo),
+      .opts   = PO_EXPERT,
+      .group  = 7,
+    },
+#endif
     {
       .type   = PT_STR,
       .id     = "wizard",
index 8cdb54d701409fc2fe3c3719a8a18c39a2af7fed..fe1f9b931e5f77aa0e05be8a46ceab64f316513c 100644 (file)
@@ -78,6 +78,9 @@ typedef struct config {
   uint32_t hdhomerun_server_tuner_count;
   char *hdhomerun_server_model_name;
   int hdhomerun_server_enable;
+#if ENABLE_VAAPI
+  int enable_vainfo;
+  #endif
 } config_t;
 
 extern const idclass_t config_class;
index 457b1917179b8f1cf21e397024a37faca1c672c2..d75a1e4e3558029b224f38773c684116d55c04a7 100644 (file)
@@ -391,6 +391,7 @@ idnode_get_u32
       ptr = ((void*)self) + p->off;
     switch (p->type) {
       case PT_INT:
+      case PT_DYN_INT:
       case PT_BOOL:
         *u32 = *(int*)ptr;
         return 0;
@@ -425,6 +426,7 @@ idnode_get_s64
       ptr = ((void*)self) + p->off;
     switch (p->type) {
       case PT_INT:
+      case PT_DYN_INT:
       case PT_BOOL:
         *s64 = *(int*)ptr;
         return 0;
@@ -495,6 +497,7 @@ idnode_get_dbl
       ptr = ((void*)self) + p->off;
     switch (p->type) {
       case PT_INT:
+      case PT_DYN_INT:
       case PT_BOOL:
         *dbl = *(int*)ptr;
         return 0;
@@ -761,6 +764,7 @@ idnode_cmp_sort
       }
       break;
     case PT_INT:
+    case PT_DYN_INT:
     case PT_U16:
     case PT_BOOL:
     case PT_PERM:
index 3b43c95347159b9d25e0485cc648a09c1f2cd72f..fa3a335d5fa3e0f1b504ec442f9bb74e88f3b2cd 100644 (file)
@@ -804,7 +804,9 @@ main(int argc, char **argv)
   } randseed;
   struct rlimit rl;
   extern int dvb_bouquets_parse;
-
+#if ENABLE_VAAPI
+  extern int vainfo_probe_enabled;
+#endif
   main_tid = pthread_self();
 
   /* Setup global mutexes */
@@ -1293,7 +1295,11 @@ main(int argc, char **argv)
   tvhftrace(LS_MAIN, fsmonitor_init);
   tvhftrace(LS_MAIN, libav_init);
   tvhftrace(LS_MAIN, tvhtime_init);
+#if ENABLE_VAAPI
+  tvhftrace(LS_MAIN, codec_init, vainfo_probe_enabled);
+#else
   tvhftrace(LS_MAIN, codec_init);
+#endif
   tvhftrace(LS_MAIN, profile_init);
   tvhftrace(LS_MAIN, imagecache_init);
   tvhftrace(LS_MAIN, http_client_init);
index e91f75b31aad6c65d1a17d35cf1d901d2ef54314..d6f830c647257d7de0b7d4bb2fd294552f021b59 100644 (file)
@@ -46,6 +46,7 @@ static const struct strtab typetab[] = {
   { "s64",     PT_S64_ATOMIC },
   { "dbl",     PT_DBL },
   { "time",    PT_TIME },
+  { "int",     PT_DYN_INT },
   { "langstr", PT_LANGSTR },
   { "perm",    PT_PERM },
 };
@@ -84,6 +85,7 @@ prop_write_values
   uint32_t u32, opts;
   uint16_t u16;
   time_t tm;
+  int dyn_i;
 #define PROP_UPDATE(v, t)\
   snew = &v;\
   if (!p->set && (*((t*)cur) != *((t*)snew))) {\
@@ -212,6 +214,13 @@ prop_write_values
         PROP_UPDATE(tm, time_t);
         break;
       }
+      case PT_DYN_INT: {
+        if (htsmsg_field_get_s64(f, &s64))
+          continue;
+        dyn_i = s64;
+        PROP_UPDATE(dyn_i, int);
+        break;
+      }
       case PT_LANGSTR: {
         lang_str_t **lstr1 = cur;
         lang_str_t  *lstr2;
@@ -349,6 +358,9 @@ prop_read_value
     case PT_TIME:
       htsmsg_add_s64(m, name, *(time_t *)val);
       break;
+    case PT_DYN_INT:
+      htsmsg_add_s64(m, name, *(int *)val);
+      break;
     case PT_LANGSTR:
       lang_str_serialize(*(lang_str_t **)val, m, name);
       break;
@@ -481,6 +493,9 @@ prop_serialize_value
       case PT_TIME:
         htsmsg_add_s64(m, "default", pl->def.tm);
         break;
+      case PT_DYN_INT:
+        htsmsg_add_s32(m, "default", pl->def.dyn_i());
+        break;
       case PT_LANGSTR:
         /* TODO? */
         break;
index 3739422815284454995aa633eb41cf16720db35e..5855b2d6f31c3aa8414ab77b25e7653b48d3d71e 100644 (file)
@@ -38,6 +38,7 @@ typedef enum {
   PT_S64_ATOMIC,
   PT_DBL,
   PT_TIME,
+  PT_DYN_INT,
   PT_LANGSTR,
   PT_PERM,                // like PT_U32 but with the special save
 } prop_type_t;
@@ -115,6 +116,7 @@ typedef struct property {
     double      d;   // PT_DBL
     time_t      tm;  // PT_TIME
     htsmsg_t *(*list)(void); // islist != 0
+    int       (*dyn_i)(void); // dynamically load a PT_DYN_INT
   } def;
 
   /* Extended options */
index b68b73925f7cfa9645a74577adaded00bc146a1b..43b708462e8dc7ef98b9ea41e39d0c56b7f58de8 100644 (file)
@@ -171,7 +171,11 @@ htsmsg_t *
 codec_get_profiles_list(enum AVMediaType media_type);
 
 void
+#if ENABLE_VAAPI
+codec_init(int vainfo_probe_enabled);
+#else
 codec_init(void);
+#endif
 
 void
 codec_done(void);
index fbaee36b842990e6b7be4717f9a1baa8660c5c22..6e5d1e3e78f8031e2701cba2a313cfc74e96237e 100644 (file)
@@ -20,6 +20,9 @@
 
 #include "internals.h"
 
+#if ENABLE_VAAPI
+#include "vainfo.h"
+#endif
 
 struct TVHCodecs tvh_codecs;
 
@@ -254,7 +257,11 @@ tvh_codec_find(const char *name)
 
 
 void
+#if ENABLE_VAAPI
+tvh_codecs_register(int vainfo_probe_enabled)
+#else
 tvh_codecs_register()
+#endif
 {
     SLIST_INIT(&tvh_codecs);
     tvh_codec_register(&tvh_codec_mpeg2video);
@@ -291,10 +298,26 @@ tvh_codecs_register()
 #endif
 
 #if ENABLE_VAAPI
-    tvh_codec_register(&tvh_codec_vaapi_h264);
-    tvh_codec_register(&tvh_codec_vaapi_hevc);
-    tvh_codec_register(&tvh_codec_vaapi_vp8);
-    tvh_codec_register(&tvh_codec_vaapi_vp9);
+    if (vainfo_probe_enabled && !vainfo_init(VAINFO_SHOW_LOGS)) {
+        if (vainfo_encoder_isavailable(VAINFO_H264) || 
+            vainfo_encoder_isavailable(VAINFO_H264_LOW_POWER))
+            tvh_codec_register(&tvh_codec_vaapi_h264);
+        if (vainfo_encoder_isavailable(VAINFO_HEVC) || 
+            vainfo_encoder_isavailable(VAINFO_HEVC_LOW_POWER))
+            tvh_codec_register(&tvh_codec_vaapi_hevc);
+        if (vainfo_encoder_isavailable(VAINFO_VP8) || 
+            vainfo_encoder_isavailable(VAINFO_VP8_LOW_POWER))
+            tvh_codec_register(&tvh_codec_vaapi_vp8);
+        if (vainfo_encoder_isavailable(VAINFO_VP9) || 
+            vainfo_encoder_isavailable(VAINFO_VP9_LOW_POWER))
+            tvh_codec_register(&tvh_codec_vaapi_vp9);
+    }
+    else {
+        tvh_codec_register(&tvh_codec_vaapi_h264);
+        tvh_codec_register(&tvh_codec_vaapi_hevc);
+        tvh_codec_register(&tvh_codec_vaapi_vp8);
+        tvh_codec_register(&tvh_codec_vaapi_vp9);
+    }
 #endif
 
 #if ENABLE_NVENC
index 5cd7ca339abc8b48cab7eaa2f946014d84b287bc..27b699e2458e93ae6e055755bbfa413f7834c5f7 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "idnode.h"
 #include "htsmsg.h"
+#include "transcoding/codec/vainfo.h"
 
 /* defines */
 #define VAAPI_ENC_PLATFORM_UNCONSTRAINED             0
 #define VAAPI_ENC_LEVEL_HEVC_61                   183
 #define VAAPI_ENC_LEVEL_HEVC_62                   186
 
+#define VAAPI_ENC_B_REFERENCE_SKIP      0
+#define VAAPI_ENC_B_REFERENCE_I_P       1
+#define VAAPI_ENC_B_REFERENCE_I_P_B     2
+
+#define UI_CODEC_AVAILABLE_OFFSET       0
+#define UI_MAX_B_FRAMES_OFFSET          1
+#define UI_MAX_QUALITY_OFFSET           4
+
+#define TVH_CODEC_PROFILE_VAAPI_UI(codec) \
+    (vainfo_encoder_isavailable(VAINFO_##codec)) + \
+    (vainfo_encoder_maxBfreames(VAINFO_##codec) << UI_MAX_B_FRAMES_OFFSET) + \
+    (vainfo_encoder_maxQuality(VAINFO_##codec) << UI_MAX_QUALITY_OFFSET)
+
 /* hts ==================================================================== */
 
 static htsmsg_t *
@@ -92,6 +106,18 @@ platform_get_list( void *o, const char *lang )
     return strtab2htsmsg(tab, 1, lang);
 }
 
+
+static htsmsg_t *
+b_reference_get_list( void *o, const char *lang )
+{
+    static const struct strtab tab[] = {
+        { N_("skip"),               VAAPI_ENC_B_REFERENCE_SKIP },
+        { N_("use P- or I-frames"), VAAPI_ENC_B_REFERENCE_I_P },
+        { N_("use any frame"),      VAAPI_ENC_B_REFERENCE_I_P_B },
+    };
+    return strtab2htsmsg(tab, 1, lang);
+}
+
 static htsmsg_t *
 rc_mode_get_list( void *o, const char *lang )
 {
@@ -179,10 +205,66 @@ typedef struct {
     TVHVideoCodecProfile;
     int qp;
     int quality;
+    int global_quality;
     int async_depth;
+/**
+ * VAAPI Encoder availablity.
+ * @note
+ * return: 
+ * bit0 - will show if normal encoder is available (VAEntrypointEncSlice)
+ */
+    int ui;
+/**
+ * VAAPI Encoder Low power availablity.
+ * @note
+ * return: 
+ * bit0 - will show if low power encoder is available (VAEntrypointEncSliceLP)
+ */
+    int uilp;
+/**
+ * VAAPI Frame used as reference for B-frame [b_depth]
+ * https://www.ffmpeg.org/ffmpeg-codecs.html#toc-VAAPI-encoders
+ * @note
+ * int: 
+ * 0 - skip
+ * 1 - all B-frames will refer only to P- or I-frames
+ * 2 - multiple layers of B-frames will be present
+ */
+    int b_reference;
+/**
+ * VAAPI Maximum consecutive B-frame [bf]
+ * https://www.ffmpeg.org/ffmpeg-codecs.html#toc-VAAPI-encoders
+ * @note
+ * int: 
+ * 0 - no B-Frames allowed
+ * >0 - number of consecutive B-frames (valid with b_reference = 1 --> "use P- or I-frames")
+ */
     int desired_b_depth;
+/**
+ * VAAPI Maximum bitrate [maxrate]
+ * https://www.ffmpeg.org/ffmpeg-codecs.html#toc-VAAPI-encoders
+ * @note
+ * int: 
+ * VALUE - max bitrate in bps
+ */
     double max_bit_rate;
+/**
+ * VAAPI Maximum bitrate [maxrate]
+ * https://www.ffmpeg.org/ffmpeg-codecs.html#toc-VAAPI-encoders
+ * @note
+ * double: 
+ * VALUE - max bitrate in bps
+ */
     double bit_rate_scale_factor;
+/**
+ * VAAPI Platform hardware [not ffmpeg parameter]
+ * https://www.ffmpeg.org/ffmpeg-codecs.html#toc-VAAPI-encoders
+ * @note
+ * int: 
+ * 0 - Unconstrained (usefull for debug)
+ * 1 - Intel
+ * 2 - AMD
+ */
     int platform;
     int loop_filter_level;
     int loop_filter_sharpness;
@@ -268,6 +350,36 @@ tvh_codec_profile_vaapi_device_list(void *obj, const char *lang)
     return result;
 }
 
+#define TVH_CODEC_PROFILE_VAAPI_CODEC_UI(codec_ui, codec_name) \
+    static const int tvh_codec_profile_vaapi_##codec_ui##_ui(void) \
+    { \
+        return TVH_CODEC_PROFILE_VAAPI_UI(codec_name); \
+    }
+
+// static const int tvh_codec_profile_vaapi_h264_ui(void)
+TVH_CODEC_PROFILE_VAAPI_CODEC_UI(h264, H264)
+
+// static const int tvh_codec_profile_vaapi_hevc_ui(void)
+TVH_CODEC_PROFILE_VAAPI_CODEC_UI(hevc, HEVC)
+
+// static const int tvh_codec_profile_vaapi_vp8_ui(void)
+TVH_CODEC_PROFILE_VAAPI_CODEC_UI(vp8, VP8)
+
+// static const int tvh_codec_profile_vaapi_vp9_ui(void)
+TVH_CODEC_PROFILE_VAAPI_CODEC_UI(vp9, VP9)
+
+// static const int tvh_codec_profile_vaapi_h264lp_ui(void)
+TVH_CODEC_PROFILE_VAAPI_CODEC_UI(h264lp, H264_LOW_POWER)
+
+// static const int tvh_codec_profile_vaapi_hevclp_ui(void)
+TVH_CODEC_PROFILE_VAAPI_CODEC_UI(hevclp, HEVC_LOW_POWER)
+
+// static const int tvh_codec_profile_vaapi_vp8lp_ui(void)
+TVH_CODEC_PROFILE_VAAPI_CODEC_UI(vp8lp, VP8_LOW_POWER)
+
+// static const int tvh_codec_profile_vaapi_vp9lp_ui(void)
+TVH_CODEC_PROFILE_VAAPI_CODEC_UI(vp9lp, VP9_LOW_POWER)
+
 static int
 tvh_codec_profile_vaapi_open(tvh_codec_profile_vaapi_t *self,
                              AVDictionary **opts)
@@ -309,7 +421,7 @@ static const codec_profile_class_t codec_profile_vaapi_class = {
                 .type     = PT_BOOL,
                 .id       = "low_power",     // Don't change
                 .name     = N_("Low Power"),
-                .desc     = N_("Set low power mode.[if disabled will not send parameter to libav, if enabled codec will disable B frames]"),
+                .desc     = N_("Set low power mode.[if disabled will not send 'low power' parameter to libav]"),
                 .group    = 3,
                 .opts     = PO_EXPERT,
                 .get_opts = codec_profile_class_get_opts,
@@ -331,12 +443,23 @@ static const codec_profile_class_t codec_profile_vaapi_class = {
                 .type     = PT_INT,
                 .id       = "desired_b_depth",     // Don't change
                 .name     = N_("Maximum B-frame"),
-                .desc     = N_("Maximum B-frame reference depth (from 1 to 3) (default 1)"),
+                .desc     = N_("Maximum B-frame depth (from 0 to 7, -1=skip) (default 0)"),
                 .group    = 3,
                 .get_opts = codec_profile_class_get_opts,
                 .off      = offsetof(tvh_codec_profile_vaapi_t, desired_b_depth),
-                .intextra = INTEXTRA_RANGE(0, 3, 1),
-                .def.i    = 1,
+                .intextra = INTEXTRA_RANGE(-1, 7, 1),
+                .def.i    = 0,
+            },
+            {
+                .type     = PT_INT,
+                .id       = "b_reference",     // Don't change
+                .name     = N_("B-frame reference"),
+                .desc     = N_("Frame used as reference for B-frame (default 0)"),
+                .group    = 3,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, b_reference),
+                .list     = b_reference_get_list,
+                .def.i    = 0,
             },
             {
                 .type     = PT_INT,
@@ -444,6 +567,19 @@ static const codec_profile_class_t codec_profile_vaapi_class = {
                 .intextra = INTEXTRA_RANGE(0, 64, 1),
                 .def.i    = 44,
             },
+            {
+                .type     = PT_INT,
+                .id       = "quality",     // Don't change
+                .name     = N_("Quality"),
+                .desc     = N_("Set encode quality (trades off against speed, "
+                               "higher is faster) [-1=skip 0-15]."),
+                .group    = 5,
+                .opts     = PO_EXPERT,
+                .get_opts = codec_profile_class_get_opts,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, quality),
+                .intextra = INTEXTRA_RANGE(-1, 15, 1),
+                .def.i    = 0,
+            },
             {}
         }
     },
@@ -471,6 +607,11 @@ tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
     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)));
+    // force max_bitrate to be >= with bitrate (to avoid crash)
+    if (int_bitrate > int_max_bitrate) {
+        tvherror(LS_VAAPI, "Bitrate %d kbps is greater than Max bitrate %d kbps, increase Max bitrate to %d kbps", int_bitrate / 1024, int_max_bitrate / 1024, int_bitrate / 1024);
+        int_max_bitrate = int_bitrate;
+    }
     tvhinfo(LS_VAAPI, "Bitrate = %d kbps; Buffer size = %d kbps; Max bitrate = %d kbps", int_bitrate / 1024, int_buffer_size / 1024, int_max_bitrate / 1024);
     // https://wiki.libav.org/Hardware/vaapi
     // https://blog.wmspanel.com/2017/03/vaapi-libva-support-nimble-streamer.html
@@ -524,15 +665,18 @@ tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
     //    6               60           E..V.......
     //    6.1             61           E..V.......
     //    6.2             62           E..V.......
-    if (self->rc_mode >= 0) {
+    if (self->rc_mode != VAAPI_ENC_PARAMS_RC_SKIP) {
         AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
     }
     switch (self->platform) {
-        case 0:
+        case VAAPI_ENC_PLATFORM_UNCONSTRAINED:
             // Uncontrained --> will allow any combination of parameters (valid or invalid)
             // this mode is usefull fur future platform and for debugging.
-            if ((self->low_power == 0) && (self->desired_b_depth)) {
-                AV_DICT_SET_INT(opts, "b_depth", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+            if (self->b_reference) {
+                // b_depth
+                AV_DICT_SET_INT(opts, "b_depth", self->b_reference, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->desired_b_depth >= 0) {
                 // max_b_frames
                 AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
             }
@@ -565,17 +709,34 @@ tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET_INT(opts, "qmax", self->qmax, AV_DICT_DONT_OVERWRITE);
             }
             break;
-        case 1:
+        case VAAPI_ENC_PLATFORM_INTEL:
             // Intel
-            if ((self->low_power == 0) && (self->desired_b_depth)) {
-                AV_DICT_SET_INT(opts, "b_depth", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+            int tempSupport = 0;
+            if (self->low_power) {
+                tempSupport = vainfo_encoder_maxBfreames(VAINFO_H264_LOW_POWER);
+            }
+            else {
+                tempSupport = vainfo_encoder_maxBfreames(VAINFO_H264);
+            }
+            if (tempSupport) {
+                if (self->b_reference) {
+                    // b_depth
+                    AV_DICT_SET_INT(opts, "b_depth", self->b_reference, AV_DICT_DONT_OVERWRITE);
+                }
+                if (self->desired_b_depth >= 0) {
+                    // max_b_frames
+                    AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+                }
+            }
+            else {
                 // max_b_frames
-                AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "bf", 0, AV_DICT_DONT_OVERWRITE);
             }
+
             switch (self->rc_mode) {
-                case -1:
+                case VAAPI_ENC_PARAMS_RC_SKIP:
                     // same like 0 but is not sending 'rc_mode'
-                case 0:
+                case VAAPI_ENC_PARAMS_RC_AUTO:
                     // 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);
@@ -588,21 +749,21 @@ tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 1:
-                case 4:
+                case VAAPI_ENC_PARAMS_RC_CONSTQP:
+                case VAAPI_ENC_PARAMS_RC_ICQ:
                     // 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:
+                case VAAPI_ENC_PARAMS_RC_CBR:
                     // 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:
+                case VAAPI_ENC_PARAMS_RC_VBR:
                     // 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);
@@ -610,7 +771,7 @@ tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 5:
+                case VAAPI_ENC_PARAMS_RC_QVBR:
                     // 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);
@@ -621,7 +782,7 @@ tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 6:
+                case VAAPI_ENC_PARAMS_RC_AVBR:
                     // 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);
@@ -629,7 +790,13 @@ tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
                     }
                     break;
             }
-            if (self->quality >= 0) {
+            if (self->low_power) {
+                tempSupport = vainfo_encoder_maxQuality(VAINFO_H264_LOW_POWER);
+            }
+            else {
+                tempSupport = vainfo_encoder_maxQuality(VAINFO_H264);
+            }
+            if (tempSupport && (self->quality >= 0)) {
                 AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
             }
             if (self->low_power) {
@@ -648,7 +815,7 @@ tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET_INT(opts, "qmax", self->qmax, AV_DICT_DONT_OVERWRITE);
             }
             break;
-        case 2:
+        case VAAPI_ENC_PLATFORM_AMD:
             // 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)
@@ -696,19 +863,6 @@ static const codec_profile_class_t codec_profile_vaapi_h264_class = {
         .ic_class      = "codec_profile_vaapi_h264",
         .ic_caption    = N_("vaapi_h264"),
         .ic_properties = (const property_t[]){
-            {
-                .type     = PT_INT,
-                .id       = "quality",     // Don't change
-                .name     = N_("Quality"),
-                .desc     = N_("Set encode quality (trades off against speed, "
-                               "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(-1, 7, 1),
-                .def.i    = 0,
-            },
             {
                 .type     = PT_INT,
                 .id       = "level",     // Don't change
@@ -721,6 +875,26 @@ static const codec_profile_class_t codec_profile_vaapi_h264_class = {
                 .list     = h264_level_get_list,
                 .def.i    = VAAPI_ENC_LEVEL_H264_3,
             },
+            {
+                .type     = PT_DYN_INT,
+                .id       = "ui",     // Don't change
+                .name     = N_("User Interface"),
+                .desc     = N_("User Interface (bits will show what features are available)."),
+                .group    = 3,
+                .opts     = PO_PHIDDEN,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, ui),
+                .def.dyn_i= tvh_codec_profile_vaapi_h264_ui,
+            },
+            {
+                .type     = PT_DYN_INT,
+                .id       = "uilp",     // Don't change
+                .name     = N_("User Interface (low power)"),
+                .desc     = N_("User Interface (bits will show what features are available)."),
+                .group    = 3,
+                .opts     = PO_PHIDDEN,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, uilp),
+                .def.dyn_i= tvh_codec_profile_vaapi_h264lp_ui,
+            },
             {}
         }
     },
@@ -758,6 +932,11 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
     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)));
+    // force max_bitrate to be >= with bitrate (to avoid crash)
+    if (int_bitrate > int_max_bitrate) {
+        tvherror(LS_VAAPI, "Bitrate %d kbps is greater than Max bitrate %d kbps, increase Max bitrate to %d kbps", int_bitrate / 1024, int_max_bitrate / 1024, int_bitrate / 1024);
+        int_max_bitrate = int_bitrate;
+    }
     tvhinfo(LS_VAAPI, "Bitrate = %d kbps; Buffer size = %d kbps; Max bitrate = %d kbps", int_bitrate / 1024, int_buffer_size / 1024, int_max_bitrate / 1024);
     // https://wiki.libav.org/Hardware/vaapi
     // to find available parameters use:
@@ -801,15 +980,18 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
     //    hdr                          E..V....... Include HDR metadata for mastering display colour volume and content light level information
     // -tiles             <image_size> E..V....... Tile columns x rows
 
-    if (self->rc_mode >= 0) {
+    if (self->rc_mode != VAAPI_ENC_PARAMS_RC_SKIP) {
         AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
     }
     switch (self->platform) {
-        case 0:
+        case VAAPI_ENC_PLATFORM_UNCONSTRAINED:
             // Unconstrained --> will allow any combination of parameters (valid or invalid)
             // this mode is usefull fur future platform and for debugging.
-            if ((self->low_power == 0) && (self->desired_b_depth)) {
-                AV_DICT_SET_INT(opts, "b_depth", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+            if (self->b_reference) {
+                // b_depth
+                AV_DICT_SET_INT(opts, "b_depth", self->b_reference, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->desired_b_depth >= 0) {
                 // max_b_frames
                 AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
             }
@@ -826,6 +1008,9 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
             if (self->tier >= 0) {
                 AV_DICT_SET_INT(opts, "tier", self->tier, 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);
             }
@@ -842,17 +1027,20 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET_INT(opts, "qmax", self->qmax, AV_DICT_DONT_OVERWRITE);
             }
             break;
-        case 1:
+        case VAAPI_ENC_PLATFORM_INTEL:
             // Intel
-            if ((self->low_power == 0) && (self->desired_b_depth)) {
-                AV_DICT_SET_INT(opts, "b_depth", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+            if (self->b_reference) {
+                // b_depth
+                AV_DICT_SET_INT(opts, "b_depth", self->b_reference, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->desired_b_depth >= 0) {
                 // max_b_frames
                 AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
             }
             switch (self->rc_mode) {
-                case -1:
+                case VAAPI_ENC_PARAMS_RC_SKIP:
                     // same like 0 but is not sending 'rc_mode'
-                case 0:
+                case VAAPI_ENC_PARAMS_RC_AUTO:
                     // 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);
@@ -865,21 +1053,21 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 1:
-                case 4:
+                case VAAPI_ENC_PARAMS_RC_CONSTQP:
+                case VAAPI_ENC_PARAMS_RC_ICQ:
                     // 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:
+                case VAAPI_ENC_PARAMS_RC_CBR:
                     // 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:
+                case VAAPI_ENC_PARAMS_RC_VBR:
                     // 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);
@@ -887,7 +1075,7 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 5:
+                case VAAPI_ENC_PARAMS_RC_QVBR:
                     // 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);
@@ -898,7 +1086,7 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 6:
+                case VAAPI_ENC_PARAMS_RC_AVBR:
                     // 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);
@@ -909,6 +1097,9 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
             if (self->tier >= 0) {
                 AV_DICT_SET_INT(opts, "tier", self->tier, 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);
             }
@@ -925,7 +1116,7 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET_INT(opts, "qmax", self->qmax, AV_DICT_DONT_OVERWRITE);
             }
             break;
-        case 2:
+        case VAAPI_ENC_PLATFORM_AMD:
             // 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)
@@ -943,6 +1134,9 @@ tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
             if (self->tier >= 0) {
                 AV_DICT_SET_INT(opts, "tier", self->tier, 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);
             }
@@ -996,6 +1190,26 @@ static const codec_profile_class_t codec_profile_vaapi_hevc_class = {
                 .list     = hevc_level_get_list,
                 .def.i    = VAAPI_ENC_LEVEL_HEVC_3,
             },
+            {
+                .type     = PT_DYN_INT,
+                .id       = "ui",     // Don't change
+                .name     = N_("User Interface"),
+                .desc     = N_("User Interface (bits will show what features are available)."),
+                .group    = 3,
+                .opts     = PO_PHIDDEN,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, ui),
+                .def.dyn_i= tvh_codec_profile_vaapi_hevc_ui,
+            },
+            {
+                .type     = PT_DYN_INT,
+                .id       = "uilp",     // Don't change
+                .name     = N_("User Interface (low power)"),
+                .desc     = N_("User Interface (bits will show what features are available)."),
+                .group    = 3,
+                .opts     = PO_PHIDDEN,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, uilp),
+                .def.dyn_i= tvh_codec_profile_vaapi_hevclp_ui,
+            },
             {}
         }
     },
@@ -1030,6 +1244,11 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
     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)));
+    // force max_bitrate to be >= with bitrate (to avoid crash)
+    if (int_bitrate > int_max_bitrate) {
+        tvherror(LS_VAAPI, "Bitrate %d kbps is greater than Max bitrate %d kbps, increase Max bitrate to %d kbps", int_bitrate / 1024, int_max_bitrate / 1024, int_bitrate / 1024);
+        int_max_bitrate = int_bitrate;
+    }
     tvhinfo(LS_VAAPI, "Bitrate = %d kbps; Buffer size = %d kbps; Max bitrate = %d kbps", int_bitrate / 1024, int_buffer_size / 1024, int_max_bitrate / 1024);
     // https://wiki.libav.org/Hardware/vaapi
     // to find available parameters use:
@@ -1049,15 +1268,18 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
     // -loop_filter_level <int>        E..V....... Loop filter level (from 0 to 63) (default 16)
     // -loop_filter_sharpness <int>        E..V....... Loop filter sharpness (from 0 to 15) (default 4)
 
-    if (self->rc_mode >= 0) {
+    if (self->rc_mode != VAAPI_ENC_PARAMS_RC_SKIP) {
         AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
     }
     switch (self->platform) {
-        case 0:
+        case VAAPI_ENC_PLATFORM_UNCONSTRAINED:
             // Unconstrained --> will allow any combination of parameters (valid or invalid)
             // this mode is usefull fur future platform and for debugging.
-            if ((self->low_power == 0) && (self->desired_b_depth)) {
-                AV_DICT_SET_INT(opts, "b_depth", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+            if (self->b_reference) {
+                // b_depth
+                AV_DICT_SET_INT(opts, "b_depth", self->b_reference, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->desired_b_depth >= 0) {
                 // max_b_frames
                 AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
             }
@@ -1072,7 +1294,10 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
                 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);
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->global_quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->global_quality, AV_DICT_DONT_OVERWRITE);
             }
             if (self->low_power) {
                 AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
@@ -1093,20 +1318,26 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET_INT(opts, "qmax", self->qmax, AV_DICT_DONT_OVERWRITE);
             }
             break;
-        case 1:
+        case VAAPI_ENC_PLATFORM_INTEL:
             // Intel
-            if ((self->low_power == 0) && (self->desired_b_depth)) {
-                AV_DICT_SET_INT(opts, "b_depth", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+            if (self->b_reference) {
+                // b_depth
+                AV_DICT_SET_INT(opts, "b_depth", self->b_reference, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->desired_b_depth >= 0) {
                 // max_b_frames
                 AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
             }
             if (self->quality >= 0) {
-                AV_DICT_SET_INT(opts, "global_quality", self->quality, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->global_quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->global_quality, AV_DICT_DONT_OVERWRITE);
             }
             switch (self->rc_mode) {
-                case -1:
+                case VAAPI_ENC_PARAMS_RC_SKIP:
                     // same like 0 but is not sending 'rc_mode'
-                case 0:
+                case VAAPI_ENC_PARAMS_RC_AUTO:
                     // 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);
@@ -1119,21 +1350,21 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 1:
-                case 4:
+                case VAAPI_ENC_PARAMS_RC_CONSTQP:
+                case VAAPI_ENC_PARAMS_RC_ICQ:
                     // 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:
+                case VAAPI_ENC_PARAMS_RC_CBR:
                     // 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:
+                case VAAPI_ENC_PARAMS_RC_VBR:
                     // 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);
@@ -1141,7 +1372,7 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 5:
+                case VAAPI_ENC_PARAMS_RC_QVBR:
                     // 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);
@@ -1152,7 +1383,7 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 6:
+                case VAAPI_ENC_PARAMS_RC_AVBR:
                     // 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);
@@ -1179,7 +1410,7 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET_INT(opts, "qmax", self->qmax, AV_DICT_DONT_OVERWRITE);
             }
             break;
-        case 2:
+        case VAAPI_ENC_PLATFORM_AMD:
             // 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)
@@ -1195,7 +1426,10 @@ tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
             }
             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);
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->global_quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->global_quality, AV_DICT_DONT_OVERWRITE);
             }
             if (self->low_power) {
                 AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
@@ -1231,13 +1465,13 @@ static const codec_profile_class_t codec_profile_vaapi_vp8_class = {
         .ic_properties = (const property_t[]){
             {
                 .type     = PT_INT,
-                .id       = "quality",     // Don't change
+                .id       = "global_quality",     // Don't change
                 .name     = N_("Global Quality"),
-                .desc     = N_("Set encode quality [-1=skip 0-127]."),
+                .desc     = N_("Set encode global 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),
+                .off      = offsetof(tvh_codec_profile_vaapi_t, global_quality),
                 .intextra = INTEXTRA_RANGE(-1, 127, 1),
                 .def.i    = 40,
             },
@@ -1265,6 +1499,26 @@ static const codec_profile_class_t codec_profile_vaapi_vp8_class = {
                 .intextra = INTEXTRA_RANGE(-1, 15, 1),
                 .def.i    = 4,
             },
+            {
+                .type     = PT_DYN_INT,
+                .id       = "ui",     // Don't change
+                .name     = N_("User Interface"),
+                .desc     = N_("User Interface (bits will show what features are available)."),
+                .group    = 3,
+                .opts     = PO_PHIDDEN,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, ui),
+                .def.dyn_i= tvh_codec_profile_vaapi_vp8_ui,
+            },
+            {
+                .type     = PT_DYN_INT,
+                .id       = "uilp",     // Don't change
+                .name     = N_("User Interface (low power)"),
+                .desc     = N_("User Interface (bits will show what features are available)."),
+                .group    = 3,
+                .opts     = PO_PHIDDEN,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, uilp),
+                .def.dyn_i= tvh_codec_profile_vaapi_vp8lp_ui,
+            },
             {}
         }
     },
@@ -1298,6 +1552,11 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
     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)));
+    // force max_bitrate to be >= with bitrate (to avoid crash)
+    if (int_bitrate > int_max_bitrate) {
+        tvherror(LS_VAAPI, "Bitrate %d kbps is greater than Max bitrate %d kbps, increase Max bitrate to %d kbps", int_bitrate / 1024, int_max_bitrate / 1024, int_bitrate / 1024);
+        int_max_bitrate = int_bitrate;
+    }
     tvhinfo(LS_VAAPI, "Bitrate = %d kbps; Buffer size = %d kbps; Max bitrate = %d kbps", int_bitrate / 1024, int_buffer_size / 1024, int_max_bitrate / 1024);
     // https://wiki.libav.org/Hardware/vaapi
     // to find available parameters use:
@@ -1317,15 +1576,18 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
     // -loop_filter_level <int>        E..V....... Loop filter level (from 0 to 63) (default 16)
     // -loop_filter_sharpness <int>        E..V....... Loop filter sharpness (from 0 to 15) (default 4)
 
-    if (self->rc_mode >= 0) {
+    if (self->rc_mode != VAAPI_ENC_PARAMS_RC_SKIP) {
         AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
     }
     switch (self->platform) {
-        case 0:
+        case VAAPI_ENC_PLATFORM_UNCONSTRAINED:
             // Unconstrained --> will allow any combination of parameters (valid or invalid)
             // this mode is usefull fur future platform and for debugging.
-            if ((self->low_power == 0) && (self->desired_b_depth)) {
-                AV_DICT_SET_INT(opts, "b_depth", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+            if (self->b_reference) {
+                // b_depth
+                AV_DICT_SET_INT(opts, "b_depth", self->b_reference, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->desired_b_depth >= 0) {
                 // max_b_frames
                 AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
             }
@@ -1345,7 +1607,10 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
                 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);
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->global_quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->global_quality, AV_DICT_DONT_OVERWRITE);
             }
             if (self->low_power) {
                 AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
@@ -1366,10 +1631,13 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET_INT(opts, "qmax", self->qmax, AV_DICT_DONT_OVERWRITE);
             }
             break;
-        case 1:
+        case VAAPI_ENC_PLATFORM_INTEL:
             // Intel
-            if ((self->low_power == 0) && (self->desired_b_depth)) {
-                AV_DICT_SET_INT(opts, "b_depth", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
+            if (self->b_reference) {
+                // b_depth
+                AV_DICT_SET_INT(opts, "b_depth", self->b_reference, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->desired_b_depth >= 0) {
                 // max_b_frames
                 AV_DICT_SET_INT(opts, "bf", self->desired_b_depth, AV_DICT_DONT_OVERWRITE);
             }
@@ -1379,12 +1647,15 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET(opts, "bsf", "vp9_raw_reorder,vp9_superframe", AV_DICT_DONT_OVERWRITE);
             }
             if (self->quality >= 0) {
-                AV_DICT_SET_INT(opts, "global_quality", self->quality, AV_DICT_DONT_OVERWRITE);
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->global_quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->global_quality, AV_DICT_DONT_OVERWRITE);
             }
             switch (self->rc_mode) {
-                case -1:
+                case VAAPI_ENC_PARAMS_RC_SKIP:
                     // same like 0 but is not sending 'rc_mode'
-                case 0:
+                case VAAPI_ENC_PARAMS_RC_AUTO:
                     // 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);
@@ -1397,21 +1668,21 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 1:
-                case 4:
+                case VAAPI_ENC_PARAMS_RC_CONSTQP:
+                case VAAPI_ENC_PARAMS_RC_ICQ:
                     // 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:
+                case VAAPI_ENC_PARAMS_RC_CBR:
                     // 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:
+                case VAAPI_ENC_PARAMS_RC_VBR:
                     // 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);
@@ -1419,7 +1690,7 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "bufsize", int_buffer_size, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 5:
+                case VAAPI_ENC_PARAMS_RC_QVBR:
                     // 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);
@@ -1430,7 +1701,7 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
                         AV_DICT_SET_INT(opts, "qp", self->qp, AV_DICT_DONT_OVERWRITE);
                     }
                     break;
-                case 6:
+                case VAAPI_ENC_PARAMS_RC_AVBR:
                     // 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);
@@ -1457,7 +1728,7 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
                 AV_DICT_SET_INT(opts, "qmax", self->qmax, AV_DICT_DONT_OVERWRITE);
             }
             break;
-        case 2:
+        case VAAPI_ENC_PLATFORM_AMD:
             // 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)
@@ -1473,7 +1744,10 @@ tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
             }
             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);
+                AV_DICT_SET_INT(opts, "quality", self->quality, AV_DICT_DONT_OVERWRITE);
+            }
+            if (self->global_quality >= 0) {
+                AV_DICT_SET_INT(opts, "global_quality", self->global_quality, AV_DICT_DONT_OVERWRITE);
             }
             if (self->low_power) {
                 AV_DICT_SET_INT(opts, "low_power", self->low_power, AV_DICT_DONT_OVERWRITE);
@@ -1509,13 +1783,13 @@ static const codec_profile_class_t codec_profile_vaapi_vp9_class = {
         .ic_properties = (const property_t[]){
             {
                 .type     = PT_INT,
-                .id       = "quality",     // Don't change
+                .id       = "global_quality",     // Don't change
                 .name     = N_("Global Quality"),
-                .desc     = N_("Set encode quality [-1=skip 0-255]."),
+                .desc     = N_("Set encode global 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),
+                .off      = offsetof(tvh_codec_profile_vaapi_t, global_quality),
                 .intextra = INTEXTRA_RANGE(-1, 255, 1),
                 .def.i    = 40,
             },
@@ -1554,6 +1828,26 @@ static const codec_profile_class_t codec_profile_vaapi_vp9_class = {
                 .off      = offsetof(tvh_codec_profile_vaapi_t, super_frame),
                 .def.i    = 0,
             },
+            {
+                .type     = PT_DYN_INT,
+                .id       = "ui",     // Don't change
+                .name     = N_("User Interface"),
+                .desc     = N_("User Interface (bits will show what features are available)."),
+                .group    = 3,
+                .opts     = PO_PHIDDEN,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, ui),
+                .def.dyn_i= tvh_codec_profile_vaapi_vp9_ui,
+            },
+            {
+                .type     = PT_DYN_INT,
+                .id       = "uilp",     // Don't change
+                .name     = N_("User Interface (low power)"),
+                .desc     = N_("User Interface (bits will show what features are available)."),
+                .group    = 3,
+                .opts     = PO_PHIDDEN,
+                .off      = offsetof(tvh_codec_profile_vaapi_t, uilp),
+                .def.dyn_i= tvh_codec_profile_vaapi_vp9lp_ui,
+            },
             {}
         }
     },
index 978bf717581af5982e6c1d8ecf5758a317474717..db88d575bddb381105e9e02bd35065ab4ea163fa 100644 (file)
@@ -153,7 +153,11 @@ TVHCodec *
 tvh_codec_find(const char *name);
 
 void
+#if ENABLE_VAAPI
+tvh_codecs_register(int vainfo_probe_enabled);
+#else
 tvh_codecs_register(void);
+#endif
 
 void
 tvh_codecs_forget(void);
index 8c78eda5fca3438c2b99c71c3b1dda0c1b27ccaa..bfe62442735e60306bd38ddc3e20c5cd21e1c98f 100644 (file)
@@ -58,10 +58,18 @@ codec_get_profiles_list(enum AVMediaType media_type)
 
 
 void
+#if ENABLE_VAAPI
+codec_init(int vainfo_probe_enabled)
+#else
 codec_init(void)
+#endif
 {
     // codecs
+#if ENABLE_VAAPI
+    tvh_codecs_register(vainfo_probe_enabled);
+#else
     tvh_codecs_register();
+#endif
     // codec profiles
     tvh_codec_profiles_load();
 }
index 35bd9353a3e5d3b5be44d21f4e3882c4e111064b..00bfbbf998efc0546e7c013ee7edc9fa04c0fab0 100644 (file)
@@ -126,8 +126,6 @@ tvh_codec_profile_video_open(TVHVideoCodecProfile *self, AVDictionary **opts)
     }
     // pix_fmt
     AV_DICT_SET_PIX_FMT(opts, self->pix_fmt, AV_PIX_FMT_YUV420P);
-    // max_b_frames
-    AV_DICT_SET_INT(opts, "bf", 3, AV_DICT_DONT_OVERWRITE);
     return 0;
 }
 
diff --git a/src/transcoding/codec/vainfo.c b/src/transcoding/codec/vainfo.c
new file mode 100644 (file)
index 0000000..cca42a1
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ *  tvheadend - Transcoding
+ *
+ *  Copyright (C) 2023 Tvheadend
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "vainfo.h"
+#include "internals.h"
+
+#if ENABLE_VAAPI
+#include <va/va.h>
+#include <fcntl.h>
+#include <va/va_drm.h>
+#include <va/va_str.h>
+#endif
+
+#define CODEC_IS_AVAILABLE      1
+#define CODEC_IS_NOT_AVAILABLE  0
+#define MIN_B_FRAMES            0
+#define MAX_B_FRAMES            7
+#define MIN_QUALITY             0
+#define MAX_QUALITY             15
+
+/* external =================================================================== */
+#if ENABLE_VAAPI
+// this variable is loaded from config: Enable vaapi detection
+extern int vainfo_probe_enabled;
+#endif
+
+/* internal =================================================================== */
+int encoder_h264_isavailable = 0;
+int encoder_h264lp_isavailable = 0;
+int encoder_hevc_isavailable = 0;
+int encoder_hevclp_isavailable = 0;
+int encoder_vp8_isavailable = 0;
+int encoder_vp8lp_isavailable = 0;
+int encoder_vp9_isavailable = 0;
+int encoder_vp9lp_isavailable = 0;
+
+int encoder_h264_maxBfreames = 0;
+int encoder_h264lp_maxBfreames = 0;
+int encoder_hevc_maxBfreames = 0;
+int encoder_hevclp_maxBfreames = 0;
+int encoder_vp8_maxBfreames = 0;
+int encoder_vp8lp_maxBfreames = 0;
+int encoder_vp9_maxBfreames = 0;
+int encoder_vp9lp_maxBfreames = 0;
+
+int encoder_h264_maxQuality = 0;
+int encoder_h264lp_maxQuality = 0;
+int encoder_hevc_maxQuality = 0;
+int encoder_hevclp_maxQuality = 0;
+int encoder_vp8_maxQuality = 0;
+int encoder_vp8lp_maxQuality = 0;
+int encoder_vp9_maxQuality = 0;
+int encoder_vp9lp_maxQuality = 0;
+
+#if ENABLE_VAAPI
+/**
+ * VAINFO was initialized
+ * @note
+ * return: 
+ * 0 - not initialized --> will return invalid data
+ * 1 - initialized properly
+ * 
+ * NOTE: initialization was performed in /src/transcoding/codec/codec.c
+ */
+int init_done = 0;
+
+int init(int show_log);
+
+static int drm_fd = -1;
+
+static VADisplay
+va_open_display_drm(void)
+{
+    VADisplay va_dpy;
+    int i;
+    static const char *drm_device_paths[] = {
+        "/dev/dri/renderD128",
+        "/dev/dri/card0",
+        "/dev/dri/renderD129",
+        "/dev/dri/card1",
+        NULL
+    };
+    for (i = 0; drm_device_paths[i]; i++) {
+        drm_fd = open(drm_device_paths[i], O_RDWR);
+        if (drm_fd < 0)
+            continue;
+        va_dpy = vaGetDisplayDRM(drm_fd);
+        if (va_dpy)
+            return va_dpy;
+
+        close(drm_fd);
+        drm_fd = -1;
+    }
+    return NULL;
+}
+
+static void
+va_close_display_drm(VADisplay va_dpy)
+{
+    if (drm_fd < 0)
+        return;
+
+    close(drm_fd);
+    drm_fd = -1;
+}
+
+
+static int 
+get_config_attributes(VADisplay va_dpy, VAProfile profile, VAEntrypoint entrypoint, int show_log, int codec)
+{
+
+    VAStatus va_status;
+    int i, temp;
+
+    VAConfigAttrib attrib_list[VAConfigAttribTypeMax];
+    int max_num_attributes = VAConfigAttribTypeMax;
+
+    for (i = 0; i < max_num_attributes; i++) {
+        attrib_list[i].type = i;
+    }
+
+    va_status = vaGetConfigAttributes(va_dpy,
+                                      profile, entrypoint,
+                                      attrib_list, max_num_attributes);
+    if (VA_STATUS_ERROR_UNSUPPORTED_PROFILE == va_status ||
+        VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT == va_status)
+        return 0;
+
+    if (attrib_list[VAConfigAttribEncMaxRefFrames].value & (~VA_ATTRIB_NOT_SUPPORTED)) {
+        if (show_log) {
+            tvhinfo(LS_VAINFO, "            %-35s: l0=%d, l1=%d", vaConfigAttribTypeStr(attrib_list[VAConfigAttribEncMaxRefFrames].type),
+                attrib_list[VAConfigAttribEncMaxRefFrames].value & 0xffff, 
+                (attrib_list[VAConfigAttribEncMaxRefFrames].value >> 16) & 0xffff);
+        }
+        temp = (attrib_list[VAConfigAttribEncMaxRefFrames].value >> 16) & 0xffff;
+        if (temp)
+            // this value has to be increased by 1
+            temp++;
+        // limit to max space available in ui
+        if (temp > MAX_B_FRAMES) {
+            tvherror(LS_VAINFO, "show_config_attributes() failed to set max B frames (vainfo:%d --> max=%d)", temp, MAX_B_FRAMES);
+            temp = MAX_B_FRAMES;
+        }
+        switch (codec) {
+            case VAINFO_H264:
+                encoder_h264_maxBfreames = temp;
+                break;
+            case VAINFO_H264_LOW_POWER:
+                encoder_h264lp_maxBfreames = temp;
+                break;
+            case VAINFO_HEVC:
+                encoder_hevc_maxBfreames = temp;
+                break;
+            case VAINFO_HEVC_LOW_POWER:
+                encoder_hevclp_maxBfreames = temp;
+                break;
+            case VAINFO_VP8:
+                encoder_vp8_maxBfreames = temp;
+                break;
+            case VAINFO_VP8_LOW_POWER:
+                encoder_vp8lp_maxBfreames = temp;
+                break;
+            case VAINFO_VP9:
+                encoder_vp9_maxBfreames = temp;
+                break;
+            case VAINFO_VP9_LOW_POWER:
+                encoder_vp9lp_maxBfreames = temp;
+                break;
+            default:
+                tvherror(LS_VAINFO, "codec not available: codec=%d", codec);
+                break;
+        }
+    }
+
+    if (attrib_list[VAConfigAttribEncQualityRange].value != VA_ATTRIB_NOT_SUPPORTED) {
+        if (show_log) {
+            tvhinfo(LS_VAINFO, "            %-35s: number of supported quality levels is %d", vaConfigAttribTypeStr(attrib_list[VAConfigAttribEncQualityRange].type),
+                attrib_list[VAConfigAttribEncQualityRange].value <= 1 ? 1 : attrib_list[VAConfigAttribEncQualityRange].value);
+        }
+        temp = attrib_list[VAConfigAttribEncQualityRange].value <= 1 ? 1 : attrib_list[VAConfigAttribEncQualityRange].value;
+        // limit to max space available in ui
+        if (temp > MAX_QUALITY) {
+            tvherror(LS_VAINFO, "show_config_attributes() failed to set max quality (vainfo:%d --> max=%d)", temp, MAX_QUALITY);
+            temp = MAX_QUALITY;
+        }
+        switch (codec) {
+            case VAINFO_H264:
+                encoder_h264_maxQuality = temp;
+                break;
+            case VAINFO_H264_LOW_POWER:
+                encoder_h264lp_maxQuality = temp;
+                break;
+            case VAINFO_HEVC:
+                encoder_hevc_maxQuality = temp;
+                break;
+            case VAINFO_HEVC_LOW_POWER:
+                encoder_hevclp_maxQuality = temp;
+                break;
+            case VAINFO_VP8:
+                encoder_vp8_maxQuality = temp;
+                break;
+            case VAINFO_VP8_LOW_POWER:
+                encoder_vp8lp_maxQuality = temp;
+                break;
+            case VAINFO_VP9:
+                encoder_vp9_maxQuality = temp;
+                break;
+            case VAINFO_VP9_LOW_POWER:
+                encoder_vp9lp_maxQuality = temp;
+                break;
+            default:
+                tvherror(LS_VAINFO, "codec not available: codec=%d", codec);
+                break;
+        }
+    }
+    return 0;
+}
+
+int init(int show_log)
+{
+    VADisplay va_dpy;
+    VAStatus va_status;
+    int major_version, minor_version;
+    int ret_val;
+    const char *driver;
+    int num_entrypoint = 0;
+    VAEntrypoint entrypoint, *entrypoints = NULL;
+    int num_profiles, max_num_profiles, i;
+    VAProfile profile, *profile_list = NULL;
+
+    va_dpy = va_open_display_drm();
+    if (NULL == va_dpy) {
+        tvherror(LS_VAINFO, "vaGetDisplay() failed");
+        ret_val = 2;                                                      \
+        goto error_open_display;
+    }
+
+    va_status = vaInitialize(va_dpy, &major_version, &minor_version);
+    if (va_status != VA_STATUS_SUCCESS) { 
+        tvherror(LS_VAINFO, "vaInitialize failed with error code %d (%s)", va_status, vaErrorStr(va_status));
+        ret_val = 3;
+        goto error_Initialize;
+    }
+    if (show_log)
+        tvhinfo(LS_VAINFO, "VA-API version: %d.%d", major_version, minor_version);
+
+    driver = vaQueryVendorString(va_dpy);
+    if (show_log)
+        tvhinfo(LS_VAINFO, "Driver version: %s", driver ? driver : "<unknown>");
+
+    num_entrypoint = vaMaxNumEntrypoints(va_dpy);
+    entrypoints = malloc(num_entrypoint * sizeof(VAEntrypoint));
+    if (!entrypoints) {
+        tvherror(LS_VAINFO, "Failed to allocate memory for entrypoint list");
+        ret_val = -1;
+        goto error_entrypoints;
+    }
+
+    max_num_profiles = vaMaxNumProfiles(va_dpy);
+    profile_list = malloc(max_num_profiles * sizeof(VAProfile));
+
+    if (!profile_list) {
+        tvherror(LS_VAINFO, "Failed to allocate memory for profile list");
+        ret_val = 5;
+        goto error_profile_list;
+    }
+
+    va_status = vaQueryConfigProfiles(va_dpy, profile_list, &num_profiles);
+    if (va_status != VA_STATUS_SUCCESS) { 
+        tvherror(LS_VAINFO, "vaQueryConfigProfiles failed with error code %d (%s)", va_status, vaErrorStr(va_status));
+        ret_val = 6;
+        goto error_QueryConfigProfiles;
+    }
+
+    for (i = 0; i < num_profiles; i++) {
+        profile = profile_list[i];
+        va_status = vaQueryConfigEntrypoints(va_dpy, profile, entrypoints,
+                                                &num_entrypoint);
+        if (va_status == VA_STATUS_ERROR_UNSUPPORTED_PROFILE)
+            continue;
+
+        if (va_status != VA_STATUS_SUCCESS) { 
+            tvherror(LS_VAINFO, "vaQueryConfigEntrypoints failed with error code %d (%s)", va_status, vaErrorStr(va_status));
+            ret_val = 4;
+            goto error_QueryConfigProfiles;
+        }
+
+        for (entrypoint = 0; entrypoint < num_entrypoint; entrypoint++) {
+            if (show_log)
+                tvhinfo(LS_VAINFO, "       %-32s:      %s", vaProfileStr(profile), vaEntrypointStr(entrypoints[entrypoint]));
+            // h264
+            if (profile == VAProfileH264High || profile == VAProfileH264ConstrainedBaseline || profile == VAProfileH264Main) {
+                if (entrypoints[entrypoint] == VAEntrypointEncSlice) {
+                    encoder_h264_isavailable = 1;
+                    // extract attributes
+                    ret_val = get_config_attributes(va_dpy, profile_list[i], entrypoints[entrypoint], show_log, VAINFO_H264);
+                    if (ret_val) {
+                        tvherror(LS_VAINFO, "Failed to get config attributes (error %d)", ret_val);
+                    }
+                }
+                if (entrypoints[entrypoint] == VAEntrypointEncSliceLP) {
+                    encoder_h264lp_isavailable = 1;
+                    // extract attributes
+                    ret_val = get_config_attributes(va_dpy, profile_list[i], entrypoints[entrypoint], show_log, VAINFO_H264_LOW_POWER);
+                    if (ret_val) {
+                        tvherror(LS_VAINFO, "Failed to get config attributes (error %d)", ret_val);
+                    }
+                }
+            }
+            // hevc
+            if (profile == VAProfileHEVCMain || profile == VAProfileHEVCMain10) {
+                if (entrypoints[entrypoint] == VAEntrypointEncSlice) {
+                    encoder_hevc_isavailable = 1;
+                    // extract attributes
+                    ret_val = get_config_attributes(va_dpy, profile_list[i], entrypoints[entrypoint], show_log, VAINFO_HEVC);
+                    if (ret_val) {
+                        tvherror(LS_VAINFO, "Failed to get config attributes (error %d)", ret_val);
+                    }
+                }
+                if (entrypoints[entrypoint] == VAEntrypointEncSliceLP) {
+                    encoder_hevclp_isavailable = 1;
+                    // extract attributes
+                    ret_val = get_config_attributes(va_dpy, profile_list[i], entrypoints[entrypoint], show_log, VAINFO_HEVC_LOW_POWER);
+                    if (ret_val) {
+                        tvherror(LS_VAINFO, "Failed to get config attributes (error %d)", ret_val);
+                    }
+                }
+            }
+            // vp8
+            if (profile == VAProfileVP8Version0_3) {
+                if (entrypoints[entrypoint] == VAEntrypointEncSlice) {
+                    encoder_vp8_isavailable = 1;
+                    // extract attributes
+                    ret_val = get_config_attributes(va_dpy, profile_list[i], entrypoints[entrypoint], show_log, VAINFO_VP8);
+                    if (ret_val) {
+                        tvherror(LS_VAINFO, "Failed to get config attributes (error %d)", ret_val);
+                    }
+                }
+                if (entrypoints[entrypoint] == VAEntrypointEncSliceLP) {
+                    encoder_vp8lp_isavailable = 1;
+                    // extract attributes
+                    ret_val = get_config_attributes(va_dpy, profile_list[i], entrypoints[entrypoint], show_log, VAINFO_VP8_LOW_POWER);
+                    if (ret_val) {
+                        tvherror(LS_VAINFO, "Failed to get config attributes (error %d)", ret_val);
+                    }
+                }
+            }
+            // vp9
+            if (profile == VAProfileVP9Profile0 || profile == VAProfileVP9Profile1 || profile == VAProfileVP9Profile2 || profile == VAProfileVP9Profile3) {
+                if (entrypoints[entrypoint] == VAEntrypointEncSlice) {
+                    encoder_vp9_isavailable = 1;
+                    ret_val = get_config_attributes(va_dpy, profile_list[i], entrypoints[entrypoint], show_log, VAINFO_VP9);
+                    if (ret_val) {
+                        tvherror(LS_VAINFO, "Failed to get config attributes (error %d)", ret_val);
+                    }
+                }
+                if (entrypoints[entrypoint] == VAEntrypointEncSliceLP) {
+                    encoder_vp9lp_isavailable = 1;
+                    ret_val = get_config_attributes(va_dpy, profile_list[i], entrypoints[entrypoint], show_log, VAINFO_VP9_LOW_POWER);
+                    if (ret_val) {
+                        tvherror(LS_VAINFO, "Failed to get config attributes (error %d)", ret_val);
+                    }
+                }
+            }
+        }
+    }
+    init_done = 1;
+    ret_val = 0;
+
+error_QueryConfigProfiles:
+error_profile_list:
+    free(profile_list);
+error_entrypoints:
+    free(entrypoints);
+error_Initialize:
+    vaTerminate(va_dpy);
+error_open_display:
+    va_close_display_drm(va_dpy);
+    // if we had any errors we enable show all codecs (for debugging)
+    if (ret_val) {
+        encoder_h264_isavailable = 1;
+        encoder_h264lp_isavailable = 1;
+        encoder_hevc_isavailable = 1;
+        encoder_hevclp_isavailable = 1;
+        encoder_vp8_isavailable = 1;
+        encoder_vp8lp_isavailable = 1;
+        encoder_vp9_isavailable = 1;
+        encoder_vp9lp_isavailable = 1;
+    }
+
+    return ret_val;
+}
+#endif
+
+/* exposed =================================================================== */
+
+/**
+ * VAINFO initialize.
+ *
+ * @note
+ * Initialize all internal variables according to VAAPI advertised feature
+ * parameter: show_log
+ * 1 = will show vainfo logs with available VAAPI entries
+ * 0 = no logs generated
+ * 
+ */
+int vainfo_init(int show_log)
+{
+#if ENABLE_VAAPI
+    int ret = init(show_log);
+    if (ret) {
+        tvherror(LS_VAINFO, "vainfo_init() error: %d", ret);
+        return ret;
+    }
+#endif
+    return 0;
+}
+
+/**
+ * VAINFO Encoder availablity.
+ *
+ * @note
+ * param: CODEC_ID
+ *
+ * return: 
+ * 0 - if encoder is not available
+ * 1 - if encoder is available
+ * 
+ */
+int vainfo_encoder_isavailable(int codec)
+{
+#if ENABLE_VAAPI
+    if (vainfo_probe_enabled) {
+        if (!init_done)
+            tvherror(LS_VAINFO, "vainfo_init() was not run or generated errors");
+        switch (codec) {
+            case VAINFO_H264:
+                return encoder_h264_isavailable;
+            case VAINFO_H264_LOW_POWER:
+                return encoder_h264lp_isavailable;
+            case VAINFO_HEVC:
+                return encoder_hevc_isavailable;
+            case VAINFO_HEVC_LOW_POWER:
+                return encoder_hevclp_isavailable;
+            case VAINFO_VP8:
+                return encoder_vp8_isavailable;
+            case VAINFO_VP8_LOW_POWER:
+                return encoder_vp8lp_isavailable;
+            case VAINFO_VP9:
+                return encoder_vp9_isavailable;
+            case VAINFO_VP9_LOW_POWER:
+                return encoder_vp9lp_isavailable;
+            default:
+                tvherror(LS_VAINFO, "codec not available: codec=%d", codec);
+                return CODEC_IS_NOT_AVAILABLE;
+        }
+    }
+    else
+#endif
+        return CODEC_IS_AVAILABLE;
+}
+
+
+/**
+ * VAINFO Encoder support for B frames.
+ *
+ * @note
+ * return: 
+ * 0 - if encoder is not supporting B frames
+ * > 0 - if encoder is supporting B frames and how many (MAX = 7)
+ * 
+ */
+int vainfo_encoder_maxBfreames(int codec)
+{
+#if ENABLE_VAAPI
+    if (vainfo_probe_enabled) {
+        if (!init_done)
+            tvherror(LS_VAINFO, "vainfo_init() was not run or generated errors");
+        switch (codec) {
+            case VAINFO_H264:
+                return encoder_h264_maxBfreames;
+            case VAINFO_H264_LOW_POWER:
+                return encoder_h264lp_maxBfreames;
+            case VAINFO_HEVC:
+                return encoder_hevc_maxBfreames;
+            case VAINFO_HEVC_LOW_POWER:
+                return encoder_hevclp_maxBfreames;
+            case VAINFO_VP8:
+                return encoder_vp8_maxBfreames;
+            case VAINFO_VP8_LOW_POWER:
+                return encoder_vp8lp_maxBfreames;
+            case VAINFO_VP9:
+                return encoder_vp9_maxBfreames;
+            case VAINFO_VP9_LOW_POWER:
+                return encoder_vp9lp_maxBfreames;
+            default:
+                tvherror(LS_VAINFO, "codec not available: codec=%d", codec);
+                return MIN_B_FRAMES;
+        }
+    }
+    else
+#endif
+        return MAX_B_FRAMES;
+}
+
+
+/**
+ * VAINFO Encoder max Quality.
+ *
+ * @note
+ * return: 
+ * 0 - if encoder is not supporting Quality
+ * 1 - if encoder is supporting Quality and how much (MAX = 15)
+ * 
+ */
+int vainfo_encoder_maxQuality(int codec)
+{
+#if ENABLE_VAAPI
+    if (vainfo_probe_enabled) {
+        if (!init_done)
+            tvherror(LS_VAINFO, "vainfo_init() was not run or generated errors");
+        switch (codec) {
+            case VAINFO_H264:
+                return encoder_h264_maxQuality;
+            case VAINFO_H264_LOW_POWER:
+                return encoder_h264lp_maxQuality;
+            case VAINFO_HEVC:
+                return encoder_hevc_maxQuality;
+            case VAINFO_HEVC_LOW_POWER:
+                return encoder_hevclp_maxQuality;
+            case VAINFO_VP8:
+                return encoder_vp8_maxQuality;
+            case VAINFO_VP8_LOW_POWER:
+                return encoder_vp8lp_maxQuality;
+            case VAINFO_VP9:
+                return encoder_vp9_maxQuality;
+            case VAINFO_VP9_LOW_POWER:
+                return encoder_vp9lp_maxQuality;
+            default:
+                tvherror(LS_VAINFO, "codec not available: codec=%d", codec);
+                return MIN_QUALITY;
+        }
+    }
+    else
+#endif
+        return MAX_QUALITY;
+}
+
+
+/**
+ * VAINFO deinitialize.
+ *
+ * @note
+ * Return all variables to default state
+ * 
+ */
+void vainfo_deinit()
+{
+    // this function should not be called
+}
\ No newline at end of file
diff --git a/src/transcoding/codec/vainfo.h b/src/transcoding/codec/vainfo.h
new file mode 100644 (file)
index 0000000..21d2a4d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  tvheadend - Transcoding
+ *
+ *  Copyright (C) 2023 Tvheadend
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef TVH_TRANSCODING_TRANSCODE_CODEC_VAINFO_H__
+#define TVH_TRANSCODING_TRANSCODE_CODEC_VAINFO_H__
+
+
+/**
+ * VAINFO VAINFO_DONT_SHOW_LOGS.
+ *
+ * @note
+ * Will not print output with detected codec/profiles
+ * 
+ */
+#define VAINFO_DONT_SHOW_LOGS   0
+
+/**
+ * VAINFO VAINFO_SHOW_LOGS.
+ *
+ * @note
+ * Will print output with detected codec/profiles
+ * 
+ */
+#define VAINFO_SHOW_LOGS        1
+
+
+/**
+ * VAINFO CODEC DEFINE.
+ * @note
+ * Define used when calling functions for H264
+ */
+#define VAINFO_H264                 1
+/**
+ * VAINFO CODEC DEFINE.
+ * @note
+ * Define used when calling functions for H264 low power
+ */
+#define VAINFO_H264_LOW_POWER       2
+/**
+ * VAINFO CODEC DEFINE.
+ * @note
+ * Define used when calling functions for HEVC
+ */
+#define VAINFO_HEVC                 3
+/**
+ * VAINFO CODEC DEFINE.
+ * @note
+ * Define used when calling functions for HEVC low power
+ */
+#define VAINFO_HEVC_LOW_POWER       4
+/**
+ * VAINFO CODEC DEFINE.
+ * @note
+ * Define used when calling functions for VP8
+ */
+#define VAINFO_VP8                  5
+/**
+ * VAINFO CODEC DEFINE.
+ * @note
+ * Define used when calling functions for VP8 low power
+ */
+#define VAINFO_VP8_LOW_POWER        6
+/**
+ * VAINFO CODEC DEFINE.
+ * @note
+ * Define used when calling functions for VP9
+ */
+#define VAINFO_VP9                  7
+/**
+ * VAINFO CODEC DEFINE.
+ * @note
+ * Define used when calling functions for VP9 low power
+ */
+#define VAINFO_VP9_LOW_POWER        8
+
+/**
+ * VAINFO initialize.
+ *
+ * @note
+ * Initialize all internal variables according to VAAPI advertised feature
+ * parameter: show_log
+ * 1 = will show vainfo logs with available VAAPI entries
+ * 0 = no logs generated
+ * 
+ */
+int vainfo_init(int show_log);
+
+
+/**
+ * VAINFO Encoder availablity.
+ *
+ * @note
+ * param: CODEC_ID
+ *
+ * return: 
+ * 0 - if encoder is not available
+ * 1 - if encoder is available
+ * 
+ */
+int vainfo_encoder_isavailable(int codec);
+
+
+/**
+ * VAINFO Encoder support for B frames.
+ *
+ * @note
+ * return: 
+ * 0 - if encoder is not supporting B frames
+ * > 0 - if encoder is supporting B frames and how many (MAX = 7)
+ * 
+ */
+int vainfo_encoder_maxBfreames(int codec);
+
+
+/**
+ * VAINFO Encoder max Quality.
+ *
+ * @note
+ * return: 
+ * 0 - if encoder is not supporting Quality
+ * 1 - if encoder is supporting Quality and how much (MAX = 15)
+ * 
+ */
+int vainfo_encoder_maxQuality(int codec);
+
+
+/**
+ * VAINFO deinitialize.
+ *
+ * @note
+ * Return all variables to default state
+ * 
+ */
+void vainfo_deinit(void);
+
+#endif // TVH_TRANSCODING_TRANSCODE_CODEC_VAINFO_H__
\ No newline at end of file
index cf526f5c20236f2acefd6d0b6491c2dcba54e13a..bc67e40dc36a3c8f58c116dbc37be4d1b547edc0 100644 (file)
@@ -180,6 +180,7 @@ tvhlog_subsys_t tvhlog_subsystems[] = {
   [LS_TSDEBUG]       = { "tsdebug",       N_("MPEG-TS Input Debug") },
   [LS_CODEC]         = { "codec",         N_("Codec") },
   [LS_VAAPI]         = { "vaapi",         N_("VA-API") },
+  [LS_VAINFO]        = { "vainfo",        N_("VAINFO") },
 #if ENABLE_DDCI
   [LS_DDCI]          = { "ddci",          N_("DD-CI") },
 #endif
index c69cd8fc9bff906cb5c9bdf5179ef89e6887d2e9..481d362e019726b47fafabec01e8cb2693fe936f 100644 (file)
@@ -195,6 +195,7 @@ enum {
   LS_TSDEBUG,
   LS_CODEC,
   LS_VAAPI,
+  LS_VAINFO,
 #if ENABLE_DDCI
   LS_DDCI,
 #endif
index afdfad066d2edb79a9af0133250c1011da83109b..c791f353a808eb9d5a227de2221d3ae172ea06a6 100644 (file)
@@ -236,7 +236,81 @@ var codec_profile_forms = {
             form.findField('hw_sharpness').setDisabled(!hwaccel_field.getValue());
         }
 
-        function updateFilters(form) {
+        function checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field) {
+            // enable max B frames based on ui (vainfo)
+            var uibframe = 0;
+            if (low_power_field.getValue()) {
+                // low power is enabled
+                uibframe = (uilp_value & 0xe) >> 1
+            }
+            else {
+                // low power is disabled
+                uibframe = (ui_value & 0xe) >> 1
+            }
+            // messagebox if max B grames > VAINFO.max_b_frames
+            if (uibframe) {
+                if (desired_b_depth_field.getValue() > uibframe)
+                    alert('VAINFO maximum B fames is: ' + uibframe)
+                desired_b_depth_field.setDisabled(false);
+                b_reference_field.setDisabled(false);
+            }
+            else {
+                desired_b_depth_field.setDisabled(true);
+                b_reference_field.setDisabled(true);
+            }
+            // enable Quality based on ui (vainfo)
+            var uiquality = 0;
+            if (low_power_field.getValue()) {
+                // low power is enabled
+                uiquality = (uilp_value & 0xf0) >> 4
+            }
+            else {
+                // low power is disabled
+                uiquality = (ui_value & 0xf0) >> 4
+            }
+            // messagebox if Qality > VAINFO.quality
+            if (uiquality > 1) {
+                if (quality_field.getValue() > uiquality)
+                    alert('VAINFO maximum Quality is: ' + uiquality)
+            }
+            else {
+                quality_field.setValue(-1);
+                quality_field.setDisabled(true);
+            }
+        }
+
+        function updateLowPower(form) {
+            var low_power_field = form.findField('low_power');
+            var desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
+            
+            checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field);
+        }
+
+        function removeConstrains(form) {
+            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 desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
+
+            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);
+            desired_b_depth_field.setDisabled(false);
+            b_reference_field.setDisabled(false);
+            quality_field.setDisabled(false);
+        }
+
+        function updateFilters(form, ui_value, uilp_value) {
             var platform_field = form.findField('platform');
             var rc_mode_field = form.findField('rc_mode');
             var bit_rate_field = form.findField('bit_rate');
@@ -246,6 +320,8 @@ var codec_profile_forms = {
             var qp_field = form.findField('qp');
             var low_power_field = form.findField('low_power');
             var desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
 
             var platform = platform_field.getValue();
             switch (platform) {
@@ -253,18 +329,24 @@ var codec_profile_forms = {
                     // 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);
-                    desired_b_depth_field.setDisabled(false);
+                    removeConstrains(form);
                     break;
                 case 1:
                     // Intel
-                    // low_power is disabling Max B frame
-                    desired_b_depth_field.setDisabled(low_power_field.getValue());
+                    // enable low_power mode based on ui (vainfo)
+                    if ((ui_value & 0x1) && (uilp_value & 0x1))
+                        low_power_field.setDisabled(false);
+                    else {
+                        low_power_field.setDisabled(true);
+                        if (uilp_value & 0x1)
+                            // only low power is available
+                            low_power_field.setValue(true);
+                        if (ui_value & 0x1)
+                            // only normal is available
+                            low_power_field.setValue(false);
+                    }
+                    checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field);
+                    // filter based in rc_mode
                     var rc_mode = rc_mode_field.getValue();
                     switch (rc_mode) {
                         case -1:
@@ -318,20 +400,13 @@ var codec_profile_forms = {
                             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)
                     // NOTE: filters to be added later
-                    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);
-                    desired_b_depth_field.setDisabled(false);
+                    removeConstrains(form);
                     break;
                 default:
             }
@@ -341,27 +416,41 @@ var codec_profile_forms = {
         var rc_mode_field = form.findField('rc_mode');
         var low_power_field = form.findField('low_power');
         var hwaccel_field = form.findField('hwaccel');
+        var ui_field = form.findField('ui');
+        var uilp_field = form.findField('uilp');
+        var desired_b_depth_field = form.findField('desired_b_depth');
+        var quality_field = form.findField('quality');
+        var ui_value = ui_field.getValue();
+        var uilp_value = uilp_field.getValue();
         
         // first time we have to call this manually
-        updateFilters(form);
+        updateFilters(form, ui_value, uilp_value);
         updateHWFilters(form);
         
         // on platform change
         platform_field.on('select', function(combo, record, index) {
-            updateFilters(form);
+            updateFilters(form, ui_value, uilp_value);
         });
         // on rc_mode change
         rc_mode_field.on('select', function(combo, record, index) {
-            updateFilters(form);
+            updateFilters(form, ui_value, uilp_value);
         });
         // on low_power change
         low_power_field.on('check', function(checkbox, value) {
-            updateFilters(form);
+            updateLowPower(form);
         });
         // on hwaccel change
         hwaccel_field.on('check', function(checkbox, value) {
             updateHWFilters(form);
         });
+        // on desired_b_depth change
+        desired_b_depth_field.on('spin', function(spinner, direction, eOpts) {
+            updateFilters(form, ui_value, uilp_value);
+        });
+        // on quality change
+        quality_field.on('spin', function(spinner, direction, eOpts) {
+            updateFilters(form, ui_value, uilp_value);
+        });
     },
 
     'codec_profile_vaapi_hevc': function(form) {
@@ -371,7 +460,81 @@ var codec_profile_forms = {
             form.findField('hw_sharpness').setDisabled(!hwaccel_field.getValue());
         }
 
-        function updateFilters(form) {
+        function checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field) {
+            // enable max B frames based on ui (vainfo)
+            var uibframe = 0;
+            if (low_power_field.getValue()) {
+                // low power is enabled
+                uibframe = (uilp_value & 0xe) >> 1
+            }
+            else {
+                // low power is disabled
+                uibframe = (ui_value & 0xe) >> 1
+            }
+            // messagebox if max B grames > VAINFO.max_b_frames
+            if (uibframe) {
+                if (desired_b_depth_field.getValue() > uibframe)
+                    alert('VAINFO maximum B fames is: ' + uibframe)
+                desired_b_depth_field.setDisabled(false);
+                b_reference_field.setDisabled(false);
+            }
+            else {
+                desired_b_depth_field.setDisabled(true);
+                b_reference_field.setDisabled(true);
+            }
+            // enable Quality based on ui (vainfo)
+            var uiquality = 0;
+            if (low_power_field.getValue()) {
+                // low power is enabled
+                uiquality = (uilp_value & 0xf0) >> 4
+            }
+            else {
+                // low power is disabled
+                uiquality = (ui_value & 0xf0) >> 4
+            }
+            // messagebox if Qality > VAINFO.quality
+            if (uiquality > 1) {
+                if (quality_field.getValue() > uiquality)
+                    alert('VAINFO maximum Quality is: ' + uiquality)
+            }
+            else {
+                quality_field.setValue(-1);
+                quality_field.setDisabled(true);
+            }
+        }
+
+        function updateLowPower(form) {
+            var low_power_field = form.findField('low_power');
+            var desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
+            
+            checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field);
+        }
+
+        function removeConstrains(form) {
+            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 desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
+
+            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);
+            desired_b_depth_field.setDisabled(false);
+            b_reference_field.setDisabled(false);
+            quality_field.setDisabled(false);
+        }
+
+        function updateFilters(form, ui_value, uilp_value) {
             var platform_field = form.findField('platform');
             var rc_mode_field = form.findField('rc_mode');
             var bit_rate_field = form.findField('bit_rate');
@@ -381,6 +544,8 @@ var codec_profile_forms = {
             var qp_field = form.findField('qp');
             var low_power_field = form.findField('low_power');
             var desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
 
             var platform = platform_field.getValue();
             switch (platform) {
@@ -388,18 +553,24 @@ var codec_profile_forms = {
                     // 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);
-                    desired_b_depth_field.setDisabled(false);
+                    removeConstrains(form);
                     break;
                 case 1:
                     // Intel
-                    // low_power is disabling Max B frame
-                    desired_b_depth_field.setDisabled(low_power_field.getValue());
+                    // enable low_power mode based on ui (vainfo)
+                    if ((ui_value & 0x1) && (uilp_value & 0x1))
+                        low_power_field.setDisabled(false);
+                    else {
+                        low_power_field.setDisabled(true);
+                        if (uilp_value & 0x1)
+                            // only low power is available
+                            low_power_field.setValue(true);
+                        if (ui_value & 0x1)
+                            // only normal is available
+                            low_power_field.setValue(false);
+                    }
+                    checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field);
+                    // filter based in rc_mode
                     var rc_mode = rc_mode_field.getValue();
                     switch (rc_mode) {
                         case -1:
@@ -449,24 +620,17 @@ var codec_profile_forms = {
                             bit_rate_field.setDisabled(false);
                             max_bit_rate_field.setDisabled(false);
                             buff_factor_field.setDisabled(true);
-                            bit_rate_scale_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)
                     // NOTE: filters to be added later
-                    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);
-                    desired_b_depth_field.setDisabled(false);
+                    removeConstrains(form);
                     break;
                 default:
             }
@@ -476,27 +640,41 @@ var codec_profile_forms = {
         var rc_mode_field = form.findField('rc_mode');
         var low_power_field = form.findField('low_power');
         var hwaccel_field = form.findField('hwaccel');
-
+        var ui_field = form.findField('ui');
+        var uilp_field = form.findField('uilp');
+        var desired_b_depth_field = form.findField('desired_b_depth');
+        var quality_field = form.findField('quality');
+        var ui_value = ui_field.getValue();
+        var uilp_value = uilp_field.getValue();
+        
         // first time we have to call this manually
-        updateFilters(form);
+        updateFilters(form, ui_value, uilp_value);
         updateHWFilters(form);
         
         // on platform change
         platform_field.on('select', function(combo, record, index) {
-            updateFilters(form);
+            updateFilters(form, ui_value, uilp_value);
         });
         // on rc_mode change
         rc_mode_field.on('select', function(combo, record, index) {
-            updateFilters(form);
+            updateFilters(form, ui_value, uilp_value);
         });
         // on low_power change
         low_power_field.on('check', function(checkbox, value) {
-            updateFilters(form);
+            updateLowPower(form);
         });
         // on hwaccel change
         hwaccel_field.on('check', function(checkbox, value) {
             updateHWFilters(form);
         });
+        // on desired_b_depth change
+        desired_b_depth_field.on('spin', function(spinner, direction, eOpts) {
+            updateFilters(form, ui_value, uilp_value);
+        });
+        // on quality change
+        quality_field.on('spin', function(spinner, direction, eOpts) {
+            updateFilters(form, ui_value, uilp_value);
+        });
     },
 
     'codec_profile_vaapi_vp8': function(form) {
@@ -506,7 +684,81 @@ var codec_profile_forms = {
             form.findField('hw_sharpness').setDisabled(!hwaccel_field.getValue());
         }
 
-        function updateFilters(form) {
+        function checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field) {
+            // enable max B frames based on ui (vainfo)
+            var uibframe = 0;
+            if (low_power_field.getValue()) {
+                // low power is enabled
+                uibframe = (uilp_value & 0xe) >> 1
+            }
+            else {
+                // low power is disabled
+                uibframe = (ui_value & 0xe) >> 1
+            }
+            // messagebox if max B grames > VAINFO.max_b_frames
+            if (uibframe) {
+                if (desired_b_depth_field.getValue() > uibframe)
+                    alert('VAINFO maximum B fames is: ' + uibframe)
+                desired_b_depth_field.setDisabled(false);
+                b_reference_field.setDisabled(false);
+            }
+            else {
+                desired_b_depth_field.setDisabled(true);
+                b_reference_field.setDisabled(true);
+            }
+            // enable Quality based on ui (vainfo)
+            var uiquality = 0;
+            if (low_power_field.getValue()) {
+                // low power is enabled
+                uiquality = (uilp_value & 0xf0) >> 4
+            }
+            else {
+                // low power is disabled
+                uiquality = (ui_value & 0xf0) >> 4
+            }
+            // messagebox if Qality > VAINFO.quality
+            if (uiquality > 1) {
+                if (quality_field.getValue() > uiquality)
+                    alert('VAINFO maximum Quality is: ' + uiquality)
+            }
+            else {
+                quality_field.setValue(-1);
+                quality_field.setDisabled(true);
+            }
+        }
+
+        function updateLowPower(form) {
+            var low_power_field = form.findField('low_power');
+            var desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
+            
+            checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field);
+        }
+
+        function removeConstrains(form) {
+            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 desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
+
+            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);
+            desired_b_depth_field.setDisabled(false);
+            b_reference_field.setDisabled(false);
+            quality_field.setDisabled(false);
+        }
+
+        function updateFilters(form, ui_value, uilp_value) {
             var platform_field = form.findField('platform');
             var rc_mode_field = form.findField('rc_mode');
             var bit_rate_field = form.findField('bit_rate');
@@ -514,6 +766,10 @@ var codec_profile_forms = {
             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 desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
 
             var platform = platform_field.getValue();
             switch (platform) {
@@ -521,14 +777,24 @@ var codec_profile_forms = {
                     // 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);
+                    removeConstrains(form);
                     break;
                 case 1:
                     // Intel
+                    // enable low_power mode based on ui (vainfo)
+                    if ((ui_value & 0x1) && (uilp_value & 0x1))
+                        low_power_field.setDisabled(false);
+                    else {
+                        low_power_field.setDisabled(true);
+                        if (uilp_value & 0x1)
+                            // only low power is available
+                            low_power_field.setValue(true);
+                        if (ui_value & 0x1)
+                            // only normal is available
+                            low_power_field.setValue(false);
+                    }
+                    checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field);
+                    // filter based in rc_mode
                     var rc_mode = rc_mode_field.getValue();
                     switch (rc_mode) {
                         case -1:
@@ -578,7 +844,7 @@ var codec_profile_forms = {
                             bit_rate_field.setDisabled(false);
                             max_bit_rate_field.setDisabled(false);
                             buff_factor_field.setDisabled(true);
-                            bit_rate_scale_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(false);
                             qp_field.setDisabled(true);
                             break;
                     }
@@ -588,11 +854,7 @@ var codec_profile_forms = {
                     // 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)
                     // NOTE: filters to be added later
-                    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);
+                    removeConstrains(form);
                     break;
                 default:
             }
@@ -600,24 +862,43 @@ var codec_profile_forms = {
 
         var platform_field = form.findField('platform');
         var rc_mode_field = form.findField('rc_mode');
+        var low_power_field = form.findField('low_power');
         var hwaccel_field = form.findField('hwaccel');
-
+        var ui_field = form.findField('ui');
+        var uilp_field = form.findField('uilp');
+        var desired_b_depth_field = form.findField('desired_b_depth');
+        var quality_field = form.findField('quality');
+        var ui_value = ui_field.getValue();
+        var uilp_value = uilp_field.getValue();
+        
         // first time we have to call this manually
-        updateFilters(form);
+        updateFilters(form, ui_value, uilp_value);
         updateHWFilters(form);
-
+        
         // on platform change
         platform_field.on('select', function(combo, record, index) {
-            updateFilters(form);
+            updateFilters(form, ui_value, uilp_value);
         });
         // on rc_mode change
         rc_mode_field.on('select', function(combo, record, index) {
-            updateFilters(form);
+            updateFilters(form, ui_value, uilp_value);
+        });
+        // on low_power change
+        low_power_field.on('check', function(checkbox, value) {
+            updateLowPower(form);
         });
         // on hwaccel change
         hwaccel_field.on('check', function(checkbox, value) {
             updateHWFilters(form);
         });
+        // on desired_b_depth change
+        desired_b_depth_field.on('spin', function(spinner, direction, eOpts) {
+            updateFilters(form, ui_value, uilp_value);
+        });
+        // on quality change
+        quality_field.on('spin', function(spinner, direction, eOpts) {
+            updateFilters(form, ui_value, uilp_value);
+        });
     },
 
     'codec_profile_vaapi_vp9': function(form) {
@@ -627,7 +908,81 @@ var codec_profile_forms = {
             form.findField('hw_sharpness').setDisabled(!hwaccel_field.getValue());
         }
 
-        function updateFilters(form) {
+        function checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field) {
+            // enable max B frames based on ui (vainfo)
+            var uibframe = 0;
+            if (low_power_field.getValue()) {
+                // low power is enabled
+                uibframe = (uilp_value & 0xe) >> 1
+            }
+            else {
+                // low power is disabled
+                uibframe = (ui_value & 0xe) >> 1
+            }
+            // messagebox if max B grames > VAINFO.max_b_frames
+            if (uibframe) {
+                if (desired_b_depth_field.getValue() > uibframe)
+                    alert('VAINFO maximum B fames is: ' + uibframe)
+                desired_b_depth_field.setDisabled(false);
+                b_reference_field.setDisabled(false);
+            }
+            else {
+                desired_b_depth_field.setDisabled(true);
+                b_reference_field.setDisabled(true);
+            }
+            // enable Quality based on ui (vainfo)
+            var uiquality = 0;
+            if (low_power_field.getValue()) {
+                // low power is enabled
+                uiquality = (uilp_value & 0xf0) >> 4
+            }
+            else {
+                // low power is disabled
+                uiquality = (ui_value & 0xf0) >> 4
+            }
+            // messagebox if Qality > VAINFO.quality
+            if (uiquality > 1) {
+                if (quality_field.getValue() > uiquality)
+                    alert('VAINFO maximum Quality is: ' + uiquality)
+            }
+            else {
+                quality_field.setValue(-1);
+                quality_field.setDisabled(true);
+            }
+        }
+
+        function updateLowPower(form) {
+            var low_power_field = form.findField('low_power');
+            var desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
+            
+            checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field);
+        }
+
+        function removeConstrains(form) {
+            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 desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
+
+            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);
+            desired_b_depth_field.setDisabled(false);
+            b_reference_field.setDisabled(false);
+            quality_field.setDisabled(false);
+        }
+
+        function updateFilters(form, ui_value, uilp_value) {
             var platform_field = form.findField('platform');
             var rc_mode_field = form.findField('rc_mode');
             var bit_rate_field = form.findField('bit_rate');
@@ -635,6 +990,10 @@ var codec_profile_forms = {
             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 desired_b_depth_field = form.findField('desired_b_depth');
+            var b_reference_field = form.findField('b_reference');
+            var quality_field = form.findField('quality');
 
             var platform = platform_field.getValue();
             switch (platform) {
@@ -642,14 +1001,24 @@ var codec_profile_forms = {
                     // 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);
+                    removeConstrains(form);
                     break;
                 case 1:
                     // Intel
+                    // enable low_power mode based on ui (vainfo)
+                    if ((ui_value & 0x1) && (uilp_value & 0x1))
+                        low_power_field.setDisabled(false);
+                    else {
+                        low_power_field.setDisabled(true);
+                        if (uilp_value & 0x1)
+                            // only low power is available
+                            low_power_field.setValue(true);
+                        if (ui_value & 0x1)
+                            // only normal is available
+                            low_power_field.setValue(false);
+                    }
+                    checkBFrameQuality(low_power_field, desired_b_depth_field, b_reference_field, quality_field);
+                    // filter based in rc_mode
                     var rc_mode = rc_mode_field.getValue();
                     switch (rc_mode) {
                         case -1:
@@ -699,7 +1068,7 @@ var codec_profile_forms = {
                             bit_rate_field.setDisabled(false);
                             max_bit_rate_field.setDisabled(false);
                             buff_factor_field.setDisabled(true);
-                            bit_rate_scale_factor_field.setDisabled(true);
+                            bit_rate_scale_factor_field.setDisabled(false);
                             qp_field.setDisabled(true);
                             break;
                     }
@@ -709,11 +1078,7 @@ var codec_profile_forms = {
                     // 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)
                     // NOTE: filters to be added later
-                    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);
+                    removeConstrains(form);
                     break;
                 default:
             }
@@ -721,24 +1086,43 @@ var codec_profile_forms = {
 
         var platform_field = form.findField('platform');
         var rc_mode_field = form.findField('rc_mode');
+        var low_power_field = form.findField('low_power');
         var hwaccel_field = form.findField('hwaccel');
-
+        var ui_field = form.findField('ui');
+        var uilp_field = form.findField('uilp');
+        var desired_b_depth_field = form.findField('desired_b_depth');
+        var quality_field = form.findField('quality');
+        var ui_value = ui_field.getValue();
+        var uilp_value = uilp_field.getValue();
+        
         // first time we have to call this manually
-        updateFilters(form);
+        updateFilters(form, ui_value, uilp_value);
         updateHWFilters(form);
-
+        
         // on platform change
         platform_field.on('select', function(combo, record, index) {
-            updateFilters(form);
+            updateFilters(form, ui_value, uilp_value);
         });
         // on rc_mode change
         rc_mode_field.on('select', function(combo, record, index) {
-            updateFilters(form);
+            updateFilters(form, ui_value, uilp_value);
+        });
+        // on low_power change
+        low_power_field.on('check', function(checkbox, value) {
+            updateLowPower(form);
         });
         // on hwaccel change
         hwaccel_field.on('check', function(checkbox, value) {
             updateHWFilters(form);
         });
+        // on desired_b_depth change
+        desired_b_depth_field.on('spin', function(spinner, direction, eOpts) {
+            updateFilters(form, ui_value, uilp_value);
+        });
+        // on quality change
+        quality_field.on('spin', function(spinner, direction, eOpts) {
+            updateFilters(form, ui_value, uilp_value);
+        });
     }
 };