[x265] [PATCH 4 of 4] implement QP based RD refinement for Intra slices [CHANGES OUTPUT]

kavitha at multicorewareinc.com kavitha at multicorewareinc.com
Wed Oct 14 08:35:48 CEST 2015


# HG changeset patch
# User Kavitha Sampath <kavitha at multicorewareinc.com>
# Date 1444801800 -19800
#      Wed Oct 14 11:20:00 2015 +0530
# Node ID 0c97c1dc969033237c5eaa8079604dab6b590070
# Parent  cab9ae709e7bdd5451b0d8d3ddfbdd201e802b8b
implement QP based RD refinement for Intra slices [CHANGES OUTPUT]

After CU analysis, calculate R-D cost on the best partition mode
for a range of QP values to find the optimal rounding effect.

diff -r cab9ae709e7b -r 0c97c1dc9690 source/encoder/analysis.cpp
--- a/source/encoder/analysis.cpp	Tue Oct 13 17:26:53 2015 +0530
+++ b/source/encoder/analysis.cpp	Wed Oct 14 11:20:00 2015 +0530
@@ -197,6 +197,9 @@
         }
     }
 
+    if (m_slice->m_sliceType == I_SLICE && m_param->bEnableRdRefine)
+        qpRdRefine(ctu, cuGeom);
+
     return *m_modeDepth[0].bestMode;
 }
 
@@ -225,7 +228,54 @@
     }
 }
 
-void Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp)
+void Analysis::qpRdRefine(const CUData& parentCTU, const CUGeom& cuGeom)
+{
+    uint64_t origCost, bestCost, cost, prevCost;
+    int failure, nQP, lambdaQP;
+    double bestQp, origQP;
+    bestQp = origQP = m_frame->m_encData->m_cuStat[parentCTU.m_cuAddr].baseQp;
+    bestCost = origCost = m_modeDepth[0].bestMode->rdCost;
+    lambdaQP = calculateQpforCuSize(parentCTU, cuGeom);
+
+    for (int16_t dir = 1; dir >= -1; dir -= 2)
+    {
+        int threshold = !!m_param->psyRd;
+
+        failure = 0;
+        prevCost = origCost;
+        double modQP = origQP + dir;
+
+        while (modQP >= QP_MIN && modQP <= QP_MAX_SPEC)
+        {
+             /* set modified QP for quant, maintain constant lambda for all QPs
+              * use lambda of QP used for CU analysis for cost calculation */
+             nQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, cuGeom, modQP), lambdaQP);
+
+            compressIntraCU(parentCTU, cuGeom, nQP, modQP);
+            cost = m_modeDepth[0].bestMode->rdCost;
+            COPY2_IF_LT(bestCost, cost, bestQp, modQP);
+
+            if (cost < prevCost)
+                failure = 0;
+            else
+                failure++;
+
+            if (failure > threshold)
+                break;
+
+            prevCost = cost;
+            modQP += dir;
+       }
+    }
+
+    /* TODO: Try last CU's QP to decide the bestQP before re-encode */
+
+    /* Re-encode CU for best chosen QP */
+    nQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, cuGeom, bestQp));
+    compressIntraCU(parentCTU, cuGeom, nQP, bestQp);
+}
+
+void Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, double modQp)
 {
     uint32_t depth = cuGeom.depth;
     ModeDepth& md = m_modeDepth[depth];
@@ -237,9 +287,6 @@
     bool bAlreadyDecided = parentCTU.m_lumaIntraDir[cuGeom.absPartIdx] != (uint8_t)ALL_IDX;
     bool bDecidedDepth = parentCTU.m_cuDepth[cuGeom.absPartIdx] == depth;
 
-    // stop recursion if we reach the depth of previous analysis decision
-    mightSplit &= !(bAlreadyDecided && bDecidedDepth);
-
     if (bAlreadyDecided)
     {
         if (bDecidedDepth)
@@ -278,6 +325,9 @@
             addSplitFlagCost(*md.bestMode, cuGeom.depth);
     }
 
+    // stop recursion if we reach the depth of previous analysis decision
+    mightSplit &= !(bAlreadyDecided && bDecidedDepth);
+
     if (mightSplit)
     {
         Mode* splitPred = &md.pred[PRED_SPLIT];
@@ -300,9 +350,11 @@
                 m_rqt[nextDepth].cur.load(*nextContext);
 
                 if (m_slice->m_pps->bUseDQP && nextDepth <= m_slice->m_pps->maxCuDQPDepth)
-                    nextQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, childGeom));
-
-                compressIntraCU(parentCTU, childGeom, nextQP);
+                {
+                    int constLambdaQp = bAlreadyDecided ? calculateQpforCuSize(parentCTU, childGeom) : -1;
+                    nextQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, childGeom, modQp), constLambdaQp);
+                }
+                compressIntraCU(parentCTU, childGeom, nextQP, modQp);
 
                 // Save best CU and pred data for this sub CU
                 splitCU->copyPartFrom(nd.bestMode->cu, childGeom, subPartIdx);
@@ -314,6 +366,10 @@
             {
                 /* record the depth of this non-present sub-CU */
                 splitCU->setEmptyPart(childGeom, subPartIdx);
+
+                /* Set depth of non-present CU to 0 to ensure that correct CU is fetched as reference to code deltaQP */
+                if (bAlreadyDecided)
+                    memset(parentCTU.m_cuDepth + childGeom.absPartIdx, 0, childGeom.numPartitions);
             }
         }
         nextContext->store(splitPred->contexts);
diff -r cab9ae709e7b -r 0c97c1dc9690 source/encoder/analysis.h
--- a/source/encoder/analysis.h	Tue Oct 13 17:26:53 2015 +0530
+++ b/source/encoder/analysis.h	Wed Oct 14 11:20:00 2015 +0530
@@ -110,8 +110,11 @@
 
     uint32_t m_splitRefIdx[4];
 
+    /* refine RD based on QP for rd-levels 5 and 6 */
+    void qpRdRefine(const CUData& ctu, const CUGeom& cuGeom);
+
     /* full analysis for an I-slice CU */
-    void compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp);
+    void compressIntraCU(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp, double modQp = 0);
 
     /* full analysis for a P or B slice CU */
     uint32_t compressInterCU_dist(const CUData& parentCTU, const CUGeom& cuGeom, int32_t qp);


More information about the x265-devel mailing list