# HG changeset patch # User Niranjan <niran...@multicorewareinc.com> # Date 1582622787 -19800 # Tue Feb 25 14:56:27 2020 +0530 # Node ID 2ec7d27dc576cd993fd0bfe4b116514e8f2ddc0c # Parent 1a47c3802fa38bdb4606e3d8203b73b4474d1ce6 Add: Auto AQ Mode
This patch does the following: 1. Automatically decides the AQ Mode for each frame, using its scene statistics, such as luma intensity and edge density. 2. Add option "--auto-aq" to enable auto detection of AQ Mode per frame. diff -r 1a47c3802fa3 -r 2ec7d27dc576 doc/reST/cli.rst --- a/doc/reST/cli.rst Mon Feb 24 12:51:41 2020 +0530 +++ b/doc/reST/cli.rst Tue Feb 25 14:56:27 2020 +0530 @@ -1721,6 +1721,12 @@ 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> Adjust the strength of the adaptive quantization offsets. Setting diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/CMakeLists.txt --- a/source/CMakeLists.txt Mon Feb 24 12:51:41 2020 +0530 +++ b/source/CMakeLists.txt Tue Feb 25 14:56:27 2020 +0530 @@ -29,7 +29,7 @@ option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF) mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD) # X265_BUILD must be incremented each time the public API is changed -set(X265_BUILD 189) +set(X265_BUILD 190) configure_file("${PROJECT_SOURCE_DIR}/x265.def.in" "${PROJECT_BINARY_DIR}/x265.def") configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in" diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/common/common.h --- a/source/common/common.h Mon Feb 24 12:51:41 2020 +0530 +++ b/source/common/common.h Tue Feb 25 14:56:27 2020 +0530 @@ -131,6 +131,7 @@ typedef int64_t ssum2_t; #define SHIFT_TO_BITPLANE 9 #define HISTOGRAM_BINS 1024 +#define BRIGHTNESS_THRESHOLD 120 // The threshold above which a pixel is bright #else typedef uint8_t pixel; typedef uint16_t sum_t; @@ -139,6 +140,7 @@ typedef int32_t ssum2_t; // Signed sum #define SHIFT_TO_BITPLANE 7 #define HISTOGRAM_BINS 256 +#define BRIGHTNESS_THRESHOLD 30 // The threshold above which a pixel is bright #endif // if HIGH_BIT_DEPTH #if X265_DEPTH < 10 @@ -163,6 +165,8 @@ #define MIN_QPSCALE 0.21249999999999999 #define MAX_MAX_QPSCALE 615.46574234477100 +#define FRAME_BRIGHTNESS_THRESHOLD 50.0 // Min % of pixels in a frame, that are above BRIGHTNESS_THRESHOLD for it to be considered a bright frame +#define FRAME_EDGE_THRESHOLD 10.0 // Min % of edge pixels in a frame, for it to be considered to have high edge density template<typename T> inline T x265_min(T a, T b) { return a < b ? a : b; } diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/common/frame.cpp --- a/source/common/frame.cpp Mon Feb 24 12:51:41 2020 +0530 +++ b/source/common/frame.cpp Tue Feb 25 14:56:27 2020 +0530 @@ -63,6 +63,7 @@ m_thetaPic = NULL; m_edgeBitPlane = NULL; m_edgeBitPic = NULL; + m_frameAq = X265_AQ_NONE; } bool Frame::create(x265_param *param, float* quantOffsets) @@ -103,7 +104,7 @@ CHECKED_MALLOC_ZERO(m_classifyCount, uint32_t, size); } - if (param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED || (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; diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/common/frame.h --- a/source/common/frame.h Mon Feb 24 12:51:41 2020 +0530 +++ b/source/common/frame.h Tue Feb 25 14:56:27 2020 +0530 @@ -141,6 +141,9 @@ pixel* m_edgeBitPlane; pixel* m_edgeBitPic; + /* AQ mode for each frame */ + int m_frameAq; + Frame(); bool create(x265_param *param, float* quantOffsets); diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/common/lowres.cpp --- a/source/common/lowres.cpp Mon Feb 24 12:51:41 2020 +0530 +++ b/source/common/lowres.cpp Tue Feb 25 14:56:27 2020 +0530 @@ -190,6 +190,9 @@ } } + if (param->rc.bAutoAq) + lowresEdgePlane = X265_MALLOC(pixel, lumaStride * (lines + (origPic->m_lumaMarginY * 2))); + return true; fail: @@ -235,6 +238,7 @@ X265_FREE(edgeInclined); X265_FREE(qpAqMotionOffset); X265_FREE(blockVariance); + X265_FREE(lowresEdgePlane); if (maxAQDepth > 0) { for (uint32_t d = 0; d < 4; d++) diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/common/lowres.h --- a/source/common/lowres.h Mon Feb 24 12:51:41 2020 +0530 +++ b/source/common/lowres.h Tue Feb 25 14:56:27 2020 +0530 @@ -44,6 +44,9 @@ pixel* fpelLowerResPlane[3]; pixel* lowerResPlane[4]; + /* Edge Plane in Lowres */ + pixel* lowresEdgePlane; + bool isWeighted; bool isLowres; bool isHMELowres; diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/common/param.cpp --- a/source/common/param.cpp Mon Feb 24 12:51:41 2020 +0530 +++ b/source/common/param.cpp Tue Feb 25 14:56:27 2020 +0530 @@ -286,6 +286,7 @@ param->rc.bEnableConstVbv = 0; param->bResetZoneConfig = 1; param->reconfigWindowSize = 0; + param->rc.bAutoAq = 0; /* Video Usability Information (VUI) */ param->vui.aspectRatioIdc = 0; @@ -1229,6 +1230,7 @@ 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") { @@ -1877,9 +1879,12 @@ 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"); @@ -2187,6 +2192,7 @@ s += sprintf(s, " hist-threshold=%.2f", p->edgeTransitionThreshold); 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"); @@ -2468,6 +2474,7 @@ 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 -r 1a47c3802fa3 -r 2ec7d27dc576 source/encoder/slicetype.cpp --- a/source/encoder/slicetype.cpp Mon Feb 24 12:51:41 2020 +0530 +++ b/source/encoder/slicetype.cpp Tue Feb 25 14:56:27 2020 +0530 @@ -473,9 +473,9 @@ 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) { @@ -516,18 +516,18 @@ double bias_strength = 0.f; double strength = 0.f; - if (param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED) + 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->bHistBasedSceneCut && param->enableRecursionSkip >= EDGE_BASED_RSKIP) + if (curFrame->m_frameAq == X265_AQ_EDGE && !param->bHistBasedSceneCut && param->enableRecursionSkip >= 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 || param->rc.aqMode == X265_AQ_EDGE_BIASED) + 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) @@ -536,7 +536,7 @@ { uint32_t energy, edgeDensity, avgAngle; energy = acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize); - if (param->rc.aqMode == X265_AQ_EDGE || param->rc.aqMode == X265_AQ_EDGE_BIASED) + 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) @@ -576,17 +576,17 @@ { 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]; @@ -595,7 +595,7 @@ else qp_adj = strength * (qp_adj - avg_adj); } - else if (param->rc.aqMode == X265_AQ_EDGE_BIASED) + else if (curFrame->m_frameAq == X265_AQ_EDGE_BIASED) { inclinedEdge = curFrame->m_lowres.edgeInclined[blockXY]; qp_adj = curFrame->m_lowres.qpCuTreeOffset[blockXY]; @@ -1387,6 +1387,44 @@ } } +double computeBrightnessIntensity(pixel *inPlane, int width, int height, intptr_t stride) +{ + pixel* rowStart = inPlane; + double 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; + double 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; +} + void PreLookaheadGroup::processTasks(int workerThreadID) { if (workerThreadID < 0) @@ -1401,6 +1439,36 @@ ProfileScopeEvent(prelookahead); m_lock.release(); preFrame->m_lowres.init(preFrame->m_fencPic, preFrame->m_poc); + + /* Auto AQ */ + if (preFrame->m_param->rc.bAutoAq) + { + 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_EDGE_BIASED; + } + else + preFrame->m_frameAq = preFrame->m_param->rc.aqMode; + if (m_lookahead.m_bAdaptiveQuant) tld.calcAdaptiveQuantFrame(preFrame, m_lookahead.m_param); tld.lowresIntraEstimate(preFrame->m_lowres, m_lookahead.m_param->rc.qgSize); diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/test/regression-tests.txt --- a/source/test/regression-tests.txt Mon Feb 24 12:51:41 2020 +0530 +++ b/source/test/regression-tests.txt Tue Feb 25 14:56:27 2020 +0530 @@ -171,6 +171,7 @@ crowd_run_1080p50.yuv, --preset slow --ctu 32 --rskip 3 --rskip-edge-threshold 5 --hist-scenecut --hist-threshold 0.1 crowd_run_1080p50.yuv, --preset slower --ctu 16 --rskip 3 --rskip-edge-threshold 5 --hist-scenecut --hist-threshold 0.1 --aq-mode 4 sintel_trailer_2k_1920x1080_24.yuv, --preset medium --aq-mode 5 +ducks_take_off_420_720p50.y4m, --preset slow --auto-aq --aq-strength 1.5 --aq-motion # Main12 intraCost overflow bug test 720p50_parkrun_ter.y4m,--preset medium diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/x265.h --- a/source/x265.h Mon Feb 24 12:51:41 2020 +0530 +++ b/source/x265.h Tue Feb 25 14:56:27 2020 +0530 @@ -1477,6 +1477,9 @@ /* internally enable if tune grain is set */ int bEnableConstVbv; + /* automatically switch AQ mode for each frame */ + int bAutoAq; + } rc; /*== Video Usability Information ==*/ diff -r 1a47c3802fa3 -r 2ec7d27dc576 source/x265cli.h --- a/source/x265cli.h Mon Feb 24 12:51:41 2020 +0530 +++ b/source/x265cli.h Tue Feb 25 14:56:27 2020 +0530 @@ -172,6 +172,8 @@ { "qp", required_argument, NULL, 'q' }, { "aq-mode", required_argument, NULL, 0 }, { "aq-strength", required_argument, NULL, 0 }, + { "auto-aq", no_argument, NULL, 0 }, + { "no-auto-aq", no_argument, NULL, 0 }, { "rc-grain", no_argument, NULL, 0 }, { "no-rc-grain", no_argument, NULL, 0 }, { "ipratio", required_argument, NULL, 0 }, @@ -594,6 +596,7 @@ H0(" --aq-strength <float> Reduces blocking and blurring in flat and textured areas (0 to 3.0). Default %.2f\n", param->rc.aqStrength); 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)); 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)); H0(" --[no-]rc-grain Enable ratecontrol mode to handle grains specifically. turned on with tune grain. Default %s\n", OPT(param->rc.bEnableGrain)); Thanks & Regards *Niranjan Kumar B* Video Codec Engineer Media & AI Analytics +91 958 511 1449 <https://multicorewareinc.com/>
AutoAQ.patch
Description: Binary data
_______________________________________________ x265-devel mailing list x265-devel@videolan.org https://mailman.videolan.org/listinfo/x265-devel