Skip to content

Instantly share code, notes, and snippets.

@noizuy
Last active July 24, 2023 01:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save noizuy/fbd25590a4cd2ca3a1c635d3a01f59cf to your computer and use it in GitHub Desktop.
Save noizuy/fbd25590a4cd2ca3a1c635d3a01f59cf to your computer and use it in GitHub Desktop.
x265 patch to add an AQ mode adding AQ mode 3's dark bias to AQ mode 4.
From f694f1439f7306dcfe19f1d547d6854a3fa64f2c Mon Sep 17 00:00:00 2001
From: noizuy <85082087+noizuy@users.noreply.github.com>
Date: Fri, 18 Feb 2022 17:09:39 +0000
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.
(rebased on SBRC c0e4716)
---
doc/reST/cli.rst | 12 ++++++++++--
source/common/frame.cpp | 4 ++--
source/common/param.cpp | 7 ++++++-
source/encoder/frameencoder.cpp | 2 +-
source/encoder/slicetype.cpp | 23 +++++++++++++++++------
source/x265.h | 5 ++++-
source/x265cli.cpp | 5 +++--
source/x265cli.h | 1 +
8 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
index 9fa12fa92..29a73c8ed 100755
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -1747,7 +1747,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
@@ -1762,6 +1762,7 @@ Quality, rate control and rate distortion options
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 <float>
@@ -1773,6 +1774,13 @@ Quality, rate control and rate distortion options
Default 1.0.
**Range of values:** 0.0 to 3.0
+.. option:: --aq-bias-strength <float>
+
+ 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.
@@ -2399,7 +2407,7 @@ VUI fields must be manually specified.
.. option:: --hdr10-opt, --no-hdr10-opt
Enable block-level luma and chroma QP optimization for HDR10 content
- as suggested in ITU-T H-series Recommendations – Supplement 15.
+ as suggested in ITU-T H-series Recommendations Supplement 15.
Source video should have HDR10 characteristics such as 10-bit depth 4:2:0
with Bt.2020 color primaries and SMPTE ST.2084 transfer characteristics.
It is recommended that AQ-mode be enabled along with this feature. Default disabled.
diff --git a/source/common/frame.cpp b/source/common/frame.cpp
index e1bdc39b6..094029e71 100644
--- a/source/common/frame.cpp
+++ b/source/common/frame.cpp
@@ -131,7 +131,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.frameSegment || (param->rc.zonefileCount && param->rc.aqMode != 0))
+ if (param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED || param->rc.frameSegment || (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;
@@ -342,7 +342,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.frameSegment || (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 b13131cc8..29b8dba3e 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -275,6 +275,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;
@@ -766,6 +767,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);
@@ -1069,6 +1071,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);
@@ -1718,7 +1721,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");
@@ -2281,6 +2284,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)
@@ -2576,6 +2580,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 6f567b9cf..aafee4f2b 100644
--- a/source/encoder/frameencoder.cpp
+++ b/source/encoder/frameencoder.cpp
@@ -471,7 +471,7 @@ void FrameEncoder::compressFrame()
m_ssimCnt = 0;
memset(&(m_frame->m_encData->m_frameStats), 0, sizeof(m_frame->m_encData->m_frameStats));
- if (!m_param->bHistBasedSceneCut && m_param->rc.aqMode != X265_AQ_EDGE && m_param->recursionSkipMode == EDGE_BASED_RSKIP)
+ if (!m_param->bHistBasedSceneCut && m_param->rc.aqMode != X265_AQ_EDGE && m_param->rc.aqMode != X265_AQ_EDGE_BIASED && m_param->recursionSkipMode == EDGE_BASED_RSKIP)
{
int height = m_frame->m_fencPic->m_picHeight;
int width = m_frame->m_fencPic->m_picWidth;
diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp
index ae908e626..ba0d44c90 100644
--- a/source/encoder/slicetype.cpp
+++ b/source/encoder/slicetype.cpp
@@ -516,17 +516,17 @@ void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param)
double bias_strength = 0.f;
double strength = 0.f;
- if (curFrame->m_frameSegment == X265_AQ_EDGE )
+ if (curFrame->m_frameSegment == X265_AQ_EDGE || curFrame->m_frameSegment == X265_AQ_EDGE_BIASED)
edgeFilter(curFrame, param);
- if (curFrame->m_frameSegment == X265_AQ_EDGE && !param->bHistBasedSceneCut && param->recursionSkipMode == EDGE_BASED_RSKIP)
+ if ((curFrame->m_frameSegment == X265_AQ_EDGE || curFrame->m_frameSegment == X265_AQ_EDGE_BIASED) && !param->bHistBasedSceneCut && 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 (curFrame->m_frameSegment == X265_AQ_AUTO_VARIANCE || curFrame->m_frameSegment == X265_AQ_AUTO_VARIANCE_BIASED || curFrame->m_frameSegment == X265_AQ_EDGE)
+ if (curFrame->m_frameSegment == X265_AQ_AUTO_VARIANCE || curFrame->m_frameSegment == X265_AQ_AUTO_VARIANCE_BIASED || curFrame->m_frameSegment == X265_AQ_EDGE || curFrame->m_frameSegment == X265_AQ_EDGE_BIASED)
{
double bit_depth_correction = 1.f / (1 << (2 * (X265_DEPTH - 8)));
for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
@@ -535,7 +535,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 (curFrame->m_frameSegment == X265_AQ_EDGE)
+ if (curFrame->m_frameSegment == X265_AQ_EDGE || curFrame->m_frameSegment == X265_AQ_EDGE_BIASED)
{
edgeDensity = edgeDensityCu(curFrame, avgAngle, blockX, blockY, param->rc.qgSize);
if (edgeDensity)
@@ -565,7 +565,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;
@@ -594,6 +594,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);
@@ -1455,7 +1466,7 @@ void PreLookaheadGroup::processTasks(int workerThreadID)
if (edgeIntensity < FRAME_EDGE_THRESHOLD)
preFrame->m_frameSegment = brightnessIntensity > FRAME_BRIGHTNESS_THRESHOLD? X265_AQ_AUTO_VARIANCE : X265_AQ_AUTO_VARIANCE_BIASED;
else
- preFrame->m_frameSegment = brightnessIntensity > FRAME_BRIGHTNESS_THRESHOLD? X265_AQ_EDGE : X265_AQ_EDGE_BIASED;
+ preFrame->m_frameSegment = brightnessIntensity > FRAME_BRIGHTNESS_THRESHOLD? X265_AQ_EDGE : X265_AQ_VARIANCE;
}
else
preFrame->m_frameSegment = preFrame->m_param->rc.aqMode;
diff --git a/source/x265.h b/source/x265.h
index e0be6a25a..e12a1b9fa 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -581,7 +581,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 1
+#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 */
@@ -1413,6 +1413,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 d7e6e95c1..ea048345d 100755
--- a/source/x265cli.cpp
+++ b/source/x265cli.cpp
@@ -257,9 +257,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 <integer> 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 <integer> 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 <float> Reduces blocking and blurring in flat and textured areas (0 to 3.0). Default %.2f\n", param->rc.aqStrength);
+ H0(" --aq-bias-strength <float> Sets the bias to dark strength in AQ modes 3 and 5. Default %.2f\n", param->rc.aqBiasStrength);
H0(" --qp-adaptation-range <float> 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, using its scene statistics. Default %s\n", OPT(param->rc.frameSegment));
@@ -1095,4 +1096,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 84c3adf25..b99b7fce6 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 },
--
2.36.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment