[x265] [PATCH] 2-pass: Fix incorrect weighted prediction when cu-tree is enabled
Aruna Matheswaran
aruna at multicorewareinc.com
Thu Sep 12 12:38:52 CEST 2019
Pushed into Release_3.1 and grafted to default.
On Tue, Sep 10, 2019 at 11:27 AM Aruna Matheswaran <
aruna at multicorewareinc.com> wrote:
> # HG changeset patch
> # User Aruna Matheswaran
> # Date 1567490246 -19800
> # Tue Sep 03 11:27:26 2019 +0530
> # Node ID 55bc4aa1433c01c99002e702bc49e572399cbd32
> # Parent a092e82e6acfe7afe6a9a381e9ef52323e4e2467
> 2-pass: Fix incorrect weighted prediction when cu-tree is enabled
>
> diff -r a092e82e6acf -r 55bc4aa1433c source/encoder/slicetype.cpp
> --- a/source/encoder/slicetype.cpp Thu Aug 01 22:55:21 2019 +0200
> +++ b/source/encoder/slicetype.cpp Tue Sep 03 11:27:26 2019 +0530
> @@ -437,175 +437,178 @@
> curFrame->m_lowres.wp_sum[y] = 0;
> }
>
> - /* Calculate Qp offset for each 16x16 or 8x8 block in the frame */
> - if ((param->rc.aqMode == X265_AQ_NONE || param->rc.aqStrength == 0)
> || (param->rc.bStatRead && param->rc.cuTree && IS_REFERENCED(curFrame)))
> - {
> - if (param->rc.aqMode && param->rc.aqStrength == 0)
> - {
> - if (quantOffsets)
> + 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 (param->rc.aqMode && param->rc.aqStrength == 0)
> + {
> + if (quantOffsets)
> + {
> + for (int cuxy = 0; cuxy <
> blockCount; cuxy++)
> + {
> +
> curFrame->m_lowres.qpCuTreeOffset[cuxy] =
> curFrame->m_lowres.qpAqOffset[cuxy] = quantOffsets[cuxy];
> +
> curFrame->m_lowres.invQscaleFactor[cuxy] =
> x265_exp2fix8(curFrame->m_lowres.qpCuTreeOffset[cuxy]);
> + }
> + }
> + else
> + {
> +
> memset(curFrame->m_lowres.qpCuTreeOffset, 0, blockCount * sizeof(double));
> +
> memset(curFrame->m_lowres.qpAqOffset, 0, blockCount * sizeof(double));
> + for (int cuxy = 0; cuxy <
> blockCount; cuxy++)
> +
> curFrame->m_lowres.invQscaleFactor[cuxy] = 256;
> + }
> + }
> +
> + /* Need variance data for weighted prediction and dynamic
> refinement*/
> + if (param->bEnableWeightedPred ||
> param->bEnableWeightedBiPred)
> {
> - for (int cuxy = 0; cuxy < blockCount; cuxy++)
> - {
> - curFrame->m_lowres.qpCuTreeOffset[cuxy] =
> curFrame->m_lowres.qpAqOffset[cuxy] = quantOffsets[cuxy];
> - curFrame->m_lowres.invQscaleFactor[cuxy] =
> x265_exp2fix8(curFrame->m_lowres.qpCuTreeOffset[cuxy]);
> - }
> - }
> - else
> - {
> - memset(curFrame->m_lowres.qpCuTreeOffset, 0, blockCount *
> sizeof(double));
> - memset(curFrame->m_lowres.qpAqOffset, 0, blockCount *
> sizeof(double));
> - for (int cuxy = 0; cuxy < blockCount; cuxy++)
> - curFrame->m_lowres.invQscaleFactor[cuxy] = 256;
> + for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
> + for (int blockX = 0; blockX < maxCol; blockX +=
> loopIncr)
> + acEnergyCu(curFrame, blockX, blockY,
> param->internalCsp, param->rc.qgSize);
> }
> - }
> -
> - /* Need variance data for weighted prediction and dynamic
> refinement*/
> - if (param->bEnableWeightedPred || param->bEnableWeightedBiPred)
> - {
> - for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
> - for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
> - acEnergyCu(curFrame, blockX, blockY,
> param->internalCsp, param->rc.qgSize);
> - }
> - }
> - else
> - {
> - if (param->rc.hevcAq)
> - {
> - // New method for calculating variance and qp offset
> - xPreanalyze(curFrame);
> - }
> - else
> - {
> + }
> + else
> + {
> + if (param->rc.hevcAq)
> + {
> + // New method for calculating variance and
> qp offset
> + xPreanalyze(curFrame);
> + }
> + else
> + {
> #define AQ_EDGE_BIAS 0.5
> #define EDGE_INCLINATION 45
> - uint32_t numCuInHeight = (maxRow + param->maxCUSize - 1) /
> param->maxCUSize;
> - int maxHeight = numCuInHeight * param->maxCUSize;
> - intptr_t stride = curFrame->m_fencPic->m_stride;
> - pixel *edgePic = X265_MALLOC(pixel, stride * (maxHeight +
> (curFrame->m_fencPic->m_lumaMarginY * 2)));
> - pixel *gaussianPic = X265_MALLOC(pixel, stride * (maxHeight +
> (curFrame->m_fencPic->m_lumaMarginY * 2)));
> - pixel *thetaPic = X265_MALLOC(pixel, stride * (maxHeight +
> (curFrame->m_fencPic->m_lumaMarginY * 2)));
> - memset(edgePic, 0, stride * (maxHeight +
> (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
> - memset(gaussianPic, 0, stride * (maxHeight +
> (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
> - memset(thetaPic, 0, stride * (maxHeight +
> (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
> - if (param->rc.aqMode == X265_AQ_EDGE)
> - edgeFilter(curFrame, edgePic, gaussianPic, thetaPic,
> stride, maxRow, maxCol);
> -
> - int blockXY = 0, inclinedEdge = 0;
> - double avg_adj_pow2 = 0, avg_adj = 0, qp_adj = 0;
> - double bias_strength = 0.f;
> - double strength = 0.f;
> - if (param->rc.aqMode == X265_AQ_AUTO_VARIANCE ||
> param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED || param->rc.aqMode ==
> X265_AQ_EDGE)
> - {
> - double bit_depth_correction = 1.f / (1 << (2 *
> (X265_DEPTH - 8)));
> - for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
> - {
> - for (int blockX = 0; blockX < maxCol; blockX +=
> loopIncr)
> - {
> - uint32_t energy, edgeDensity, avgAngle;
> - energy = acEnergyCu(curFrame, blockX, blockY,
> param->internalCsp, param->rc.qgSize);
> - if (param->rc.aqMode == X265_AQ_EDGE)
> - {
> - pixel *edgeImage = edgePic +
> curFrame->m_fencPic->m_lumaMarginY * stride +
> curFrame->m_fencPic->m_lumaMarginX;
> - pixel *edgeTheta = thetaPic +
> curFrame->m_fencPic->m_lumaMarginY * stride +
> curFrame->m_fencPic->m_lumaMarginX;
> - edgeDensity = edgeDensityCu(curFrame,
> edgeImage, edgeTheta, avgAngle, blockX, blockY, param->rc.qgSize);
> - if (edgeDensity)
> - {
> - qp_adj = pow(edgeDensity *
> bit_depth_correction + 1, 0.1);
> - //Increasing the QP of a block if its
> edge orientation lies around the multiples of 45 degree
> - if ((avgAngle >= EDGE_INCLINATION - 15 &&
> avgAngle <= EDGE_INCLINATION + 15) || (avgAngle >= EDGE_INCLINATION + 75 &&
> avgAngle <= EDGE_INCLINATION + 105))
> -
> curFrame->m_lowres.edgeInclined[blockXY] = 1;
> - else
> -
> curFrame->m_lowres.edgeInclined[blockXY] = 0;
> - }
> - else
> - {
> - qp_adj = pow(energy *
> bit_depth_correction + 1, 0.1);
> - curFrame->m_lowres.edgeInclined[blockXY]
> = 0;
> - }
> - }
> - else
> - qp_adj = pow(energy * bit_depth_correction +
> 1, 0.1);
> - curFrame->m_lowres.qpCuTreeOffset[blockXY] =
> qp_adj;
> - avg_adj += qp_adj;
> - avg_adj_pow2 += qp_adj * qp_adj;
> - blockXY++;
> - }
> - }
> - avg_adj /= blockCount;
> - 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;
> - }
> - else
> - strength = param->rc.aqStrength * 1.0397f;
> -
> - X265_FREE(edgePic);
> - X265_FREE(gaussianPic);
> - X265_FREE(thetaPic);
> - blockXY = 0;
> - for (int blockY = 0; blockY < maxRow; blockY += loopIncr)
> - {
> - for (int blockX = 0; blockX < maxCol; blockX += loopIncr)
> - {
> - if (param->rc.aqMode == 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)
> - {
> - qp_adj =
> curFrame->m_lowres.qpCuTreeOffset[blockXY];
> - qp_adj = strength * (qp_adj - avg_adj);
> - }
> - else if (param->rc.aqMode == X265_AQ_EDGE)
> - {
> - 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));
> - else
> - qp_adj = strength * (qp_adj - avg_adj);
> - }
> - else
> - {
> - uint32_t energy = acEnergyCu(curFrame, blockX,
> blockY, param->internalCsp, param->rc.qgSize);
> - qp_adj = strength * (X265_LOG2(X265_MAX(energy,
> 1)) - (modeOneConst + 2 * (X265_DEPTH - 8)));
> - }
> -
> - if (param->bHDROpt)
> - {
> - uint32_t sum = lumaSumCu(curFrame, blockX,
> blockY, param->rc.qgSize);
> - uint32_t lumaAvg = sum / (loopIncr * loopIncr);
> - if (lumaAvg < 301)
> - qp_adj += 3;
> - else if (lumaAvg >= 301 && lumaAvg < 367)
> - qp_adj += 2;
> - else if (lumaAvg >= 367 && lumaAvg < 434)
> - qp_adj += 1;
> - else if (lumaAvg >= 501 && lumaAvg < 567)
> - qp_adj -= 1;
> - else if (lumaAvg >= 567 && lumaAvg < 634)
> - qp_adj -= 2;
> - else if (lumaAvg >= 634 && lumaAvg < 701)
> - qp_adj -= 3;
> - else if (lumaAvg >= 701 && lumaAvg < 767)
> - qp_adj -= 4;
> - else if (lumaAvg >= 767 && lumaAvg < 834)
> - qp_adj -= 5;
> - else if (lumaAvg >= 834)
> - qp_adj -= 6;
> - }
> - if (quantOffsets != NULL)
> - qp_adj += quantOffsets[blockXY];
> - curFrame->m_lowres.qpAqOffset[blockXY] = qp_adj;
> - curFrame->m_lowres.qpCuTreeOffset[blockXY] = qp_adj;
> - curFrame->m_lowres.invQscaleFactor[blockXY] =
> x265_exp2fix8(qp_adj);
> - blockXY++;
> - }
> - }
> - }
> - }
> + uint32_t numCuInHeight = (maxRow +
> param->maxCUSize - 1) / param->maxCUSize;
> + int maxHeight = numCuInHeight *
> param->maxCUSize;
> + intptr_t stride =
> curFrame->m_fencPic->m_stride;
> + pixel *edgePic = X265_MALLOC(pixel, stride
> * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)));
> + pixel *gaussianPic = X265_MALLOC(pixel,
> stride * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)));
> + pixel *thetaPic = X265_MALLOC(pixel,
> stride * (maxHeight + (curFrame->m_fencPic->m_lumaMarginY * 2)));
> + memset(edgePic, 0, stride * (maxHeight +
> (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
> + memset(gaussianPic, 0, stride * (maxHeight
> + (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
> + memset(thetaPic, 0, stride * (maxHeight +
> (curFrame->m_fencPic->m_lumaMarginY * 2)) * sizeof(pixel));
> + if (param->rc.aqMode == X265_AQ_EDGE)
> + edgeFilter(curFrame, edgePic,
> gaussianPic, thetaPic, stride, maxRow, maxCol);
> +
> + int blockXY = 0, inclinedEdge = 0;
> + double avg_adj_pow2 = 0, avg_adj = 0,
> qp_adj = 0;
> + double bias_strength = 0.f;
> + double strength = 0.f;
> + if (param->rc.aqMode ==
> X265_AQ_AUTO_VARIANCE || param->rc.aqMode == X265_AQ_AUTO_VARIANCE_BIASED
> || param->rc.aqMode == X265_AQ_EDGE)
> + {
> + double bit_depth_correction = 1.f
> / (1 << (2 * (X265_DEPTH - 8)));
> + for (int blockY = 0; blockY <
> maxRow; blockY += loopIncr)
> + {
> + for (int blockX = 0;
> blockX < maxCol; blockX += loopIncr)
> + {
> + uint32_t energy,
> edgeDensity, avgAngle;
> + energy =
> acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
> + if
> (param->rc.aqMode == X265_AQ_EDGE)
> + {
> + pixel
> *edgeImage = edgePic + curFrame->m_fencPic->m_lumaMarginY * stride +
> curFrame->m_fencPic->m_lumaMarginX;
> + pixel
> *edgeTheta = thetaPic + curFrame->m_fencPic->m_lumaMarginY * stride +
> curFrame->m_fencPic->m_lumaMarginX;
> +
> edgeDensity = edgeDensityCu(curFrame, edgeImage, edgeTheta, avgAngle,
> blockX, blockY, param->rc.qgSize);
> + if
> (edgeDensity)
> + {
> +
> qp_adj = pow(edgeDensity * bit_depth_correction + 1, 0.1);
> +
> //Increasing the QP of a block if its edge orientation lies around the
> multiples of 45 degree
> + if
> ((avgAngle >= EDGE_INCLINATION - 15 && avgAngle <= EDGE_INCLINATION + 15)
> || (avgAngle >= EDGE_INCLINATION + 75 && avgAngle <= EDGE_INCLINATION +
> 105))
> +
> curFrame->m_lowres.edgeInclined[blockXY] = 1;
> +
> else
> +
> curFrame->m_lowres.edgeInclined[blockXY] = 0;
> + }
> + else
> + {
> +
> qp_adj = pow(energy * bit_depth_correction + 1, 0.1);
> +
> curFrame->m_lowres.edgeInclined[blockXY] = 0;
> + }
> + }
> + else
> + qp_adj =
> pow(energy * bit_depth_correction + 1, 0.1);
> +
> curFrame->m_lowres.qpCuTreeOffset[blockXY] = qp_adj;
> + avg_adj += qp_adj;
> + avg_adj_pow2 +=
> qp_adj * qp_adj;
> + blockXY++;
> + }
> + }
> + avg_adj /= blockCount;
> + 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;
> + }
> + else
> + strength = param->rc.aqStrength *
> 1.0397f;
> +
> + X265_FREE(edgePic);
> + X265_FREE(gaussianPic);
> + X265_FREE(thetaPic);
> + blockXY = 0;
> + for (int blockY = 0; blockY < maxRow;
> blockY += loopIncr)
> + {
> + for (int blockX = 0; blockX <
> maxCol; blockX += loopIncr)
> + {
> + if (param->rc.aqMode ==
> 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)
> + {
> + qp_adj =
> curFrame->m_lowres.qpCuTreeOffset[blockXY];
> + qp_adj = strength
> * (qp_adj - avg_adj);
> + }
> + else if (param->rc.aqMode
> == X265_AQ_EDGE)
> + {
> + 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));
> + else
> + qp_adj =
> strength * (qp_adj - avg_adj);
> + }
> + else
> + {
> + uint32_t energy =
> acEnergyCu(curFrame, blockX, blockY, param->internalCsp, param->rc.qgSize);
> + qp_adj = strength
> * (X265_LOG2(X265_MAX(energy, 1)) - (modeOneConst + 2 * (X265_DEPTH - 8)));
> + }
> +
> + if (param->bHDROpt)
> + {
> + uint32_t sum =
> lumaSumCu(curFrame, blockX, blockY, param->rc.qgSize);
> + uint32_t lumaAvg =
> sum / (loopIncr * loopIncr);
> + if (lumaAvg < 301)
> + qp_adj +=
> 3;
> + else if (lumaAvg
> >= 301 && lumaAvg < 367)
> + qp_adj +=
> 2;
> + else if (lumaAvg
> >= 367 && lumaAvg < 434)
> + qp_adj +=
> 1;
> + else if (lumaAvg
> >= 501 && lumaAvg < 567)
> + qp_adj -=
> 1;
> + else if (lumaAvg
> >= 567 && lumaAvg < 634)
> + qp_adj -=
> 2;
> + else if (lumaAvg
> >= 634 && lumaAvg < 701)
> + qp_adj -=
> 3;
> + else if (lumaAvg
> >= 701 && lumaAvg < 767)
> + qp_adj -=
> 4;
> + else if (lumaAvg
> >= 767 && lumaAvg < 834)
> + qp_adj -=
> 5;
> + else if (lumaAvg
> >= 834)
> + qp_adj -=
> 6;
> + }
> + if (quantOffsets != NULL)
> + qp_adj +=
> quantOffsets[blockXY];
> +
> curFrame->m_lowres.qpAqOffset[blockXY] = qp_adj;
> +
> curFrame->m_lowres.qpCuTreeOffset[blockXY] = qp_adj;
> +
> curFrame->m_lowres.invQscaleFactor[blockXY] = x265_exp2fix8(qp_adj);
> + blockXY++;
> + }
> + }
> + }
> + }
> + }
>
> if (param->rc.qgSize == 8)
> {
> @@ -624,6 +627,11 @@
>
> if (param->bEnableWeightedPred || param->bEnableWeightedBiPred)
> {
> + if (param->rc.bStatRead && param->rc.cuTree &&
> IS_REFERENCED(curFrame))
> + for (int blockY = 0; blockY < maxRow; blockY +=
> loopIncr)
> + for (int blockX = 0; blockX < maxCol; blockX
> += loopIncr)
> + acEnergyCu(curFrame, blockX, blockY,
> param->internalCsp, param->rc.qgSize);
> +
> int hShift = CHROMA_H_SHIFT(param->internalCsp);
> int vShift = CHROMA_V_SHIFT(param->internalCsp);
> maxCol = ((maxCol + 8) >> 4) << 4;
> @@ -1356,9 +1364,7 @@
> ProfileScopeEvent(prelookahead);
> m_lock.release();
> preFrame->m_lowres.init(preFrame->m_fencPic, preFrame->m_poc);
> - if (m_lookahead.m_param->rc.bStatRead &&
> m_lookahead.m_param->rc.cuTree && IS_REFERENCED(preFrame))
> - /* cu-tree offsets were read from stats file */;
> - else if (m_lookahead.m_bAdaptiveQuant)
> + if (m_lookahead.m_bAdaptiveQuant)
> tld.calcAdaptiveQuantFrame(preFrame, m_lookahead.m_param);
> tld.lowresIntraEstimate(preFrame->m_lowres,
> m_lookahead.m_param->rc.qgSize);
> preFrame->m_lowresInit = true;
>
--
Regards,
Aruna
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20190912/f99e3434/attachment-0001.html>
More information about the x265-devel
mailing list