[x265] [PATCH 01 of 10 RFC] analysis: re-order RD 5/6 analysis to do splits before ME or intra

Steve Borho steve at borho.org
Tue Mar 31 03:29:37 CEST 2015


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1426555173 18000
#      Mon Mar 16 20:19:33 2015 -0500
# Node ID af259ac3d304009043f95f72d6d5b7d1519a1838
# Parent  c4f7463e0b4e399445b3dfd718798c334c8849f9
analysis: re-order RD 5/6 analysis to do splits before ME or intra

This commit changes outputs because splits used to be avoided when an inter or
intra mode was chosen without residual coding. This recursion early-out is no
longer possible. Only merge without residual (aka skip) can abort recursion.

This commit changes the order of analysis such that the four split blocks are
analyzed prior to attempting any ME or intra modes. Future commits we will use
the knowledge learned during split analysis to avoid unlikely work at the
current depth (reducing motion references avoiding unlikely intra, rectangular,
asymmetric, and lossless modes)

diff -r c4f7463e0b4e -r af259ac3d304 source/encoder/analysis.cpp
--- a/source/encoder/analysis.cpp	Mon Mar 30 19:18:19 2015 -0500
+++ b/source/encoder/analysis.cpp	Mon Mar 16 20:19:33 2015 -0500
@@ -1058,103 +1058,19 @@
         }
     }
 
+    bool foundSkip = false;
+
+    /* Step 1. Evaluate Merge/Skip candidates for likely early-outs */
     if (mightNotSplit)
     {
         md.pred[PRED_SKIP].cu.initSubCU(parentCTU, cuGeom);
         md.pred[PRED_MERGE].cu.initSubCU(parentCTU, cuGeom);
         checkMerge2Nx2N_rd5_6(md.pred[PRED_SKIP], md.pred[PRED_MERGE], cuGeom, false);
-        bool earlySkip = m_param->bEnableEarlySkip && md.bestMode && !md.bestMode->cu.getQtRootCbf(0);
-
-        if (!earlySkip)
-        {
-            md.pred[PRED_2Nx2N].cu.initSubCU(parentCTU, cuGeom);
-            checkInter_rd5_6(md.pred[PRED_2Nx2N], cuGeom, SIZE_2Nx2N, false);
-            checkBestMode(md.pred[PRED_2Nx2N], cuGeom.depth);
-
-            if (m_slice->m_sliceType == B_SLICE)
-            {
-                md.pred[PRED_BIDIR].cu.initSubCU(parentCTU, cuGeom);
-                checkBidir2Nx2N(md.pred[PRED_2Nx2N], md.pred[PRED_BIDIR], cuGeom);
-                if (md.pred[PRED_BIDIR].sa8dCost < MAX_INT64)
-                {
-                    encodeResAndCalcRdInterCU(md.pred[PRED_BIDIR], cuGeom);
-                    checkBestMode(md.pred[PRED_BIDIR], cuGeom.depth);
-                }
-            }
-
-            if (m_param->bEnableRectInter)
-            {
-                md.pred[PRED_Nx2N].cu.initSubCU(parentCTU, cuGeom);
-                checkInter_rd5_6(md.pred[PRED_Nx2N], cuGeom, SIZE_Nx2N, false);
-                checkBestMode(md.pred[PRED_Nx2N], cuGeom.depth);
-
-                md.pred[PRED_2NxN].cu.initSubCU(parentCTU, cuGeom);
-                checkInter_rd5_6(md.pred[PRED_2NxN], cuGeom, SIZE_2NxN, false);
-                checkBestMode(md.pred[PRED_2NxN], cuGeom.depth);
-            }
-
-            // Try AMP (SIZE_2NxnU, SIZE_2NxnD, SIZE_nLx2N, SIZE_nRx2N)
-            if (m_slice->m_sps->maxAMPDepth > depth)
-            {
-                bool bMergeOnly = cuGeom.log2CUSize == 6;
-
-                bool bHor = false, bVer = false;
-                if (md.bestMode->cu.m_partSize[0] == SIZE_2NxN)
-                    bHor = true;
-                else if (md.bestMode->cu.m_partSize[0] == SIZE_Nx2N)
-                    bVer = true;
-                else if (md.bestMode->cu.m_partSize[0] == SIZE_2Nx2N && !md.bestMode->cu.m_mergeFlag[0])
-                {
-                    bHor = true;
-                    bVer = true;
-                }
-
-                if (bHor)
-                {
-                    md.pred[PRED_2NxnU].cu.initSubCU(parentCTU, cuGeom);
-                    checkInter_rd5_6(md.pred[PRED_2NxnU], cuGeom, SIZE_2NxnU, bMergeOnly);
-                    checkBestMode(md.pred[PRED_2NxnU], cuGeom.depth);
-
-                    md.pred[PRED_2NxnD].cu.initSubCU(parentCTU, cuGeom);
-                    checkInter_rd5_6(md.pred[PRED_2NxnD], cuGeom, SIZE_2NxnD, bMergeOnly);
-                    checkBestMode(md.pred[PRED_2NxnD], cuGeom.depth);
-                }
-                if (bVer)
-                {
-                    md.pred[PRED_nLx2N].cu.initSubCU(parentCTU, cuGeom);
-                    checkInter_rd5_6(md.pred[PRED_nLx2N], cuGeom, SIZE_nLx2N, bMergeOnly);
-                    checkBestMode(md.pred[PRED_nLx2N], cuGeom.depth);
-
-                    md.pred[PRED_nRx2N].cu.initSubCU(parentCTU, cuGeom);
-                    checkInter_rd5_6(md.pred[PRED_nRx2N], cuGeom, SIZE_nRx2N, bMergeOnly);
-                    checkBestMode(md.pred[PRED_nRx2N], cuGeom.depth);
-                }
-            }
-
-            if (m_slice->m_sliceType != B_SLICE || m_param->bIntraInBFrames)
-            {
-                md.pred[PRED_INTRA].cu.initSubCU(parentCTU, cuGeom);
-                checkIntra(md.pred[PRED_INTRA], cuGeom, SIZE_2Nx2N, NULL, NULL);
-                checkBestMode(md.pred[PRED_INTRA], depth);
-
-                if (cuGeom.log2CUSize == 3 && m_slice->m_sps->quadtreeTULog2MinSize < 3)
-                {
-                    md.pred[PRED_INTRA_NxN].cu.initSubCU(parentCTU, cuGeom);
-                    checkIntra(md.pred[PRED_INTRA_NxN], cuGeom, SIZE_NxN, NULL, NULL);
-                    checkBestMode(md.pred[PRED_INTRA_NxN], depth);
-                }
-            }
-        }
-
-        if (m_bTryLossless)
-            tryLossless(cuGeom);
-
-        if (mightSplit)
-            addSplitFlagCost(*md.bestMode, cuGeom.depth);
+        foundSkip = md.bestMode && !md.bestMode->cu.getQtRootCbf(0);
     }
 
-    // estimate split cost
-    if (mightSplit && (!md.bestMode || !md.bestMode->cu.isSkipped(0)))
+    /* Step 2. Evaluate each of the 4 split sub-blocks in series */
+    if (mightSplit && !foundSkip)
     {
         Mode* splitPred = &md.pred[PRED_SPLIT];
         splitPred->initCosts();
@@ -1187,20 +1103,112 @@
                 zOrder += g_depthInc[g_maxCUDepth - 1][nextDepth];
             }
         }
+
         nextContext->store(splitPred->contexts);
         if (mightNotSplit)
             addSplitFlagCost(*splitPred, cuGeom.depth);
         else
             updateModeCost(*splitPred);
+	    checkDQPForSplitPred(splitPred->cu, cuGeom);
+    }
 
-        checkDQPForSplitPred(splitPred->cu, cuGeom);
-        checkBestMode(*splitPred, depth);
+    /* Step 3. Evaluate ME (2Nx2N, rect, amp) and intra modes at current depth */
+    if (mightNotSplit && !(foundSkip && m_param->bEnableEarlySkip))
+    {
+        md.pred[PRED_2Nx2N].cu.initSubCU(parentCTU, cuGeom);
+        checkInter_rd5_6(md.pred[PRED_2Nx2N], cuGeom, SIZE_2Nx2N, false);
+        checkBestMode(md.pred[PRED_2Nx2N], cuGeom.depth);
+
+        if (m_slice->m_sliceType == B_SLICE)
+        {
+            md.pred[PRED_BIDIR].cu.initSubCU(parentCTU, cuGeom);
+            checkBidir2Nx2N(md.pred[PRED_2Nx2N], md.pred[PRED_BIDIR], cuGeom);
+
+            if (md.pred[PRED_BIDIR].sa8dCost < MAX_INT64)
+            {
+                encodeResAndCalcRdInterCU(md.pred[PRED_BIDIR], cuGeom);
+                checkBestMode(md.pred[PRED_BIDIR], cuGeom.depth);
+            }
+        }
+
+        if (m_param->bEnableRectInter)
+        {
+            md.pred[PRED_Nx2N].cu.initSubCU(parentCTU, cuGeom);
+            checkInter_rd5_6(md.pred[PRED_Nx2N], cuGeom, SIZE_Nx2N, false);
+            checkBestMode(md.pred[PRED_Nx2N], cuGeom.depth);
+
+            md.pred[PRED_2NxN].cu.initSubCU(parentCTU, cuGeom);
+            checkInter_rd5_6(md.pred[PRED_2NxN], cuGeom, SIZE_2NxN, false);
+            checkBestMode(md.pred[PRED_2NxN], cuGeom.depth);
+        }
+
+        if (m_slice->m_sps->maxAMPDepth > depth)
+        {
+            /* derive likely AMP modes based on current best mode */
+            bool bMergeOnly = cuGeom.log2CUSize == 6;
+
+            bool bHor = false, bVer = false;
+            if (md.bestMode->cu.m_partSize[0] == SIZE_2NxN)
+                bHor = true;
+            else if (md.bestMode->cu.m_partSize[0] == SIZE_Nx2N)
+                bVer = true;
+            else if (md.bestMode->cu.m_partSize[0] == SIZE_2Nx2N && !md.bestMode->cu.m_mergeFlag[0])
+            {
+                bHor = true;
+                bVer = true;
+            }
+
+            if (bHor)
+            {
+                md.pred[PRED_2NxnU].cu.initSubCU(parentCTU, cuGeom);
+                checkInter_rd5_6(md.pred[PRED_2NxnU], cuGeom, SIZE_2NxnU, bMergeOnly);
+                checkBestMode(md.pred[PRED_2NxnU], cuGeom.depth);
+
+                md.pred[PRED_2NxnD].cu.initSubCU(parentCTU, cuGeom);
+                checkInter_rd5_6(md.pred[PRED_2NxnD], cuGeom, SIZE_2NxnD, bMergeOnly);
+                checkBestMode(md.pred[PRED_2NxnD], cuGeom.depth);
+            }
+            if (bVer)
+            {
+                md.pred[PRED_nLx2N].cu.initSubCU(parentCTU, cuGeom);
+                checkInter_rd5_6(md.pred[PRED_nLx2N], cuGeom, SIZE_nLx2N, bMergeOnly);
+                checkBestMode(md.pred[PRED_nLx2N], cuGeom.depth);
+
+                md.pred[PRED_nRx2N].cu.initSubCU(parentCTU, cuGeom);
+                checkInter_rd5_6(md.pred[PRED_nRx2N], cuGeom, SIZE_nRx2N, bMergeOnly);
+                checkBestMode(md.pred[PRED_nRx2N], cuGeom.depth);
+            }
+        }
+
+        if (m_slice->m_sliceType != B_SLICE || m_param->bIntraInBFrames)
+        {
+            md.pred[PRED_INTRA].cu.initSubCU(parentCTU, cuGeom);
+            checkIntra(md.pred[PRED_INTRA], cuGeom, SIZE_2Nx2N, NULL, NULL);
+            checkBestMode(md.pred[PRED_INTRA], depth);
+
+            if (cuGeom.log2CUSize == 3 && m_slice->m_sps->quadtreeTULog2MinSize < 3)
+            {
+                md.pred[PRED_INTRA_NxN].cu.initSubCU(parentCTU, cuGeom);
+                checkIntra(md.pred[PRED_INTRA_NxN], cuGeom, SIZE_NxN, NULL, NULL);
+                checkBestMode(md.pred[PRED_INTRA_NxN], depth);
+            }
+        }
+
+        if (m_bTryLossless)
+            tryLossless(cuGeom);
+
+        if (mightSplit)
+            addSplitFlagCost(*md.bestMode, cuGeom.depth);
     }
 
+    /* compare split RD cost against best cost */
+    if (mightSplit && !foundSkip)
+        
+        checkBestMode(md.pred[PRED_SPLIT], depth);
+
     /* Copy best data to encData CTU and recon */
     md.bestMode->cu.copyToPic(depth);
-    if (md.bestMode != &md.pred[PRED_SPLIT])
-        md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic, parentCTU.m_cuAddr, cuGeom.absPartIdx);
+    md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic, parentCTU.m_cuAddr, cuGeom.absPartIdx);
 }
 
 /* sets md.bestMode if a valid merge candidate is found, else leaves it NULL */


More information about the x265-devel mailing list