From 3f2eb5a16a39e6280383b11bdb265f5211326dd5 Mon Sep 17 00:00:00 2001 From: noizuy <85082087+noizuy@users.noreply.github.com> Date: Fri, 18 Feb 2022 19:09:39 +0200 Subject: [PATCH] add new AQ mode (#17) add new AQ mode This just adds AQ mode 3's dark bias to AQ mode 4. Because of normal AQ strength values for mode 4 not really working well with the dark bias, an additional bias-strength parameter has been added. --- doc/reST/cli.rst | 10 +++++++++- source/common/frame.cpp | 4 ++-- source/common/param.cpp | 7 ++++++- source/encoder/frameencoder.cpp | 2 +- source/encoder/slicetype.cpp | 21 ++++++++++++++++----- source/x265.h | 4 ++++ source/x265cli.cpp | 5 +++-- source/x265cli.h | 1 + 8 files changed, 42 insertions(+), 12 deletions(-) diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst index f1aca5320..bbad057f5 100755 --- a/doc/reST/cli.rst +++ b/doc/reST/cli.rst @@ -1724,7 +1724,7 @@ Quality, rate control and rate distortion options ignored. Slower presets will generally achieve better compression efficiency (and generate smaller bitstreams). Default disabled. -.. option:: --aq-mode <0|1|2|3|4> +.. option:: --aq-mode <0|1|2|3|4|5> Adaptive Quantization operating mode. Raise or lower per-block quantization based on complexity analysis of the source image. The @@ -1737,6 +1737,7 @@ Quality, rate control and rate distortion options 2. AQ enabled with auto-variance **(default)** 3. AQ enabled with auto-variance and bias to dark scenes. This is recommended for 8-bit encodes or low-bitrate 10-bit encodes, to prevent color banding/blocking. 4. AQ enabled with auto-variance and edge information. + 5. AQ enabled with auto-variance, edge information, and bias to dark scenes. .. option:: --aq-strength @@ -1748,6 +1749,13 @@ Quality, rate control and rate distortion options Default 1.0. **Range of values:** 0.0 to 3.0 +.. option:: --aq-bias-strength + + Adjust the strength of dark scene bias in AQ modes 3 and 5. Setting this + to 0 will disable the dark scene bias, meaning modes will be equivalent to + their unbiased counterparts (2 and 4). + Default 1.0. + .. option:: --sbrc, --no-sbrc To enable and disable segment-based rate control. SBRC controls the overflow with diff --git a/source/common/frame.cpp b/source/common/frame.cpp index 4c800e94e..fcf4e753d 100644 --- a/source/common/frame.cpp +++ b/source/common/frame.cpp @@ -139,7 +139,7 @@ bool Frame::create(x265_param *param, float* quantOffsets) CHECKED_MALLOC_ZERO(m_classifyCount, uint32_t, size); } - if (param->rc.aqMode == X265_AQ_EDGE || (param->rc.zonefileCount && param->rc.aqMode != 0)) + if (param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED || (param->rc.zonefileCount && param->rc.aqMode != 0)) { uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize; uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize; @@ -388,7 +388,7 @@ void Frame::destroy() X265_FREE_ZERO(m_classifyCount); } - if (m_param->rc.aqMode == X265_AQ_EDGE || (m_param->rc.zonefileCount && m_param->rc.aqMode != 0)) + if (m_param->rc.aqMode == X265_AQ_EDGE || m_param->rc.aqMode == X265_AQ_EDGE_BIASED || (m_param->rc.zonefileCount && m_param->rc.aqMode != 0)) { X265_FREE(m_edgePic); X265_FREE(m_gaussianPic); diff --git a/source/common/param.cpp b/source/common/param.cpp index 0bc98457d..b38cc1e07 100755 --- a/source/common/param.cpp +++ b/source/common/param.cpp @@ -283,6 +283,7 @@ void x265_param_default(x265_param* param) param->rc.hevcAq = 0; param->rc.qgSize = 32; param->rc.aqStrength = 1.0; + param->rc.aqBiasStrength = 1.0; param->rc.qpAdaptationRange = 1.0; param->rc.cuTree = 1; param->rc.rfConstantMax = 0; @@ -829,6 +830,7 @@ int x265_zone_param_parse(x265_param* p, const char* name, const char* value) } OPT("aq-mode") p->rc.aqMode = atoi(value); OPT("aq-strength") p->rc.aqStrength = atof(value); + OPT("aq-bias-strength") p->rc.aqBiasStrength = atof(value); OPT("nr-intra") p->noiseReductionIntra = atoi(value); OPT("nr-inter") p->noiseReductionInter = atoi(value); OPT("limit-modes") p->limitModes = atobool(value); @@ -1130,6 +1132,7 @@ int x265_param_parse(x265_param* p, const char* name, const char* value) OPT("qblur") p->rc.qblur = atof(value); OPT("aq-mode") p->rc.aqMode = atoi(value); OPT("aq-strength") p->rc.aqStrength = atof(value); + OPT("aq-bias-strength") p->rc.aqBiasStrength = atof(value); OPT("vbv-maxrate") p->rc.vbvMaxBitrate = atoi(value); OPT("vbv-bufsize") p->rc.vbvBufferSize = atoi(value); OPT("vbv-init") p->rc.vbvBufferInit = atof(value); @@ -1728,7 +1731,7 @@ int x265_check_params(x265_param* param) "Lookahead depth must be less than 256"); CHECK(param->lookaheadSlices > 16 || param->lookaheadSlices < 0, "Lookahead slices must between 0 and 16"); - CHECK(param->rc.aqMode < X265_AQ_NONE || X265_AQ_EDGE < param->rc.aqMode, + CHECK(param->rc.aqMode < X265_AQ_NONE || X265_AQ_EDGE_BIASED < param->rc.aqMode, "Aq-Mode is out of range"); CHECK(param->rc.aqStrength < 0 || param->rc.aqStrength > 3, "Aq-Strength is out of range"); @@ -2310,6 +2313,7 @@ char *x265_param2string(x265_param* p, int padx, int pady) } s += sprintf(s, " aq-mode=%d", p->rc.aqMode); s += sprintf(s, " aq-strength=%.2f", p->rc.aqStrength); + s += sprintf(s, " aq-bias-strength=%.2f", p->rc.aqBiasStrength); BOOL(p->rc.cuTree, "cutree"); s += sprintf(s, " zone-count=%d", p->rc.zoneCount); if (p->rc.zoneCount) @@ -2760,6 +2764,7 @@ void x265_copy_params(x265_param* dst, x265_param* src) dst->rc.qpStep = src->rc.qpStep; dst->rc.aqMode = src->rc.aqMode; dst->rc.aqStrength = src->rc.aqStrength; + dst->rc.aqBiasStrength = src->rc.aqBiasStrength; dst->rc.vbvBufferSize = src->rc.vbvBufferSize; dst->rc.vbvMaxBitrate = src->rc.vbvMaxBitrate; diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp index 296ca4581..27cde29bc 100644 --- a/source/encoder/frameencoder.cpp +++ b/source/encoder/frameencoder.cpp @@ -484,7 +484,7 @@ void FrameEncoder::compressFrame(int layer) memset(&(m_frame[layer]->m_encData->m_frameStats), 0, sizeof(m_frame[layer]->m_encData->m_frameStats)); m_sLayerId = layer; - if (m_param->rc.aqMode != X265_AQ_EDGE && m_param->recursionSkipMode == EDGE_BASED_RSKIP) + if (m_param->rc.aqMode != X265_AQ_EDGE_BIASED && m_param->rc.aqMode != X265_AQ_EDGE && m_param->recursionSkipMode == EDGE_BASED_RSKIP) { int height = m_frame[layer]->m_fencPic->m_picHeight; int width = m_frame[layer]->m_fencPic->m_picWidth; diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp index 8bbac8244..e86f481db 100644 --- a/source/encoder/slicetype.cpp +++ b/source/encoder/slicetype.cpp @@ -524,17 +524,17 @@ void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param) double bias_strength = 0.f; double strength = 0.f; - if (param->rc.aqMode == X265_AQ_EDGE) + if (param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED) edgeFilter(curFrame, param); - if (param->rc.aqMode == X265_AQ_EDGE && param->recursionSkipMode == EDGE_BASED_RSKIP) + if ((param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED) && param->recursionSkipMode == EDGE_BASED_RSKIP) { pixel* src = curFrame->m_edgePic + curFrame->m_fencPic->m_lumaMarginY * curFrame->m_fencPic->m_stride + curFrame->m_fencPic->m_lumaMarginX; primitives.planecopy_pp_shr(src, curFrame->m_fencPic->m_stride, curFrame->m_edgeBitPic, curFrame->m_fencPic->m_stride, curFrame->m_fencPic->m_picWidth, curFrame->m_fencPic->m_picHeight, SHIFT_TO_BITPLANE); } - if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE || param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED || param->rc.aqMode == X265_AQ_EDGE) + if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE || param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED || param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED) { double bit_depth_correction = 1.f / (1 << (2 * (X265_DEPTH - 8))); for (int blockY = 0; blockY < maxRow; blockY += loopIncr) @@ -543,7 +543,7 @@ void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param) { uint32_t energy, edgeDensity, avgAngle; energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize); - if (param->rc.aqMode == X265_AQ_EDGE) + if (param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED) { edgeDensity = edgeDensityCu(curFrame, avgAngle, blockX, blockY, param->rc.qgSize); if (edgeDensity) @@ -573,7 +573,7 @@ void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param) avg_adj_pow2 /= blockCount; strength = param->rc.aqStrength * avg_adj; avg_adj = avg_adj - 0.5f * (avg_adj_pow2 - modeTwoConst) / avg_adj; - bias_strength = param->rc.aqStrength; + bias_strength = param->rc.aqBiasStrength * param->rc.aqStrength; } else strength = param->rc.aqStrength * 1.0397f; @@ -602,6 +602,17 @@ void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param) else qp_adj = strength * (qp_adj - avg_adj); } + else if (param->rc.aqMode == X265_AQ_EDGE_BIASED) + { + inclinedEdge = curFrame->m_lowres.edgeInclined[blockXY]; + qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY]; + double dark_bias = bias_strength * (1.f - modeTwoConst / (qp_adj * qp_adj)) / 10.f; + if(inclinedEdge && (qp_adj - avg_adj > 0)) + qp_adj = ((strength + AQ_EDGE_BIAS) * (qp_adj - avg_adj)); + else + qp_adj = strength * (qp_adj - avg_adj); + qp_adj += dark_bias; + } else { uint32_t energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize); diff --git a/source/x265.h b/source/x265.h index 80d1358cd..234a01afe 100644 --- a/source/x265.h +++ b/source/x265.h @@ -594,6 +594,7 @@ typedef enum #define X265_AQ_AUTO_VARIANCE 2 #define X265_AQ_AUTO_VARIANCE_BIASED 3 #define X265_AQ_EDGE 4 +#define X265_AQ_EDGE_BIASED 5 #define x265_ADAPT_RD_STRENGTH 4 #define X265_REFINE_INTER_LEVELS 3 /* NOTE! For this release only X265_CSP_I420 and X265_CSP_I444 are supported */ @@ -1730,6 +1731,9 @@ typedef struct x265_param * AQ is enabled. Default value: 1.0. Acceptable values between 0.0 and 3.0 */ double aqStrength; + /* Sets the bias towards dark scenes in AQ modes 3 and 5. */ + double aqBiasStrength; + /* Delta QP range by QP adaptation based on a psycho-visual model. * Acceptable values between 1.0 to 6.0 */ double qpAdaptationRange; diff --git a/source/x265cli.cpp b/source/x265cli.cpp index 0fd6448e0..990b2d834 100755 --- a/source/x265cli.cpp +++ b/source/x265cli.cpp @@ -280,9 +280,10 @@ namespace X265_NS { " - 0 : Disabled.\n" " - 1 : Store/Load ctu distortion to/from the file specified in analysis-save/load.\n" " Default 0 - Disabled\n"); - H0(" --aq-mode Mode for Adaptive Quantization - 0:none 1:uniform AQ 2:auto variance 3:auto variance with bias to dark scenes 4:auto variance with edge information. Default %d\n", param->rc.aqMode); + H0(" --aq-mode Mode for Adaptive Quantization - 0:none 1:uniform AQ 2:auto variance 3:auto variance with bias to dark scenes 4:auto variance with edge information 5:auto variance with edge information and bias to dark scenes. Default %d\n", param->rc.aqMode); H0(" --[no-]hevc-aq Mode for HEVC Adaptive Quantization. Default %s\n", OPT(param->rc.hevcAq)); H0(" --aq-strength Reduces blocking and blurring in flat and textured areas (0 to 3.0). Default %.2f\n", param->rc.aqStrength); + H0(" --aq-bias-strength Sets the bias to dark strength in AQ modes 3 and 5. Default %.2f\n", param->rc.aqBiasStrength); H0(" --qp-adaptation-range Delta QP range by QP adaptation based on a psycho-visual model (1.0 to 6.0). Default %.2f\n", param->rc.qpAdaptationRange); H0(" --[no-]aq-motion Block level QP adaptation based on the relative motion between the block and the frame. Default %s\n", OPT(param->bAQMotion)); H1(" --[no-]sbrc Enables the segment based rate control. Default %s\n", OPT(param->bEnableSBRC)); @@ -1486,4 +1487,4 @@ namespace X265_NS { #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/source/x265cli.h b/source/x265cli.h index 466a8c0a2..4b80851cd 100644 --- a/source/x265cli.h +++ b/source/x265cli.h @@ -184,6 +184,7 @@ static const struct option long_options[] = { "qp", required_argument, NULL, 'q' }, { "aq-mode", required_argument, NULL, 0 }, { "aq-strength", required_argument, NULL, 0 }, + { "aq-bias-strength", required_argument, NULL, 0 }, { "sbrc", no_argument, NULL, 0 }, { "no-sbrc", no_argument, NULL, 0 }, { "rc-grain", no_argument, NULL, 0 },