Skip to content

Commit

Permalink
[ffmpeg-qsv] add string api support
Browse files Browse the repository at this point in the history
Signed-off-by: Focus Luo <[email protected]>
  • Loading branch information
FocusLuo committed May 14, 2024
1 parent f8f499c commit bc17525
Show file tree
Hide file tree
Showing 3 changed files with 322 additions and 7 deletions.
130 changes: 123 additions & 7 deletions lib/ffmpeg/qsv/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
from ....lib import platform
from ....lib.ffmpeg.encoderbase import BaseEncoderTest, Encoder as FFEncoder
from ....lib.ffmpeg.util import have_ffmpeg_hwaccel, have_ffmpeg_encoder, have_ffmpeg_decoder
from ....lib.ffmpeg.qsv.util import mapprofile, using_compatible_driver, have_encode_main10sp
from ....lib.ffmpeg.qsv.util import mapprofile, mapprofile_stringapi, using_compatible_driver, have_encode_main10sp
from ....lib.ffmpeg.qsv.decoder import Decoder
from ....lib.common import mapRangeInt, get_media, call, exe2os
from ....lib.common import mapRangeInt, get_media, call, exe2os, timefn, filepath2os
from ....lib.codecs import Codec
from ....lib.formats import PixelFormat
from ....lib.string_api import *


class Encoder(FFEncoder):
hwaccel = property(lambda s: "qsv")
Expand Down Expand Up @@ -57,12 +59,125 @@ def inner(quality):
return f" -preset {quality}"
return self.ifprop("quality", inner)

def map_profile_stringapi(self, codec, profile):
return mapprofile_stringapi(codec, profile)

@property
def encparams(self):
return (
f"{super().encparams}{self.ldb}"
f"{self.iqfactor}{self.bqfactor}"
f"{self.iqoffset}{self.bqoffset}"
# return (
# f"{super().encparams}{self.ldb}"
# f"{self.iqfactor}{self.bqfactor}"
# f"{self.iqoffset}{self.bqoffset}"
# )
_encparams = ""
if self.profile != None and len(self.profile.strip())>0:
r,_,_profile=self.profile.partition('-profile:v')
_profile=_profile.strip()
_codec_profile = self.map_profile_stringapi(self.codec, _profile)
if _codec_profile is None:
slash.skip_test("profile is not supported".format(**vars(self)))
_encparams = f"CodecProfile={_codec_profile}"
if self.level != None and len(self.level.strip())>0:
_level=re.findall("\d+", self.level)[0]
_encparams = f"{_encparams}:CodecLevel={_level}"
if self.rcmode != None and len(self.rcmode.strip())>0:
_rc_mode=RateControlMethod.MFX_RATECONTROL_CQP.value
if self.rcmode.upper() in ["CQP"]:
_rc_mode=RateControlMethod.MFX_RATECONTROL_CQP.value
elif self.rcmode.upper() in ["CBR"]:
_rc_mode=RateControlMethod.MFX_RATECONTROL_CBR.value
elif self.rcmode.upper() in ["VBR"]:
_rc_mode=RateControlMethod.MFX_RATECONTROL_VBR.value
elif self.rcmode.upper() in ["ICQ"]:
_rc_mode=RateControlMethod.MFX_RATECONTROL_ICQ.value
_encparams = f"{_encparams}:RateControlMethod={_rc_mode}"
if self.qp != None and len(self.qp.strip())>0:
_qp=re.findall("\d+", self.qp)[0]
_rc_mode=RateControlMethod.MFX_RATECONTROL_CQP.value
_encparams = f"{_encparams}:QPI={_qp}:QPP={_qp}:QPB={_qp}"
if self.gop != None and len(self.gop.strip())>0:
_gop=re.findall("\d+", self.gop)[0]
_encparams = f"{_encparams}:GopPicSize={_gop}"
if self.bframes != None and len(self.bframes.strip())>0:
_bframes=re.findall("\d+", self.bframes)[0]
_encparams = f"{_encparams}:GopRefDist={_bframes}"
if self.slices != None and len(self.slices.strip())>0:
_slices=re.findall("\d+", self.slices)[0]
_encparams = f"{_encparams}:NumSlice={_slices}"
if self.maxframesize != None and len(self.maxframesize.strip())>0:
_maxframesize=re.findall("\d+", self.maxframesize)[0]
_encparams = f"{_encparams}:MaxSliceSize={_maxframesize}"
if self.minrate != None and len(self.minrate.strip())>0:
_minrate=re.findall("\d+", self.minrate)[0]
_encparams = f"{_encparams}:TargetKbps={_minrate}"
if self.maxrate != None and len(self.maxrate.strip())>0:
_maxrate=re.findall("\d+", self.maxrate)[0]
_encparams = f"{_encparams}:MaxKbps={_maxrate}"
if self.refs != None and len(self.refs.strip())>0:
_refs=re.findall("\d+", self.refs)[0]
_encparams = f"{_encparams}:NumRefFrame={_refs}"
if self.ladepth != None and len(self.ladepth.strip())>0:
_ladepth=re.findall("\d+", self.ladepth)[0]
_encparams = f"{_encparams}:LookAheadDepth={ladepth}"
if self.intref != None and len(self.intref.strip())>0:
# for exampe: self.intref=" -int_ref_type 1 -int_ref_cycle_size 4 -int_ref_cycle_dist 20"
# to get intref_type
r,_,_intref_type=self.intref.partition('-int_ref_type')
_intref_type,_,r=_intref_type.partition('-int_ref_cycle_size')
# to get intref_size
_intref_type=_intref_type.strip()
r,_,_intref_size=self.intref.partition('-int_ref_cycle_size')
_intref_size,_,r=_intref_size.partition('-int_ref_cycle_dist')
_intref_size=_intref_size.strip()
# to get intref_dist
r,_,_intref_refdist=self.intref.partition('-int_ref_cycle_dist')
_intref_refdist=_intref_refdist.strip()
_encparams = f"{_encparams}:mfxExtCodingOption2.IntRefType={_intref_type}:mfxExtCodingOption2.IntRefCycleSize={_intref_size}:mfxExtCodingOption3.IntRefCycleDist={_intref_refdist}"
if self.extbrc != None and len(self.extbrc.strip())>0:
_extbrc=re.findall("\d+", self.extbrc)[0]
_encparams = f"{_encparams}:ExtBRC={_extbrc}"
if self.ldb != None and len(self.ldb.strip())>0:
_ldb=re.findall("\d+", self.ldb)[0]
_encparams = f"{_encparams}:mfxExtCodingOption3.LowDelayBRC={_ldb}"
if self.tilecols != None and len(self.tilecols.strip())>0:
_tilecols=re.findall("\d+", self.tilecols)[0]
_encparams = f"{_encparams}:mfxExtAV1TileParam.NumTileColumns={_tilecols}"
if self.tilerows != None and len(self.tilerows.strip())>0:
_tilerows=re.findall("\d+", self.tilerows)[0]
_encparams = f"{_encparams}:mfxExtAV1TileParam.NumTileRows={_tilerows}"
if self.strict != None and len(self.strict.strip())>0:
_strict=re.findall("\d+", self.strict)[0]
_encparams = f"{_encparams}:GopOptFlag={_strict}"
if self.pict != None and len(self.pict.strip())>0:
_pict=re.findall("\d+", self.pict)[0]
_encparams = f"{_encparams}:mfxExtCodingOption.PicTimingSEI={_pict}"
if self.quality != None and len(self.quality.strip())>0:
_quality=re.findall("\d+", self.quality)[0]
_encparams = f"{_encparams}:TargetUsage={_quality}"
if self.lowpower != None and len(self.lowpower.strip())>0:
_lowpower=re.findall("\d+", self.lowpower)[0]
_encparams = f"{_encparams}:LowPower={_lowpower}"
#{self.forced_idr} ffmpeg
#{self.pict}{self.rqp}

if _encparams != None and len(_encparams.strip()) > 1:
if ':' == _encparams[0]:
_encparams = _encparams[1:]
return f"{_encparams}"

@timefn("ffmpeg:encode")
def encode(self):
if vars(self).get("_encoded", None) is not None:
get_media().artifacts.purge(self._encoded)
self._encoded = get_media().artifacts.reserve(self.encoded_ext)

return call(
f"{exe2os('ffmpeg')} -v verbose {self.hwinit}"
f" -f rawvideo -pix_fmt {self.format} -s:v {self.width}x{self.height}"
f" {self.fps} -i {self.ossource}"
f" -vf 'format={self.hwformat}{self.hwupload}{self.roi}'"
f" -an -c:v {self.ffencoder} -qsv_params '{self.encparams}'"
f" -vframes {self.frames} -y {self.ffoutput}"
)

@slash.requires(*have_ffmpeg_hwaccel("qsv"))
Expand Down Expand Up @@ -160,7 +275,8 @@ def check_output(self):
# intref
if vars(self).get("intref", None) is not None:
patterns = [
f"IntRefType: {self.intref['type']};",
f"IntRefType: {self.intref['type']};"
f"|IntRefType, value: {self.intref['type']}",
f"IntRefCycleSize: {self.intref['size']};",
f"IntRefCycleDist: {self.intref['dist']}",
]
Expand Down
32 changes: 32 additions & 0 deletions lib/ffmpeg/qsv/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ....lib.common import memoize, get_media
from ....lib.ffmpeg.util import *
from ....lib.codecs import Codec
from ....lib.string_api import *

def using_compatible_driver():
return get_media()._get_driver_name() in ["iHD", "d3d11", "dxva2"]
Expand Down Expand Up @@ -78,6 +79,37 @@ def mapprofile(codec, profile):
},
}.get(codec, {}).get(profile, None)

@memoize
def mapprofile_stringapi(codec, profile):
return {
Codec.AVC : {
"high" : CodecProfile.MFX_PROFILE_AVC_HIGH.value,
"main" : CodecProfile.MFX_PROFILE_AVC_MAIN.value,
"baseline" : CodecProfile.MFX_PROFILE_AVC_BASELINE.value,
"unknown" : CodecProfile.MFX_PROFILE_UNKNOWN.value
},
Codec.HEVC : {
"main" : CodecProfile.MFX_PROFILE_HEVC_MAIN.value,
"main444" : CodecProfile.MFX_PROFILE_HEVC_REXT.value,
"scc" : CodecProfile.MFX_PROFILE_HEVC_SCC.value,
"scc-444" : CodecProfile.MFX_PROFILE_HEVC_SCC.value,
"mainsp" : CodecProfile.MFX_PROFILE_HEVC_MAINSP.value,
"main10" : CodecProfile.MFX_PROFILE_HEVC_MAIN10.value,
"main10sp" : CodecProfile.MFX_PROFILE_HEVC_MAINSP.value,
"main444-10" : CodecProfile.MFX_PROFILE_HEVC_REXT.value,
"unknown" : CodecProfile.MFX_PROFILE_UNKNOWN.value
},
Codec.AV1 : {
"main" : CodecProfile.MFX_PROFILE_AV1_MAIN.value,
},
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
},
}.get(codec, {}).get(profile, None)

def load_test_spec(*ctx):
from ....lib import util as libutil
return libutil.load_test_spec("ffmpeg-qsv", *ctx)
167 changes: 167 additions & 0 deletions lib/string_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
from enum import Enum, unique

#define come from _install/include/vpl/mfxstructures.h

class CodecProfile(Enum):
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(Enum):
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(Enum):
#/*! 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

0 comments on commit bc17525

Please sign in to comment.