[x265] [PATCH 2 of 2] aq: add cost of sub-LCU level QP to RD costs
Deepthi Nandakumar
deepthi at multicorewareinc.com
Wed Apr 8 08:00:01 CEST 2015
This patch will cause a valid change in outputs in all commandlines that
use AQ/CUTree/VBV - in other words, that change QP mid-frame.
It measures the RD cost of signalling deltaQP (current QP -predicted QP),
and occasionally mode/split decisions can change in
favour of a mode which has no residual, thus saving the trouble of sending
deltaQP.
Most of the output changes measured by this patch are in favour of the
efficiency curve. Visual quality effects are less well defined. Might be
ideal to
bias away from zero/low residual modes in general for psy- optimizations,
but it's not quite clear how that can be done properly.
Currently, this patch only changes outputs for rdLevels > 4. I will send a
follow-on patch which will also change outputs at the lower rdLevels,
as it should.
On Mon, Apr 6, 2015 at 3:49 PM, <deepthi at multicorewareinc.com> wrote:
> # HG changeset patch
> # User Deepthi Nandakumar <deepthi at multicorewareinc.com>
> # Date 1428314947 -19800
> # Mon Apr 06 15:39:07 2015 +0530
> # Node ID 5e944fdd03bbebb8b2d926a848fab1fc37a9fbee
> # Parent 30e209c9bab6acc8028f922c652d80dd51ac263f
> aq: add cost of sub-LCU level QP to RD costs
>
> diff -r 30e209c9bab6 -r 5e944fdd03bb source/encoder/analysis.cpp
> --- a/source/encoder/analysis.cpp Mon Mar 23 14:23:42 2015 +0530
> +++ b/source/encoder/analysis.cpp Mon Apr 06 15:39:07 2015 +0530
> @@ -365,7 +365,7 @@
> else
> updateModeCost(*splitPred);
>
> - checkDQPForSplitPred(splitPred->cu, cuGeom);
> + checkDQPForSplitPred(*splitPred, cuGeom);
> checkBestMode(*splitPred, depth);
> }
>
> @@ -771,7 +771,7 @@
> else
> updateModeCost(*splitPred);
>
> - checkDQPForSplitPred(splitPred->cu, cuGeom);
> + checkDQPForSplitPred(*splitPred, cuGeom);
> checkBestMode(*splitPred, depth);
> }
>
> @@ -1063,7 +1063,7 @@
> else if (splitPred->sa8dCost < md.bestMode->sa8dCost)
> md.bestMode = splitPred;
>
> - checkDQPForSplitPred(md.bestMode->cu, cuGeom);
> + checkDQPForSplitPred(*md.bestMode, cuGeom);
> }
> if (mightNotSplit)
> {
> @@ -1257,7 +1257,7 @@
> else
> updateModeCost(*splitPred);
>
> - checkDQPForSplitPred(splitPred->cu, cuGeom);
> + checkDQPForSplitPred(*splitPred, cuGeom);
> checkBestMode(*splitPred, depth);
> }
>
> @@ -1372,7 +1372,7 @@
> md.bestMode->cu.setPUMv(1, candMvField[bestSadCand][1].mv, 0, 0);
> md.bestMode->cu.setPURefIdx(0,
> (int8_t)candMvField[bestSadCand][0].refIdx, 0, 0);
> md.bestMode->cu.setPURefIdx(1,
> (int8_t)candMvField[bestSadCand][1].refIdx, 0, 0);
> - checkDQP(md.bestMode->cu, cuGeom);
> + checkDQP(*md.bestMode, cuGeom);
> X265_CHECK(md.bestMode->ok(), "Merge mode not ok\n");
> }
>
> @@ -1504,7 +1504,7 @@
> bestPred->cu.setPUMv(1, candMvField[bestCand][1].mv, 0, 0);
> bestPred->cu.setPURefIdx(0,
> (int8_t)candMvField[bestCand][0].refIdx, 0, 0);
> bestPred->cu.setPURefIdx(1,
> (int8_t)candMvField[bestCand][1].refIdx, 0, 0);
> - checkDQP(bestPred->cu, cuGeom);
> + checkDQP(*bestPred, cuGeom);
> X265_CHECK(bestPred->ok(), "merge mode is not ok");
> }
>
> diff -r 30e209c9bab6 -r 5e944fdd03bb source/encoder/entropy.h
> --- a/source/encoder/entropy.h Mon Mar 23 14:23:42 2015 +0530
> +++ b/source/encoder/entropy.h Mon Apr 06 15:39:07 2015 +0530
> @@ -179,7 +179,7 @@
> inline void codeQtCbfChroma(uint32_t cbf, uint32_t tuDepth)
> { encodeBin(cbf, m_contextState[OFF_QT_CBF_CTX + 2 + tuDepth]); }
> inline void codeQtRootCbf(uint32_t cbf)
> { encodeBin(cbf, m_contextState[OFF_QT_ROOT_CBF_CTX]); }
> inline void codeTransformSkipFlags(uint32_t transformSkip, TextType
> ttype) { encodeBin(transformSkip, m_contextState[OFF_TRANSFORMSKIP_FLAG_CTX
> + (ttype ? NUM_TRANSFORMSKIP_FLAG_CTX : 0)]); }
> -
> + void codeDeltaQP(const CUData& cu, uint32_t absPartIdx);
> void codeSaoOffset(const SaoCtuParam& ctuParam, int plane);
>
> /* RDO functions */
> @@ -242,7 +242,6 @@
>
> void codeSaoMaxUvlc(uint32_t code, uint32_t maxSymbol);
>
> - void codeDeltaQP(const CUData& cu, uint32_t absPartIdx);
> void codeLastSignificantXY(uint32_t posx, uint32_t posy, uint32_t
> log2TrSize, bool bIsLuma, uint32_t scanIdx);
>
> void encodeTransform(const CUData& cu, uint32_t absPartIdx, uint32_t
> tuDepth, uint32_t log2TrSize,
> diff -r 30e209c9bab6 -r 5e944fdd03bb source/encoder/search.cpp
> --- a/source/encoder/search.cpp Mon Mar 23 14:23:42 2015 +0530
> +++ b/source/encoder/search.cpp Mon Apr 06 15:39:07 2015 +0530
> @@ -1185,7 +1185,7 @@
> intraMode.psyEnergy = m_rdCost.psyCost(cuGeom.log2CUSize - 2,
> fencYuv->m_buf[0], fencYuv->m_size, intraMode.reconYuv.m_buf[0],
> intraMode.reconYuv.m_size);
> }
> updateModeCost(intraMode);
> - checkDQP(cu, cuGeom);
> + checkDQP(intraMode, cuGeom);
> }
>
> /* Note that this function does not save the best intra prediction, it
> must
> @@ -1400,7 +1400,7 @@
>
> m_entropyCoder.store(intraMode.contexts);
> updateModeCost(intraMode);
> - checkDQP(intraMode.cu, cuGeom);
> + checkDQP(intraMode, cuGeom);
> }
>
> uint32_t Search::estIntraPredQT(Mode &intraMode, const CUGeom& cuGeom,
> const uint32_t depthRange[2], uint8_t* sharedModes)
> @@ -2620,7 +2620,7 @@
> interMode.coeffBits = coeffBits;
> interMode.mvBits = bits - coeffBits;
> updateModeCost(interMode);
> - checkDQP(interMode.cu, cuGeom);
> + checkDQP(interMode, cuGeom);
> }
>
> void Search::residualTransformQuantInter(Mode& mode, const CUGeom&
> cuGeom, uint32_t absPartIdx, uint32_t tuDepth, const uint32_t depthRange[2])
> @@ -3437,22 +3437,29 @@
> }
> }
>
> -void Search::checkDQP(CUData& cu, const CUGeom& cuGeom)
> +void Search::checkDQP(Mode& mode, const CUGeom& cuGeom)
> {
> + CUData& cu = mode.cu;
> if (cu.m_slice->m_pps->bUseDQP && cuGeom.depth <=
> cu.m_slice->m_pps->maxCuDQPDepth)
> {
> if (cu.getQtRootCbf(0))
> {
> - /* When analysing RDO with DQP bits, the entropy encoder
> should add the cost of DQP bits here
> - * i.e Encode QP */
> + mode.contexts.resetBits();
> + mode.contexts.codeDeltaQP(cu, 0);
> + uint32_t bits = mode.contexts.getNumberOfWrittenBits();
> + mode.mvBits += bits;
> + mode.totalBits += bits;
> + updateModeCost(mode);
> }
> else
> cu.setQPSubParts(cu.getRefQP(0), 0, cuGeom.depth);
> }
> }
>
> -void Search::checkDQPForSplitPred(CUData& cu, const CUGeom& cuGeom)
> +void Search::checkDQPForSplitPred(Mode& mode, const CUGeom& cuGeom)
> {
> + CUData& cu = mode.cu;
> +
> if ((cuGeom.depth == cu.m_slice->m_pps->maxCuDQPDepth) &&
> cu.m_slice->m_pps->bUseDQP)
> {
> bool hasResidual = false;
> @@ -3467,10 +3474,17 @@
> }
> }
> if (hasResidual)
> - /* TODO: Encode QP, and recalculate RD cost of splitPred */
> + {
> + mode.contexts.resetBits();
> + mode.contexts.codeDeltaQP(cu, 0);
> + uint32_t bits = mode.contexts.getNumberOfWrittenBits();
> + mode.mvBits += bits;
> + mode.totalBits += bits;
> + updateModeCost(mode);
> /* For all zero CBF sub-CUs, reset QP to RefQP (so that
> deltaQP is not signalled).
> When the non-zero CBF sub-CU is found, stop */
> cu.setQPSubCUs(cu.getRefQP(0), 0, cuGeom.depth);
> + }
> else
> /* No residual within this CU or subCU, so reset QP to RefQP
> */
> cu.setQPSubParts(cu.getRefQP(0), 0, cuGeom.depth);
> diff -r 30e209c9bab6 -r 5e944fdd03bb source/encoder/search.h
> --- a/source/encoder/search.h Mon Mar 23 14:23:42 2015 +0530
> +++ b/source/encoder/search.h Mon Apr 06 15:39:07 2015 +0530
> @@ -316,8 +316,8 @@
> void getBestIntraModeChroma(Mode& intraMode, const CUGeom&
> cuGeom);
>
> /* update CBF flags and QP values to be internally consistent */
> - void checkDQP(CUData& cu, const CUGeom& cuGeom);
> - void checkDQPForSplitPred(CUData& cu, const CUGeom& cuGeom);
> + void checkDQP(Mode& mode, const CUGeom& cuGeom);
> + void checkDQPForSplitPred(Mode& mode, const CUGeom& cuGeom);
>
> class PME : public BondedTaskGroup
> {
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20150408/427f46c9/attachment-0001.html>
More information about the x265-devel
mailing list