[x265] [PATCH]Add: Auto AQ Mode

Nomis101 Nomis101 at web.de
Wed Apr 15 17:59:02 CEST 2020


What did happen with this auto-aq idea? Is it planned to pursue this idea further? I quite liked this idea and it gives me a nice reduction in file size.
Thanks and regards.


Am 27.02.20 um 09:59 schrieb Niranjan Bala:
> # HG changeset patch
> # User Niranjan <niranjan at multicorewareinc.com <mailto:niranjan at 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 <http://x265.def.in>"
>                 "${PROJECT_BINARY_DIR}/x265.def")
>  configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in <http://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/>
> 
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
> 




More information about the x265-devel mailing list