Skip to content

Instantly share code, notes, and snippets.

@Nomis101
Last active January 14, 2023 10:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nomis101/9953a2feb69e9f4b96a73fabca2d5ff8 to your computer and use it in GitHub Desktop.
Save Nomis101/9953a2feb69e9f4b96a73fabca2d5ff8 to your computer and use it in GitHub Desktop.
x265 patch to add an auto-AQ mode, AQ 5 (bias towards dark scenes) and option to adjust the strength of dark scene bias
diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
index f1d9fa36c..dd2511ffa 100755
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -1733,7 +1733,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
@@ -1741,13 +1741,21 @@ Quality, rate control and rate distortion options
the tendency of the encoder to spend too many bits on complex areas
and not enough in flat areas.
- 0. disabled
- 1. AQ enabled
- 2. AQ enabled with auto-variance **(default)**
+ 0. disabled.
+ 1. Uniform AQ.
+ 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. Same as AQ mode 3, but uses edge density instead of auto-variance.
+ i.e, AQ with bias towards dark scenes which have high edge density.
+
+.. option:: --auto-aq --no-auto-aq
+
+ To enable and disable automatic AQ mode detection per frame.
+ This option adaptively sets the AQ mode for each frame between 2, 3, 4 and 5 based on the scene statistics.
+ Default: disabled.
.. option:: --aq-strength <float>
@@ -1759,6 +1767,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.Segment duration depends on the
@@ -2428,7 +2443,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/common.h b/source/common/common.h
index 37c19ae72..7212f3496 100644
--- a/source/common/common.h
+++ b/source/common/common.h
@@ -130,6 +130,7 @@ typedef uint64_t sum2_t;
typedef uint64_t pixel4;
typedef int64_t ssum2_t;
#define SHIFT_TO_BITPLANE 9
+#define BRIGHTNESS_THRESHOLD 120 // The threshold above which a pixel is bright
#else
typedef uint8_t pixel;
typedef uint16_t sum_t;
@@ -137,6 +138,7 @@ typedef uint32_t sum2_t;
typedef uint32_t pixel4;
typedef int32_t ssum2_t; // Signed sum
#define SHIFT_TO_BITPLANE 7
+#define BRIGHTNESS_THRESHOLD 30 // The threshold above which a pixel is bright
#endif // if HIGH_BIT_DEPTH
#if X265_DEPTH < 10
diff --git a/source/common/frame.cpp b/source/common/frame.cpp
index ae3773e83..dedcb9c84 100644
--- a/source/common/frame.cpp
+++ b/source/common/frame.cpp
@@ -64,6 +64,7 @@ Frame::Frame()
m_edgeBitPlane = NULL;
m_edgeBitPic = NULL;
m_isInsideWindow = 0;
+ m_frameAq = X265_AQ_NONE;
// mcstf
m_isSubSampled = NULL;
@@ -132,7 +133,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.bAutoAq || (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 +343,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.bAutoAq || (m_param->rc.zonefileCount && m_param->rc.aqMode != 0))
{
X265_FREE(m_edgePic);
X265_FREE(m_gaussianPic);
diff --git a/source/common/frame.h b/source/common/frame.h
index 9a3a3a4f9..93635b7e5 100644
--- a/source/common/frame.h
+++ b/source/common/frame.h
@@ -153,7 +153,10 @@ public:
/* edge bit plane for rskips 2 and 3 */
pixel* m_edgeBitPlane;
pixel* m_edgeBitPic;
-
+
+ /* AQ mode for each frame */
+ int m_frameAq;
+
int m_isInsideWindow;
/*Frame's temporal layer info*/
diff --git a/source/common/lowres.cpp b/source/common/lowres.cpp
index 857414e91..ad0063997 100644
--- a/source/common/lowres.cpp
+++ b/source/common/lowres.cpp
@@ -211,6 +211,9 @@ bool Lowres::create(x265_param* param, PicYuv *origPic, uint32_t qgSize)
CHECKED_MALLOC(lowerResMvCosts[1][i], int32_t, cuCountLowerRes);
}
}
+
+ if (param->rc.bAutoAq)
+ lowresEdgePlane = X265_MALLOC(pixel, lumaStride * (lines + (origPic->m_lumaMarginY * 2)));
if (param->bHistBasedSceneCut)
{
@@ -288,6 +291,7 @@ void Lowres::destroy(x265_param* param)
X265_FREE(invQscaleFactor8x8);
X265_FREE(edgeInclined);
X265_FREE(qpAqMotionOffset);
+ X265_FREE(lowresEdgePlane);
if (param->bDynamicRefine || param->bEnableFades)
X265_FREE(blockVariance);
if (maxAQDepth > 0)
diff --git a/source/common/lowres.h b/source/common/lowres.h
index c727f488a..4f6399e35 100644
--- a/source/common/lowres.h
+++ b/source/common/lowres.h
@@ -48,6 +48,9 @@ struct ReferencePlanes
pixel* fpelLowerResPlane[3];
pixel* lowerResPlane[4];
+ /* Edge Plane in Lowres */
+ pixel* lowresEdgePlane;
+
bool isWeighted;
bool isLowres;
bool isHMELowres;
diff --git a/source/common/param.cpp b/source/common/param.cpp
index fe85d8726..d5ac6e751 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -281,6 +281,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;
@@ -304,6 +305,7 @@ void x265_param_default(x265_param* param)
param->rc.bEnableConstVbv = 0;
param->bResetZoneConfig = 1;
param->reconfigWindowSize = 0;
+ param->rc.bAutoAq = 0;
param->decoderVbvMaxRate = 0;
param->bliveVBV2pass = 0;
@@ -952,6 +954,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);
@@ -1253,6 +1256,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);
@@ -1424,6 +1428,7 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)
OPT("multi-pass-opt-analysis") p->analysisMultiPassRefine = atobool(value);
OPT("multi-pass-opt-distortion") p->analysisMultiPassDistortion = atobool(value);
OPT("aq-motion") p->bAQMotion = atobool(value);
+ OPT("auto-aq") p->rc.bAutoAq = atobool(value);
OPT("dynamic-rd") p->dynamicRd = atof(value);
OPT("analysis-reuse-level")
{
@@ -1821,7 +1826,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 || param->rc.aqMode > X265_AQ_EDGE_BIASED,
"Aq-Mode is out of range");
CHECK(param->rc.aqStrength < 0 || param->rc.aqStrength > 3,
"Aq-Strength is out of range");
@@ -2123,9 +2128,11 @@ void x265_print_params(x265_param* param)
param->maxNumReferences, (param->limitReferences & X265_REF_LIMIT_CU) ? "on" : "off",
(param->limitReferences & X265_REF_LIMIT_DEPTH) ? "on" : "off");
- if (param->rc.aqMode)
+ if (param->rc.aqMode && !param->rc.bAutoAq)
x265_log(param, X265_LOG_INFO, "AQ: mode / str / qg-size / cu-tree : %d / %0.1f / %d / %d\n", param->rc.aqMode,
param->rc.aqStrength, param->rc.qgSize, param->rc.cuTree);
+ else if (param->rc.bAutoAq)
+ x265_log(param, X265_LOG_INFO, "AQ: mode / str / qg-size / cu-tree : auto / %0.1f / %d / %d\n", param->rc.aqStrength, param->rc.qgSize, param->rc.cuTree);
if (param->bLossless)
x265_log(param, X265_LOG_INFO, "Rate Control : Lossless\n");
@@ -2381,6 +2388,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)
@@ -2436,6 +2444,7 @@ char *x265_param2string(x265_param* p, int padx, int pady)
s += sprintf(s, " scenecut-bias=%.2f", p->scenecutBias);
BOOL(p->bOptCUDeltaQP, "opt-cu-delta-qp");
BOOL(p->bAQMotion, "aq-motion");
+ BOOL(p->rc.bAutoAq, "auto-aq");
BOOL(p->bEmitHDR10SEI, "hdr10");
BOOL(p->bHDR10Opt, "hdr10-opt");
BOOL(p->bDhdr10opt, "dhdr10-opt");
@@ -2674,6 +2683,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;
@@ -2731,6 +2741,7 @@ void x265_copy_params(x265_param* dst, x265_param* src)
dst->rc.bEnableConstVbv = src->rc.bEnableConstVbv;
dst->rc.hevcAq = src->rc.hevcAq;
dst->rc.qpAdaptationRange = src->rc.qpAdaptationRange;
+ dst->rc.bAutoAq = src->rc.bAutoAq;
dst->vui.aspectRatioIdc = src->vui.aspectRatioIdc;
dst->vui.sarWidth = src->vui.sarWidth;
diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp
index 659b87c89..85791952b 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->rc.aqMode != X265_AQ_EDGE && m_param->recursionSkipMode == EDGE_BASED_RSKIP)
+ if (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 453ca5b40..e9861359c 100644
--- a/source/encoder/slicetype.cpp
+++ b/source/encoder/slicetype.cpp
@@ -237,6 +237,44 @@ inline void findAvgAngle(const pixel* block, intptr_t stride, uint32_t size, uin
angle = sum / (size*size);
}
+double computeBrightnessIntensity(pixel *inPlane, int width, int height, intptr_t stride)
+{
+ pixel* rowStart = inPlane;
+ int count = 0;
+
+ for (int i = 0; i < height; i++)
+ {
+ for (int j = 0; j < width; j++)
+ {
+ if (rowStart[j] > BRIGHTNESS_THRESHOLD)
+ count++;
+ }
+ rowStart += stride;
+ }
+
+ /* Returns the brightness percentage of the input plane */
+ return (count / (width * height)) * 100;
+}
+
+double computeEdgeIntensity(pixel *inPlane, int width, int height, intptr_t stride)
+{
+ pixel* rowStart = inPlane;
+ int count = 0;
+
+ for (int i = 0; i < height; i++)
+ {
+ for (int j = 0; j < width; j++)
+ {
+ if (rowStart[j] > 0)
+ count++;
+ }
+ rowStart += stride;
+ }
+
+ /* Returns the edge percentage of the input plane */
+ return (count / (width * height)) * 100;
+}
+
uint32_t LookaheadTLD::edgeDensityCu(Frame* curFrame, uint32_t &avgAngle, uint32_t blockX, uint32_t blockY, uint32_t qgSize)
{
pixel *edgeImage = curFrame->m_edgePic + curFrame->m_fencPic->m_lumaMarginY * curFrame->m_fencPic->m_stride + curFrame->m_fencPic->m_lumaMarginX;
@@ -481,9 +519,9 @@ void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param)
if (!(param->rc.bStatRead && param->rc.cuTree && IS_REFERENCED(curFrame)))
{
/* Calculate Qp offset for each 16x16 or 8x8 block in the frame */
- if (param->rc.aqMode == X265_AQ_NONE || param->rc.aqStrength == 0)
+ if (curFrame->m_frameAq == X265_AQ_NONE || param->rc.aqStrength == 0)
{
- if (param->rc.aqMode && param->rc.aqStrength == 0)
+ if (curFrame->m_frameAq && param->rc.aqStrength == 0)
{
if (quantOffsets)
{
@@ -524,17 +562,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 (curFrame->m_frameAq == X265_AQ_EDGE || curFrame->m_frameAq == X265_AQ_EDGE_BIASED)
edgeFilter(curFrame, param);
- if (param->rc.aqMode == X265_AQ_EDGE && param->recursionSkipMode == EDGE_BASED_RSKIP)
+ if (curFrame->m_frameAq == X265_AQ_EDGE && 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 (curFrame->m_frameAq == X265_AQ_AUTO_VARIANCE || curFrame->m_frameAq == X265_AQ_AUTO_VARIANCE_BIASED || curFrame->m_frameAq == X265_AQ_EDGE || curFrame->m_frameAq == 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 +581,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 (curFrame->m_frameAq == X265_AQ_EDGE || curFrame->m_frameAq == X265_AQ_EDGE_BIASED)
{
edgeDensity = edgeDensityCu(curFrame, avgAngle, blockX, blockY, param->rc.qgSize);
if (edgeDensity)
@@ -573,7 +611,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;
@@ -583,17 +621,17 @@ void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param)
{
for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
{
- if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED)
+ if (curFrame->m_frameAq == X265_AQ_AUTO_VARIANCE_BIASED)
{
qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
qp_adj = strength * (qp_adj - avg_adj) + bias_strength * (1.f - modeTwoConst / (qp_adj * qp_adj));
}
- else if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE)
+ else if (curFrame->m_frameAq == X265_AQ_AUTO_VARIANCE)
{
qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
qp_adj = strength * (qp_adj - avg_adj);
}
- else if (param->rc.aqMode == X265_AQ_EDGE)
+ else if (curFrame->m_frameAq == X265_AQ_EDGE)
{
inclinedEdge = curFrame->m_lowres.edgeInclined[blockXY];
qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
@@ -602,6 +640,15 @@ void LookaheadTLD::calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param)
else
qp_adj = strength * (qp_adj - avg_adj);
}
+ else if (curFrame->m_frameAq == X265_AQ_EDGE_BIASED)
+ {
+ inclinedEdge = curFrame->m_lowres.edgeInclined[blockXY];
+ qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY];
+ if (inclinedEdge && (qp_adj - avg_adj > 0))
+ qp_adj = ((strength + AQ_EDGE_BIAS) * (qp_adj - avg_adj)) + bias_strength * (1.f - modeTwoConst / (qp_adj * qp_adj));
+ else
+ qp_adj = strength * (qp_adj - avg_adj) + bias_strength * (1.f - modeTwoConst / (qp_adj * qp_adj));
+ }
else
{
uint32_t energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
@@ -1712,6 +1759,34 @@ void LookaheadTLD::collectPictureStatistics(Frame *curFrame)
curFrame->m_lowres.bHistScenecutAnalyzed = false;
}
+void LookaheadTLD::calcFrameSegment(Frame *preFrame)
+{
+ int heightL = preFrame->m_lowres.lines;
+ int widthL = preFrame->m_lowres.width;
+ pixel *lumaPlane = preFrame->m_lowres.fpelPlane[0];
+ intptr_t stride = preFrame->m_lowres.lumaStride;
+ double brightnessIntensity = 0, edgeIntensity = 0;
+
+ /* Edge plane computation */
+ memset(preFrame->m_lowres.lowresEdgePlane, 0, stride * (heightL + (preFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
+ pixel* lowresEdgePic = preFrame->m_lowres.lowresEdgePlane + preFrame->m_fencPic->m_lumaMarginY * stride + preFrame->m_fencPic->m_lumaMarginX;
+ computeEdge(lowresEdgePic, lumaPlane, NULL, stride, heightL, widthL, false);
+
+ /*Frame edge percentage computation */
+ edgeIntensity = computeEdgeIntensity(lowresEdgePic, widthL, heightL, stride);
+
+ /* Frame Brightness percentage computation */
+ brightnessIntensity = computeBrightnessIntensity(lumaPlane, widthL, heightL, stride);
+
+ /* AQ mode switch */
+ if (edgeIntensity < FRAME_EDGE_THRESHOLD)
+ preFrame->m_frameAq = brightnessIntensity > FRAME_BRIGHTNESS_THRESHOLD ? X265_AQ_AUTO_VARIANCE : X265_AQ_AUTO_VARIANCE_BIASED;
+ else
+ preFrame->m_frameAq = brightnessIntensity > FRAME_BRIGHTNESS_THRESHOLD ? X265_AQ_EDGE : X265_AQ_VARIANCE;
+
+ preFrame->m_param->rc.aqMode = preFrame->m_frameAq;
+}
+
void PreLookaheadGroup::processTasks(int workerThreadID)
{
if (workerThreadID < 0)
@@ -1726,6 +1801,11 @@ void PreLookaheadGroup::processTasks(int workerThreadID)
ProfileScopeEvent(prelookahead);
m_lock.release();
preFrame->m_lowres.init(preFrame->m_fencPic, preFrame->m_poc);
+
+ /* Auto AQ */
+ if (preFrame->m_param->rc.bAutoAq)
+ tld.calcFrameSegment(preFrame);
+
if (m_lookahead.m_bAdaptiveQuant)
tld.calcAdaptiveQuantFrame(preFrame, m_lookahead.m_param);
diff --git a/source/x265.h b/source/x265.h
index 9f3abd9d9..7aeb05450 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -583,6 +583,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 */
@@ -1677,6 +1678,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;
@@ -1761,6 +1765,9 @@ typedef struct x265_param
/* internally enable if tune grain is set */
int bEnableConstVbv;
+ /* automatically switch AQ mode for each frame */
+ int bAutoAq;
+
/* if only the focused frames would be re-encode or not */
int bEncFocusedFramesOnly;
diff --git a/source/x265cli.cpp b/source/x265cli.cpp
index 4d10076c0..9523ed238 100755
--- a/source/x265cli.cpp
+++ b/source/x265cli.cpp
@@ -257,11 +257,20 @@ 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.\n"
+ " - 0 : none.\n"
+ " - 1 : uniform AQ.\n"
+ " - 2 : auto variance.\n"
+ " - 3 : auto variance with bias to dark scenes.\n"
+ " - 4 : auto variance with edge density.\n"
+ " - 5 : auto variance with edge density and bias towards dark scenes.\n"
+ " 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-]auto-aq Automatically decides the AQ Mode for each frame, using its scene statistics, such as luma intensity and edge density. Default %s\n", OPT(param->rc.bAutoAq));
H1(" --[no-]sbrc Enables the segment based rate control. Default %s\n", OPT(param->bEnableSBRC));
H0(" --qg-size <int> Specifies the size of the quantization group (64, 32, 16, 8). Default %d\n", param->rc.qgSize);
H0(" --[no-]cutree Enable cutree for Adaptive Quantization. Default %s\n", OPT(param->rc.cuTree));
@@ -1223,4 +1232,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 d5b816e80..e594dc34d 100644
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -180,7 +180,10 @@ static const struct option long_options[] =
{ "bitrate", required_argument, NULL, 0 },
{ "qp", required_argument, NULL, 'q' },
{ "aq-mode", required_argument, NULL, 0 },
+ { "auto-aq", no_argument, NULL, 0 },
+ { "no-auto-aq", no_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 },
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment