[x265] [PATCH 1 of 3] De-couple analysis reuse levels of --analysis-save and --analysis-load

Aruna Matheswaran aruna at multicorewareinc.com
Mon Jan 13 10:08:37 CET 2020


# HG changeset patch
# User Aruna Matheswaran <aruna at multicorewareinc.com>
# Date 1578655868 -19800
#      Fri Jan 10 17:01:08 2020 +0530
# Node ID 396790ff1f9b71f4d6fe24156692ea35e4c36669
# Parent  4fcd8f1701a6dd7a502c4e48f04a27bb397664cf
De-couple analysis reuse levels of --analysis-save and --analysis-load.

Currently, analysis reuse level of the load encode has to be the same as that of
the reuse level of the save encode. This commit de-couples the reuse level
constraints and let the load encode re-use a subset of the available analysis
info.

Two CLI and x265_param options are introduced to get the desired reuse level
during save and load.

The existing option --analysis-reuse-level is deprecated.

diff -r 4fcd8f1701a6 -r 396790ff1f9b doc/reST/cli.rst
--- a/doc/reST/cli.rst	Fri Jan 10 14:16:04 2020 +0530
+++ b/doc/reST/cli.rst	Fri Jan 10 17:01:08 2020 +0530
@@ -918,12 +918,16 @@
 	Specify a filename for `multi-pass-opt-analysis` and `multi-pass-opt-distortion`.
 	If no filename is specified, x265_analysis.dat is used.
 
-.. option:: --analysis-reuse-level <1..10>
-
-	Amount of information stored/reused in :option:`--analysis-reuse-mode` is distributed across levels.
-	Higher the value, higher the information stored/reused, faster the encode. Default 5.
-
-	Note that --analysis-reuse-level must be paired with analysis-reuse-mode.
+.. option:: --analysis-save-reuse-level <1..10>, --analysis-load-reuse-level <1..10>
+
+	:option:`--analysis-save-reuse-level` denotes the amount of information stored during :option:`--analysis-save` and
+	:option:`--analysis-load-reuse-level` denotes the amount of information reused during :option:`--analysis-load`.
+	Higher the value, higher the information stored/reused, faster the encode. 
+	Default 0. If not set, the encoder will internally configure :option:`--analysis-save-reuse-level` and
+	:option:`--analysis-load-reuse-level` to 5.
+
+	Note that :option:`--analysis-save-reuse-level` and :option:`--analysis-load-reuse-level` must be paired
+	with :option:`--analysis-save` and :option:`--analysis-load` respectively.
 
 	+--------------+------------------------------------------+
 	| Level        | Description                              |
diff -r 4fcd8f1701a6 -r 396790ff1f9b source/CMakeLists.txt
--- a/source/CMakeLists.txt	Fri Jan 10 14:16:04 2020 +0530
+++ b/source/CMakeLists.txt	Fri Jan 10 17:01:08 2020 +0530
@@ -29,7 +29,7 @@
 option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
 mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 186)
+set(X265_BUILD 187)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r 4fcd8f1701a6 -r 396790ff1f9b source/common/param.cpp
--- a/source/common/param.cpp	Fri Jan 10 14:16:04 2020 +0530
+++ b/source/common/param.cpp	Fri Jan 10 17:01:08 2020 +0530
@@ -321,7 +321,9 @@
     param->bAQMotion = 0;
     param->bHDROpt = 0; /*DEPRECATED*/
     param->bHDR10Opt = 0;
-    param->analysisReuseLevel = 5;
+    param->analysisReuseLevel = 0;  /*DEPRECATED*/
+    param->analysisSaveReuseLevel = 0;
+    param->analysisLoadReuseLevel = 0;
     param->toneMapFile = NULL;
     param->bDhdr10opt = 0;
     param->dolbyProfile = 0;
@@ -1221,7 +1223,14 @@
         OPT("multi-pass-opt-distortion") p->analysisMultiPassDistortion = atobool(value);
         OPT("aq-motion") p->bAQMotion = atobool(value);
         OPT("dynamic-rd") p->dynamicRd = atof(value);
-        OPT("analysis-reuse-level") p->analysisReuseLevel = atoi(value);
+        OPT("analysis-reuse-level")
+        {
+            p->analysisReuseLevel = atoi(value);
+            p->analysisSaveReuseLevel = atoi(value);
+            p->analysisLoadReuseLevel = atoi(value);
+        }
+        OPT("analysis-save-reuse-level") p->analysisSaveReuseLevel = atoi(value);
+        OPT("analysis-load-reuse-level") p->analysisLoadReuseLevel = atoi(value);
         OPT("ssim-rd")
         {
             int bval = atobool(value);
@@ -1264,7 +1273,7 @@
             }
             else if (strcmp(strdup(value), "off") == 0)
             {
-                p->bAnalysisType = NO_INFO;
+                p->bAnalysisType = DEFAULT;
             }
             else
             {
@@ -1700,8 +1709,10 @@
           "Constant QP is incompatible with 2pass");
     CHECK(param->rc.bStrictCbr && (param->rc.bitrate <= 0 || param->rc.vbvBufferSize <=0),
           "Strict-cbr cannot be applied without specifying target bitrate or vbv bufsize");
-    CHECK((param->analysisSave || param->analysisLoad) && (param->analysisReuseLevel < 1 || param->analysisReuseLevel > 10),
-        "Invalid analysis refine level. Value must be between 1 and 10 (inclusive)");
+    CHECK(param->analysisSave && (param->analysisSaveReuseLevel < 0 || param->analysisSaveReuseLevel > 10),
+        "Invalid analysis save refine level. Value must be between 1 and 10 (inclusive)");
+    CHECK(param->analysisLoad && (param->analysisLoadReuseLevel < 0 || param->analysisLoadReuseLevel > 10),
+        "Invalid analysis load refine level. Value must be between 1 and 10 (inclusive)");
     CHECK(param->analysisLoad && (param->mvRefine < 1 || param->mvRefine > 3),
         "Invalid mv refinement level. Value must be between 1 and 3 (inclusive)");
     CHECK(param->scaleFactor > 2, "Invalid scale-factor. Supports factor <= 2");
@@ -2164,6 +2175,8 @@
     if (p->analysisLoad)
         s += sprintf(s, " analysis-load");
     s += sprintf(s, " analysis-reuse-level=%d", p->analysisReuseLevel);
+    s += sprintf(s, " analysis-save-reuse-level=%d", p->analysisSaveReuseLevel);
+    s += sprintf(s, " analysis-load-reuse-level=%d", p->analysisLoadReuseLevel);
     s += sprintf(s, " scale-factor=%d", p->scaleFactor);
     s += sprintf(s, " refine-intra=%d", p->intraRefine);
     s += sprintf(s, " refine-inter=%d", p->interRefine);
@@ -2482,6 +2495,8 @@
     dst->bHDROpt = src->bHDROpt; /*DEPRECATED*/
     dst->bHDR10Opt = src->bHDR10Opt;
     dst->analysisReuseLevel = src->analysisReuseLevel;
+    dst->analysisSaveReuseLevel = src->analysisSaveReuseLevel;
+    dst->analysisLoadReuseLevel = src->analysisLoadReuseLevel;
     dst->bLimitSAO = src->bLimitSAO;
     if (src->toneMapFile) dst->toneMapFile = strdup(src->toneMapFile);
     else dst->toneMapFile = NULL;
diff -r 4fcd8f1701a6 -r 396790ff1f9b source/encoder/analysis.cpp
--- a/source/encoder/analysis.cpp	Fri Jan 10 14:16:04 2020 +0530
+++ b/source/encoder/analysis.cpp	Fri Jan 10 17:01:08 2020 +0530
@@ -202,14 +202,17 @@
         m_reuseDepth = &m_reuseInterDataCTU->depth[ctu.m_cuAddr * ctu.m_numPartitions];
     }
     
-    if ((m_param->analysisSave || m_param->analysisLoad) && m_slice->m_sliceType != I_SLICE && m_param->analysisReuseLevel > 1 && m_param->analysisReuseLevel < 10)
+    int reuseLevel = X265_MAX(m_param->analysisSaveReuseLevel, m_param->analysisLoadReuseLevel);
+    if ((m_param->analysisSave || m_param->analysisLoad) && m_slice->m_sliceType != I_SLICE && reuseLevel > 1 && reuseLevel < 10)
     {
         int numPredDir = m_slice->isInterP() ? 1 : 2;
         m_reuseInterDataCTU = m_frame->m_analysisData.interData;
-        m_reuseRef = &m_reuseInterDataCTU->ref [ctu.m_cuAddr * X265_MAX_PRED_MODE_PER_CTU * numPredDir];
+        if (((m_param->analysisSaveReuseLevel > 1) && (m_param->analysisSaveReuseLevel < 7)) ||
+            ((m_param->analysisLoadReuseLevel > 1) && (m_param->analysisLoadReuseLevel < 7)))
+            m_reuseRef = &m_reuseInterDataCTU->ref[ctu.m_cuAddr * X265_MAX_PRED_MODE_PER_CTU * numPredDir];
         m_reuseDepth = &m_reuseInterDataCTU->depth[ctu.m_cuAddr * ctu.m_numPartitions];
         m_reuseModes = &m_reuseInterDataCTU->modes[ctu.m_cuAddr * ctu.m_numPartitions];
-        if (m_param->analysisReuseLevel > 4)
+        if (reuseLevel > 4)
         {
             m_reusePartSize = &m_reuseInterDataCTU->partSize[ctu.m_cuAddr * ctu.m_numPartitions];
             m_reuseMergeFlag = &m_reuseInterDataCTU->mergeFlag[ctu.m_cuAddr * ctu.m_numPartitions];
@@ -223,7 +226,7 @@
     if (m_slice->m_sliceType == I_SLICE)
     {
         x265_analysis_intra_data* intraDataCTU = m_frame->m_analysisData.intraData;
-        if (m_param->analysisLoad && m_param->analysisReuseLevel > 1)
+        if (m_param->analysisLoadReuseLevel > 1)
         {
             memcpy(ctu.m_cuDepth, &intraDataCTU->depth[ctu.m_cuAddr * numPartition], sizeof(uint8_t) * numPartition);
             memcpy(ctu.m_lumaIntraDir, &intraDataCTU->modes[ctu.m_cuAddr * numPartition], sizeof(uint8_t) * numPartition);
@@ -234,10 +237,10 @@
     }
     else
     {
-        bool bCopyAnalysis = ((m_param->analysisLoad && m_param->analysisReuseLevel == 10) || (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel >= 7 && ctu.m_numPartitions <= 16));
-        bool BCompressInterCUrd0_4 = (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel >= 7 && m_param->rdLevel <= 4);
-        bool BCompressInterCUrd5_6 = (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel >= 7 && m_param->rdLevel >= 5 && m_param->rdLevel <= 6);
-        bCopyAnalysis = bCopyAnalysis || BCompressInterCUrd0_4 || BCompressInterCUrd5_6;
+        bool bCopyAnalysis = ((m_param->analysisLoadReuseLevel == 10) || (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel >= 7 && ctu.m_numPartitions <= 16));
+        bool bCompressInterCUrd0_4 = (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel >= 7 && m_param->rdLevel <= 4);
+        bool bCompressInterCUrd5_6 = (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel >= 7 && m_param->rdLevel >= 5 && m_param->rdLevel <= 6);
+        bCopyAnalysis = bCopyAnalysis || bCompressInterCUrd0_4 || bCompressInterCUrd5_6;
 
         if (bCopyAnalysis)
         {
@@ -275,8 +278,8 @@
             /* generate residual for entire CTU at once and copy to reconPic */
             encodeResidue(ctu, cuGeom);
         }
-        else if ((m_param->analysisLoad && m_param->analysisReuseLevel == 10 && (!(m_param->bAnalysisType == HEVC_INFO) || m_slice->m_sliceType != P_SLICE)) ||
-                 ((m_param->bAnalysisType == AVC_INFO) && m_param->analysisReuseLevel >= 7 && ctu.m_numPartitions <= 16))
+        else if ((m_param->analysisLoadReuseLevel == 10 && (!(m_param->bAnalysisType == HEVC_INFO) || m_slice->m_sliceType != P_SLICE)) ||
+                ((m_param->bAnalysisType == AVC_INFO) && m_param->analysisLoadReuseLevel >= 7 && ctu.m_numPartitions <= 16))
         {
             x265_analysis_inter_data* interDataCTU = m_frame->m_analysisData.interData;
             int posCTU = ctu.m_cuAddr * numPartition;
@@ -456,7 +459,7 @@
     int bestCUQP = qp;
     int lambdaQP = lqp;
     bool doQPRefine = (bDecidedDepth && depth <= m_slice->m_pps->maxCuDQPDepth) || (!bDecidedDepth && depth == m_slice->m_pps->maxCuDQPDepth);
-    if (m_param->analysisReuseLevel >= 7)
+    if (m_param->analysisLoadReuseLevel >= 7)
         doQPRefine = false;
     if (doQPRefine)
     {
@@ -1164,7 +1167,7 @@
     SplitData splitCUData;
 
     bool bHEVCBlockAnalysis = (m_param->bAnalysisType == AVC_INFO && cuGeom.numPartitions > 16);
-    bool bRefineAVCAnalysis = (m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1]));
+    bool bRefineAVCAnalysis = (m_param->analysisLoadReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1]));
     bool bNooffloading = !(m_param->bAnalysisType == AVC_INFO);
 
     if (bHEVCBlockAnalysis || bRefineAVCAnalysis || bNooffloading)
@@ -1259,7 +1262,7 @@
                 mightSplit &= !bDecidedDepth;
             }
         }
-        if ((m_param->analysisLoad && m_param->analysisReuseLevel > 1 && m_param->analysisReuseLevel != 10))
+        if ((m_param->analysisLoadReuseLevel > 1 && m_param->analysisLoadReuseLevel != 10))
         {
             if (mightNotSplit && depth == m_reuseDepth[cuGeom.absPartIdx])
             {
@@ -1273,7 +1276,7 @@
                     if (m_param->rdLevel)
                         skipModes = m_param->bEnableEarlySkip && md.bestMode;
                 }
-                if (m_param->analysisReuseLevel > 4 && m_reusePartSize[cuGeom.absPartIdx] == SIZE_2Nx2N)
+                if (m_param->analysisLoadReuseLevel > 4 && m_reusePartSize[cuGeom.absPartIdx] == SIZE_2Nx2N)
                 {
                     if (m_reuseModes[cuGeom.absPartIdx] != MODE_INTRA  && m_reuseModes[cuGeom.absPartIdx] != 4)
                     {
@@ -1300,7 +1303,8 @@
             }
         }
         /* Step 1. Evaluate Merge/Skip candidates for likely early-outs, if skip mode was not set above */
-        if ((mightNotSplit && depth >= minDepth && !md.bestMode && !bCtuInfoCheck) || (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1]))) /* TODO: Re-evaluate if analysis load/save still works */
+        if ((mightNotSplit && depth >= minDepth && !md.bestMode && !bCtuInfoCheck) || (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel == 7 && (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);
@@ -1310,7 +1314,7 @@
                 skipModes = (m_param->bEnableEarlySkip || m_refineLevel == 2)
                 && md.bestMode && md.bestMode->cu.isSkipped(0); // TODO: sa8d threshold per depth
         }
-        if (md.bestMode && m_param->bEnableRecursionSkip && !bCtuInfoCheck && !(m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1])))
+        if (md.bestMode && m_param->bEnableRecursionSkip && !bCtuInfoCheck && !(m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1])))
         {
             skipRecursion = md.bestMode->cu.isSkipped(0);
             if (mightSplit && depth >= minDepth && !skipRecursion)
@@ -1321,7 +1325,7 @@
                     skipRecursion = complexityCheckCU(*md.bestMode);
             }
         }
-        if (m_param->bAnalysisType == AVC_INFO && md.bestMode && cuGeom.numPartitions <= 16 && m_param->analysisReuseLevel == 7)
+        if (m_param->bAnalysisType == AVC_INFO && md.bestMode && cuGeom.numPartitions <= 16 && m_param->analysisLoadReuseLevel == 7)
             skipRecursion = true;
         /* Step 2. Evaluate each of the 4 split sub-blocks in series */
         if (mightSplit && !skipRecursion)
@@ -1378,7 +1382,7 @@
                 splitPred->sa8dCost = m_rdCost.calcRdSADCost((uint32_t)splitPred->distortion, splitPred->sa8dBits);
         }
         /* If analysis mode is simple do not Evaluate other modes */
-        if (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel == 7)
+        if (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel == 7)
         {
             if (m_slice->m_sliceType == P_SLICE)
             {
@@ -1857,7 +1861,7 @@
     SplitData splitCUData;
 
     bool bHEVCBlockAnalysis = (m_param->bAnalysisType == AVC_INFO && cuGeom.numPartitions > 16);
-    bool bRefineAVCAnalysis = (m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1]));
+    bool bRefineAVCAnalysis = (m_param->analysisLoadReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1]));
     bool bNooffloading = !(m_param->bAnalysisType == AVC_INFO);
 
     if (bHEVCBlockAnalysis || bRefineAVCAnalysis || bNooffloading)
@@ -1953,7 +1957,7 @@
                 mightSplit &= !bDecidedDepth;
             }
         }
-        if (m_param->analysisLoad && m_param->analysisReuseLevel > 1 && m_param->analysisReuseLevel != 10)
+        if (m_param->analysisLoadReuseLevel > 1 && m_param->analysisLoadReuseLevel != 10)
         {
             if (mightNotSplit && depth == m_reuseDepth[cuGeom.absPartIdx])
             {
@@ -1971,7 +1975,7 @@
                     if (m_param->bEnableRecursionSkip && depth && m_modeDepth[depth - 1].bestMode)
                         skipRecursion = md.bestMode && !md.bestMode->cu.getQtRootCbf(0);
                 }
-                if (m_param->analysisReuseLevel > 4 && m_reusePartSize[cuGeom.absPartIdx] == SIZE_2Nx2N)
+                if (m_param->analysisLoadReuseLevel > 4 && m_reusePartSize[cuGeom.absPartIdx] == SIZE_2Nx2N)
                     skipRectAmp = true && !!md.bestMode;
             }
         }
@@ -1999,7 +2003,7 @@
         }
         /* Step 1. Evaluate Merge/Skip candidates for likely early-outs */
         if ((mightNotSplit && !md.bestMode && !bCtuInfoCheck) ||
-            (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1])))
+            (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel == 7 && (m_modeFlag[0] || m_modeFlag[1])))
         {
             md.pred[PRED_SKIP].cu.initSubCU(parentCTU, cuGeom, qp);
             md.pred[PRED_MERGE].cu.initSubCU(parentCTU, cuGeom, qp);
@@ -2014,7 +2018,7 @@
             if (m_param->bEnableRecursionSkip && depth && m_modeDepth[depth - 1].bestMode)
                 skipRecursion = md.bestMode && !md.bestMode->cu.getQtRootCbf(0);
         }
-        if (m_param->bAnalysisType == AVC_INFO && md.bestMode && cuGeom.numPartitions <= 16 && m_param->analysisReuseLevel == 7)
+        if (m_param->bAnalysisType == AVC_INFO && md.bestMode && cuGeom.numPartitions <= 16 && m_param->analysisLoadReuseLevel == 7)
             skipRecursion = true;
         // estimate split cost
         /* Step 2. Evaluate each of the 4 split sub-blocks in series */
@@ -2068,7 +2072,7 @@
             checkDQPForSplitPred(*splitPred, cuGeom);
         }
         /* If analysis mode is simple do not Evaluate other modes */
-        if (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel == 7)
+        if (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel == 7)
         {
             if (m_slice->m_sliceType == P_SLICE)
             {
@@ -2461,7 +2465,7 @@
             for (uint32_t part = 0; part < numPU; part++)
             {
                 PredictionUnit pu(mode.cu, cuGeom, part);
-                if ((m_param->analysisLoad && m_param->analysisReuseLevel == 10) || (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel >= 7))
+                if (m_param->analysisLoadReuseLevel == 10 || (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel >= 7))
                 {
                     x265_analysis_inter_data* interDataCTU = m_frame->m_analysisData.interData;
                     int cuIdx = (mode.cu.m_cuAddr * parentCTU.m_numPartitions) + cuGeom.absPartIdx;
@@ -2552,7 +2556,7 @@
                 checkDQPForSplitPred(*md.bestMode, cuGeom);
         }
 
-        if (m_param->bAnalysisType == AVC_INFO && m_param->analysisReuseLevel == 7)
+        if (m_param->bAnalysisType == AVC_INFO && m_param->analysisLoadReuseLevel == 7)
         {
             for (int list = 0; list < m_slice->isInterB() + 1; list++)
             {
@@ -2607,7 +2611,7 @@
                 if (m_slice->m_pps->bUseDQP && nextDepth <= m_slice->m_pps->maxCuDQPDepth)
                     nextQP = setLambdaFromQP(parentCTU, calculateQpforCuSize(parentCTU, childGeom));
 
-                int lamdaQP = (m_param->analysisReuseLevel >= 7) ? nextQP : lqp;
+                int lamdaQP = (m_param->analysisLoadReuseLevel >= 7) ? nextQP : lqp;
 
                 if (split)
                     m_param->rdLevel > 4 ? compressInterCU_rd5_6(parentCTU, childGeom, nextQP) : compressInterCU_rd0_4(parentCTU, childGeom, nextQP);
@@ -3013,7 +3017,7 @@
     interMode.cu.setPredModeSubParts(MODE_INTER);
     int numPredDir = m_slice->isInterP() ? 1 : 2;
 
-    if (m_param->analysisLoad && m_reuseInterDataCTU && m_param->analysisReuseLevel > 1 && m_param->analysisReuseLevel != 10)
+    if (m_param->analysisLoadReuseLevel > 1 && m_param->analysisLoadReuseLevel != 10 && m_reuseInterDataCTU)
     {
         int refOffset = cuGeom.geomRecurId * 16 * numPredDir + partSize * numPredDir * 2;
         int index = 0;
@@ -3056,7 +3060,7 @@
     }
     interMode.sa8dCost = m_rdCost.calcRdSADCost((uint32_t)interMode.distortion, interMode.sa8dBits);
 
-    if (m_param->analysisSave && m_reuseInterDataCTU && m_param->analysisReuseLevel > 1)
+    if (m_param->analysisSaveReuseLevel > 1 && m_reuseInterDataCTU)
     {
         int refOffset = cuGeom.geomRecurId * 16 * numPredDir + partSize * numPredDir * 2;
         int index = 0;
@@ -3078,7 +3082,7 @@
     interMode.cu.setPredModeSubParts(MODE_INTER);
     int numPredDir = m_slice->isInterP() ? 1 : 2;
 
-    if (m_param->analysisLoad && m_reuseInterDataCTU && m_param->analysisReuseLevel > 1 && m_param->analysisReuseLevel != 10)
+    if (m_param->analysisLoadReuseLevel > 1 && m_param->analysisLoadReuseLevel != 10 && m_reuseInterDataCTU)
     {
         int refOffset = cuGeom.geomRecurId * 16 * numPredDir + partSize * numPredDir * 2;
         int index = 0;
@@ -3113,7 +3117,7 @@
     /* predInterSearch sets interMode.sa8dBits, but this is ignored */
     encodeResAndCalcRdInterCU(interMode, cuGeom);
 
-    if (m_param->analysisSave && m_reuseInterDataCTU && m_param->analysisReuseLevel > 1)
+    if (m_param->analysisSaveReuseLevel > 1 && m_reuseInterDataCTU)
     {
         int refOffset = cuGeom.geomRecurId * 16 * numPredDir + partSize * numPredDir * 2;
         int index = 0;
@@ -3612,7 +3616,7 @@
             qp += distortionData->offset[ctu.m_cuAddr];
     }
 
-    if (m_param->analysisLoad && m_param->analysisReuseLevel == 10 && m_param->rc.cuTree)
+    if (m_param->analysisLoadReuseLevel == 10 && m_param->rc.cuTree)
     {
         int cuIdx = (ctu.m_cuAddr * ctu.m_numPartitions) + cuGeom.absPartIdx;
         if (ctu.m_slice->m_sliceType == I_SLICE)
diff -r 4fcd8f1701a6 -r 396790ff1f9b source/encoder/api.cpp
--- a/source/encoder/api.cpp	Fri Jan 10 14:16:04 2020 +0530
+++ b/source/encoder/api.cpp	Fri Jan 10 17:01:08 2020 +0530
@@ -771,6 +771,12 @@
     int numDir = 2; //irrespective of P or B slices set direction as 2
     uint32_t numPlanes = param->internalCsp == X265_CSP_I400 ? 1 : 3;
 
+    int maxReuseLevel = X265_MAX(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel);
+    int minReuseLevel = (param->analysisSaveReuseLevel && param->analysisLoadReuseLevel) ?
+                        X265_MIN(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel) : maxReuseLevel;
+
+    bool isMultiPassOpt = param->analysisMultiPassRefine || param->analysisMultiPassDistortion;
+                      
 #if X265_DEPTH < 10 && (LINKED_10BIT || LINKED_12BIT)
     uint32_t numCUs_sse_t = param->internalBitDepth > 8 ? analysis->numCUsInFrame << 1 : analysis->numCUsInFrame;
 #elif X265_DEPTH >= 10 && LINKED_8BIT
@@ -778,7 +784,7 @@
 #else
     uint32_t numCUs_sse_t = analysis->numCUsInFrame;
 #endif
-    if (param->analysisMultiPassRefine || param->analysisMultiPassDistortion || param->ctuDistortionRefine)
+    if (isMultiPassOpt || param->ctuDistortionRefine)
     {
         //Allocate memory for distortionData pointer
         CHECKED_MALLOC_ZERO(distortionData, x265_analysis_distortion_data, 1);
@@ -792,7 +798,7 @@
         analysis->distortionData = distortionData;
     }
 
-    if (param->bDisableLookahead && isVbv)
+    if (!isMultiPassOpt && param->bDisableLookahead && isVbv)
     {
         CHECKED_MALLOC_ZERO(analysis->lookahead.intraSatdForVbv, uint32_t, analysis->numCuInHeight);
         CHECKED_MALLOC_ZERO(analysis->lookahead.satdForVbv, uint32_t, analysis->numCuInHeight);
@@ -801,20 +807,23 @@
     }
 
     //Allocate memory for weightParam pointer
-    if (!(param->bAnalysisType == AVC_INFO))
+    if (!isMultiPassOpt && !(param->bAnalysisType == AVC_INFO))
         CHECKED_MALLOC_ZERO(analysis->wt, x265_weight_param, numPlanes * numDir);
 
-    if (param->analysisReuseLevel < 2)
+    if (maxReuseLevel < 2)
         return;
 
     //Allocate memory for intraData pointer
     CHECKED_MALLOC_ZERO(intraData, x265_analysis_intra_data, 1);
     CHECKED_MALLOC(intraData->depth, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
-    CHECKED_MALLOC_ZERO(intraData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
-    CHECKED_MALLOC_ZERO(intraData->partSizes, char, analysis->numPartitions * analysis->numCUsInFrame);
-    CHECKED_MALLOC_ZERO(intraData->chromaModes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
-    if (param->rc.cuTree)
-        CHECKED_MALLOC_ZERO(intraData->cuQPOff, int8_t, analysis->numPartitions * analysis->numCUsInFrame);
+    if (!isMultiPassOpt)
+    {
+        CHECKED_MALLOC_ZERO(intraData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
+        CHECKED_MALLOC_ZERO(intraData->partSizes, char, analysis->numPartitions * analysis->numCUsInFrame);
+        CHECKED_MALLOC_ZERO(intraData->chromaModes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
+        if (param->rc.cuTree)
+            CHECKED_MALLOC_ZERO(intraData->cuQPOff, int8_t, analysis->numPartitions * analysis->numCUsInFrame);
+    }
     analysis->intraData = intraData;
 
     //Allocate memory for interData pointer based on ReuseLevels
@@ -822,19 +831,19 @@
     CHECKED_MALLOC(interData->depth, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
     CHECKED_MALLOC_ZERO(interData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
 
-    if (param->rc.cuTree)
+    if (param->rc.cuTree && !isMultiPassOpt)
         CHECKED_MALLOC_ZERO(interData->cuQPOff, int8_t, analysis->numPartitions * analysis->numCUsInFrame);
     CHECKED_MALLOC_ZERO(interData->mvpIdx[0], uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
     CHECKED_MALLOC_ZERO(interData->mvpIdx[1], uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
     CHECKED_MALLOC_ZERO(interData->mv[0], x265_analysis_MV, analysis->numPartitions * analysis->numCUsInFrame);
     CHECKED_MALLOC_ZERO(interData->mv[1], x265_analysis_MV, analysis->numPartitions * analysis->numCUsInFrame);
 
-    if (param->analysisReuseLevel > 4)
+    if (maxReuseLevel > 4)
     {
         CHECKED_MALLOC_ZERO(interData->partSize, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
         CHECKED_MALLOC_ZERO(interData->mergeFlag, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
     }
-    if (param->analysisReuseLevel >= 7)
+    if (maxReuseLevel >= 7)
     {
         CHECKED_MALLOC_ZERO(interData->interDir, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
         CHECKED_MALLOC_ZERO(interData->sadCost, int64_t, analysis->numPartitions * analysis->numCUsInFrame);
@@ -844,14 +853,13 @@
             CHECKED_MALLOC_ZERO(analysis->modeFlag[dir], uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
         }
     }
-    else
+    if ((minReuseLevel >= 2) && (minReuseLevel <= 6))
     {
-        if (param->analysisMultiPassRefine || param->analysisMultiPassDistortion){
-            CHECKED_MALLOC_ZERO(interData->ref, int32_t, 2 * analysis->numPartitions * analysis->numCUsInFrame);
-        }
-        else
-            CHECKED_MALLOC_ZERO(interData->ref, int32_t, analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * numDir);
+        CHECKED_MALLOC_ZERO(interData->ref, int32_t, analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * numDir);
     }
+    if (isMultiPassOpt)
+        CHECKED_MALLOC_ZERO(interData->ref, int32_t, 2 * analysis->numPartitions * analysis->numCUsInFrame);
+
     analysis->interData = interData;
 
     return;
@@ -862,10 +870,15 @@
 
 void x265_free_analysis_data(x265_param *param, x265_analysis_data* analysis)
 {
+    int maxReuseLevel = X265_MAX(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel);
+    int minReuseLevel = (param->analysisSaveReuseLevel && param->analysisLoadReuseLevel) ?
+                        X265_MIN(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel) : maxReuseLevel;
+
     bool isVbv = param->rc.vbvMaxBitrate > 0 && param->rc.vbvBufferSize > 0;
+    bool isMultiPassOpt = param->analysisMultiPassRefine || param->analysisMultiPassDistortion;
 
     //Free memory for Lookahead pointers
-    if (param->bDisableLookahead && isVbv)
+    if (!isMultiPassOpt && param->bDisableLookahead && isVbv)
     {
         X265_FREE(analysis->lookahead.satdForVbv);
         X265_FREE(analysis->lookahead.intraSatdForVbv);
@@ -887,21 +900,24 @@
     }
 
     /* Early exit freeing weights alone if level is 1 (when there is no analysis inter/intra) */
-    if (analysis->wt && !(param->bAnalysisType == AVC_INFO))
+    if (!isMultiPassOpt && analysis->wt && !(param->bAnalysisType == AVC_INFO))
         X265_FREE(analysis->wt);
 
-    if (param->analysisReuseLevel < 2)
+    if (maxReuseLevel < 2)
         return;
 
     //Free memory for intraData pointers
     if (analysis->intraData)
     {
         X265_FREE((analysis->intraData)->depth);
-        X265_FREE((analysis->intraData)->modes);
-        X265_FREE((analysis->intraData)->partSizes);
-        X265_FREE((analysis->intraData)->chromaModes);
-        if (param->rc.cuTree)
-            X265_FREE((analysis->intraData)->cuQPOff);
+        if (!isMultiPassOpt)
+        {
+            X265_FREE((analysis->intraData)->modes);
+            X265_FREE((analysis->intraData)->partSizes);
+            X265_FREE((analysis->intraData)->chromaModes);
+            if (param->rc.cuTree)
+                X265_FREE((analysis->intraData)->cuQPOff);
+        }
         X265_FREE(analysis->intraData);
         analysis->intraData = NULL;
     }
@@ -911,19 +927,19 @@
     {
         X265_FREE((analysis->interData)->depth);
         X265_FREE((analysis->interData)->modes);
-        if (param->rc.cuTree)
+        if (!isMultiPassOpt && param->rc.cuTree)
             X265_FREE((analysis->interData)->cuQPOff);
         X265_FREE((analysis->interData)->mvpIdx[0]);
         X265_FREE((analysis->interData)->mvpIdx[1]);
         X265_FREE((analysis->interData)->mv[0]);
         X265_FREE((analysis->interData)->mv[1]);
 
-        if (param->analysisReuseLevel > 4)
+        if (maxReuseLevel > 4)
         {
             X265_FREE((analysis->interData)->mergeFlag);
             X265_FREE((analysis->interData)->partSize);
         }
-        if (param->analysisReuseLevel >= 7)
+        if (maxReuseLevel >= 7)
         {
             int numDir = 2;
             X265_FREE((analysis->interData)->interDir);
@@ -932,13 +948,13 @@
             {
                 X265_FREE((analysis->interData)->refIdx[dir]);
                 if (analysis->modeFlag[dir] != NULL)
-                {
+                { 
                     X265_FREE(analysis->modeFlag[dir]);
                     analysis->modeFlag[dir] = NULL;
                 }
             }
         }
-        else
+        if (((minReuseLevel >= 2) && (minReuseLevel <= 6)) || isMultiPassOpt)
             X265_FREE((analysis->interData)->ref);
         X265_FREE(analysis->interData);
         analysis->interData = NULL;
diff -r 4fcd8f1701a6 -r 396790ff1f9b source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Fri Jan 10 14:16:04 2020 +0530
+++ b/source/encoder/encoder.cpp	Fri Jan 10 17:01:08 2020 +0530
@@ -650,7 +650,7 @@
     if (analysis_data->sliceType == X265_TYPE_IDR || analysis_data->sliceType == X265_TYPE_I)
     {
         curFrame->m_analysisData.sliceType = X265_TYPE_I;
-        if (m_param->analysisReuseLevel < 7)
+        if (m_param->analysisLoadReuseLevel < 7)
             return -1;
         curFrame->m_analysisData.numPartitions = m_param->num4x4Partitions;
         int num16x16inCUWidth = m_param->maxCUSize >> 4;
@@ -680,7 +680,7 @@
     else
     {
         uint32_t numDir = analysis_data->sliceType == X265_TYPE_P ? 1 : 2;
-        if (m_param->analysisReuseLevel < 7)
+        if (m_param->analysisLoadReuseLevel < 7)
             return -1;
         curFrame->m_analysisData.numPartitions = m_param->num4x4Partitions;
         int num16x16inCUWidth = m_param->maxCUSize >> 4;
@@ -722,7 +722,7 @@
                             (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 && numPU == PU_2Nx2N &&
+                            if (m_param->analysisLoadReuseLevel == 7 && numPU == PU_2Nx2N &&
                                 ((interData)->depth[cuPos + cuOffset] == (m_param->maxCUSize >> 5)))
                             {
                                 int mv_x = (interData)->mv[k][cuPos + cuOffset].x;
@@ -756,7 +756,7 @@
             if (analysis_data->sliceType == X265_TYPE_IDR || analysis_data->sliceType == X265_TYPE_I)
             {
                 curFrame->m_analysisData.sliceType = X265_TYPE_I;
-                if (m_param->analysisReuseLevel < 2)
+                if (m_param->analysisLoadReuseLevel < 2)
                     return -1;
 
                 curFrame->m_analysisData.numPartitions = m_param->num4x4Partitions;
@@ -777,7 +777,7 @@
             else
             {
                 uint32_t numDir = analysis_data->sliceType == X265_TYPE_P ? 1 : 2;
-                if (m_param->analysisReuseLevel < 2)
+                if (m_param->analysisLoadReuseLevel < 2)
                     return -1;
 
                 curFrame->m_analysisData.numPartitions = m_param->num4x4Partitions;
@@ -790,7 +790,7 @@
                     memset(&(currInterData)->depth[count], (interData)->depth[d], bytes);
                     memset(&(currInterData)->modes[count], (interData)->modes[d], bytes);
                     memcpy(&(currInterData)->sadCost[count], &(analysis_data->interData)->sadCost[d], bytes);
-                    if (m_param->analysisReuseLevel > 4)
+                    if (m_param->analysisLoadReuseLevel > 4)
                     {
                         memset(&(currInterData)->partSize[count], (interData)->partSize[d], bytes);
                         int numPU = nbPartsTable[(interData)->partSize[d]];
@@ -798,7 +798,7 @@
                         {
                             if (pu) d++;
                             (currInterData)->mergeFlag[count + pu] = (interData)->mergeFlag[d];
-                            if (m_param->analysisReuseLevel >= 7)
+                            if (m_param->analysisLoadReuseLevel >= 7)
                             {
                                 (currInterData)->interDir[count + pu] = (interData)->interDir[d];
                                 for (uint32_t i = 0; i < numDir; i++)
@@ -806,7 +806,7 @@
                                     (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 && numPU == PU_2Nx2N && m_param->num4x4Partitions <= 16)
+                                    if (m_param->analysisLoadReuseLevel == 7 && numPU == PU_2Nx2N && m_param->num4x4Partitions <= 16)
                                     {
                                         int mv_x = (currInterData)->mv[i][count + pu].x;
                                         int mv_y = (currInterData)->mv[i][count + pu].y;
@@ -3577,10 +3577,38 @@
         p->rc.rfConstantMin = 0;
     }
 
-    if (!(p->bAnalysisType == HEVC_INFO) && (p->analysisLoad || p->analysisSave) && p->rc.cuTree && p->analysisReuseLevel < 10)
-    {
-        x265_log(p, X265_LOG_WARNING, "cu-tree works only with analysis reuse level 10, Disabling cu-tree\n");
-        p->rc.cuTree = 0;
+    if (p->analysisSaveReuseLevel && !p->analysisSave)
+    {
+        x265_log(p, X265_LOG_WARNING, "analysis-save-reuse-level can be set only when analysis-save is enabled."
+            " Resetting analysis-save-reuse-level to 0.\n");
+        p->analysisSaveReuseLevel = 0;
+    }
+
+    if (p->analysisLoadReuseLevel && !p->analysisLoad)
+    {
+        x265_log(p, X265_LOG_WARNING, "analysis-load-reuse-level can be set only when analysis-load is enabled."
+            " Resetting analysis-load-reuse-level to 0.\n");
+        p->analysisLoadReuseLevel = 0;
+    }
+
+    if (p->analysisSave && !p->analysisSaveReuseLevel)
+        p->analysisSaveReuseLevel = 5;
+
+    if (p->analysisLoad && !p->analysisLoadReuseLevel)
+        p->analysisLoadReuseLevel = 5;
+
+    if ((p->bAnalysisType == DEFAULT) && p->rc.cuTree)
+    {
+        if (p->analysisSaveReuseLevel && p->analysisSaveReuseLevel < 10)
+        {
+            x265_log(p, X265_LOG_WARNING, "cu-tree works only with analysis-save-reuse-level 10, Disabling cu-tree\n");
+            p->rc.cuTree = 0;
+        }
+        if (p->analysisLoadReuseLevel && p->analysisLoadReuseLevel < 10)
+        {
+            x265_log(p, X265_LOG_WARNING, "cu-tree works only with analysis-load-reuse-level 10, Disabling cu-tree\n");
+            p->rc.cuTree = 0;
+        }
     }
 
     if ((p->analysisLoad || p->analysisSave) && (p->bDistributeModeAnalysis || p->bDistributeMotionEstimation))
@@ -3602,45 +3630,37 @@
         {
             p->scaleFactor = 0;
         }
-        else if ((!p->analysisLoad && !p->analysisSave) || (p->analysisReuseLevel > 6 && p->analysisReuseLevel != 10))
+        else if ((p->analysisSaveReuseLevel > 6 && p->analysisSaveReuseLevel != 10) || (p->analysisLoadReuseLevel > 6 && p->analysisLoadReuseLevel != 10))
         {
-            x265_log(p, X265_LOG_WARNING, "Input scaling works with analysis load/save and analysis-reuse-level 1-6 and 10. Disabling scale-factor.\n");
+            x265_log(p, X265_LOG_WARNING, "Input scaling works with analysis-save/load and analysis-save/load-reuse-level 1-6 and 10. Disabling scale-factor.\n");
             p->scaleFactor = 0;
         }
     }
 
-    if (p->intraRefine)
-    {
-        if (!p->analysisLoad || p->analysisReuseLevel < 10)
-        {
-            x265_log(p, X265_LOG_WARNING, "Intra refinement requires analysis load, analysis-reuse-level 10. Disabling intra refine.\n");
-            p->intraRefine = 0;
-        }
-    }
-
-    if (p->interRefine)
-    {
-        if (!p->analysisLoad || p->analysisReuseLevel < 10)
-        {
-            x265_log(p, X265_LOG_WARNING, "Inter refinement requires analysis load, analysis-reuse-level 10. Disabling inter refine.\n");
-            p->interRefine = 0;
-        }
-    }
-
-    if (p->bDynamicRefine)
-    {
-        if (!p->analysisLoad || p->analysisReuseLevel < 10)
-        {
-            x265_log(p, X265_LOG_WARNING, "Dynamic refinement requires analysis load, analysis-reuse-level 10. Disabling dynamic refine.\n");
-            p->bDynamicRefine = 0;
-        }
+    if (p->intraRefine && p->analysisLoadReuseLevel && p->analysisLoadReuseLevel < 10)
+    {
+        x265_log(p, X265_LOG_WARNING, "Intra refinement requires analysis load, analysis-load-reuse-level 10. Disabling intra refine.\n");
+        p->intraRefine = 0;
+    }
+
+    if (p->interRefine && p->analysisLoadReuseLevel && p->analysisLoadReuseLevel < 10)
+    {
+        x265_log(p, X265_LOG_WARNING, "Inter refinement requires analysis load, analysis-load-reuse-level 10. Disabling inter refine.\n");
+        p->interRefine = 0;
+    }
+
+    if (p->bDynamicRefine && p->analysisLoadReuseLevel && p->analysisLoadReuseLevel < 10)
+    {
+        x265_log(p, X265_LOG_WARNING, "Dynamic refinement requires analysis load, analysis-load-reuse-level 10. Disabling dynamic refine.\n");
+        p->bDynamicRefine = 0;
+
         if (p->interRefine)
         {
             x265_log(p, X265_LOG_WARNING, "Inter refine cannot be used with dynamic refine. Disabling refine-inter.\n");
             p->interRefine = 0;
         }
     }
-    if (p->scaleFactor && p->analysisLoad && !p->interRefine && !p->bDynamicRefine && p->analysisReuseLevel == 10)
+    if (p->scaleFactor && !p->interRefine && !p->bDynamicRefine && p->analysisLoadReuseLevel == 10)
     {
         x265_log(p, X265_LOG_WARNING, "Inter refinement 0 is not supported with scaling and analysis-reuse-level=10. Enabling refine-inter 1.\n");
         p->interRefine = 1;
@@ -4205,7 +4225,7 @@
     {
         if (m_param->bAnalysisType == HEVC_INFO)
             return;
-        if (m_param->analysisReuseLevel < 2)
+        if (m_param->analysisLoadReuseLevel < 2)
             return;
 
         uint8_t *tempBuf = NULL, *depthBuf = NULL, *modeBuf = NULL, *partSizes = NULL;
@@ -4265,7 +4285,7 @@
         uint32_t numDir = analysis->sliceType == X265_TYPE_P ? 1 : 2;
         uint32_t numPlanes = m_param->internalCsp == X265_CSP_I400 ? 1 : 3;
         X265_FREAD((WeightParam*)analysis->wt, sizeof(WeightParam), numPlanes * numDir, m_analysisFileIn, (picIn->analysisData.wt));
-        if (m_param->analysisReuseLevel < 2)
+        if (m_param->analysisLoadReuseLevel < 2)
             return;
 
         uint8_t *tempBuf = NULL, *depthBuf = NULL, *modeBuf = NULL, *partSize = NULL, *mergeFlag = NULL;
@@ -4274,9 +4294,9 @@
         int8_t* refIdx[2];
         int8_t* cuQPBuf = NULL;
 
-        int numBuf = m_param->analysisReuseLevel > 4 ? 4 : 2;
+        int numBuf = m_param->analysisLoadReuseLevel > 4 ? 4 : 2;
         bool bIntraInInter = false;
-        if (m_param->analysisReuseLevel == 10)
+        if (m_param->analysisLoadReuseLevel == 10)
         {
             numBuf++;
             bIntraInInter = (analysis->sliceType == X265_TYPE_P || m_param->bIntraInBFrames);
@@ -4299,14 +4319,14 @@
             X265_FREAD(modeBuf, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->modes);
             if (m_param->rc.cuTree) { X265_FREAD(cuQPBuf, sizeof(int8_t), depthBytes, m_analysisFileIn, interPic->cuQPOff); }
 
-            if (m_param->analysisReuseLevel > 4)
+            if (m_param->analysisLoadReuseLevel > 4)
             {
                 partSize = modeBuf + depthBytes;
                 mergeFlag = partSize + depthBytes;
                 X265_FREAD(partSize, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->partSize);
                 X265_FREAD(mergeFlag, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->mergeFlag);
 
-                if (m_param->analysisReuseLevel == 10)
+                if (m_param->analysisLoadReuseLevel == 10)
                 {
                     interDir = mergeFlag + depthBytes;
                     X265_FREAD(interDir, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->interDir);
@@ -4337,7 +4357,7 @@
                 memset(&(analysis->interData)->modes[count], modeBuf[d], bytes);
                 if (m_param->rc.cuTree)
                     memset(&(analysis->interData)->cuQPOff[count], cuQPBuf[d], bytes);
-                if (m_param->analysisReuseLevel > 4)
+                if (m_param->analysisLoadReuseLevel > 4)
                 {
                     if (m_param->scaleFactor && modeBuf[d] == MODE_INTRA && partSize[d] == SIZE_NxN)
                         partSize[d] = SIZE_2Nx2N;
@@ -4347,7 +4367,7 @@
                     {
                         if (pu) d++;
                         (analysis->interData)->mergeFlag[count + pu] = mergeFlag[d];
-                        if (m_param->analysisReuseLevel == 10)
+                        if (m_param->analysisLoadReuseLevel == 10)
                         {
                             (analysis->interData)->interDir[count + pu] = interDir[d];
                             for (uint32_t i = 0; i < numDir; i++)
@@ -4363,7 +4383,7 @@
                             }
                         }
                     }
-                    if (m_param->analysisReuseLevel == 10 && bIntraInInter)
+                    if (m_param->analysisLoadReuseLevel == 10 && bIntraInInter)
                         memset(&(analysis->intraData)->chromaModes[count], chromaDir[d], bytes);
                 }
                 count += bytes;
@@ -4373,7 +4393,7 @@
                 X265_FREE(cuQPBuf);
             X265_FREE(tempBuf);
         }
-        if (m_param->analysisReuseLevel == 10)
+        if (m_param->analysisLoadReuseLevel == 10)
         {
             if (m_param->bAnalysisType != HEVC_INFO)
             {
@@ -4556,7 +4576,7 @@
 
     if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I)
     {
-        if (m_param->analysisReuseLevel < 2)
+        if (m_param->analysisLoadReuseLevel < 2)
             return;
 
         uint8_t *tempBuf = NULL, *depthBuf = NULL, *modeBuf = NULL, *partSizes = NULL;
@@ -4625,7 +4645,7 @@
         uint32_t numDir = analysis->sliceType == X265_TYPE_P ? 1 : 2;
         uint32_t numPlanes = m_param->internalCsp == X265_CSP_I400 ? 1 : 3;
         X265_FREAD((WeightParam*)analysis->wt, sizeof(WeightParam), numPlanes * numDir, m_analysisFileIn, (picIn->analysisData.wt));
-        if (m_param->analysisReuseLevel < 2)
+        if (m_param->analysisLoadReuseLevel < 2)
             return;
 
         uint8_t *tempBuf = NULL, *depthBuf = NULL, *modeBuf = NULL, *partSize = NULL, *mergeFlag = NULL;
@@ -4634,9 +4654,9 @@
         int8_t* refIdx[2];
         int8_t* cuQPBuf = NULL;
 
-        int numBuf = m_param->analysisReuseLevel > 4 ? 4 : 2;
+        int numBuf = m_param->analysisLoadReuseLevel > 4 ? 4 : 2;
         bool bIntraInInter = false;
-        if (m_param->analysisReuseLevel == 10)
+        if (m_param->analysisLoadReuseLevel == 10)
         {
             numBuf++;
             bIntraInInter = (analysis->sliceType == X265_TYPE_P || m_param->bIntraInBFrames);
@@ -4652,13 +4672,13 @@
         X265_FREAD(depthBuf, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->depth);
         X265_FREAD(modeBuf, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->modes);
         if (m_param->rc.cuTree) { X265_FREAD(cuQPBuf, sizeof(int8_t), depthBytes, m_analysisFileIn, interPic->cuQPOff); }
-        if (m_param->analysisReuseLevel > 4)
+        if (m_param->analysisLoadReuseLevel > 4)
         {
             partSize = modeBuf + depthBytes;
             mergeFlag = partSize + depthBytes;
             X265_FREAD(partSize, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->partSize);
             X265_FREAD(mergeFlag, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->mergeFlag);
-            if (m_param->analysisReuseLevel == 10)
+            if (m_param->analysisLoadReuseLevel == 10)
             {
                 interDir = mergeFlag + depthBytes;
                 X265_FREAD(interDir, sizeof(uint8_t), depthBytes, m_analysisFileIn, interPic->interDir);
@@ -4702,10 +4722,10 @@
                 memset(&(analysis->interData)->modes[count], modeBuf[d], bytes);
                 if (m_param->rc.cuTree)
                     memset(&(analysis->interData)->cuQPOff[count], cuQPBuf[d], bytes);
-                if (m_param->analysisReuseLevel == 10 && bIntraInInter)
+                if (m_param->analysisLoadReuseLevel == 10 && bIntraInInter)
                     memset(&(analysis->intraData)->chromaModes[count], chromaDir[d], bytes);
 
-                if (m_param->analysisReuseLevel > 4)
+                if (m_param->analysisLoadReuseLevel > 4)
                 {
                     puOrientation puOrient;
                     puOrient.init();
@@ -4731,7 +4751,7 @@
                             d++;
 
                         (analysis->interData)->mergeFlag[count + pu] = mergeFlag[d];
-                        if (m_param->analysisReuseLevel == 10)
+                        if (m_param->analysisLoadReuseLevel == 10)
                         {
                             (analysis->interData)->interDir[count + pu] = interDir[d];
                             MV mvCopy[2];
@@ -4766,7 +4786,7 @@
             X265_FREE(cuQPBuf);
         X265_FREE(tempBuf);
 
-        if (m_param->analysisReuseLevel == 10)
+        if (m_param->analysisLoadReuseLevel == 10)
         {
             for (uint32_t i = 0; i < numDir; i++)
             {
@@ -4855,7 +4875,6 @@
 
     X265_PARAM_VALIDATE(saveParam->intraRefresh, sizeof(int), 1, &m_param->bIntraRefresh, intra-refresh);
     X265_PARAM_VALIDATE(saveParam->maxNumReferences, sizeof(int), 1, &m_param->maxNumReferences, ref);
-    X265_PARAM_VALIDATE(saveParam->analysisReuseLevel, sizeof(int), 1, &m_param->analysisReuseLevel, analysis-reuse-level);
     X265_PARAM_VALIDATE(saveParam->keyframeMax, sizeof(int), 1, &m_param->keyframeMax, keyint);
     X265_PARAM_VALIDATE(saveParam->keyframeMin, sizeof(int), 1, &m_param->keyframeMin, min-keyint);
     X265_PARAM_VALIDATE(saveParam->openGOP, sizeof(int), 1, &m_param->bOpenGOP, open-gop);
@@ -4871,6 +4890,7 @@
     int sourceHeight, sourceWidth;
     if (writeFlag)
     {
+        X265_PARAM_VALIDATE(saveParam->analysisReuseLevel, sizeof(int), 1, &m_param->analysisSaveReuseLevel, analysis - save - reuse - level);
         sourceHeight = m_param->sourceHeight - m_conformanceWindow.bottomOffset;
         sourceWidth = m_param->sourceWidth - m_conformanceWindow.rightOffset;
         X265_PARAM_VALIDATE(saveParam->sourceWidth, sizeof(int), 1, &sourceWidth, res-width);
@@ -4880,10 +4900,35 @@
     else
     {
         fileOffset = m_analysisFileIn;
+
+        int saveLevel = 0;
+        bool isIncompatibleReuseLevel = false;
+        int loadLevel = m_param->analysisLoadReuseLevel;
+
+        X265_FREAD(&saveLevel, sizeof(int), 1, m_analysisFileIn, &(saveParam->analysisReuseLevel));
+        
+        if (loadLevel == 10 && saveLevel != 10)
+            isIncompatibleReuseLevel = true;
+        else if (((loadLevel >= 7) && (loadLevel <= 9)) && ((saveLevel < 7) || (saveLevel > 9)))
+            isIncompatibleReuseLevel = true;
+        else if ((loadLevel == 5 || loadLevel == 6) && ((saveLevel != 5) && (saveLevel != 6)))
+            isIncompatibleReuseLevel = true;
+        else if ((loadLevel >= 2 && loadLevel <= 4) && (saveLevel < 2 || saveLevel > 6))
+            isIncompatibleReuseLevel = true;
+        else if (!saveLevel)
+            isIncompatibleReuseLevel = true;
+
+        if (isIncompatibleReuseLevel)
+        {
+            x265_log(NULL, X265_LOG_ERROR, "Error reading analysis data. Incompatible reuse-levels.\n");
+            m_aborted = true;
+            return -1;
+        }
+
         bool error = false;
         int curSourceHeight = m_param->sourceHeight - m_conformanceWindow.bottomOffset;
         int curSourceWidth = m_param->sourceWidth - m_conformanceWindow.rightOffset;
-
+      
         X265_FREAD(&sourceWidth, sizeof(int), 1, m_analysisFileIn, &(saveParam->sourceWidth));
         X265_FREAD(&sourceHeight, sizeof(int), 1, m_analysisFileIn, &(saveParam->sourceHeight));
         X265_FREAD(&readValue, sizeof(int), 1, m_analysisFileIn, &(saveParam->maxCUSize));
@@ -5205,7 +5250,7 @@
         analysis->frameRecordSize += analysis->numCUsInFrame * sizeof(sse_t);
     }
 
-    if (m_param->analysisReuseLevel > 1)
+    if (m_param->analysisSaveReuseLevel > 1)
     {
 
         if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I)
@@ -5258,14 +5303,14 @@
                     interDataCTU->depth[depthBytes] = depth;
 
                     predMode = ctu->m_predMode[absPartIdx];
-                    if (m_param->analysisReuseLevel != 10 && ctu->m_refIdx[1][absPartIdx] != -1)
+                    if (m_param->analysisSaveReuseLevel != 10 && ctu->m_refIdx[1][absPartIdx] != -1)
                         predMode = 4; // used as indicator if the block is coded as bidir
 
                     interDataCTU->modes[depthBytes] = predMode;
                     if (m_param->rc.cuTree)
                         interDataCTU->cuQPOff[depthBytes] = (int8_t)(ctu->m_qpAnalysis[absPartIdx] - baseQP);
 
-                    if (m_param->analysisReuseLevel > 4)
+                    if (m_param->analysisSaveReuseLevel > 4)
                     {
                         partSize = ctu->m_partSize[absPartIdx];
                         interDataCTU->partSize[depthBytes] = partSize;
@@ -5278,7 +5323,7 @@
                             if (puIdx) depthBytes++;
                             interDataCTU->mergeFlag[depthBytes] = ctu->m_mergeFlag[puabsPartIdx];
 
-                            if (m_param->analysisReuseLevel == 10)
+                            if (m_param->analysisSaveReuseLevel == 10)
                             {
                                 interDataCTU->interDir[depthBytes] = ctu->m_interDir[puabsPartIdx];
                                 for (uint32_t dir = 0; dir < numDir; dir++)
@@ -5289,12 +5334,12 @@
                                 }
                             }
                         }
-                        if (m_param->analysisReuseLevel == 10 && bIntraInInter)
+                        if (m_param->analysisSaveReuseLevel == 10 && bIntraInInter)
                             intraDataCTU->chromaModes[depthBytes] = ctu->m_chromaIntraDir[absPartIdx];
                     }
                     absPartIdx += ctu->m_numPartitions >> (depth * 2);
                 }
-                if (m_param->analysisReuseLevel == 10 && bIntraInInter)
+                if (m_param->analysisSaveReuseLevel == 10 && bIntraInInter)
                     memcpy(&intraDataCTU->modes[ctu->m_cuAddr * ctu->m_numPartitions], ctu->m_lumaIntraDir, sizeof(uint8_t)* ctu->m_numPartitions);
             }
         }
@@ -5309,10 +5354,10 @@
             analysis->frameRecordSize += depthBytes * 2;
             if (m_param->rc.cuTree)
             analysis->frameRecordSize += (sizeof(int8_t) * depthBytes);
-            if (m_param->analysisReuseLevel > 4)
+            if (m_param->analysisSaveReuseLevel > 4)
                 analysis->frameRecordSize += (depthBytes * 2);
 
-            if (m_param->analysisReuseLevel == 10)
+            if (m_param->analysisSaveReuseLevel == 10)
             {
                 /* Add Size of interDir, mvpIdx, refIdx, mv, luma and chroma modes */
                 analysis->frameRecordSize += depthBytes;
@@ -5344,7 +5389,7 @@
     if (analysis->sliceType > X265_TYPE_I)
         X265_FWRITE((WeightParam*)analysis->wt, sizeof(WeightParam), numPlanes * numDir, m_analysisFileOut);
 
-    if (m_param->analysisReuseLevel < 2)
+    if (m_param->analysisSaveReuseLevel < 2)
         return;
 
     if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I)
@@ -5362,11 +5407,11 @@
         X265_FWRITE((analysis->interData)->modes, sizeof(uint8_t), depthBytes, m_analysisFileOut);
         if (m_param->rc.cuTree)
             X265_FWRITE((analysis->interData)->cuQPOff, sizeof(int8_t), depthBytes, m_analysisFileOut);
-        if (m_param->analysisReuseLevel > 4)
+        if (m_param->analysisSaveReuseLevel > 4)
         {
             X265_FWRITE((analysis->interData)->partSize, sizeof(uint8_t), depthBytes, m_analysisFileOut);
             X265_FWRITE((analysis->interData)->mergeFlag, sizeof(uint8_t), depthBytes, m_analysisFileOut);
-            if (m_param->analysisReuseLevel == 10)
+            if (m_param->analysisSaveReuseLevel == 10)
             {
                 X265_FWRITE((analysis->interData)->interDir, sizeof(uint8_t), depthBytes, m_analysisFileOut);
                 if (bIntraInInter) X265_FWRITE((analysis->intraData)->chromaModes, sizeof(uint8_t), depthBytes, m_analysisFileOut);
@@ -5380,7 +5425,7 @@
                     X265_FWRITE((analysis->intraData)->modes, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFileOut);
             }
         }
-        if (m_param->analysisReuseLevel != 10)
+        if (m_param->analysisSaveReuseLevel != 10)
             X265_FWRITE((analysis->interData)->ref, sizeof(int32_t), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * numDir, m_analysisFileOut);
 
     }
diff -r 4fcd8f1701a6 -r 396790ff1f9b source/encoder/search.cpp
--- a/source/encoder/search.cpp	Fri Jan 10 14:16:04 2020 +0530
+++ b/source/encoder/search.cpp	Fri Jan 10 17:01:08 2020 +0530
@@ -2208,7 +2208,7 @@
         x265_analysis_inter_data* interDataCTU = NULL;
         int cuIdx;
         cuIdx = (interMode.cu.m_cuAddr * m_param->num4x4Partitions) + cuGeom.absPartIdx;
-        if (m_param->analysisReuseLevel == 10 && m_param->interRefine > 1)
+        if (m_param->analysisLoadReuseLevel == 10 && m_param->interRefine > 1)
         {
             interDataCTU = m_frame->m_analysisData.interData;
             if ((cu.m_predMode[pu.puAbsPartIdx] == interDataCTU->modes[cuIdx + pu.puAbsPartIdx])
@@ -2227,7 +2227,7 @@
 
         cu.getNeighbourMV(puIdx, pu.puAbsPartIdx, interMode.interNeighbours);
         /* Uni-directional prediction */
-        if ((m_param->analysisLoad && m_param->analysisReuseLevel > 1 && m_param->analysisReuseLevel != 10)
+        if ((m_param->analysisLoadReuseLevel > 1 && m_param->analysisLoadReuseLevel != 10)
             || (m_param->analysisMultiPassRefine && m_param->rc.bStatRead) || (m_param->bAnalysisType == AVC_INFO) || (useAsMVP))
         {
             for (int list = 0; list < numPredDir; list++)
diff -r 4fcd8f1701a6 -r 396790ff1f9b source/x265.h
--- a/source/x265.h	Fri Jan 10 14:16:04 2020 +0530
+++ b/source/x265.h	Fri Jan 10 17:01:08 2020 +0530
@@ -320,7 +320,7 @@
 
 typedef enum
 {
-    NO_INFO = 0,
+    DEFAULT = 0,
     AVC_INFO = 1,
     HEVC_INFO = 2,
 }AnalysisRefineType;
@@ -1656,7 +1656,7 @@
 
     /* A value between 1 and 10 (both inclusive) determines the level of
     * information stored/reused in analysis save/load. Higher the refine
-    * level higher the information stored/reused. Default is 5 */
+    * level higher the information stored/reused. Default is 5. Now deprecated. */
     int       analysisReuseLevel;
 
      /* Limit Sample Adaptive Offset filter computation by early terminating SAO
@@ -1867,6 +1867,16 @@
     * Auto-enabled when max-cll, max-fall, or mastering display info is specified.
     * Default is disabled */
     int       bEmitHDR10SEI;
+
+    /* A value between 1 and 10 (both inclusive) determines the level of
+    * analysis information stored in analysis-save. Higher the refine level higher
+    * the information stored. Default is 5 */
+    int       analysisSaveReuseLevel;
+    
+    /* A value between 1 and 10 (both inclusive) determines the level of
+    * analysis information reused in analysis-load. Higher the refine level higher
+    * the information reused. Default is 5 */
+    int       analysisLoadReuseLevel;
 } x265_param;
 
 /* x265_param_alloc:
diff -r 4fcd8f1701a6 -r 396790ff1f9b source/x265cli.h
--- a/source/x265cli.h	Fri Jan 10 14:16:04 2020 +0530
+++ b/source/x265cli.h	Fri Jan 10 17:01:08 2020 +0530
@@ -275,7 +275,9 @@
     { "no-multi-pass-opt-rps", no_argument, NULL, 0 },
     { "analysis-reuse-mode", required_argument, NULL, 0 }, /* DEPRECATED */
     { "analysis-reuse-file", required_argument, NULL, 0 },
-    { "analysis-reuse-level", required_argument, NULL, 0 },
+    { "analysis-reuse-level", required_argument, NULL, 0 }, /* DEPRECATED */
+    { "analysis-save-reuse-level", required_argument, NULL, 0 },
+    { "analysis-load-reuse-level", required_argument, NULL, 0 },
     { "analysis-save",  required_argument, NULL, 0 },
     { "analysis-load",  required_argument, NULL, 0 },
     { "scale-factor",   required_argument, NULL, 0 },
@@ -553,7 +555,9 @@
     H0("   --analysis-save <filename>    Dump analysis info into the specified file. Default Disabled\n");
     H0("   --analysis-load <filename>    Load analysis buffers from the file specified. Default Disabled\n");
     H0("   --analysis-reuse-file <filename>    Specify file name used for either dumping or reading analysis data. Deault x265_analysis.dat\n");
-    H0("   --analysis-reuse-level <1..10>      Level of analysis reuse indicates amount of info stored/reused in save/load mode, 1:least..10:most. Default %d\n", param->analysisReuseLevel);
+    H0("   --analysis-reuse-level <1..10>      Level of analysis reuse indicates amount of info stored/reused in save/load mode, 1:least..10:most. Now deprecated. Default %d\n", param->analysisReuseLevel);
+    H0("   --analysis-save-reuse-level <1..10> Indicates the amount of analysis info stored in save mode, 1:least..10:most. Default %d\n", param->analysisSaveReuseLevel);
+    H0("   --analysis-load-reuse-level <1..10> Indicates the amount of analysis info reused in load mode, 1:least..10:most. Default %d\n", param->analysisLoadReuseLevel);
     H0("   --refine-analysis-type <string>     Reuse anlaysis information received through API call. Supported options are avc and hevc. Default disabled - %d\n", param->bAnalysisType);
     H0("   --scale-factor <int>          Specify factor by which input video is scaled down for analysis save mode. Default %d\n", param->scaleFactor);
     H0("   --refine-intra <0..4>         Enable intra refinement for encode that uses analysis-load.\n"
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265_push-1.patch
Type: text/x-patch
Size: 61238 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20200113/85188176/attachment-0001.bin>


More information about the x265-devel mailing list