目录
- 1. 默认配置
- 2. 档位配置(preset & tune)
在熟悉编码器过程中,一个比较有效的方法是了解其配置参数,根据其配置参数就可以知道编码器使用了哪些工具,从中筛选出重要的工具重点看看。本文记录一下x265编码器中的配置参数
x265编码器代码获取:x265官网
1. 默认配置
默认配置函数x265_param_default()位于common\param.cpp中,如下所示
void x265_param_default(x265_param* param)
{
#ifdef SVT_HEVCEB_H265_ENC_CONFIGURATION* svtParam = (EB_H265_ENC_CONFIGURATION*)param->svtHevcParam;
#endifmemset(param, 0, sizeof(x265_param));/* Applying default values to all elements in the param structure */param->cpuid = X265_NS::cpu_detect(false);param->bEnableWavefront = 1; // 波前下倾的编码方式(并行编码),编码损失小于1%param->frameNumThreads = 0; // 帧级编码线程数(1到16),可能影响运动搜索param->logLevel = X265_LOG_INFO;param->csvLogLevel = 0; // csv日志级别param->csvfn = NULL;param->rc.lambdaFileName = NULL; // 码控的lambda文件,可以用来覆盖默认的x265_lambda_tabparam->bLogCuStats = 0; // 分析记录CU(已弃用)param->decodedPictureHashSEI = 0; // 为重建帧生成SEI信息,可以用来检查重建帧是否匹配(似乎是调试功能)/* Quality Measurement Metrics */param->bEnablePsnr = 0; // 是否计算PSNRparam->bEnableSsim = 0; // 是否计算SSIM/* Source specifications */param->internalBitDepth = X265_DEPTH; // 内部计算时的位宽param->sourceBitDepth = 8; // 输入源的位宽param->internalCsp = X265_CSP_I420; // 内部pic的color space ,默认为I420param->levelIdc = 0; //Auto-detect level,最低解码器要求级别。默认为0,表示由编码器自动检测param->uhdBluray = 0; // 启用UHD蓝光兼容支持param->bHighTier = 1; //Allow high tier by default,如果指定了levelIdc(非零),这个标志将区分Main(0)和High(1)层。默认为Main层(0)param->interlaceMode = 0; // 源图片的交错类型。0 -渐进式图片(默认)。1 -顶部字段优先,2 -底部字段优先param->bField = 0; // 允许场编码param->bAnnexB = 1; // 是否按照AnnexB的格式生成start code或lengthparam->bRepeatHeaders = 0; // 表示每个关键帧是否输出VPS, SPS和PPS报头的标志param->bEnableAccessUnitDelimiters = 0; // 指示编码器是否应在每个访问单元的开始处发出访问单元分隔符NAL的标志// SEI相关功能param->bEmitHRDSEI = 0; // 启用缓冲周期SEI和图片定时SEIparam->bEmitInfoSEI = 1; // 启用带有描述编码器版本、构建信息和参数的流标头的用户数据SEI的输出param->bEmitHDRSEI = 0; /*Deprecated*/param->bEmitHDR10SEI = 0; // 使能发送包含HDR10特定参数的HDR10 SEI报文。当指定了max-cll、max-fall或master显示信息时自动启用param->bEmitIDRRecoverySEI = 0; // 启用恢复点SEI的输出/* CU definitions */param->maxCUSize = 64; // 最大CU尺寸param->minCUSize = 8; // 最小CU尺寸param->tuQTMaxInterDepth = 1; // TU的额外深度允许递归到QT之外,用于帧间编码param->tuQTMaxIntraDepth = 1; // TU的额外深度允许递归到QT之外,用于帧内编码param->maxTUSize = 32; // 最大的TU尺寸/* Coding Structure */param->keyframeMin = 0; // 最小关键帧距离param->keyframeMax = 250; // 最大关键帧距离param->gopLookahead = 0; // 提前查找最佳的gop结构param->bOpenGOP = 1; // 是否启用开放式gop(I slice不一定是IDR)param->bframes = 4; // 最大连续的b帧数量param->lookaheadDepth = 20; // lookahead队列的长度param->bFrameAdaptive = X265_B_ADAPT_TRELLIS; // B帧的自适应选择方式param->bBPyramid = 1; // 是否使用双向预测的金字塔结构param->scenecutThreshold = 40; /* Magic number pulled in from x264 */ // 场景切换的阈值(超过这个阈值就认为发生了场景切换)param->edgeTransitionThreshold = 0.03; // 边缘过渡阈值(超过这个阈值则认为这个像素是边缘过渡点)param->bHistBasedSceneCut = 0; // 启用基于直方图的场景检测算法来检测场景param->lookaheadSlices = 8; // 使用多少个工作线程来分析每帧的costparam->lookaheadThreads = 0; // lookahead线程数param->scenecutBias = 5.0; // 场景切换敏感度,减小scenecutBias的值会使得编码器对场景切换不那么敏感param->radl = 0; // IDR前允许的RADL图片数量param->chunkStart = 0; param->chunkEnd = 0;param->bEnableHRDConcatFlag = 0;param->bEnableFades = 0;param->bEnableSceneCutAwareQp = 0; // 在速率控制pass2算法中增加QP来减少场景切换前后场景窗口内intra cost使用比特数param->scenecutWindow = 500;param->refQpDelta = 5;param->nonRefQpDelta = param->refQpDelta + (SLICE_TYPE_DELTA * param->refQpDelta);/* Intra Coding Tools */param->bEnableConstrainedIntra = 0; // 启用受限的帧内预测。这会导致对已经进行帧间预测的输入样本进行帧内预测param->bEnableStrongIntraSmoothing = 1; // 为参考样本平坦的32x32区块启用强帧内平滑param->bEnableFastIntra = 0; // 使用快速搜索方法去寻找最佳的intra模式param->bEnableSplitRdSkip = 0; // 当划分CU的RDCost总和大于不划分CU的rdcost时,启用跳过划分rd分析的功能/* Inter Coding tools */param->searchMethod = X265_HEX_SEARCH; // 帧间搜索方式(默认为六边形搜索)param->subpelRefine = 2; // 亚像素运动估计级别(默认为2,即1/4像素)param->searchRange = 57; // 搜索范围param->maxNumMergeCand = 3; // merge模式中候选列表的最大数量param->limitReferences = 1; // 用于运动搜索的参考帧数量param->limitModes = 0; // 用于控制编码过程中的模式数量param->bEnableWeightedPred = 1; // 启用P帧的加权预测功能param->bEnableWeightedBiPred = 0; // 启用B帧的加权预测功能param->bEnableEarlySkip = 1; // 启用early skip来跳过一些模式决策param->recursionSkipMode = 1; // 启用early CU size决策,从而跳过深层次划分param->edgeVarThreshold = 0.05f; // 边缘检测的阈值param->bEnableAMP = 0; // 启用不对称运动预测param->bEnableRectInter = 0; // 启用矩形运动预测分区param->rdLevel = 3; // 在模式和深度决策期间执行的速率失真优化的levelparam->rdoqLevel = 0; // 控制RDQO的levelparam->bEnableSignHiding = 1; // 运动矢量的符号隐藏param->bEnableTransformSkip = 0; // 变换跳过模式(不进行DCT变换)param->bEnableTSkipFast = 0; // 允许快速决策,决策的对象为是否要进行变换跳过模式param->maxNumReferences = 3; // P帧或B帧前向参考队列中最大帧数(范围为1到16)param->bEnableTemporalMvp = 1; // Temporal MVPparam->bEnableHME = 0; // 多层级运动估计param->hmeSearchMethod[0] = X265_HEX_SEARCH;param->hmeSearchMethod[1] = param->hmeSearchMethod[2] = X265_UMH_SEARCH;param->hmeRange[0] = 16;param->hmeRange[1] = 32;param->hmeRange[2] = 48;param->bSourceReferenceEstimation = 0;param->limitTU = 0;param->dynamicRd = 0;/* Loop Filter */param->bEnableLoopFilter = 1; // 环路滤波/* SAO Loop Filter */param->bEnableSAO = 1; // SAO滤波param->bSaoNonDeblocked = 0;param->bLimitSAO = 0;param->selectiveSAO = 0;/* Coding Quality */param->cbQpOffset = 0; // Cb分量的Qp offsetparam->crQpOffset = 0; // Cr分量的Qp offsetparam->rdPenalty = 0; // Rate和Distortion之间的惩罚项,penalty增加,视频质量增加而编码比特增加;penalty减小,视频质量降低而编码比特也减小param->psyRd = 2.0; // psy表示心理视觉,这里基于主观质量来调控Rdparam->psyRdoq = 0.0; // 基于主观质量调控Rdoqparam->analysisReuseMode = 0; /*DEPRECATED*/param->analysisMultiPassRefine = 0; // 通过多步细化分析来优化编码设置param->analysisMultiPassDistortion = 0; // 多通道失真分析,以优化编码质量和性能param->analysisReuseFileName = NULL; // 重分析文件名param->analysisSave = NULL; // 存储每帧的分析信息param->analysisLoad = NULL; // 读取信息param->bIntraInBFrames = 1; // 控制B帧是否允许进行帧内预测编码param->bLossless = 0; // 无损模式param->bCULossless = 0; // CU级无损模式(相对于Lossless而言,性能影响较小)param->bEnableTemporalSubLayers = 0; // TemporalSubLayersparam->bEnableRdRefine = 0; // 允许Rd的Refineparam->bMultiPassOptRPS = 0; // 多边编码优化param->bSsimRd = 0; // SSIM相关的比特率控制/* Rate control options */param->rc.vbvMaxBitrate = 0; // VBV Buffer max rateparam->rc.vbvBufferSize = 0; // VBV Buffer size (kilobits)param->rc.vbvBufferInit = 0.9; // VBV Buffer初始比例(开始编码之前)param->vbvBufferEnd = 0; // VBV Buffer的结束阈值param->vbvEndFrameAdjust = 0; // 调整VBV缓冲区结束帧的大小param->minVbvFullness = 50; // VBV Buffer最小水量(至少达到50%)param->maxVbvFullness = 80; // VBV Buffer最大水量(不超过80%)param->rc.rfConstant = 28; // crf参数,用于计算拉格朗日乘数param->rc.bitrate = 0; // 码率param->rc.qCompress = 0.6; // qCompress的强度(增大qcompress,提高压缩率但降低视频质量)param->rc.ipFactor = 1.4f; // I帧到P帧的QP Offsetparam->rc.pbFactor = 1.3f; // P帧到B帧的QP Offsetparam->rc.qpStep = 4; // 帧之间最大的QP差值param->rc.rateControlMode = X265_RC_CRF; // 默认使用的码控模式param->rc.qp = 32; // Base QPparam->rc.aqMode = X265_AQ_AUTO_VARIANCE; // AQ模式param->rc.hevcAq = 0; // 是否启用hevcAQparam->rc.qgSize = 32; // 量化群组的大小(Quantization Group)param->rc.aqStrength = 1.0; // AQ强度param->rc.qpAdaptationRange = 1.0; // QP的自适应调整范围param->rc.cuTree = 1; // 启用CUTree速率控制。这样可以跟踪在帧间临时传播的cu,并为这些cu分配更多的bitparam->rc.rfConstantMax = 0; // 在CRF模式下,最大CRF的值param->rc.rfConstantMin = 0; // 在CRF模式下,最小CRF的值param->rc.bStatRead = 0; // 在multi-pass模式下,允许读取stat文件param->rc.bStatWrite = 0; // 在multi-pass模式下,允许写入stat文件param->rc.statFileName = NULL; // 在multi-pass模式下,写入或读取的stat文件param->rc.complexityBlur = 20; // 时域的复杂度模糊param->rc.qblur = 0.5; // 时域的模糊量化param->rc.zoneCount = 0; param->rc.zonefileCount = 0;param->rc.zones = NULL;param->rc.bEnableSlowFirstPass = 1; param->rc.bStrictCbr = 0; // 启用更严格的条件来检查CBR模式下的比特率偏差(可能会牺牲质量来维持比特率稳定)param->rc.bEnableGrain = 0; // 启用或禁用颗粒(噪声)效果,以改善视频的视觉感官param->rc.qpMin = 0; // 最小QP值param->rc.qpMax = QP_MAX_MAX; // 最大QP值param->rc.bEnableConstVbv = 0; // 是否使用固定的VBVparam->bResetZoneConfig = 1;param->reconfigWindowSize = 0;param->decoderVbvMaxRate = 0;param->bliveVBV2pass = 0;/* Video Usability Information (VUI) */param->vui.aspectRatioIdc = 0;param->vui.sarWidth = 0; // sample ratio widthparam->vui.sarHeight = 0;param->vui.bEnableOverscanAppropriateFlag = 0;param->vui.bEnableVideoSignalTypePresentFlag = 0;param->vui.videoFormat = 5;param->vui.bEnableVideoFullRangeFlag = 0;param->vui.bEnableColorDescriptionPresentFlag = 0;param->vui.colorPrimaries = 2;param->vui.transferCharacteristics = 2;param->vui.matrixCoeffs = 2;param->vui.bEnableChromaLocInfoPresentFlag = 0;param->vui.chromaSampleLocTypeTopField = 0;param->vui.chromaSampleLocTypeBottomField = 0;param->vui.bEnableDefaultDisplayWindowFlag = 0;param->vui.defDispWinLeftOffset = 0;param->vui.defDispWinRightOffset = 0;param->vui.defDispWinTopOffset = 0;param->vui.defDispWinBottomOffset = 0;param->maxCLL = 0;param->maxFALL = 0;param->minLuma = 0;param->maxLuma = PIXEL_MAX;param->log2MaxPocLsb = 8;param->maxSlices = 1;/*Conformance window*/param->confWinRightOffset = 0;param->confWinBottomOffset = 0;param->bEmitVUITimingInfo = 1;param->bEmitVUIHRDInfo = 1;param->bOptQpPPS = 0;param->bOptRefListLengthPPS = 0;param->bOptCUDeltaQP = 0;param->bAQMotion = 0;param->bHDROpt = 0; /*DEPRECATED*/param->bHDR10Opt = 0;param->analysisReuseLevel = 0; /*DEPRECATED*/param->analysisSaveReuseLevel = 0;param->analysisLoadReuseLevel = 0;param->toneMapFile = NULL;param->bDhdr10opt = 0;param->dolbyProfile = 0;param->bCTUInfo = 0;param->bUseRcStats = 0;param->scaleFactor = 0;param->intraRefine = 0;param->interRefine = 0;param->bDynamicRefine = 0;param->mvRefine = 1;param->ctuDistortionRefine = 0;param->bUseAnalysisFile = 1;param->csvfpt = NULL;param->forceFlush = 0;param->bDisableLookahead = 0;param->bCopyPicToFrame = 1;param->maxAUSizeFactor = 1;param->naluFile = NULL;/* DCT Approximations */param->bLowPassDct = 0;param->bAnalysisType = 0;param->bSingleSeiNal = 0;/* SEI messages */param->preferredTransferCharacteristics = -1;param->pictureStructure = -1;param->bEmitCLL = 1;param->bEnableFrameDuplication = 0;param->dupThreshold = 70;/* SVT Hevc Encoder specific params */param->bEnableSvtHevc = 0;param->svtHevcParam = NULL;#ifdef SVT_HEVCparam->svtHevcParam = svtParam;svt_param_default(param);
#endif
}
2. 档位配置(preset & tune)
档位配置函数x265_param_default_preset()位于common\param.cpp中,主要有三个步骤:
(1)配置默认参数(x265_param_default)
(2)配置preset
(3)配置tune
int x265_param_default_preset(x265_param* param, const char* preset, const char* tune)
{
#if EXPORT_C_API// 1. 配置默认参数::x265_param_default(param);
#elseX265_NS::x265_param_default(param);
#endif// 2. 配置presetif (preset){char *end;int i = strtol(preset, &end, 10);if (*end == 0 && i >= 0 && i < (int)(sizeof(x265_preset_names) / sizeof(*x265_preset_names) - 1))preset = x265_preset_names[i];if (!strcmp(preset, "ultrafast")){param->maxNumMergeCand = 2;param->bIntraInBFrames = 0;param->lookaheadDepth = 5;param->scenecutThreshold = 0; // disable lookaheadparam->maxCUSize = 32; // 减小了CU尺寸param->minCUSize = 16;param->bframes = 3;param->bFrameAdaptive = 0;param->subpelRefine = 0;param->searchMethod = X265_DIA_SEARCH;param->bEnableSAO = 0;param->bEnableSignHiding = 0;param->bEnableWeightedPred = 0;param->rdLevel = 2;param->maxNumReferences = 1;param->limitReferences = 0;param->rc.aqStrength = 0.0;param->rc.aqMode = X265_AQ_NONE;param->rc.hevcAq = 0;param->rc.qgSize = 32;param->bEnableFastIntra = 1;}else if (!strcmp(preset, "superfast")){param->maxNumMergeCand = 2;param->bIntraInBFrames = 0;param->lookaheadDepth = 10;param->maxCUSize = 32;param->bframes = 3;param->bFrameAdaptive = 0;param->subpelRefine = 1;param->bEnableWeightedPred = 0;param->rdLevel = 2;param->maxNumReferences = 1;param->limitReferences = 0;param->rc.aqStrength = 0.0;param->rc.aqMode = X265_AQ_NONE;param->rc.hevcAq = 0;param->rc.qgSize = 32;param->bEnableSAO = 0;param->bEnableFastIntra = 1;}else if (!strcmp(preset, "veryfast")){param->maxNumMergeCand = 2;param->limitReferences = 3;param->bIntraInBFrames = 0;param->lookaheadDepth = 15;param->bFrameAdaptive = 0;param->subpelRefine = 1;param->rdLevel = 2;param->maxNumReferences = 2;param->rc.qgSize = 32;param->bEnableFastIntra = 1;}else if (!strcmp(preset, "faster")){param->maxNumMergeCand = 2;param->limitReferences = 3;param->bIntraInBFrames = 0;param->lookaheadDepth = 15;param->bFrameAdaptive = 0;param->rdLevel = 2;param->maxNumReferences = 2;param->bEnableFastIntra = 1;}else if (!strcmp(preset, "fast")){param->maxNumMergeCand = 2;param->limitReferences = 3;param->bEnableEarlySkip = 0;param->bIntraInBFrames = 0;param->lookaheadDepth = 15;param->bFrameAdaptive = 0;param->rdLevel = 2;param->maxNumReferences = 3;param->bEnableFastIntra = 1;}else if (!strcmp(preset, "medium")){/* defaults */// 前面进行默认配置时,就是medium配置}else if (!strcmp(preset, "slow")){param->limitReferences = 3;param->bEnableEarlySkip = 0;param->bIntraInBFrames = 0;param->bEnableRectInter = 1;param->lookaheadDepth = 25;param->rdLevel = 4;param->rdoqLevel = 2;param->psyRdoq = 1.0;param->subpelRefine = 3;param->searchMethod = X265_STAR_SEARCH;param->maxNumReferences = 4;param->limitModes = 1;param->lookaheadSlices = 4; // limit parallelism as already enough work exists}else if (!strcmp(preset, "slower")){param->bEnableEarlySkip = 0;param->bEnableWeightedBiPred = 1;param->bEnableAMP = 1;param->bEnableRectInter = 1;param->lookaheadDepth = 40;param->bframes = 8;param->tuQTMaxInterDepth = 3;param->tuQTMaxIntraDepth = 3;param->rdLevel = 6;param->rdoqLevel = 2;param->psyRdoq = 1.0;param->subpelRefine = 4;param->maxNumMergeCand = 4;param->searchMethod = X265_STAR_SEARCH;param->maxNumReferences = 5;param->limitModes = 1;param->lookaheadSlices = 0; // disabled for best qualityparam->limitTU = 4;}else if (!strcmp(preset, "veryslow")){param->bEnableEarlySkip = 0;param->bEnableWeightedBiPred = 1;param->bEnableAMP = 1;param->bEnableRectInter = 1;param->lookaheadDepth = 40;param->bframes = 8;param->tuQTMaxInterDepth = 3;param->tuQTMaxIntraDepth = 3;param->rdLevel = 6;param->rdoqLevel = 2;param->psyRdoq = 1.0;param->subpelRefine = 4;param->maxNumMergeCand = 5;param->searchMethod = X265_STAR_SEARCH;param->maxNumReferences = 5;param->limitReferences = 0;param->limitModes = 0;param->lookaheadSlices = 0; // disabled for best qualityparam->limitTU = 0;}else if (!strcmp(preset, "placebo")){param->bEnableEarlySkip = 0;param->bEnableWeightedBiPred = 1;param->bEnableAMP = 1;param->bEnableRectInter = 1;param->lookaheadDepth = 60;param->searchRange = 92;param->bframes = 8;param->tuQTMaxInterDepth = 4;param->tuQTMaxIntraDepth = 4;param->rdLevel = 6;param->rdoqLevel = 2;param->psyRdoq = 1.0;param->subpelRefine = 5;param->maxNumMergeCand = 5;param->searchMethod = X265_STAR_SEARCH;param->bEnableTransformSkip = 1;param->recursionSkipMode = 0;param->maxNumReferences = 5;param->limitReferences = 0;param->lookaheadSlices = 0; // disabled for best quality// TODO: optimized esa}elsereturn -1;}// 3. 配置tuneif (tune){if (!strcmp(tune, "psnr")){param->rc.aqStrength = 0.0;param->psyRd = 0.0;param->psyRdoq = 0.0;}else if (!strcmp(tune, "ssim")){param->rc.aqMode = X265_AQ_AUTO_VARIANCE;param->psyRd = 0.0;param->psyRdoq = 0.0;}else if (!strcmp(tune, "fastdecode") ||!strcmp(tune, "fast-decode")){// 快速解码模式// 不允许进行滤波和加权预测,节省时间param->bEnableLoopFilter = 0;param->bEnableSAO = 0;param->bEnableWeightedPred = 0;param->bEnableWeightedBiPred = 0;param->bIntraInBFrames = 0;}else if (!strcmp(tune, "zerolatency") ||!strcmp(tune, "zero-latency")){// 零延时模式param->bFrameAdaptive = 0;param->bframes = 0; // 不使用B帧param->lookaheadDepth = 0; // lookaheadDepth限制param->scenecutThreshold = 0; // 不进行场景切换param->bHistBasedSceneCut = 0;param->rc.cuTree = 0; // 不进行CUTree码控,因为涉及到了视频内容变化快慢param->frameNumThreads = 1;}else if (!strcmp(tune, "grain")) // 添加颗粒噪声,能够改善视觉质感{param->rc.ipFactor = 1.1;param->rc.pbFactor = 1.0;param->rc.cuTree = 0;param->rc.aqMode = 0;param->rc.hevcAq = 0;param->rc.qpStep = 1;param->rc.bEnableGrain = 1;param->recursionSkipMode = 0;param->psyRd = 4.0;param->psyRdoq = 10.0;param->bEnableSAO = 0;param->rc.bEnableConstVbv = 1;}else if (!strcmp(tune, "animation")) // 优化动画内容的编码效率{// 动画内容的特点是具有高色彩饱和度和大量平缓无纹理区域param->bframes = (param->bframes + 2) >= param->lookaheadDepth? param->bframes : param->bframes + 2;param->psyRd = 0.4; // 设置主观的Rd调控param->rc.aqStrength = 0.4;param->deblockingFilterBetaOffset = 1;param->deblockingFilterTCOffset = 1;}else if (!strcmp(tune, "vmaf")) /*Adding vmaf for x265 + SVT-HEVC integration support*/{/*vmaf is under development, currently x265 won't support vmaf*/}elsereturn -1;}#ifdef SVT_HEVCif (svt_set_preset(param, preset))return -1;
#endifreturn 0;
}
从配置项来看,x265需要熟悉的模块包括:
(1)编码块大小的改动
x265编码块的最大尺寸为64,最小尺寸为8
(2)帧内预测和帧间预测
相对比于x264而言,x265增加了帧内预测模式,也增加了帧间预测的工具,例如更高精度的运动补偿,AMVP和Merge Candidate List
(3)变换量化
x265使用了TU这一变换块,使得变换过程更加高效,量化工具也有变化
(4)滤波
新增SAO滤波
针对于这些模块,后续再逐一记录