From: uknunknown Date: Tue, 23 May 2023 02:48:04 +0000 (-0700) Subject: update vaapi - vainfo X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=76d8fc8bc5455322558c764c84755ebbba254ad5;p=thirdparty%2Ftvheadend.git update vaapi - vainfo - 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' --- diff --git a/src/config.c b/src/config.c index d5926df64..c5bd4ef4d 100644 --- a/src/config.c +++ b/src/config.c @@ -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", diff --git a/src/config.h b/src/config.h index 8cdb54d70..fe1f9b931 100644 --- a/src/config.h +++ b/src/config.h @@ -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; diff --git a/src/idnode.c b/src/idnode.c index 457b19171..d75a1e4e3 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -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: diff --git a/src/main.c b/src/main.c index 3b43c9534..fa3a335d5 100644 --- a/src/main.c +++ b/src/main.c @@ -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); diff --git a/src/prop.c b/src/prop.c index e91f75b31..d6f830c64 100644 --- a/src/prop.c +++ b/src/prop.c @@ -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; diff --git a/src/prop.h b/src/prop.h index 373942281..5855b2d6f 100644 --- a/src/prop.h +++ b/src/prop.h @@ -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 */ diff --git a/src/transcoding/codec.h b/src/transcoding/codec.h index b68b73925..43b708462 100644 --- a/src/transcoding/codec.h +++ b/src/transcoding/codec.h @@ -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); diff --git a/src/transcoding/codec/codec.c b/src/transcoding/codec/codec.c index fbaee36b8..6e5d1e3e7 100644 --- a/src/transcoding/codec/codec.c +++ b/src/transcoding/codec/codec.c @@ -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 diff --git a/src/transcoding/codec/codecs/libs/vaapi.c b/src/transcoding/codec/codecs/libs/vaapi.c index 5cd7ca339..27b699e24 100644 --- a/src/transcoding/codec/codecs/libs/vaapi.c +++ b/src/transcoding/codec/codecs/libs/vaapi.c @@ -24,6 +24,7 @@ #include "idnode.h" #include "htsmsg.h" +#include "transcoding/codec/vainfo.h" /* defines */ #define VAAPI_ENC_PLATFORM_UNCONSTRAINED 0 @@ -79,6 +80,19 @@ #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 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 E..V....... Loop filter level (from 0 to 63) (default 16) // -loop_filter_sharpness 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 E..V....... Loop filter level (from 0 to 63) (default 16) // -loop_filter_sharpness 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, + }, {} } }, diff --git a/src/transcoding/codec/internals.h b/src/transcoding/codec/internals.h index 978bf7175..db88d575b 100644 --- a/src/transcoding/codec/internals.h +++ b/src/transcoding/codec/internals.h @@ -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); diff --git a/src/transcoding/codec/module.c b/src/transcoding/codec/module.c index 8c78eda5f..bfe624427 100644 --- a/src/transcoding/codec/module.c +++ b/src/transcoding/codec/module.c @@ -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(); } diff --git a/src/transcoding/codec/profile_video_class.c b/src/transcoding/codec/profile_video_class.c index 35bd9353a..00bfbbf99 100644 --- a/src/transcoding/codec/profile_video_class.c +++ b/src/transcoding/codec/profile_video_class.c @@ -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 index 000000000..cca42a13b --- /dev/null +++ b/src/transcoding/codec/vainfo.c @@ -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 . + */ + + +#include "vainfo.h" +#include "internals.h" + +#if ENABLE_VAAPI +#include +#include +#include +#include +#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 : ""); + + 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 index 000000000..21d2a4dce --- /dev/null +++ b/src/transcoding/codec/vainfo.h @@ -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 . + */ + + +#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 diff --git a/src/tvhlog.c b/src/tvhlog.c index cf526f5c2..bc67e40dc 100644 --- a/src/tvhlog.c +++ b/src/tvhlog.c @@ -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 diff --git a/src/tvhlog.h b/src/tvhlog.h index c69cd8fc9..481d362e0 100644 --- a/src/tvhlog.h +++ b/src/tvhlog.h @@ -195,6 +195,7 @@ enum { LS_TSDEBUG, LS_CODEC, LS_VAAPI, + LS_VAINFO, #if ENABLE_DDCI LS_DDCI, #endif diff --git a/src/webui/static/app/codec.js b/src/webui/static/app/codec.js index afdfad066..c791f353a 100644 --- a/src/webui/static/app/codec.js +++ b/src/webui/static/app/codec.js @@ -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); + }); } };