changeset 11926:0f0d608e732b

analysis: use AVC CU analysis-info for HEVC mode analysis This patch work implements the functionality for anlysis-reuselevel 7, here we want to use AVC analysis-info for HEVC mode decision and use the depth from offload for AVC sizes
author Praveen Tiwari <praveen@multicorewareinc.com>
date Fri, 17 Nov 2017 19:23:14 +0530
parents 1f5586d03d85
children a7c2f80c18af
files source/common/cudata.cpp source/common/cudata.h source/common/framedata.h source/encoder/analysis.cpp source/encoder/analysis.h source/encoder/encoder.cpp source/x265.h
diffstat 7 files changed, 87 insertions(+-), 6 deletions(-) [+]
line wrap: on
line diff
--- a/source/common/cudata.cpp	Fri Nov 17 14:56:12 2017 +0530
+++ b/source/common/cudata.cpp	Fri Nov 17 19:23:14 2017 +0530
@@ -201,6 +201,8 @@ void CUData::initialize(const CUDataMemP
         m_cuDepth            = charBuf; charBuf += m_numPartitions;
         m_predMode           = charBuf; charBuf += m_numPartitions; /* the order up to here is important in initCTU() and initSubCU() */
         m_partSize           = charBuf; charBuf += m_numPartitions;
+        m_skipFlag[0]        = charBuf; charBuf += m_numPartitions;
+        m_skipFlag[1]        = charBuf; charBuf += m_numPartitions;
         m_mergeFlag          = charBuf; charBuf += m_numPartitions;
         m_interDir           = charBuf; charBuf += m_numPartitions;
         m_mvpIdx[0]          = charBuf; charBuf += m_numPartitions;
@@ -239,6 +241,8 @@ void CUData::initialize(const CUDataMemP
         m_cuDepth            = charBuf; charBuf += m_numPartitions;
         m_predMode           = charBuf; charBuf += m_numPartitions; /* the order up to here is important in initCTU() and initSubCU() */
         m_partSize           = charBuf; charBuf += m_numPartitions;
+        m_skipFlag[0]        = charBuf; charBuf += m_numPartitions;
+        m_skipFlag[1]        = charBuf; charBuf += m_numPartitions;
         m_mergeFlag          = charBuf; charBuf += m_numPartitions;
         m_interDir           = charBuf; charBuf += m_numPartitions;
         m_mvpIdx[0]          = charBuf; charBuf += m_numPartitions;
--- a/source/common/cudata.h	Fri Nov 17 14:56:12 2017 +0530
+++ b/source/common/cudata.h	Fri Nov 17 19:23:14 2017 +0530
@@ -199,13 +199,14 @@ public:
     uint8_t*      m_predMode;         // array of prediction modes
     uint8_t*      m_partSize;         // array of partition sizes
     uint8_t*      m_mergeFlag;        // array of merge flags
+    uint8_t*      m_skipFlag[2];
     uint8_t*      m_interDir;         // array of inter directions
     uint8_t*      m_mvpIdx[2];        // array of motion vector predictor candidates or merge candidate indices [0]
     uint8_t*      m_tuDepth;          // array of transform indices
     uint8_t*      m_transformSkip[3]; // array of transform skipping flags per plane
     uint8_t*      m_cbf[3];           // array of coded block flags (CBF) per plane
     uint8_t*      m_chromaIntraDir;   // array of intra directions (chroma)
-    enum { BytesPerPartition = 21 };  // combined sizeof() of all per-part data
+    enum { BytesPerPartition = 23 };  // combined sizeof() of all per-part data
 
     sse_t*        m_distortion;
     coeff_t*      m_trCoeff[3];       // transformed coefficient buffer per plane
--- a/source/common/framedata.h	Fri Nov 17 14:56:12 2017 +0530
+++ b/source/common/framedata.h	Fri Nov 17 19:23:14 2017 +0530
@@ -195,6 +195,7 @@ struct analysis_inter_data
     uint8_t*    mvpIdx[2];
     int8_t*     refIdx[2];
     MV*         mv[2];
+   int64_t*     sadCost;
 };
 
 struct analysis2PassFrameData
--- a/source/encoder/analysis.cpp	Fri Nov 17 14:56:12 2017 +0530
+++ b/source/encoder/analysis.cpp	Fri Nov 17 19:23:14 2017 +0530
@@ -75,6 +75,10 @@ Analysis::Analysis()
     m_reuseInterDataCTU = NULL;
     m_reuseRef = NULL;
     m_bHD = false;
+    m_modeFlag[0] = false;
+    m_modeFlag[1] = false;
+    m_checkMergeAndSkipOnly[0] = false;
+    m_checkMergeAndSkipOnly[1] = false;
     m_evaluateInter = 0;
 }
 
@@ -247,6 +251,9 @@ Mode& Analysis::compressCTU(CUData& ctu,
             memcpy(ctu.m_cuDepth, &interDataCTU->depth[posCTU], sizeof(uint8_t) * numPartition);
             memcpy(ctu.m_predMode, &interDataCTU->modes[posCTU], sizeof(uint8_t) * numPartition);
             memcpy(ctu.m_partSize, &interDataCTU->partSize[posCTU], sizeof(uint8_t) * numPartition);
+            for (int list = 0; list < m_slice->isInterB() + 1; list++)
+                memcpy(ctu.m_skipFlag[list], &m_frame->m_analysisData.modeFlag[list][posCTU], sizeof(uint8_t) * numPartition);
+
             if ((m_slice->m_sliceType == P_SLICE || m_param->bIntraInBFrames) && !m_param->bMVType)
             {
                 analysis_intra_data* intraDataCTU = (analysis_intra_data*)m_frame->m_analysisData.intraData;
@@ -1162,7 +1169,11 @@ SplitData Analysis::compressInterCU_rd0_
     PicYuv& reconPic = *m_frame->m_reconPic;
     SplitData splitCUData;
 
-    if ((m_param->bMVType && cuGeom.numPartitions > 16) || !m_param->bMVType)
+    bool bHEVCBlockAnalysis = (m_param->bMVType && cuGeom.numPartitions > 16);
+    bool bRefineAVCAnalysis = (m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1]));
+    bool bNooffloading = !m_param->bMVType;
+
+    if (bHEVCBlockAnalysis || bRefineAVCAnalysis || bNooffloading)
     {
         md.bestMode = NULL;
         bool mightSplit = !(cuGeom.flags & CUGeom::LEAF);
@@ -1296,7 +1307,7 @@ SplitData Analysis::compressInterCU_rd0_
         }
 
         /* Step 1. Evaluate Merge/Skip candidates for likely early-outs, if skip mode was not set above */
-        if (mightNotSplit && depth >= minDepth && !md.bestMode && !bCtuInfoCheck) /* TODO: Re-evaluate if analysis load/save still works */
+        if ((mightNotSplit && depth >= minDepth && !md.bestMode && !bCtuInfoCheck) || (m_param->bMVType && (m_modeFlag[0] || m_modeFlag[1]))) /* TODO: Re-evaluate if analysis load/save still works */
         {
             /* Compute Merge Cost */
             md.pred[PRED_MERGE].cu.initSubCU(parentCTU, cuGeom, qp);
@@ -1307,7 +1318,7 @@ SplitData Analysis::compressInterCU_rd0_
                 && md.bestMode && md.bestMode->cu.isSkipped(0); // TODO: sa8d threshold per depth
         }
 
-        if (md.bestMode && m_param->bEnableRecursionSkip && !bCtuInfoCheck)
+        if (md.bestMode && m_param->bEnableRecursionSkip && !bCtuInfoCheck && !(m_param->bMVType && (m_modeFlag[0] || m_modeFlag[1])))
         {
             skipRecursion = md.bestMode->cu.isSkipped(0);
             if (mightSplit && depth >= minDepth && !skipRecursion)
@@ -1319,6 +1330,9 @@ SplitData Analysis::compressInterCU_rd0_
             }
         }
 
+        if (m_param->bMVType && md.bestMode && cuGeom.numPartitions <= 16)
+            skipRecursion = true;
+
         /* Step 2. Evaluate each of the 4 split sub-blocks in series */
         if (mightSplit && !skipRecursion)
         {
@@ -1374,6 +1388,10 @@ SplitData Analysis::compressInterCU_rd0_
                 splitPred->sa8dCost = m_rdCost.calcRdSADCost((uint32_t)splitPred->distortion, splitPred->sa8dBits);
         }
 
+        /* If analysis mode is simple do not Evaluate other modes */
+        if ((m_param->bMVType && cuGeom.numPartitions <= 16) && (m_slice->m_sliceType == P_SLICE || m_slice->m_sliceType == B_SLICE))
+            mightNotSplit = !(m_checkMergeAndSkipOnly[0] || (m_checkMergeAndSkipOnly[0] && m_checkMergeAndSkipOnly[1]));
+
         /* Split CUs
          *   0  1
          *   2  3 */
@@ -1838,7 +1856,12 @@ SplitData Analysis::compressInterCU_rd5_
     }
 
     SplitData splitCUData;
-    if ((m_param->bMVType && cuGeom.numPartitions > 16) || !m_param->bMVType)
+
+    bool bHEVCBlockAnalysis = (m_param->bMVType && cuGeom.numPartitions > 16);
+    bool bRefineAVCAnalysis = (m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1]));
+    bool bNooffloading = !m_param->bMVType;
+
+    if (bHEVCBlockAnalysis || bRefineAVCAnalysis || bNooffloading)
     {
         bool mightSplit = !(cuGeom.flags & CUGeom::LEAF);
         bool mightNotSplit = !(cuGeom.flags & CUGeom::SPLIT_MANDATORY);
@@ -1977,7 +2000,7 @@ SplitData Analysis::compressInterCU_rd5_
         }
 
         /* Step 1. Evaluate Merge/Skip candidates for likely early-outs */
-        if (mightNotSplit && !md.bestMode && !bCtuInfoCheck)
+        if (mightNotSplit && !md.bestMode && !bCtuInfoCheck || (m_param->bMVType && (m_modeFlag[0] || m_modeFlag[1])))
         {
             md.pred[PRED_SKIP].cu.initSubCU(parentCTU, cuGeom, qp);
             md.pred[PRED_MERGE].cu.initSubCU(parentCTU, cuGeom, qp);
@@ -1993,6 +2016,9 @@ SplitData Analysis::compressInterCU_rd5_
                 skipRecursion = md.bestMode && !md.bestMode->cu.getQtRootCbf(0);
         }
 
+        if (m_param->bMVType && md.bestMode && cuGeom.numPartitions <= 16)
+            skipRecursion = true;
+
         // estimate split cost
         /* Step 2. Evaluate each of the 4 split sub-blocks in series */
         if (mightSplit && !skipRecursion)
@@ -2045,6 +2071,10 @@ SplitData Analysis::compressInterCU_rd5_
             checkDQPForSplitPred(*splitPred, cuGeom);
         }
 
+        /* If analysis mode is simple do not Evaluate other modes */
+        if ((m_param->bMVType && cuGeom.numPartitions <= 16) && (m_slice->m_sliceType == P_SLICE || m_slice->m_sliceType == B_SLICE))
+            mightNotSplit = !(m_checkMergeAndSkipOnly[0] || (m_checkMergeAndSkipOnly[0] && m_checkMergeAndSkipOnly[1]));
+
         /* Split CUs
          *   0  1
          *   2  3 */
@@ -2478,6 +2508,22 @@ void Analysis::recodeCU(const CUData& pa
                 checkDQPForSplitPred(*md.bestMode, cuGeom);
         }
 
+        if (m_param->bMVType && m_param->analysisReuseLevel == 7)
+        {
+            for (int list = 0; list < m_slice->isInterB() + 1; list++)
+            {
+                m_modeFlag[list] = true;
+                if (parentCTU.m_skipFlag[list][cuGeom.absPartIdx] == 1 && cuGeom.numPartitions <= 16)
+                    m_checkMergeAndSkipOnly[list] = true;
+            }
+            m_param->rdLevel > 4 ? compressInterCU_rd5_6(parentCTU, cuGeom, qp) : compressInterCU_rd0_4(parentCTU, cuGeom, qp);
+            for (int list = 0; list < m_slice->isInterB() + 1; list++)
+            {
+                m_modeFlag[list] = false;
+                m_checkMergeAndSkipOnly[list] = false;
+            }
+        }
+
         if (m_param->interRefine > 1 || (m_param->interRefine && parentCTU.m_predMode[cuGeom.absPartIdx] == MODE_SKIP  && !mode.cu.isSkipped(0)))
         {
             m_evaluateInter = 1;
--- a/source/encoder/analysis.h	Fri Nov 17 14:56:12 2017 +0530
+++ b/source/encoder/analysis.h	Fri Nov 17 19:23:14 2017 +0530
@@ -110,6 +110,9 @@ public:
     bool      m_bChromaSa8d;
     bool      m_bHD;
 
+    bool      m_modeFlag[2];
+    bool      m_checkMergeAndSkipOnly[2];
+
     Analysis();
 
     bool create(ThreadLocalData* tld);
--- a/source/encoder/encoder.cpp	Fri Nov 17 14:56:12 2017 +0530
+++ b/source/encoder/encoder.cpp	Fri Nov 17 19:23:14 2017 +0530
@@ -48,6 +48,12 @@ namespace X265_NS {
 const char g_sliceTypeToChar[] = {'B', 'P', 'I'};
 }
 
+/* Threshold for motion vection, based on expermental result.
+ * TODO: come up an algorithm for adoptive threshold */
+
+#define MVTHRESHOLD 10
+#define PU_2Nx2N 1
+
 static const char* defaultAnalysisFileName = "x265_analysis.dat";
 
 using namespace X265_NS;
@@ -565,6 +571,14 @@ int Encoder::setAnalysisDataAfterZScan(x
                             (interData)->mvpIdx[k][cuPos + cuOffset] = (srcInterData)->mvpIdx[k][(mbIndex * 16) + cuOffset];
                             (interData)->refIdx[k][cuPos + cuOffset] = (srcInterData)->refIdx[k][(mbIndex * 16) + cuOffset];
                             memcpy(&(interData)->mv[k][cuPos + cuOffset], &(srcInterData)->mv[k][(mbIndex * 16) + cuOffset], sizeof(MV));
+                            if (m_param->analysisReuseLevel == 7)
+                            {
+                                int mv_x = ((analysis_inter_data *)curFrame->m_analysisData.interData)->mv[k][(mbIndex * 16) + cuOffset].x;
+                                int mv_y = ((analysis_inter_data *)curFrame->m_analysisData.interData)->mv[k][(mbIndex * 16) + cuOffset].y;
+                                double mv = sqrt(mv_x*mv_x + mv_y*mv_y);
+                                if (numPU == PU_2Nx2N && ((srcInterData)->depth[cuPos + cuOffset] == (m_param->maxCUSize >> 5)) && mv <= MVTHRESHOLD)
+                                    memset(&curFrame->m_analysisData.modeFlag[k][cuPos + cuOffset], 1, bytes);
+                            }
                         }
                     }
                 }
@@ -624,6 +638,7 @@ int Encoder::setAnalysisData(x265_analys
                     int bytes = curFrame->m_analysisData.numPartitions >> ((interData)->depth[d] * 2);
                     memset(&(currInterData)->depth[count], (interData)->depth[d], bytes);
                     memset(&(currInterData)->modes[count], (interData)->modes[d], bytes);
+                    memcpy(&(currInterData)->sadCost[count], &((analysis_inter_data*)analysis_data->interData)->sadCost[d], bytes);
                     if (m_param->analysisReuseLevel > 4)
                     {
                         memset(&(currInterData)->partSize[count], (interData)->partSize[d], bytes);
@@ -639,6 +654,14 @@ int Encoder::setAnalysisData(x265_analys
                                     (currInterData)->mvpIdx[i][count + pu] = (interData)->mvpIdx[i][d];
                                     (currInterData)->refIdx[i][count + pu] = (interData)->refIdx[i][d];
                                     memcpy(&(currInterData)->mv[i][count + pu], &(interData)->mv[i][d], sizeof(MV));
+                                    if (m_param->analysisReuseLevel == 7)
+                                    {
+                                        int mv_x = ((analysis_inter_data *)curFrame->m_analysisData.interData)->mv[i][count + pu].x;
+                                        int mv_y = ((analysis_inter_data *)curFrame->m_analysisData.interData)->mv[i][count + pu].y;
+                                        double mv = sqrt(mv_x*mv_x + mv_y*mv_y);
+                                        if (numPU == PU_2Nx2N && m_param->num4x4Partitions <= 16 && mv <= MVTHRESHOLD)
+                                            memset(&curFrame->m_analysisData.modeFlag[i][count + pu], 1, bytes);
+                                    }
                                 }
                             }
                         }
@@ -3116,12 +3139,14 @@ void Encoder::freeAnalysis(x265_analysis
             if (m_param->analysisReuseLevel >= 7)
             {
                 X265_FREE(((analysis_inter_data*)analysis->interData)->interDir);
+                X265_FREE(((analysis_inter_data*)analysis->interData)->sadCost);
                 int numDir = analysis->sliceType == X265_TYPE_P ? 1 : 2;
                 for (int dir = 0; dir < numDir; dir++)
                 {
                     X265_FREE(((analysis_inter_data*)analysis->interData)->mvpIdx[dir]);
                     X265_FREE(((analysis_inter_data*)analysis->interData)->refIdx[dir]);
                     X265_FREE(((analysis_inter_data*)analysis->interData)->mv[dir]);
+                    X265_FREE(analysis->modeFlag[dir]);
                 }
             }
             else
--- a/source/x265.h	Fri Nov 17 14:56:12 2017 +0530
+++ b/source/x265.h	Fri Nov 17 19:23:14 2017 +0530
@@ -123,6 +123,7 @@ typedef struct x265_analysis_data
     void*            intraData;
     uint32_t         numCuInHeight;
     x265_lookahead_data lookahead;
+    uint8_t*         modeFlag[2];
 } x265_analysis_data;
 
 /* cu statistics */