From 208fa3f73bb87e9d2a8b9a29e444c6ddd630808c Mon Sep 17 00:00:00 2001 From: Focus Luo Date: Wed, 21 Aug 2024 19:33:37 -0700 Subject: [PATCH 1/7] [strapi] added str api class and data struct define Signed-off-by: Focus Luo --- lib/mfx/api.py | 347 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 lib/mfx/api.py diff --git a/lib/mfx/api.py b/lib/mfx/api.py new file mode 100644 index 00000000..347f59dc --- /dev/null +++ b/lib/mfx/api.py @@ -0,0 +1,347 @@ +from ...lib.codecs import Codec +from ...lib.common import memoize +from ...lib.properties import PropertyHandler +from enum import IntEnum, unique + +#define come from _install/include/vpl/mfxstructures.h +class CodecProfile(IntEnum): + MFX_PROFILE_UNKNOWN =0 #/*!< Unspecified profile. */ + + #/* Combined with H.264 profile these flags impose additional constrains. See H.264 specification for the list of constrains. */ + MFX_PROFILE_AVC_CONSTRAINT_SET0 = (0x100 << 0) + MFX_PROFILE_AVC_CONSTRAINT_SET1 = (0x100 << 1) + MFX_PROFILE_AVC_CONSTRAINT_SET2 = (0x100 << 2) + MFX_PROFILE_AVC_CONSTRAINT_SET3 = (0x100 << 3) + MFX_PROFILE_AVC_CONSTRAINT_SET4 = (0x100 << 4) + MFX_PROFILE_AVC_CONSTRAINT_SET5 = (0x100 << 5) + + #/* H.264 Profiles. */ + MFX_PROFILE_AVC_BASELINE =66 + MFX_PROFILE_AVC_MAIN =77 + MFX_PROFILE_AVC_EXTENDED =88 + MFX_PROFILE_AVC_HIGH =100 + MFX_PROFILE_AVC_HIGH10 =110 + MFX_PROFILE_AVC_HIGH_422 =122 + MFX_PROFILE_AVC_CONSTRAINED_BASELINE =MFX_PROFILE_AVC_BASELINE + MFX_PROFILE_AVC_CONSTRAINT_SET1 + MFX_PROFILE_AVC_CONSTRAINED_HIGH =MFX_PROFILE_AVC_HIGH + MFX_PROFILE_AVC_CONSTRAINT_SET4 + MFX_PROFILE_AVC_CONSTRAINT_SET5 + MFX_PROFILE_AVC_PROGRESSIVE_HIGH =MFX_PROFILE_AVC_HIGH + MFX_PROFILE_AVC_CONSTRAINT_SET4 + + #/* HEVC profiles */ + MFX_PROFILE_HEVC_MAIN =1 + MFX_PROFILE_HEVC_MAIN10 =2 + MFX_PROFILE_HEVC_MAINSP =3 + MFX_PROFILE_HEVC_REXT =4 + MFX_PROFILE_HEVC_SCC =9 + + #/* AV1 Profiles */ + MFX_PROFILE_AV1_MAIN = 1 + MFX_PROFILE_AV1_HIGH = 2 + MFX_PROFILE_AV1_PRO = 3 + + #/* VP9 Profiles */ + MFX_PROFILE_VP9_0 = 1 + MFX_PROFILE_VP9_1 = 2 + MFX_PROFILE_VP9_2 = 3 + MFX_PROFILE_VP9_3 = 4 + +class CodecLevel(IntEnum): + MFX_LEVEL_UNKNOWN =0 #/*!< Unspecified level. */ + #/* H.264 level 1-1.3 */ + MFX_LEVEL_AVC_1 =10 + MFX_LEVEL_AVC_1b =9 + MFX_LEVEL_AVC_11 =11 + MFX_LEVEL_AVC_12 =12 + MFX_LEVEL_AVC_13 =13 + #/* H.264 level 2-2.2 */ + MFX_LEVEL_AVC_2 =20 + MFX_LEVEL_AVC_21 =21 + MFX_LEVEL_AVC_22 =22 + #/* H.264 level 3-3.2 */ + MFX_LEVEL_AVC_3 =30 + MFX_LEVEL_AVC_31 =31 + MFX_LEVEL_AVC_32 =32 + #/* H.264 level 4-4.2 */ + MFX_LEVEL_AVC_4 =40 + MFX_LEVEL_AVC_41 =41 + MFX_LEVEL_AVC_42 =42 + #/* H.264 level 5-5.2 */ + MFX_LEVEL_AVC_5 =50 + MFX_LEVEL_AVC_51 =51 + MFX_LEVEL_AVC_52 =52 + #/* H.264 level 6-6.2 */ + MFX_LEVEL_AVC_6 =60 + MFX_LEVEL_AVC_61 =61 + MFX_LEVEL_AVC_62 =62 + + #/* HEVC levels */ + MFX_LEVEL_HEVC_1 = 10 + MFX_LEVEL_HEVC_2 = 20 + MFX_LEVEL_HEVC_21 = 21 + MFX_LEVEL_HEVC_3 = 30 + MFX_LEVEL_HEVC_31 = 31 + MFX_LEVEL_HEVC_4 = 40 + MFX_LEVEL_HEVC_41 = 41 + MFX_LEVEL_HEVC_5 = 50 + MFX_LEVEL_HEVC_51 = 51 + MFX_LEVEL_HEVC_52 = 52 + MFX_LEVEL_HEVC_6 = 60 + MFX_LEVEL_HEVC_61 = 61 + MFX_LEVEL_HEVC_62 = 62 + + #/* AV1 Levels */ + MFX_LEVEL_AV1_2 = 20 + MFX_LEVEL_AV1_21 = 21 + MFX_LEVEL_AV1_22 = 22 + MFX_LEVEL_AV1_23 = 23 + MFX_LEVEL_AV1_3 = 30 + MFX_LEVEL_AV1_31 = 31 + MFX_LEVEL_AV1_32 = 32 + MFX_LEVEL_AV1_33 = 33 + MFX_LEVEL_AV1_4 = 40 + MFX_LEVEL_AV1_41 = 41 + MFX_LEVEL_AV1_42 = 42 + MFX_LEVEL_AV1_43 = 43 + MFX_LEVEL_AV1_5 = 50 + MFX_LEVEL_AV1_51 = 51 + MFX_LEVEL_AV1_52 = 52 + MFX_LEVEL_AV1_53 = 53 + MFX_LEVEL_AV1_6 = 60 + MFX_LEVEL_AV1_61 = 61 + MFX_LEVEL_AV1_62 = 62 + MFX_LEVEL_AV1_63 = 63 + MFX_LEVEL_AV1_7 = 70 + MFX_LEVEL_AV1_71 = 71 + MFX_LEVEL_AV1_72 = 72 + MFX_LEVEL_AV1_73 = 73 + +class RateControlMethod(IntEnum): +#/*! The RateControlMethod enumerator itemizes bitrate control methods. */ + MFX_RATECONTROL_CBR =1 #/*!< Use the constant bitrate control algorithm. */ + MFX_RATECONTROL_VBR =2 #/*!< Use the variable bitrate control algorithm. */ + MFX_RATECONTROL_CQP =3 #/*!< Use the constant quantization parameter algorithm. */ + MFX_RATECONTROL_AVBR =4 #/*!< Use the average variable bitrate control algorithm. */ + MFX_RATECONTROL_RESERVED1 =5 + MFX_RATECONTROL_RESERVED2 =6 + MFX_RATECONTROL_RESERVED3 =100 + MFX_RATECONTROL_RESERVED4 =7 + #/*! + # Use the VBR algorithm with look ahead. It is a special bitrate control mode in the AVC encoder that has been designed + # to improve encoding quality. It works by performing extensive analysis of several dozen frames before the actual encoding and as a side + # effect significantly increases encoding delay and memory consumption. + + # The only available rate control parameter in this mode is mfxInfoMFX::TargetKbps. Two other parameters, MaxKbps and InitialDelayInKB, + # are ignored. To control LA depth the application can use mfxExtCodingOption2::LookAheadDepth parameter. + + # This method is not HRD compliant. + #*/ + MFX_RATECONTROL_LA =8 + #/*! + # Use the Intelligent Constant Quality algorithm. This algorithm improves subjective video quality of encoded stream. Depending on content, + # it may or may not decrease objective video quality. Only one control parameter is used - quality factor, specified by mfxInfoMFX::ICQQuality. + #*/ + MFX_RATECONTROL_ICQ =9 + #/*! + # Use the Video Conferencing Mode algorithm. This algorithm is similar to the VBR and uses the same set of parameters mfxInfoMFX::InitialDelayInKB, + # TargetKbpsandMaxKbps. It is tuned for IPPP GOP pattern and streams with strong temporal correlation between frames. + # It produces better objective and subjective video quality in these conditions than other bitrate control algorithms. + # It does not support interlaced content, B-frames and produced stream is not HRD compliant. + #*/ + MFX_RATECONTROL_VCM =10 + #/*! + # Use Intelligent Constant Quality algorithm with look ahead. Quality factor is specified by mfxInfoMFX::ICQQuality. + # To control LA depth the application can use mfxExtCodingOption2::LookAheadDepth parameter. + # + # This method is not HRD compliant. + #*/ + MFX_RATECONTROL_LA_ICQ =11 + #/*! + # MFX_RATECONTROL_LA_EXT has been removed + #*/ + + #/*! Use HRD compliant look ahead rate control algorithm. */ + MFX_RATECONTROL_LA_HRD =13 + #/*! + # Use the variable bitrate control algorithm with constant quality. This algorithm trying to achieve the target subjective quality with + # the minimum number of bits, while the bitrate constraint and HRD compliance are satisfied. It uses the same set of parameters + # as VBR and quality factor specified by mfxExtCodingOption3::QVBRQuality. + #*/ + MFX_RATECONTROL_QVBR =14 + +class StringAPI(PropertyHandler): + gop = property(lambda s: s.ifprop("gop", "GopPicSize={gop}")) + bframes = property(lambda s: s.ifprop("bframes", "GopRefDist={bframes}")) + slices = property(lambda s: s.ifprop("slices", "NumSlice={slices}")) + minrate = property(lambda s: s.ifprop("minrate", "TargetKbps={minrate}")) + maxrate = property(lambda s: s.ifprop("maxrate", "MaxKbps={maxrate}")) + refs = property(lambda s: s.ifprop("refs", "NumRefFrame={refs}")) + ladepth = property(lambda s: s.ifprop("ladepth", "LookAheadDepth={ladepth}")) + extbrc = property(lambda s: s.ifprop("extbrc", "ExtBRC={extbrc}")) + ldb = property(lambda s: s.ifprop("ldb", "mfxExtCodingOption3.LowDelayBRC={ldb}")) + strict = property(lambda s: s.ifprop("strict", "GopOptFlag={strict}")) + pict = property(lambda s: s.ifprop("vpict", "mfxExtCodingOption.PicTimingSEI=0")) + quality = property(lambda s: s.ifprop("quality", "TargetUsage={quality}")) + lowpower = property(lambda s: s.ifprop("lowpower", "LowPower={lowpower}")) + tilecols = property(lambda s: s.ifprop("tilecols", "mfxExtAV1TileParam.NumTileColumns={tilecols}")) + tilerows = property(lambda s: s.ifprop("tilerows", "mfxExtAV1TileParam.NumTileRows={tilerows}")) + maxframesize = property(lambda s: s.ifprop("maxframesize", "MaxSliceSize={maxframesize}")) + + @property + def profile(self): + def inner(profile): + return f"CodecProfile={self.map_profile(self.codec, self.props['profile'])}" + return self.ifprop("profile", inner) + + @property + def rcmode(self): + return f"RateControlMethod={self.map_rcmode(self.props['rcmode'])}" + + @property + def level(self): + def inner(level): + # TODO: need to define map_level + return f"CodecLevel={self.map_level(self.props['level'])}" + return self.ifprop("level", inner) + + @property + def qp(self): + def inner(qp): + rcmode = self.props["rcmode"].upper() + mqp = qp + if self.codec in [Codec.MPEG2]: + mqp = mapRangeInt(qp, [0, 100], [1, 51]) + elif self.codec in [Codec.AV1] and "ICQ" == rcmode: + mqp = mapRangeInt(qp, [0, 255], [1, 51]) + elif self.codec in [Codec.HEVC] and "QVBR" == rcmode: + mqp = mapRangeInt(qp, [0, 255], [1, 51]) + return f"QPI={mqp}:QPP={mqp}:QPB={mqp}" + return self.ifprop("qp", inner) + + @property + def encparams(self): + params = [ + self.profile, self.rcmode, self.qp, self.level, self.gop, self.bframes, + self.slices, self.minrate, self.maxrate, self.refs, self.ladepth, + self.extbrc, self.ldb, self.strict, self.pict, self.quality, self.lowpower, + self.tilecols, self.tilerows, self.maxframesize, + ] + return ':'.join(v for v in params if len(v) != 0) + + @classmethod + @memoize + def map_profile(cls, codec, profile): + # TODO: we could move this method to the enum class as "lookup" + # then call MfxCodecProfile.lookup(codec, profile) + return { + Codec.AVC : { + "high" : CodecProfile.MFX_PROFILE_AVC_HIGH, + "main" : CodecProfile.MFX_PROFILE_AVC_MAIN, + "baseline" : CodecProfile.MFX_PROFILE_AVC_BASELINE, + "unknown" : CodecProfile.MFX_PROFILE_UNKNOWN + }, + Codec.HEVC : { + "main" : CodecProfile.MFX_PROFILE_HEVC_MAIN, + "main444" : CodecProfile.MFX_PROFILE_HEVC_REXT, + "scc" : CodecProfile.MFX_PROFILE_HEVC_SCC, + "scc-444" : CodecProfile.MFX_PROFILE_HEVC_SCC, + "mainsp" : CodecProfile.MFX_PROFILE_HEVC_MAINSP, + "main10" : CodecProfile.MFX_PROFILE_HEVC_MAIN10, + "main10sp" : CodecProfile.MFX_PROFILE_HEVC_MAINSP, + "main444-10" : CodecProfile.MFX_PROFILE_HEVC_REXT, + "unknown" : CodecProfile.MFX_PROFILE_UNKNOWN + }, + Codec.AV1 : { + "main" : CodecProfile.MFX_PROFILE_AV1_MAIN, + }, + Codec.VP9 : { + "profile0" : CodecProfile.MFX_PROFILE_VP9_0, + "profile1" : CodecProfile.MFX_PROFILE_VP9_1, + "profile2" : CodecProfile.MFX_PROFILE_VP9_2, + "profile3" : CodecProfile.MFX_PROFILE_VP9_3 + }, + }[codec][profile] + + @classmethod + @memoize + def map_level(cls, codec, level): + # TODO: we could move this method to the enum class as "lookup" + # then call MfxCodecProfile.lookup(codec, profile) + return { + #/* H264 levels */ + Codec.AVC : { + 10 : MFX_LEVEL_AV1_1, + 9 : MFX_LEVEL_AV1_1b, + 11 : MFX_LEVEL_AV1_11, + 12 : MFX_LEVEL_AV1_12, + 13 : MFX_LEVEL_AV1_13, + 20 : MFX_LEVEL_AV1_2, + 21 : MFX_LEVEL_AV1_21, + 22 : MFX_LEVEL_AV1_22, + 30 : MFX_LEVEL_AV1_3, + 31 : MFX_LEVEL_AV1_31, + 32 : MFX_LEVEL_AV1_32, + 40 : MFX_LEVEL_AV1_4, + 41 : MFX_LEVEL_AV1_41, + 42 : MFX_LEVEL_AV1_42, + 50 : MFX_LEVEL_AV1_5, + 51 : MFX_LEVEL_AV1_51, + 52 : MFX_LEVEL_AV1_52, + 60 : MFX_LEVEL_AV1_6, + 61 : MFX_LEVEL_AV1_61, + 62 : MFX_LEVEL_AV1_62, + }, + #/* HEVC levels */ + Codec.HEVC : { + 10 : MFX_LEVEL_HEVC_1, + 20 : MFX_LEVEL_HEVC_2, + 21 : MFX_LEVEL_HEVC_21, + 30 : MFX_LEVEL_HEVC_3, + 31 : MFX_LEVEL_HEVC_31, + 40 : MFX_LEVEL_HEVC_4, + 41 : MFX_LEVEL_HEVC_41, + 50 : MFX_LEVEL_HEVC_5, + 51 : MFX_LEVEL_HEVC_51, + 52 : MFX_LEVEL_HEVC_52, + 60 : MFX_LEVEL_HEVC_6, + 61 : MFX_LEVEL_HEVC_61, + 62 : MFX_LEVEL_HEVC_62, + }, + #/* AV1 Levels */ + Codec.AV1 : { + 20 : MFX_LEVEL_AV1_2, + 21 : MFX_LEVEL_AV1_21, + 22 : MFX_LEVEL_AV1_22, + 23 : MFX_LEVEL_AV1_23, + 30 : MFX_LEVEL_AV1_3, + 31 : MFX_LEVEL_AV1_31, + 32 : MFX_LEVEL_AV1_32, + 33 : MFX_LEVEL_AV1_33, + 40 : MFX_LEVEL_AV1_4, + 41 : MFX_LEVEL_AV1_41, + 42 : MFX_LEVEL_AV1_42, + 43 : MFX_LEVEL_AV1_43, + 50 : MFX_LEVEL_AV1_5, + 51 : MFX_LEVEL_AV1_51, + 52 : MFX_LEVEL_AV1_52, + 53 : MFX_LEVEL_AV1_53, + 60 : MFX_LEVEL_AV1_6, + 61 : MFX_LEVEL_AV1_61, + 62 : MFX_LEVEL_AV1_62, + 63 : MFX_LEVEL_AV1_63, + 70 : MFX_LEVEL_AV1_7, + 71 : MFX_LEVEL_AV1_71, + 72 : MFX_LEVEL_AV1_72, + 73 : MFX_LEVEL_AV1_73, + }, + }[codec][level] + + @classmethod + @memoize + def map_rcmode(cls, rcmode): + # TODO: we could move this method to the enum class as "lookup" + # then call MfxRateControlMethod.lookup(rcmode) + return { + "CQP" : RateControlMethod.MFX_RATECONTROL_CQP, + "CBR" : RateControlMethod.MFX_RATECONTROL_CBR, + "VBR" : RateControlMethod.MFX_RATECONTROL_VBR, + "ICQ" : RateControlMethod.MFX_RATECONTROL_ICQ, + }[rcmode.upper()] From 35fd0452b7882838d4a2446e8023a84dea32c799 Mon Sep 17 00:00:00 2001 From: Focus Luo Date: Wed, 21 Aug 2024 19:34:19 -0700 Subject: [PATCH 2/7] [strapi] consolidated strapi generators Signed-off-by: Focus Luo --- lib/parameters.py | 202 +++++++++++++++++++++++++++++++--------------- 1 file changed, 135 insertions(+), 67 deletions(-) diff --git a/lib/parameters.py b/lib/parameters.py index bc6d85b7..eb5144a7 100755 --- a/lib/parameters.py +++ b/lib/parameters.py @@ -22,15 +22,19 @@ def format_value(value, **params): return value.format(**augmented) -def gen_avc_cqp_variants(spec, profiles): +def gen_avc_cqp_variants(spec, profiles, strapi=False): for case, params in spec.items(): - variants = copy.deepcopy(params.get("variants", dict()).get("cqp", None)) - if variants is None: - keys = ["gop", "slices", "bframes", "qp", "quality", "profile"] - product = list(itertools.product([1], [1], [0], [14, 28], [1, 4, 7], profiles)) # I, single-slice - product += list(itertools.product([30], [1], [0], [14, 28], [1, 4, 7], profiles)) # IP, single-slice - product += list(itertools.product([30], [4], [2], [14, 28], [1, 4, 7], profiles)) # IPB, multi-slice - variants = [dict(zip(keys, vals)) for vals in product] + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("cqp_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("cqp", None)) + + if variants is None: + keys = ["gop", "slices", "bframes", "qp", "quality", "profile"] + product = list(itertools.product([1], [1], [0], [14, 28], [1, 4, 7], profiles)) # I, single-slice + product += list(itertools.product([30], [1], [0], [14, 28], [1, 4, 7], profiles)) # IP, single-slice + product += list(itertools.product([30], [4], [2], [14, 28], [1, 4, 7], profiles)) # IPB, multi-slice + variants = [dict(zip(keys, vals)) for vals in product] for variant in variants: uprofile = variant.get("profile", None) @@ -53,14 +57,19 @@ def gen_avc_cqp_variants(spec, profiles): variant["qp"], variant["quality"], profile ] -def gen_avc_cqp_parameters(spec, profiles): +def gen_avc_cqp_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "bframes", "qp", "quality", "profile") - params = gen_avc_cqp_variants(spec, profiles) + params = gen_avc_cqp_variants(spec, profiles, strapi) return keys, params -def gen_avc_cbr_variants(spec, profiles): +def gen_avc_cbr_variants(spec, profiles, strapi=False): for case, params in spec.items(): - for variant in copy.deepcopy(params.get("variants", dict()).get("cbr", [])): + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("cbr_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("cbr", [])) + + for variant in variants: uprofile = variant.get("profile", None) cprofiles = [uprofile] if uprofile else profiles @@ -81,12 +90,12 @@ def gen_avc_cbr_variants(spec, profiles): variant["bitrate"], variant.get("fps", 30), profile ] -def gen_avc_cbr_parameters(spec, profiles): +def gen_avc_cbr_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "bframes", "bitrate", "fps", "profile") - params = gen_avc_cbr_variants(spec, profiles) + params = gen_avc_cbr_variants(spec, profiles, strapi) return keys, params -def gen_hevc_cbr_level_variants(spec, profiles): +def gen_hevc_cbr_level_variants(spec, profiles, strapi=False): for case, params in spec.items(): for variant in copy.deepcopy(params.get("variants", dict()).get("cbr_level", [])): uprofile = variant.get("profile", None) @@ -102,9 +111,14 @@ def gen_hevc_cbr_level_parameters( spec, profiles): params = gen_hevc_cbr_level_variants(spec, profiles) return keys, params -def gen_avc_vbr_variants(spec, profiles): +def gen_avc_vbr_variants(spec, profiles, strapi=False): for case, params in spec.items(): - for variant in copy.deepcopy(params.get("variants", dict()).get("vbr", [])): + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("vbr_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("vbr", [])) + + for variant in variants: uprofile = variant.get("profile", None) cprofiles = [uprofile] if uprofile else profiles for profile in cprofiles: @@ -114,14 +128,19 @@ def gen_avc_vbr_variants(spec, profiles): variant.get("refs", 1), profile ] -def gen_avc_vbr_parameters(spec, profiles): +def gen_avc_vbr_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "bframes", "bitrate", "fps", "quality", "refs", "profile") - params = gen_avc_vbr_variants(spec, profiles) + params = gen_avc_vbr_variants(spec, profiles, strapi) return keys, params -def gen_avc_cqp_lp_variants(spec, profiles): +def gen_avc_cqp_lp_variants(spec, profiles, strapi=False): for case, params in spec.items(): - for variant in copy.deepcopy(params.get("variants", dict()).get("cqp_lp", [])): + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("cqp_lp_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("cqp_lp", [])) + + for variant in variants: uprofile = variant.get("profile", None) cprofiles = [uprofile] if uprofile else profiles for profile in cprofiles: @@ -130,14 +149,19 @@ def gen_avc_cqp_lp_variants(spec, profiles): variant["quality"], profile ] -def gen_avc_cqp_lp_parameters(spec, profiles): +def gen_avc_cqp_lp_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "bframes", "qp", "quality", "profile") - params = gen_avc_cqp_lp_variants(spec, profiles) + params = gen_avc_cqp_lp_variants(spec, profiles, strapi) return keys, params -def gen_avc_cbr_lp_variants(spec, profiles): +def gen_avc_cbr_lp_variants(spec, profiles, strapi=False): for case, params in spec.items(): - for variant in copy.deepcopy(params.get("variants", dict()).get("cbr_lp", [])): + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("cbr_lp_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("cbr_lp", [])) + + for variant in variants: uprofile = variant.get("profile", None) cprofiles = [uprofile] if uprofile else profiles for profile in cprofiles: @@ -146,14 +170,19 @@ def gen_avc_cbr_lp_variants(spec, profiles): variant["bitrate"], variant.get("fps", 30), profile ] -def gen_avc_cbr_lp_parameters(spec, profiles): +def gen_avc_cbr_lp_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "bframes", "bitrate", "fps", "profile") - params = gen_avc_cbr_lp_variants(spec, profiles) + params = gen_avc_cbr_lp_variants(spec, profiles, strapi) return keys, params -def gen_avc_vbr_lp_variants(spec, profiles): +def gen_avc_vbr_lp_variants(spec, profiles, strapi=False): for case, params in spec.items(): - for variant in copy.deepcopy(params.get("variants", dict()).get("vbr_lp", [])): + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("vbr_lp_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("vbr_lp", [])) + + for variant in variants: uprofile = variant.get("profile", None) cprofiles = [uprofile] if uprofile else profiles for profile in cprofiles: @@ -163,9 +192,9 @@ def gen_avc_vbr_lp_variants(spec, profiles): variant.get("refs", 1), profile ] -def gen_avc_vbr_lp_parameters(spec, profiles): +def gen_avc_vbr_lp_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "bframes", "bitrate", "fps", "quality", "refs", "profile") - params = gen_avc_vbr_lp_variants(spec, profiles) + params = gen_avc_vbr_lp_variants(spec, profiles, strapi) return keys, params def gen_avc_tcbrc_variants(spec, profiles): @@ -390,9 +419,14 @@ def gen_avc_rqp_parameters(spec, profiles): params = gen_avc_rqp_variants(spec, profiles) return keys, params -def gen_hevc_cqp_lp_variants(spec, profiles): +def gen_hevc_cqp_lp_variants(spec, profiles, strapi=False): for case, params in spec.items(): - for variant in copy.deepcopy(params.get("variants", dict()).get("cqp_lp", [])): + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("cqp_lp_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("cqp_lp", [])) + + for variant in variants: uprofile = variant.get("profile", None) cprofiles = [uprofile] if uprofile else profiles for profile in cprofiles: @@ -401,14 +435,19 @@ def gen_hevc_cqp_lp_variants(spec, profiles): variant["quality"], profile ] -def gen_hevc_cqp_lp_parameters(spec, profiles): +def gen_hevc_cqp_lp_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "qp", "quality", "profile") - params = gen_hevc_cqp_lp_variants(spec, profiles) + params = gen_hevc_cqp_lp_variants(spec, profiles, strapi) return keys, params -def gen_hevc_cbr_lp_variants(spec, profiles): +def gen_hevc_cbr_lp_variants(spec, profiles, strapi=False): for case, params in spec.items(): - for variant in copy.deepcopy(params.get("variants", dict()).get("cbr_lp", [])): + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("cbr_lp_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("cbr_lp", [])) + + for variant in variants: uprofile = variant.get("profile", None) cprofiles = [uprofile] if uprofile else profiles for profile in cprofiles: @@ -417,14 +456,19 @@ def gen_hevc_cbr_lp_variants(spec, profiles): variant["bitrate"], variant.get("fps", 30), profile ] -def gen_hevc_cbr_lp_parameters(spec, profiles): +def gen_hevc_cbr_lp_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "bitrate", "fps", "profile") - params = gen_hevc_cbr_lp_variants(spec, profiles) + params = gen_hevc_cbr_lp_variants(spec, profiles, strapi) return keys, params -def gen_hevc_vbr_lp_variants(spec, profiles): +def gen_hevc_vbr_lp_variants(spec, profiles, strapi=False): for case, params in spec.items(): - for variant in copy.deepcopy(params.get("variants", dict()).get("vbr_lp", [])): + if strapi: + variants = copy.deepcopy(params.get("variants", dict()).get("vbr_lp_strapi", [])) + else: + variants = copy.deepcopy(params.get("variants", dict()).get("vbr_lp", [])) + + for variant in variants: uprofile = variant.get("profile", None) cprofiles = [uprofile] if uprofile else profiles for profile in cprofiles: @@ -434,9 +478,9 @@ def gen_hevc_vbr_lp_variants(spec, profiles): variant.get("refs", 1), profile ] -def gen_hevc_vbr_lp_parameters(spec, profiles): +def gen_hevc_vbr_lp_parameters(spec, profiles, strapi=False): keys = ("case", "gop", "slices", "bitrate", "fps", "quality", "refs", "profile") - params = gen_hevc_vbr_lp_variants(spec, profiles) + params = gen_hevc_vbr_lp_variants(spec, profiles, strapi) return keys, params def gen_hevc_qvbr_variants(spec, profiles): @@ -802,17 +846,21 @@ def gen_vp9_vbr_lp_parameters(spec): params = gen_vp9_vbr_lp_variants(spec) return keys, params -def gen_av1_cqp_variants(spec): +def gen_av1_cqp_variants(spec, strapi=False): for case, params in spec.items(): - variants = params.get("variants", dict()).get("cqp", []) + if strapi: + variants = params.get("variants", dict()).get("cqp_strapi", []) + else: + variants = params.get("variants", dict()).get("cqp", []) + for variant in variants: yield [ case, variant["gop"], variant["bframes"], variant["qp"], variant["quality"], variant.get("tilecols", 0), variant.get("tilerows", 0), variant.get("profile", "profile0")] -def gen_av1_cqp_parameters(spec): +def gen_av1_cqp_parameters(spec, strapi=False): keys = ("case", "gop", "bframes", "qp", "quality", "tilecols", "tilerows", "profile") - params = gen_av1_cqp_variants(spec) + params = gen_av1_cqp_variants(spec, strapi) return keys, params def gen_av1_icq_variants(spec): @@ -841,73 +889,93 @@ def gen_av1_icq_lp_parameters(spec): params = gen_av1_icq_lp_variants(spec) return keys, params -def gen_av1_cbr_variants(spec): +def gen_av1_cbr_variants(spec, strapi=False): for case, params in spec.items(): - variants = params.get("variants", dict()).get("cbr", []) + if strapi: + variants = params.get("variants", dict()).get("cbr_strapi", []) + else: + variants = params.get("variants", dict()).get("cbr", []) + for variant in variants: yield [ case, variant["gop"], variant["bframes"], variant["bitrate"], variant.get("quality", 4), variant.get("tilecols", 0), variant.get("tilerows", 0), variant.get("fps", 30), variant.get("profile", "profile0")] -def gen_av1_cbr_parameters(spec): +def gen_av1_cbr_parameters(spec, strapi=False): keys = ("case", "gop", "bframes", "bitrate", "quality", "tilecols", "tilerows", "fps", "profile") - params = gen_av1_cbr_variants(spec) + params = gen_av1_cbr_variants(spec, strapi) return keys, params -def gen_av1_vbr_variants(spec): +def gen_av1_vbr_variants(spec, strapi=False): for case, params in spec.items(): - variants = params.get("variants", dict()).get("vbr", []) + if strapi: + variants = params.get("variants", dict()).get("vbr_strapi", []) + else: + variants = params.get("variants", dict()).get("vbr", []) + for variant in variants: yield [ case, variant["gop"], variant["bframes"], variant["bitrate"], variant.get("quality", 4), variant.get("tilecols", 0), variant.get("tilerows", 0), variant.get("fps", 30), variant.get("profile", "profile0")] -def gen_av1_vbr_parameters(spec): +def gen_av1_vbr_parameters(spec, strapi=False): keys = ("case", "gop", "bframes", "bitrate", "quality", "tilecols", "tilerows", "fps", "profile") - params = gen_av1_vbr_variants(spec) + params = gen_av1_vbr_variants(spec, strapi) return keys, params -def gen_av1_cqp_lp_variants(spec): +def gen_av1_cqp_lp_variants(spec, strapi=False): for case, params in spec.items(): - variants = params.get("variants", dict()).get("cqp_lp", []) + if strapi: + variants = params.get("variants", dict()).get("cqp_lp_strapi", []) + else: + variants = params.get("variants", dict()).get("cqp_lp", []) + for variant in variants: yield [ case, variant["gop"], variant["bframes"], variant["qp"], variant["quality"], variant.get("tilecols", 0), variant.get("tilerows", 0), variant.get("profile", "profile0")] -def gen_av1_cqp_lp_parameters(spec): +def gen_av1_cqp_lp_parameters(spec, strapi=False): keys = ("case", "gop", "bframes", "qp", "quality", "tilecols", "tilerows", "profile") - params = gen_av1_cqp_lp_variants(spec) + params = gen_av1_cqp_lp_variants(spec, strapi) return keys, params -def gen_av1_cbr_lp_variants(spec): +def gen_av1_cbr_lp_variants(spec, strapi=False): for case, params in spec.items(): - variants = params.get("variants", dict()).get("cbr_lp", []) + if strapi: + variants = params.get("variants", dict()).get("cbr_lp_strapi", []) + else: + variants = params.get("variants", dict()).get("cbr_lp", []) + for variant in variants: yield [ case, variant["gop"], variant["bframes"], variant["bitrate"], variant.get("quality", 4), variant.get("tilecols", 0), variant.get("tilerows", 0), variant.get("fps", 30), variant.get("profile", "profile0")] -def gen_av1_cbr_lp_parameters(spec): +def gen_av1_cbr_lp_parameters(spec, strapi=False): keys = ("case", "gop", "bframes", "bitrate", "quality", "tilecols", "tilerows", "fps", "profile") - params = gen_av1_cbr_lp_variants(spec) + params = gen_av1_cbr_lp_variants(spec, strapi) return keys, params -def gen_av1_vbr_lp_variants(spec): +def gen_av1_vbr_lp_variants(spec, strapi=False): for case, params in spec.items(): - variants = params.get("variants", dict()).get("vbr_lp", []) + if strapi: + variants = params.get("variants", dict()).get("vbr_lp_strapi", []) + else: + variants = params.get("variants", dict()).get("vbr_lp", []) + for variant in variants: yield [ case, variant["gop"], variant["bframes"], variant["bitrate"], variant.get("quality", 4), variant.get("tilecols", 0), variant.get("tilerows", 0), variant.get("fps", 30), variant.get("profile", "profile0")] -def gen_av1_vbr_lp_parameters(spec): +def gen_av1_vbr_lp_parameters(spec, strapi=False): keys = ("case", "gop", "bframes", "bitrate", "quality", "tilecols", "tilerows", "fps", "profile") - params = gen_av1_vbr_lp_variants(spec) + params = gen_av1_vbr_lp_variants(spec, strapi) return keys, params def gen_vpp_sharpen_variants(spec): From f64740cda2a132a0a0857ee16a17490958a94cc4 Mon Sep 17 00:00:00 2001 From: Focus Luo Date: Wed, 21 Aug 2024 19:35:25 -0700 Subject: [PATCH 3/7] [strapi] added have_ffmpeg_encoder_options checked for strapi Signed-off-by: Focus Luo --- lib/ffmpeg/util.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/ffmpeg/util.py b/lib/ffmpeg/util.py index 71a0c650..c8d50d4e 100644 --- a/lib/ffmpeg/util.py +++ b/lib/ffmpeg/util.py @@ -85,6 +85,17 @@ def have_ffmpeg_encoder(encoder): result = try_call(f"{exe2os('ffmpeg')} -hide_banner -encoders | awk '{{print $2}}' | grep -w {encoder}") return result, encoder +@memoize +def have_ffmpeg_encoder_options(name, *args): + failmsg = "{0}.{1}".format(name, '.'.join(args)) + result = try_call(f"{exe2os('ffmpeg')} -hide_banner -encoders | awk '{{print $2}}' | grep -w {name}") + if result is True: + for key in args: + result = try_call(f"{exe2os('ffmpeg')} -hide_banner -h encoder={name} | grep -e {key}") + if result is False: + break + return result, failmsg + @memoize def have_ffmpeg_decoder(decoder): result = try_call(f"{exe2os('ffmpeg')} -hide_banner -decoders | awk '{{print $2}}' | grep -w {decoder}") From 3bff72b84346fddacab4097076ea212f1c298cfb Mon Sep 17 00:00:00 2001 From: Focus Luo Date: Fri, 23 Aug 2024 09:47:50 -0700 Subject: [PATCH 4/7] [strapi] ffmpeg-qsv add dedicated strapi enc class Signed-off-by: Focus Luo --- lib/ffmpeg/qsv/encoder.py | 8 ++ lib/mfx/api.py | 152 +------------------------------------- 2 files changed, 9 insertions(+), 151 deletions(-) diff --git a/lib/ffmpeg/qsv/encoder.py b/lib/ffmpeg/qsv/encoder.py index 7af0bea0..2891f83d 100644 --- a/lib/ffmpeg/qsv/encoder.py +++ b/lib/ffmpeg/qsv/encoder.py @@ -15,6 +15,7 @@ from ....lib.common import mapRangeInt, get_media, call, exe2os from ....lib.codecs import Codec from ....lib.formats import PixelFormat +from ....lib.mfx.api import StringAPI class Encoder(FFEncoder): hwaccel = property(lambda s: "qsv") @@ -65,6 +66,13 @@ def encparams(self): f"{self.iqoffset}{self.bqoffset}" ) +# NOTE: Inherit from the StringAPI class first so that it overrides the +# Encoder class +class StringAPIEncoder(StringAPI, Encoder): + @property + def encparams(self): + return f" -qsv_params '{super().encparams}'" + @slash.requires(*have_ffmpeg_hwaccel("qsv")) @slash.requires(using_compatible_driver) class EncoderTest(BaseEncoderTest): diff --git a/lib/mfx/api.py b/lib/mfx/api.py index 347f59dc..8374b8a8 100644 --- a/lib/mfx/api.py +++ b/lib/mfx/api.py @@ -44,76 +44,6 @@ class CodecProfile(IntEnum): MFX_PROFILE_VP9_2 = 3 MFX_PROFILE_VP9_3 = 4 -class CodecLevel(IntEnum): - MFX_LEVEL_UNKNOWN =0 #/*!< Unspecified level. */ - #/* H.264 level 1-1.3 */ - MFX_LEVEL_AVC_1 =10 - MFX_LEVEL_AVC_1b =9 - MFX_LEVEL_AVC_11 =11 - MFX_LEVEL_AVC_12 =12 - MFX_LEVEL_AVC_13 =13 - #/* H.264 level 2-2.2 */ - MFX_LEVEL_AVC_2 =20 - MFX_LEVEL_AVC_21 =21 - MFX_LEVEL_AVC_22 =22 - #/* H.264 level 3-3.2 */ - MFX_LEVEL_AVC_3 =30 - MFX_LEVEL_AVC_31 =31 - MFX_LEVEL_AVC_32 =32 - #/* H.264 level 4-4.2 */ - MFX_LEVEL_AVC_4 =40 - MFX_LEVEL_AVC_41 =41 - MFX_LEVEL_AVC_42 =42 - #/* H.264 level 5-5.2 */ - MFX_LEVEL_AVC_5 =50 - MFX_LEVEL_AVC_51 =51 - MFX_LEVEL_AVC_52 =52 - #/* H.264 level 6-6.2 */ - MFX_LEVEL_AVC_6 =60 - MFX_LEVEL_AVC_61 =61 - MFX_LEVEL_AVC_62 =62 - - #/* HEVC levels */ - MFX_LEVEL_HEVC_1 = 10 - MFX_LEVEL_HEVC_2 = 20 - MFX_LEVEL_HEVC_21 = 21 - MFX_LEVEL_HEVC_3 = 30 - MFX_LEVEL_HEVC_31 = 31 - MFX_LEVEL_HEVC_4 = 40 - MFX_LEVEL_HEVC_41 = 41 - MFX_LEVEL_HEVC_5 = 50 - MFX_LEVEL_HEVC_51 = 51 - MFX_LEVEL_HEVC_52 = 52 - MFX_LEVEL_HEVC_6 = 60 - MFX_LEVEL_HEVC_61 = 61 - MFX_LEVEL_HEVC_62 = 62 - - #/* AV1 Levels */ - MFX_LEVEL_AV1_2 = 20 - MFX_LEVEL_AV1_21 = 21 - MFX_LEVEL_AV1_22 = 22 - MFX_LEVEL_AV1_23 = 23 - MFX_LEVEL_AV1_3 = 30 - MFX_LEVEL_AV1_31 = 31 - MFX_LEVEL_AV1_32 = 32 - MFX_LEVEL_AV1_33 = 33 - MFX_LEVEL_AV1_4 = 40 - MFX_LEVEL_AV1_41 = 41 - MFX_LEVEL_AV1_42 = 42 - MFX_LEVEL_AV1_43 = 43 - MFX_LEVEL_AV1_5 = 50 - MFX_LEVEL_AV1_51 = 51 - MFX_LEVEL_AV1_52 = 52 - MFX_LEVEL_AV1_53 = 53 - MFX_LEVEL_AV1_6 = 60 - MFX_LEVEL_AV1_61 = 61 - MFX_LEVEL_AV1_62 = 62 - MFX_LEVEL_AV1_63 = 63 - MFX_LEVEL_AV1_7 = 70 - MFX_LEVEL_AV1_71 = 71 - MFX_LEVEL_AV1_72 = 72 - MFX_LEVEL_AV1_73 = 73 - class RateControlMethod(IntEnum): #/*! The RateControlMethod enumerator itemizes bitrate control methods. */ MFX_RATECONTROL_CBR =1 #/*!< Use the constant bitrate control algorithm. */ @@ -168,6 +98,7 @@ class RateControlMethod(IntEnum): MFX_RATECONTROL_QVBR =14 class StringAPI(PropertyHandler): + level = property(lambda s: s.ifprop("level", "CodecLevel={level}")) gop = property(lambda s: s.ifprop("gop", "GopPicSize={gop}")) bframes = property(lambda s: s.ifprop("bframes", "GopRefDist={bframes}")) slices = property(lambda s: s.ifprop("slices", "NumSlice={slices}")) @@ -195,13 +126,6 @@ def inner(profile): def rcmode(self): return f"RateControlMethod={self.map_rcmode(self.props['rcmode'])}" - @property - def level(self): - def inner(level): - # TODO: need to define map_level - return f"CodecLevel={self.map_level(self.props['level'])}" - return self.ifprop("level", inner) - @property def qp(self): def inner(qp): @@ -260,80 +184,6 @@ def map_profile(cls, codec, profile): }, }[codec][profile] - @classmethod - @memoize - def map_level(cls, codec, level): - # TODO: we could move this method to the enum class as "lookup" - # then call MfxCodecProfile.lookup(codec, profile) - return { - #/* H264 levels */ - Codec.AVC : { - 10 : MFX_LEVEL_AV1_1, - 9 : MFX_LEVEL_AV1_1b, - 11 : MFX_LEVEL_AV1_11, - 12 : MFX_LEVEL_AV1_12, - 13 : MFX_LEVEL_AV1_13, - 20 : MFX_LEVEL_AV1_2, - 21 : MFX_LEVEL_AV1_21, - 22 : MFX_LEVEL_AV1_22, - 30 : MFX_LEVEL_AV1_3, - 31 : MFX_LEVEL_AV1_31, - 32 : MFX_LEVEL_AV1_32, - 40 : MFX_LEVEL_AV1_4, - 41 : MFX_LEVEL_AV1_41, - 42 : MFX_LEVEL_AV1_42, - 50 : MFX_LEVEL_AV1_5, - 51 : MFX_LEVEL_AV1_51, - 52 : MFX_LEVEL_AV1_52, - 60 : MFX_LEVEL_AV1_6, - 61 : MFX_LEVEL_AV1_61, - 62 : MFX_LEVEL_AV1_62, - }, - #/* HEVC levels */ - Codec.HEVC : { - 10 : MFX_LEVEL_HEVC_1, - 20 : MFX_LEVEL_HEVC_2, - 21 : MFX_LEVEL_HEVC_21, - 30 : MFX_LEVEL_HEVC_3, - 31 : MFX_LEVEL_HEVC_31, - 40 : MFX_LEVEL_HEVC_4, - 41 : MFX_LEVEL_HEVC_41, - 50 : MFX_LEVEL_HEVC_5, - 51 : MFX_LEVEL_HEVC_51, - 52 : MFX_LEVEL_HEVC_52, - 60 : MFX_LEVEL_HEVC_6, - 61 : MFX_LEVEL_HEVC_61, - 62 : MFX_LEVEL_HEVC_62, - }, - #/* AV1 Levels */ - Codec.AV1 : { - 20 : MFX_LEVEL_AV1_2, - 21 : MFX_LEVEL_AV1_21, - 22 : MFX_LEVEL_AV1_22, - 23 : MFX_LEVEL_AV1_23, - 30 : MFX_LEVEL_AV1_3, - 31 : MFX_LEVEL_AV1_31, - 32 : MFX_LEVEL_AV1_32, - 33 : MFX_LEVEL_AV1_33, - 40 : MFX_LEVEL_AV1_4, - 41 : MFX_LEVEL_AV1_41, - 42 : MFX_LEVEL_AV1_42, - 43 : MFX_LEVEL_AV1_43, - 50 : MFX_LEVEL_AV1_5, - 51 : MFX_LEVEL_AV1_51, - 52 : MFX_LEVEL_AV1_52, - 53 : MFX_LEVEL_AV1_53, - 60 : MFX_LEVEL_AV1_6, - 61 : MFX_LEVEL_AV1_61, - 62 : MFX_LEVEL_AV1_62, - 63 : MFX_LEVEL_AV1_63, - 70 : MFX_LEVEL_AV1_7, - 71 : MFX_LEVEL_AV1_71, - 72 : MFX_LEVEL_AV1_72, - 73 : MFX_LEVEL_AV1_73, - }, - }[codec][level] - @classmethod @memoize def map_rcmode(cls, rcmode): From bcbe9ddffeb5230c774759740ba33fc66cf86b3f Mon Sep 17 00:00:00 2001 From: Focus Luo Date: Fri, 23 Aug 2024 09:48:28 -0700 Subject: [PATCH 5/7] [strapi]ffmpeg-qsv avc using consolidated strapi generators Signed-off-by: Focus Luo --- test/ffmpeg-qsv/encode/avc.py | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/ffmpeg-qsv/encode/avc.py b/test/ffmpeg-qsv/encode/avc.py index e612a45d..a38303f3 100755 --- a/test/ffmpeg-qsv/encode/avc.py +++ b/test/ffmpeg-qsv/encode/avc.py @@ -7,6 +7,7 @@ from ....lib import * from ....lib.ffmpeg.qsv.util import * from ....lib.ffmpeg.qsv.encoder import AVCEncoderTest, AVCEncoderLPTest +from ....lib.ffmpeg.qsv.encoder import StringAPIEncoder spec = load_test_spec("avc", "encode") spec_r2r = load_test_spec("avc", "encode", "r2r") @@ -36,6 +37,13 @@ def test_r2r(self, case, gop, slices, bframes, qp, quality, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("h264_qsv", "qsv_params")) + @slash.parametrize(*gen_avc_cqp_parameters(spec, ['high', 'main', 'baseline'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, qp, quality, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, qp, quality, profile) + self.encode() + class cqp_lp(AVCEncoderLPTest): def init(self, tspec, case, gop, slices, bframes, qp, quality, profile): vars(self).update(tspec[case].copy()) @@ -61,6 +69,13 @@ def test_r2r(self, case, gop, slices, bframes, qp, quality, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("h264_qsv", "qsv_params")) + @slash.parametrize(*gen_avc_cqp_lp_parameters(spec, ['high', 'main'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, qp, quality, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, qp, quality, profile) + self.encode() + class cbr(AVCEncoderTest): def init(self, tspec, case, gop, slices, bframes, bitrate, fps, profile): vars(self).update(tspec[case].copy()) @@ -88,6 +103,13 @@ def test_r2r(self, case, gop, slices, bframes, bitrate, fps, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("h264_qsv", "qsv_params")) + @slash.parametrize(*gen_avc_cbr_parameters(spec, ['high', 'main', 'baseline'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, bitrate, fps, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, bitrate, fps, profile) + self.encode() + class cbr_lp(AVCEncoderLPTest): def init(self, tspec, case, gop, slices, bframes, bitrate, fps, profile): vars(self).update(tspec[case].copy()) @@ -115,6 +137,13 @@ def test_r2r(self, case, gop, slices, bframes, bitrate, fps, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("h264_qsv", "qsv_params")) + @slash.parametrize(*gen_avc_cbr_lp_parameters(spec, ['high', 'main'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, bitrate, fps, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, bitrate, fps, profile) + self.encode() + class vbr(AVCEncoderTest): def init(self, tspec, case, gop, slices, bframes, bitrate, fps, quality, refs, profile): vars(self).update(tspec[case].copy()) @@ -144,6 +173,13 @@ def test_r2r(self, case, gop, slices, bframes, bitrate, fps, quality, refs, prof vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("h264_qsv", "qsv_params")) + @slash.parametrize(*gen_avc_vbr_parameters(spec, ['high', 'main', 'baseline'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, bitrate, fps, quality, refs, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, bitrate, fps, quality, refs, profile) + self.encode() + class vbr_lp(AVCEncoderLPTest): def before(self): super().before() @@ -191,6 +227,13 @@ def test_tcbrc(self, case, bitrate, fps, profile): ) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("h264_qsv", "qsv_params")) + @slash.parametrize(*gen_avc_vbr_lp_parameters(spec, ['high', 'main'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, bitrate, fps, quality, refs, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, bitrate, fps, quality, refs, profile) + self.encode() + # TODO: This can be moved into the vbr test class in a test_la method class vbr_la(AVCEncoderTest): @slash.parametrize(*gen_avc_vbr_la_parameters(spec, ['high', 'main', 'baseline'])) From 903992afd72efae97d1518d9394109ae4113bfb9 Mon Sep 17 00:00:00 2001 From: Focus Luo Date: Fri, 23 Aug 2024 09:48:44 -0700 Subject: [PATCH 6/7] [strapi]ffmpeg-qsv hevc using consolidated strapi generators Signed-off-by: Focus Luo --- test/ffmpeg-qsv/encode/hevc.py | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/ffmpeg-qsv/encode/hevc.py b/test/ffmpeg-qsv/encode/hevc.py index c87fa4e8..90861ec1 100755 --- a/test/ffmpeg-qsv/encode/hevc.py +++ b/test/ffmpeg-qsv/encode/hevc.py @@ -7,6 +7,7 @@ from ....lib import * from ....lib.ffmpeg.qsv.util import * from ....lib.ffmpeg.qsv.encoder import HEVC8EncoderTest, HEVC8EncoderLPTest +from ....lib.ffmpeg.qsv.encoder import StringAPIEncoder spec = load_test_spec("hevc", "encode", "8bit") spec_r2r = load_test_spec("hevc", "encode", "8bit", "r2r") @@ -36,6 +37,13 @@ def test_r2r(self, case, gop, slices, bframes, qp, quality, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("hevc_qsv", "qsv_params")) + @slash.parametrize(*gen_hevc_cqp_parameters(spec, ['main'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, qp, quality, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, qp, quality, profile) + self.encode() + class cqp_lp(HEVC8EncoderLPTest): def init(self, tspec, case, gop, slices, qp, quality, profile): vars(self).update(tspec[case].copy()) @@ -60,6 +68,13 @@ def test_r2r(self, case, gop, slices, qp, quality, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("hevc_qsv", "qsv_params")) + @slash.parametrize(*gen_hevc_cqp_lp_parameters(spec, ['main'], strapi=True)) + def test_strapi(self, case, gop, slices, qp, quality, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, qp, quality, profile) + self.encode() + class cbr(HEVC8EncoderTest): def init(self, tspec, case, gop, slices, bframes, bitrate, fps, profile): vars(self).update(tspec[case].copy()) @@ -87,6 +102,13 @@ def test_r2r(self, case, gop, slices, bframes, bitrate, fps, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("hevc_qsv", "qsv_params")) + @slash.parametrize(*gen_hevc_cbr_parameters(spec, ['main'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, bitrate, fps, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, bitrate, fps, profile) + self.encode() + class cbr_lp(HEVC8EncoderLPTest): def init(self, tspec, case, gop, slices, bitrate, fps, profile): vars(self).update(tspec[case].copy()) @@ -113,6 +135,13 @@ def test_r2r(self, case, gop, slices, bitrate, fps, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("hevc_qsv", "qsv_params")) + @slash.parametrize(*gen_hevc_cbr_lp_parameters(spec, ['main'], strapi=True)) + def test_strapi(self, case, gop, slices, bitrate, fps, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bitrate, fps, profile) + self.encode() + class vbr(HEVC8EncoderTest): def init(self, tspec, case, gop, slices, bframes, bitrate, fps, quality, refs, profile): vars(self).update(tspec[case].copy()) @@ -142,6 +171,13 @@ def test_r2r(self, case, gop, slices, bframes, bitrate, fps, quality, refs, prof vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("hevc_qsv", "qsv_params")) + @slash.parametrize(*gen_hevc_vbr_parameters(spec, ['main'], strapi=True)) + def test_strapi(self, case, gop, slices, bframes, bitrate, fps, quality, refs, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bframes, bitrate, fps, quality, refs, profile) + self.encode() + class vbr_lp(HEVC8EncoderLPTest): def before(self): super().before() @@ -173,6 +209,13 @@ def test_r2r(self, case, gop, slices, bitrate, fps, quality, refs, profile): vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("hevc_qsv", "qsv_params")) + @slash.parametrize(*gen_hevc_vbr_lp_parameters(spec, ['main'], strapi=True)) + def test_strapi(self, case, gop, slices, bitrate, fps, quality, refs, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, slices, bitrate, fps, quality, refs, profile) + self.encode() + # TCBRC is VBR LP + LDB + Strict(-1) @slash.parametrize(*gen_hevc_tcbrc_parameters(spec, ['main'])) def test_tcbrc(self, case, bitrate, fps, profile): From e457674c42a61c2eef366645a26c0b0de39cbf90 Mon Sep 17 00:00:00 2001 From: Focus Luo Date: Fri, 23 Aug 2024 09:49:04 -0700 Subject: [PATCH 7/7] [strapi]ffmpeg-qsv av1 using consolidated strapi generators Signed-off-by: Focus Luo --- test/ffmpeg-qsv/encode/av1.py | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/ffmpeg-qsv/encode/av1.py b/test/ffmpeg-qsv/encode/av1.py index 3fd5cf15..7dfc0b6b 100644 --- a/test/ffmpeg-qsv/encode/av1.py +++ b/test/ffmpeg-qsv/encode/av1.py @@ -7,6 +7,7 @@ from ....lib import * from ....lib.ffmpeg.qsv.util import * from ....lib.ffmpeg.qsv.encoder import AV1EncoderLPTest, AV1EncoderTest +from ....lib.ffmpeg.qsv.encoder import StringAPIEncoder spec = load_test_spec("av1", "encode", "8bit") spec_r2r = load_test_spec("av1", "encode", "8bit", "r2r") @@ -37,6 +38,13 @@ def test_r2r(self, case, gop, bframes, tilecols, tilerows, qp, quality, profile) vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("av1_qsv", "qsv_params")) + @slash.parametrize(*gen_av1_cqp_parameters(spec, strapi=True)) + def test_strapi(self, case, gop, bframes, tilecols, tilerows, qp, quality, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, bframes, tilecols, tilerows, qp, quality, profile) + self.encode() + class icq(AV1EncoderTest): def init(self, tspec, case, gop, bframes, tilecols, tilerows,qp, quality, profile): vars(self).update(tspec[case].copy()) @@ -92,6 +100,13 @@ def test_r2r(self, case, gop, bframes, tilecols, tilerows, bitrate, quality, fps vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("av1_qsv", "qsv_params")) + @slash.parametrize(*gen_av1_cbr_parameters(spec, strapi=True)) + def test_strapi(self, case, gop, bframes, tilecols, tilerows, bitrate, quality, fps, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile) + self.encode() + class vbr(AV1EncoderTest): def init(self, tspec, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile): vars(self).update(tspec[case].copy()) @@ -122,6 +137,13 @@ def test_r2r(self, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("av1_qsv", "qsv_params")) + @slash.parametrize(*gen_av1_vbr_parameters(spec, strapi=True)) + def test_strapi(self, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile) + self.encode() + class cqp_lp(AV1EncoderLPTest): def init(self, tspec, case, gop, bframes, tilecols, tilerows,qp, quality, profile): vars(self).update(tspec[case].copy()) @@ -148,6 +170,13 @@ def test_r2r(self, case, gop, bframes, tilecols, tilerows, qp, quality, profile) vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("av1_qsv", "qsv_params")) + @slash.parametrize(*gen_av1_cqp_lp_parameters(spec, strapi=True)) + def test_strapi(self, case, gop, bframes, tilecols, tilerows, qp, quality, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, bframes, tilecols, tilerows, qp, quality, profile) + self.encode() + class icq_lp(AV1EncoderLPTest): def init(self, tspec, case, gop, bframes, tilecols, tilerows,qp, quality, profile): vars(self).update(tspec[case].copy()) @@ -203,6 +232,13 @@ def test_r2r(self, case, gop, bframes, tilecols, tilerows, bitrate, quality, fps vars(self).setdefault("r2r", 5) self.encode() + @slash.requires(*have_ffmpeg_encoder_options("av1_qsv", "qsv_params")) + @slash.parametrize(*gen_av1_cbr_lp_parameters(spec, strapi=True)) + def test_strapi(self, case, gop, bframes, tilecols, tilerows, bitrate, quality, fps, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile) + self.encode() + class vbr_lp(AV1EncoderLPTest): def init(self, tspec, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile): vars(self).update(tspec[case].copy()) @@ -232,3 +268,11 @@ def test_r2r(self, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality self.init(spec_r2r, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile) vars(self).setdefault("r2r", 5) self.encode() + + @slash.requires(*have_ffmpeg_encoder_options("av1_qsv", "qsv_params")) + @slash.parametrize(*gen_av1_vbr_lp_parameters(spec, strapi=True)) + def test_strapi(self, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile): + self.EncoderClass = StringAPIEncoder + self.init(spec, case, gop, bframes, tilecols, tilerows, bitrate, fps, quality, profile) + self.encode() +