Last active
July 24, 2023 01:03
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From f694f1439f7306dcfe19f1d547d6854a3fa64f2c Mon Sep 17 00:00:00 2001 | |
From: noizuy <[email protected]> | |
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