<div dir="ltr">Great job on this feature, Kavitha!<br><div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Oct 27, 2015 at 11:21 AM,  <span dir="ltr"><<a href="mailto:kavitha@multicorewareinc.com" target="_blank">kavitha@multicorewareinc.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"># HG changeset patch<br>
# User Kavitha Sampath <<a href="mailto:kavitha@multicorewareinc.com" target="_blank">kavitha@multicorewareinc.com</a>><br>
# Date 1445612726 -19800<br>
#      Fri Oct 23 20:35:26 2015 +0530<br>
# Node ID 067f831bfc9a6c023cbf642e8c9742deff631ea5<br>
# Parent  8f08f346dd675a638df2ca8aa030b5be61ab06d7<br>
implement QP based RD refinement [CHANGES OUTPUT]<br>
<br>
After CU analysis, calculate R-D cost on the best partition mode<br>
for a range of QP values to find the optimal rounding effect.<br>
<br>
diff -r 8f08f346dd67 -r 067f831bfc9a source/common/cudata.cpp<br>
--- a/source/common/cudata.cpp  Fri Oct 23 19:32:21 2015 +0530<br>
+++ b/source/common/cudata.cpp  Fri Oct 23 20:35:26 2015 +0530<br>
@@ -430,7 +430,7 @@<br>
 }<br>
<br>
 /* The reverse of copyToPic, called only by encodeResidue */<br>
-void CUData::copyFromPic(const CUData& ctu, const CUGeom& cuGeom)<br>
+void CUData::copyFromPic(const CUData& ctu, const CUGeom& cuGeom, bool copyQp)<br>
 {<br>
     m_encData       = ctu.m_encData;<br>
     m_slice         = ctu.m_slice;<br>
@@ -441,7 +441,8 @@<br>
     m_numPartitions = cuGeom.numPartitions;<br>
<br>
     /* copy out all prediction info for this part */<br>
-    m_partCopy((uint8_t*)m_qp, (uint8_t*)ctu.m_qp + m_absIdxInCTU);<br>
+    if (copyQp) m_partCopy((uint8_t*)m_qp, (uint8_t*)ctu.m_qp + m_absIdxInCTU);<br>
+<br>
     m_partCopy(m_log2CUSize,   ctu.m_log2CUSize + m_absIdxInCTU);<br>
     m_partCopy(m_lumaIntraDir, ctu.m_lumaIntraDir + m_absIdxInCTU);<br>
     m_partCopy(m_tqBypass,     ctu.m_tqBypass + m_absIdxInCTU);<br>
diff -r 8f08f346dd67 -r 067f831bfc9a source/common/cudata.h<br>
--- a/source/common/cudata.h    Fri Oct 23 19:32:21 2015 +0530<br>
+++ b/source/common/cudata.h    Fri Oct 23 20:35:26 2015 +0530<br>
@@ -222,7 +222,7 @@<br>
     void     copyToPic(uint32_t depth) const;<br>
<br>
     /* RD-0 methods called only from encodeResidue */<br>
-    void     copyFromPic(const CUData& ctu, const CUGeom& cuGeom);<br>
+    void     copyFromPic(const CUData& ctu, const CUGeom& cuGeom, bool copyQp = true);<br>
     void     updatePic(uint32_t depth) const;<br>
<br>
     void     setPartSizeSubParts(PartSize size)    { m_partSet(m_partSize, (uint8_t)size); }<br>
diff -r 8f08f346dd67 -r 067f831bfc9a source/encoder/analysis.cpp<br>
--- a/source/encoder/analysis.cpp       Fri Oct 23 19:32:21 2015 +0530<br>
+++ b/source/encoder/analysis.cpp       Fri Oct 23 20:35:26 2015 +0530<br>
@@ -201,6 +201,9 @@<br>
         }<br>
     }<br>
<br>
+    if (m_param->bEnableRdRefine)<br>
+        qpRdRefine(ctu, cuGeom);<br>
+<br>
     return *m_modeDepth[0].bestMode;<br>
 }<br>
<br>
@@ -229,6 +232,53 @@<br>
     }<br>
 }<br>
<br>
+void Analysis::qpRdRefine(const CUData& parentCTU, const CUGeom& cuGeom)<br>
+{<br>
+    uint64_t origCost, bestCost, cost, prevCost;<br>
+    int failure, nQP, lambdaQP;<br>
+    double bestQp, origQP;<br>
+    bestQp = origQP = m_frame->m_encData->m_cuStat[parentCTU.m_cuAddr].baseQp;<br>
+    bestCost = origCost = m_modeDepth[0].bestMode->rdCost;<br>
+    lambdaQP = calculateQpforCuSize(parentCTU, cuGeom);<br>
+<br>
+    for (int16_t dir = 1; dir >= -1; dir -= 2)<br>
+    {<br>
+        int threshold = !!m_param->psyRd;<br>
+<br>
+        failure = 0;<br>
+        prevCost = origCost;<br>
+        double modQP = origQP + dir;<br>
+<br>
+        while (modQP >= QP_MIN && modQP <= QP_MAX_SPEC)<br>
+        {<br>
+             /* set modified QP for quant, maintain constant lambda for all QPs<br>
+              * use lambda of QP used for CU analysis for cost calculation */<br>
+             nQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, cuGeom, modQP), lambdaQP);<br>
+<br>
+            recodeCU(parentCTU, cuGeom, nQP, modQP);<br>
+            cost = m_modeDepth[0].bestMode->rdCost;<br>
+            COPY2_IF_LT(bestCost, cost, bestQp, modQP);<br>
+<br>
+            if (cost < prevCost)<br>
+                failure = 0;<br>
+            else<br>
+                failure++;<br>
+<br>
+            if (failure > threshold)<br>
+                break;<br>
+<br>
+            prevCost = cost;<br>
+            modQP += dir;<br>
+       }<br>
+    }<br>
+<br>
+    /* TODO: Try last CU's QP to decide the bestQP before re-encode */<br>
+<br>
+    /* Re-encode CU for best chosen QP */<br>
+    nQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, cuGeom, bestQp));<br>
+    recodeCU(parentCTU, cuGeom, nQP, bestQp);<br>
+}<br>
+<br>
 void Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp)<br>
 {<br>
     uint32_t depth = cuGeom.depth;<br>
@@ -1422,6 +1472,110 @@<br>
     return refMask;<br>
 }<br>
<br>
+void Analysis::recodeCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, double modQP)<br>
+{<br>
+    uint32_t depth = cuGeom.depth;<br>
+    ModeDepth& md = m_modeDepth[depth];<br>
+    md.bestMode = NULL;<br>
+<br>
+    bool mightSplit = !(cuGeom.flags & CUGeom::LEAF);<br>
+    bool mightNotSplit = !(cuGeom.flags & CUGeom::SPLIT_MANDATORY);<br>
+    bool bDecidedDepth = parentCTU.m_cuDepth[cuGeom.absPartIdx] == depth;<br>
+<br>
+    if (bDecidedDepth)<br>
+    {<br>
+        Mode& mode = md.pred[0];<br>
+        md.bestMode = &mode;<br>
+        mode.cu.initSubCU(parentCTU, cuGeom, qp);<br>
+        PartSize size = (PartSize)parentCTU.m_partSize[cuGeom.absPartIdx];<br>
+        if (parentCTU.isIntra(cuGeom.absPartIdx))<br>
+        {<br>
+            memcpy(mode.cu.m_lumaIntraDir, parentCTU.m_lumaIntraDir + cuGeom.absPartIdx, cuGeom.numPartitions);<br>
+            memcpy(mode.cu.m_chromaIntraDir, parentCTU.m_chromaIntraDir + cuGeom.absPartIdx, cuGeom.numPartitions);<br>
+            checkIntra(mode, cuGeom, size);<br>
+        }<br>
+        else<br>
+        {<br>
+            mode.cu.copyFromPic(parentCTU, cuGeom, false);<br>
+            for (int part = 0; part < (int)parentCTU.getNumPartInter(cuGeom.absPartIdx); part++)<br>
+            {<br>
+                PredictionUnit pu(<a href="http://mode.cu" rel="noreferrer" target="_blank">mode.cu</a>, cuGeom, part);<br>
+                motionCompensation(<a href="http://mode.cu" rel="noreferrer" target="_blank">mode.cu</a>, pu, mode.predYuv, true, true);<br>
+            }<br>
+<br>
+            if (parentCTU.isSkipped(cuGeom.absPartIdx))<br>
+                encodeResAndCalcRdSkipCU(mode);<br>
+            else<br>
+                encodeResAndCalcRdInterCU(mode, cuGeom);<br>
+<br></blockquote><div><br>Since the first pass decided parentCTU as CBF=0, we're now not giving it an opportunity to convert to CBF=1. Lets try removing the if-else and allow encodeResAndCalcRdInterCU unconditionally?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+            /* checkMerge2Nx2N function performs checkDQP after encoding residual, do the same */<br>
+            bool mergeInter2Nx2N = size == SIZE_2Nx2N && parentCTU.m_mergeFlag[cuGeom.absPartIdx];<br>
+            if (parentCTU.isSkipped(cuGeom.absPartIdx) || mergeInter2Nx2N)<br>
+                checkDQP(mode, cuGeom);<br>
+        }<br>
+<br>
+        if (m_bTryLossless)<br>
+            tryLossless(cuGeom);<br>
+<br>
+        if (mightSplit)<br>
+            addSplitFlagCost(*md.bestMode, cuGeom.depth);<br>
+    }<br>
+    else<br>
+    {<br>
+        Mode* splitPred = &md.pred[PRED_SPLIT];<br>
+        md.bestMode = splitPred;<br>
+        splitPred->initCosts();<br>
+        CUData* splitCU = &splitPred->cu;<br>
+        splitCU->initSubCU(parentCTU, cuGeom, qp);<br>
+<br>
+        uint32_t nextDepth = depth + 1;<br>
+        ModeDepth& nd = m_modeDepth[nextDepth];<br>
+        invalidateContexts(nextDepth);<br>
+        Entropy* nextContext = &m_rqt[depth].cur;<br>
+        int nextQP = qp;<br>
+<br>
+        for (uint32_t subPartIdx = 0; subPartIdx < 4; subPartIdx++)<br>
+        {<br>
+            const CUGeom& childGeom = *(&cuGeom + cuGeom.childOffset + subPartIdx);<br>
+            if (childGeom.flags & CUGeom::PRESENT)<br>
+            {<br>
+                m_modeDepth[0].fencYuv.copyPartToYuv(nd.fencYuv, childGeom.absPartIdx);<br>
+                m_rqt[nextDepth].cur.load(*nextContext);<br>
+<br>
+                if (m_slice->m_pps->bUseDQP && nextDepth <= m_slice->m_pps->maxCuDQPDepth)<br>
+                {<br>
+                    int constLambdaQp = calculateQpforCuSize(parentCTU, childGeom);<br>
+                    nextQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, childGeom, modQP), constLambdaQp);<br>
+                }<br>
+                recodeCU(parentCTU, childGeom, nextQP, modQP);<br>
+<br>
+                // Save best CU and pred data for this sub CU<br>
+                splitCU->copyPartFrom(nd.bestMode->cu, childGeom, subPartIdx);<br>
+                splitPred->addSubCosts(*nd.bestMode);<br>
+                nd.bestMode->reconYuv.copyToPartYuv(splitPred->reconYuv, childGeom.numPartitions * subPartIdx);<br>
+                nextContext = &nd.bestMode->contexts;<br>
+            }<br>
+            else<br>
+            {<br>
+                splitCU->setEmptyPart(childGeom, subPartIdx);<br>
+                // Set depth of non-present CU to 0 to ensure that correct CU is fetched as reference to code deltaQP<br>
+                memset(parentCTU.m_cuDepth + childGeom.absPartIdx, 0, childGeom.numPartitions);<br>
+            }<br>
+        }<br>
+        nextContext->store(splitPred->contexts);<br>
+        if (mightNotSplit)<br>
+            addSplitFlagCost(*splitPred, cuGeom.depth);<br>
+        else<br>
+            updateModeCost(*splitPred);<br>
+<br>
+        checkDQPForSplitPred(*splitPred, cuGeom);<br>
+    }<br>
+<br>
+    /* Copy best data to encData CTU and recon */<br>
+    md.bestMode->cu.copyToPic(depth);<br>
+    md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic, parentCTU.m_cuAddr, cuGeom.absPartIdx);<br>
+}<br>
+<br>
 /* sets md.bestMode if a valid merge candidate is found, else leaves it NULL */<br>
 void Analysis::checkMerge2Nx2N_rd0_4(Mode& skip, Mode& merge, const CUGeom& cuGeom)<br>
 {<br>
diff -r 8f08f346dd67 -r 067f831bfc9a source/encoder/analysis.h<br>
--- a/source/encoder/analysis.h Fri Oct 23 19:32:21 2015 +0530<br>
+++ b/source/encoder/analysis.h Fri Oct 23 20:35:26 2015 +0530<br>
@@ -110,6 +110,9 @@<br>
<br>
     uint32_t m_splitRefIdx[4];<br>
<br>
+    /* refine RD based on QP for rd-levels 5 and 6 */<br>
+    void qpRdRefine(const CUData& ctu, const CUGeom& cuGeom);<br>
+<br>
     /* full analysis for an I-slice CU */<br>
     void compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp);<br>
<br>
@@ -118,6 +121,8 @@<br>
     uint32_t compressInterCU_rd0_4(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp);<br>
     uint32_t compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom& cuGeom, uint32_t &zOrder, int32_t qp);<br>
<br>
+    void recodeCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, double modQP);<br>
+<br>
     /* measure merge and skip */<br>
     void checkMerge2Nx2N_rd0_4(Mode& skip, Mode& merge, const CUGeom& cuGeom);<br>
     void checkMerge2Nx2N_rd5_6(Mode& skip, Mode& merge, const CUGeom& cuGeom, bool isShareMergeCand);<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br><br clear="all"><br>-- <br><div><div dir="ltr"><div><div>Deepthi Nandakumar<br></div>Engineering Manager, x265<br></div>Multicoreware, Inc<br></div></div>
</div></div></div>