[x265] [PATCH] add analysis 2 pass structure

santhoshini at multicorewareinc.com santhoshini at multicorewareinc.com
Mon Dec 26 16:59:46 CET 2016


# HG changeset patch
# User Santhoshini Sekar <santhoshini at multicorewareinc.com>
# Date 1482758979 -19800
#      Mon Dec 26 18:59:39 2016 +0530
# Node ID 82e4e3b0bb460c0fe140953342e12a0a1b3da004
# Parent  e40db0bdde4ac9659fae2b5b133fcadecece7412
add analysis 2 pass structure

diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -1438,6 +1438,23 @@
 	* :option:`--subme` = MIN(2, :option:`--subme`)
 	* :option:`--rd` = MIN(2, :option:`--rd`)
 
+.. option:: --multi-pass-opt-analysis, --no-multi-pass-opt-analysis
+
+    Enable/Disable multipass analysis refinement along with multipass ratecontrol. Based on 
+    the information stored in pass 1, in subsequent passes analysis data is refined 
+    and also redundant steps are skipped.
+    In pass 1 analysis information like motion vector, depth, reference and prediction
+    modes of the final best CTU partition is stored for each CTU.
+    Default disabled.
+
+.. option:: --multi-pass-opt-distortion, --no-multi-pass-opt-distortion
+
+    Enable/Disable multipass refinement of qp based on distortion data along with multipass
+    ratecontrol. In pass 1 distortion of best CTU partition is stored. CTUs with high
+    distortion get lower(negative)qp offsets and vice-versa for low distortion CTUs in pass 2.
+    This helps to improve the subjective quality.
+    Default disabled.
+
 .. option:: --strict-cbr, --no-strict-cbr
 	
 	Enables stricter conditions to control bitrate deviance from the 
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -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 104)
+set(X265_BUILD 105)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff --git a/source/common/frame.h b/source/common/frame.h
--- a/source/common/frame.h
+++ b/source/common/frame.h
@@ -98,6 +98,7 @@
     Frame*                 m_prev;
     x265_param*            m_param;              // Points to the latest param set for the frame.
     x265_analysis_data     m_analysisData;
+    x265_analysis_2Pass    m_analysis2Pass;
     RcStats*               m_rcData;
     Frame();
 
diff --git a/source/common/framedata.h b/source/common/framedata.h
--- a/source/common/framedata.h
+++ b/source/common/framedata.h
@@ -181,5 +181,15 @@
     uint8_t*    partSize;
     uint8_t*    mergeFlag;
 };
+
+struct analysis2PassFrameData
+{
+    uint8_t*      depth;
+    MV*           m_mv[2];
+    int*          mvpIdx[2];
+    int32_t*      ref[2];
+    uint8_t*      modes;
+};
+
 }
 #endif // ifndef X265_FRAMEDATA_H
diff --git a/source/common/param.cpp b/source/common/param.cpp
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -193,6 +193,8 @@
     param->psyRd = 2.0;
     param->psyRdoq = 0.0;
     param->analysisMode = 0;
+    param->analysisMultiPassRefine = 0;
+    param->analysisMultiPassDistortion = 0;
     param->analysisFileName = NULL;
     param->bIntraInBFrames = 0;
     param->bLossless = 0;
@@ -922,6 +924,8 @@
         OPT("scenecut-bias") p->scenecutBias = atof(value);
         OPT("lookahead-threads") p->lookaheadThreads = atoi(value);
         OPT("opt-cu-delta-qp") p->bOptCUDeltaQP = atobool(value);
+        OPT("multi-pass-opt-analysis") p->analysisMultiPassRefine = atobool(value);
+        OPT("multi-pass-opt-distortion") p->analysisMultiPassDistortion = atobool(value);
         else
             return X265_PARAM_BAD_NAME;
     }
diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp
--- a/source/encoder/api.cpp
+++ b/source/encoder/api.cpp
@@ -210,6 +210,7 @@
     {
         pic_in->analysisData.intraData = NULL;
         pic_in->analysisData.interData = NULL;
+        pic_in->analysis2Pass.analysisFramedata = NULL;
     }
 
     if (pp_nal && numEncoded > 0)
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -339,6 +339,20 @@
         }
     }
 
+    if (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion)
+    {
+        const char* name = m_param->analysisFileName;
+        if (!name)
+            name = defaultAnalysisFileName;
+        const char* mode = m_param->rc.bStatWrite ? "wb" : "rb";
+        m_analysisFile = fopen(name, mode);
+        if (!m_analysisFile)
+        {
+            x265_log(NULL, X265_LOG_ERROR, "Analysis 2 pass: failed to open file %s\n", name);
+            m_aborted = true;
+        }
+    }
+
     m_bZeroLatency = !m_param->bframes && !m_param->lookaheadDepth && m_param->frameNumThreads == 1;
 
     m_aborted |= parseLambdaFile(m_param);
@@ -642,7 +656,13 @@
 
         /* Use the frame types from the first pass, if available */
         int sliceType = (m_param->rc.bStatRead) ? m_rateControl->rateControlSliceType(inFrame->m_poc) : pic_in->sliceType;
-
+        if (m_param->rc.bStatRead && (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion))
+        {
+            x265_picture* inputPic = const_cast<x265_picture*>(pic_in);
+            readAnalysis2PassFile(&inputPic->analysis2Pass, inFrame->m_poc, sliceType);
+            inFrame->m_analysis2Pass.poc = inFrame->m_poc;
+            inFrame->m_analysis2Pass.analysisFramedata = inputPic->analysis2Pass.analysisFramedata;
+        }
         /* In analysisSave mode, x265_analysis_data is allocated in pic_in and inFrame points to this */
         /* Load analysis data before lookahead->addPicture, since sliceType has been decided */
         if (m_param->analysisMode == X265_ANALYSIS_LOAD)
@@ -696,6 +716,9 @@
             if (m_param->analysisMode == X265_ANALYSIS_LOAD)
                 freeAnalysis(&outFrame->m_analysisData);
 
+            if ((m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion) && m_param->rc.bStatRead)
+                freeAnalysis2Pass(&outFrame->m_analysis2Pass, slice->m_sliceType);
+
             if (pic_out)
             {
                 PicYuv *recpic = outFrame->m_reconPic;
@@ -746,6 +769,16 @@
                     freeAnalysis(&pic_out->analysisData);
                 }
             }
+            if (m_param->rc.bStatWrite && (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion))
+            {
+                if (pic_out)
+                {
+                    pic_out->analysis2Pass.poc = pic_out->poc;
+                    pic_out->analysis2Pass.analysisFramedata = outFrame->m_analysis2Pass.analysisFramedata;
+                }
+                writeAnalysis2PassFile(&outFrame->m_analysis2Pass, *outFrame->m_encData);
+                freeAnalysis2Pass(&outFrame->m_analysis2Pass, slice->m_sliceType);
+            }
             if (m_param->internalCsp == X265_CSP_I400)
             {
                 if (slice->m_sliceType == P_SLICE)
@@ -954,7 +987,12 @@
                 analysis->numPartitions  = NUM_4x4_PARTITIONS;
                 allocAnalysis(analysis);
             }
-
+            if ((m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion) && m_param->rc.bStatWrite)
+            {
+                x265_analysis_2Pass* analysisRefine = &frameEnc->m_analysis2Pass;
+                analysisRefine->poc = frameEnc->m_poc;
+                allocAnalysis2Pass(analysisRefine, frameEnc->m_lowres.sliceType);
+            }
             /* determine references, setup RPS, etc */
             m_dpb->prepareEncode(frameEnc);
 
@@ -1928,6 +1966,19 @@
         p->rc.cuTree = 0;
     }
 
+    if (p->analysisMode && (p->analysisMultiPassRefine || p->analysisMultiPassDistortion))
+    {
+        x265_log(p, X265_LOG_WARNING, "Cannot use Analysis load/save option and multi-pass-opt-analysis/multi-pass-opt-distortion together,"
+            "Disabling Analysis load/save and multi-pass-opt-analysis/multi-pass-opt-distortion\n");
+        p->analysisMode = p->analysisMultiPassRefine = p->analysisMultiPassDistortion = 0;
+    }
+
+    if ((p->analysisMultiPassRefine || p->analysisMultiPassDistortion) && (p->bDistributeModeAnalysis || p->bDistributeMotionEstimation))
+    {
+        x265_log(p, X265_LOG_WARNING, "multi-pass-opt-analysis/multi-pass-opt-distortion incompatible with pmode/pme, Disabling pmode/pme\n");
+        p->bDistributeMotionEstimation = p->bDistributeModeAnalysis = 0;
+    }
+
     if (p->rc.bEnableGrain)
     {
         x265_log(p, X265_LOG_WARNING, "Rc Grain removes qp fluctuations caused by aq/cutree, Disabling aq,cu-tree\n");
@@ -1988,6 +2039,14 @@
         p->bDistributeModeAnalysis = 0;
     }
 
+    if (!p->rc.bStatWrite && !p->rc.bStatRead && (p->analysisMultiPassRefine || p->analysisMultiPassDistortion))
+    {
+        x265_log(p, X265_LOG_WARNING, "analysis-multi-pass/distortion is enabled only when rc multi pass is enabled. Disabling multi-pass-opt-analysis and multi-pass-opt-distortion");
+        p->analysisMultiPassRefine = 0;
+        p->analysisMultiPassDistortion = 0;
+    }
+
+
     /* some options make no sense if others are disabled */
     p->bSaoNonDeblocked &= p->bEnableSAO;
     p->bEnableTSkipFast &= p->bEnableTransformSkip;
@@ -2233,6 +2292,55 @@
     }
 }
 
+void Encoder::allocAnalysis2Pass(x265_analysis_2Pass* analysis, int sliceType)
+{
+    analysis->analysisFramedata = NULL;
+    analysis2PassFrameData *analysisFrameData = (analysis2PassFrameData*)analysis->analysisFramedata;
+    uint32_t widthInCU = (m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize;
+    uint32_t heightInCU = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;
+
+    uint32_t numCUsInFrame = widthInCU * heightInCU;
+    CHECKED_MALLOC_ZERO(analysisFrameData, analysis2PassFrameData, 1);
+    CHECKED_MALLOC(analysisFrameData->depth, uint8_t, NUM_4x4_PARTITIONS * numCUsInFrame);
+    if (!IS_X265_TYPE_I(sliceType))
+    {
+        CHECKED_MALLOC_ZERO(analysisFrameData->m_mv[0], MV, NUM_4x4_PARTITIONS * numCUsInFrame);
+        CHECKED_MALLOC_ZERO(analysisFrameData->m_mv[1], MV, NUM_4x4_PARTITIONS * numCUsInFrame);
+        CHECKED_MALLOC_ZERO(analysisFrameData->mvpIdx[0], int, NUM_4x4_PARTITIONS * numCUsInFrame);
+        CHECKED_MALLOC_ZERO(analysisFrameData->mvpIdx[1], int, NUM_4x4_PARTITIONS * numCUsInFrame);
+        CHECKED_MALLOC_ZERO(analysisFrameData->ref[0], int32_t, NUM_4x4_PARTITIONS * numCUsInFrame);
+        CHECKED_MALLOC_ZERO(analysisFrameData->ref[1], int32_t, NUM_4x4_PARTITIONS * numCUsInFrame);
+        CHECKED_MALLOC(analysisFrameData->modes, uint8_t, NUM_4x4_PARTITIONS * numCUsInFrame);
+    }
+
+    analysis->analysisFramedata = analysisFrameData;
+
+    return;
+
+fail:
+    freeAnalysis2Pass(analysis, sliceType);
+    m_aborted = true;
+}
+
+void Encoder::freeAnalysis2Pass(x265_analysis_2Pass* analysis, int sliceType)
+{
+    if (analysis->analysisFramedata)
+    {
+        X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->depth);
+        if (!IS_X265_TYPE_I(sliceType))
+        {
+            X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->m_mv[0]);
+            X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->m_mv[1]);
+            X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->mvpIdx[0]);
+            X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->mvpIdx[1]);
+            X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->ref[0]);
+            X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->ref[1]);
+            X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->modes);
+        }
+        X265_FREE(analysis->analysisFramedata);
+    }
+}
+
 void Encoder::readAnalysisFile(x265_analysis_data* analysis, int curPoc)
 {
 
@@ -2348,6 +2456,127 @@
 #undef X265_FREAD
 }
 
+void Encoder::readAnalysis2PassFile(x265_analysis_2Pass* analysis2Pass, int curPoc, int sliceType)
+{
+
+#define X265_FREAD(val, size, readSize, fileOffset)\
+    if (fread(val, size, readSize, fileOffset) != readSize)\
+    {\
+    x265_log(NULL, X265_LOG_ERROR, "Error reading analysis 2 pass data\n"); \
+    freeAnalysis2Pass(analysis2Pass, sliceType); \
+    m_aborted = true; \
+    return; \
+}\
+
+    static uint64_t consumedBytes = 0;
+    static uint64_t totalConsumedBytes = 0;
+    uint32_t depthBytes = 0;
+    fseeko(m_analysisFile, totalConsumedBytes, SEEK_SET);
+
+    int poc; uint32_t frameRecordSize;
+    X265_FREAD(&frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
+    X265_FREAD(&depthBytes, sizeof(uint32_t), 1, m_analysisFile);
+    X265_FREAD(&poc, sizeof(int), 1, m_analysisFile);
+
+    uint64_t currentOffset = totalConsumedBytes;
+
+    /* Seeking to the right frame Record */
+    while (poc != curPoc && !feof(m_analysisFile))
+    {
+        currentOffset += frameRecordSize;
+        fseeko(m_analysisFile, currentOffset, SEEK_SET);
+        X265_FREAD(&frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
+        X265_FREAD(&depthBytes, sizeof(uint32_t), 1, m_analysisFile);
+        X265_FREAD(&poc, sizeof(int), 1, m_analysisFile);
+    }
+
+    if (poc != curPoc || feof(m_analysisFile))
+    {
+        x265_log(NULL, X265_LOG_WARNING, "Error reading analysis 2 pass data: Cannot find POC %d\n", curPoc);
+        freeAnalysis2Pass(analysis2Pass, sliceType);
+        return;
+    }
+    /* Memory is allocated for analysis multi pass data */
+    allocAnalysis2Pass(analysis2Pass, sliceType);
+    /* Now arrived at the right frame, read the record */
+    analysis2Pass->poc = poc;
+    analysis2Pass->frameRecordSize = frameRecordSize;
+
+    uint8_t* tempBuf = NULL, *depthBuf = NULL;
+
+    tempBuf = X265_MALLOC(uint8_t, depthBytes);
+    X265_FREAD(tempBuf, sizeof(uint8_t), depthBytes, m_analysisFile);
+
+    depthBuf = tempBuf;
+
+    size_t count = 0;
+    for (uint32_t d = 0; d < depthBytes; d++)
+    {
+        int bytes = NUM_4x4_PARTITIONS >> (depthBuf[d] * 2);
+        memset(&((analysis2PassFrameData *)analysis2Pass->analysisFramedata)->depth[count], depthBuf[d], bytes);
+        count += bytes;
+    }
+
+    if (!IS_X265_TYPE_I(sliceType))
+    {
+        MV *tempMVBuf[2], *MVBuf[2];
+        int32_t *tempRefBuf[2], *refBuf[2];
+        int *tempMvpBuf[2], *mvpBuf[2];
+        uint8_t* tempModeBuf = NULL, *modeBuf = NULL;
+
+        int numDir = sliceType == X265_TYPE_P ? 1 : 2;
+        for (int i = 0; i < numDir; i++)
+        {
+            tempMVBuf[i] = X265_MALLOC(MV, depthBytes);
+            X265_FREAD(tempMVBuf[i], sizeof(MV), depthBytes, m_analysisFile);
+            MVBuf[i] = tempMVBuf[i];
+            tempMvpBuf[i] = X265_MALLOC(int, depthBytes);
+            X265_FREAD(tempMvpBuf[i], sizeof(int), depthBytes, m_analysisFile);
+            mvpBuf[i] = tempMvpBuf[i];
+            tempRefBuf[i] = X265_MALLOC(int32_t, depthBytes);
+            X265_FREAD(tempRefBuf[i], sizeof(int32_t), depthBytes, m_analysisFile);
+            refBuf[i] = tempRefBuf[i];
+        }
+        tempModeBuf = X265_MALLOC(uint8_t, depthBytes);
+        X265_FREAD(tempModeBuf, sizeof(uint8_t), depthBytes, m_analysisFile);
+        modeBuf = tempModeBuf;
+
+        count = 0;
+        for (uint32_t d = 0; d < depthBytes; d++)
+        {
+            size_t bytes = NUM_4x4_PARTITIONS >> (depthBuf[d] * 2);
+            for (int i = 0; i < numDir; i++)
+            {
+                for (size_t j = count, k = 0; k < bytes; j++, k++)
+                {
+                    memcpy(&((analysis2PassFrameData*)analysis2Pass->analysisFramedata)->m_mv[i][j], MVBuf[i] + d, sizeof(MV));
+                    memcpy(&((analysis2PassFrameData*)analysis2Pass->analysisFramedata)->mvpIdx[i][j], mvpBuf[i] + d, sizeof(int));
+                    memcpy(&((analysis2PassFrameData*)analysis2Pass->analysisFramedata)->ref[i][j], refBuf[i] + d, sizeof(int32_t));
+                }
+            }
+            memset(&((analysis2PassFrameData *)analysis2Pass->analysisFramedata)->modes[count], modeBuf[d], bytes);
+            count += bytes;
+        }
+
+        for (int i = 0; i < numDir; i++)
+        {
+            X265_FREE(tempMVBuf[i]);
+            X265_FREE(tempMvpBuf[i]);
+            X265_FREE(tempRefBuf[i]);
+        }
+        X265_FREE(tempModeBuf);
+    }
+    X265_FREE(tempBuf);
+    consumedBytes += frameRecordSize;
+    if (!IS_X265_TYPE_I(sliceType))
+    {
+        int numDir = sliceType == X265_TYPE_P ? 1 : 2;
+        if (numDir == 1)
+            totalConsumedBytes = consumedBytes;
+    }
+#undef X265_FREAD
+}
+
 void Encoder::writeAnalysisFile(x265_analysis_data* analysis, FrameData &curEncData)
 {
 
@@ -2464,6 +2693,101 @@
 #undef X265_FWRITE
 }
 
+void Encoder::writeAnalysis2PassFile(x265_analysis_2Pass* analysis2Pass, FrameData &curEncData)
+{
+#define X265_FWRITE(val, size, writeSize, fileOffset)\
+    if (fwrite(val, size, writeSize, fileOffset) < writeSize)\
+    {\
+    x265_log(NULL, X265_LOG_ERROR, "Error writing analysis 2 pass data\n"); \
+    freeAnalysis2Pass(analysis2Pass, curEncData.m_slice->m_sliceType); \
+    m_aborted = true; \
+    return; \
+}\
+
+    uint32_t depthBytes = 0;
+    uint32_t widthInCU = (m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize;
+    uint32_t heightInCU = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;
+    uint32_t numCUsInFrame = widthInCU * heightInCU;
+    analysis2PassFrameData* analysisFrameData = (analysis2PassFrameData*)analysis2Pass->analysisFramedata;
+
+    for (uint32_t cuAddr = 0; cuAddr < numCUsInFrame; cuAddr++)
+    {
+        uint8_t depth = 0;
+
+        CUData* ctu = curEncData.getPicCTU(cuAddr);
+
+        for (uint32_t absPartIdx = 0; absPartIdx < ctu->m_numPartitions; depthBytes++)
+        {
+            depth = ctu->m_cuDepth[absPartIdx];
+            analysisFrameData->depth[depthBytes] = depth;
+            absPartIdx += ctu->m_numPartitions >> (depth * 2);
+        }
+    }
+
+    if (curEncData.m_slice->m_sliceType != I_SLICE)
+    {
+        depthBytes = 0;
+        for (uint32_t cuAddr = 0; cuAddr < numCUsInFrame; cuAddr++)
+        {
+            uint8_t depth = 0;
+            uint8_t predMode = 0;
+
+            CUData* ctu = curEncData.getPicCTU(cuAddr);
+
+            for (uint32_t absPartIdx = 0; absPartIdx < ctu->m_numPartitions; depthBytes++)
+            {
+                depth = ctu->m_cuDepth[absPartIdx];
+                analysisFrameData->m_mv[0][depthBytes] = ctu->m_mv[0][absPartIdx];
+                analysisFrameData->mvpIdx[0][depthBytes] = ctu->m_mvpIdx[0][absPartIdx];
+                analysisFrameData->ref[0][depthBytes] = ctu->m_refIdx[0][absPartIdx];
+                predMode = ctu->m_predMode[absPartIdx];
+                if (ctu->m_refIdx[1][absPartIdx] != -1)
+                {
+                    analysisFrameData->m_mv[1][depthBytes] = ctu->m_mv[1][absPartIdx];
+                    analysisFrameData->mvpIdx[1][depthBytes] = ctu->m_mvpIdx[1][absPartIdx];
+                    analysisFrameData->ref[1][depthBytes] = ctu->m_refIdx[1][absPartIdx];
+                    predMode = 4; // used as indiacator if the block is coded as bidir
+                }
+                analysisFrameData->modes[depthBytes] = predMode;
+
+                absPartIdx += ctu->m_numPartitions >> (depth * 2);
+            }
+        }
+    }
+
+    /* calculate frameRecordSize */
+    analysis2Pass->frameRecordSize = sizeof(analysis2Pass->frameRecordSize) + sizeof(depthBytes)+sizeof(analysis2Pass->poc);
+
+    analysis2Pass->frameRecordSize += depthBytes * sizeof(uint8_t);
+
+    if (curEncData.m_slice->m_sliceType != I_SLICE)
+    {
+        int numDir = (curEncData.m_slice->m_sliceType == P_SLICE) ? 1 : 2;
+        analysis2Pass->frameRecordSize += depthBytes * sizeof(MV) * numDir;
+        analysis2Pass->frameRecordSize += depthBytes * sizeof(int32_t) * numDir;
+        analysis2Pass->frameRecordSize += depthBytes * sizeof(int) * numDir;
+        analysis2Pass->frameRecordSize += depthBytes * sizeof(uint8_t);
+    }
+    X265_FWRITE(&analysis2Pass->frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
+    X265_FWRITE(&depthBytes, sizeof(uint32_t), 1, m_analysisFile);
+    X265_FWRITE(&analysis2Pass->poc, sizeof(uint32_t), 1, m_analysisFile);
+
+    X265_FWRITE(analysisFrameData->depth, sizeof(uint8_t), depthBytes, m_analysisFile);
+
+    if (curEncData.m_slice->m_sliceType != I_SLICE)
+    {
+        int numDir = curEncData.m_slice->m_sliceType == P_SLICE ? 1 : 2;
+        for (int i = 0; i < numDir; i++)
+        {
+            X265_FWRITE(analysisFrameData->m_mv[i], sizeof(MV), depthBytes, m_analysisFile);
+            X265_FWRITE(analysisFrameData->mvpIdx[i], sizeof(int), depthBytes, m_analysisFile);
+            X265_FWRITE(analysisFrameData->ref[i], sizeof(int32_t), depthBytes, m_analysisFile);
+        }
+        X265_FWRITE(analysisFrameData->modes, sizeof(uint8_t), depthBytes, m_analysisFile);
+    }
+#undef X265_FWRITE
+}
+
 void Encoder::printReconfigureParams()
 {
     if (!m_reconfigure)
diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h
--- a/source/encoder/encoder.h
+++ b/source/encoder/encoder.h
@@ -30,6 +30,7 @@
 #include "scalinglist.h"
 #include "x265.h"
 #include "nal.h"
+#include "framedata.h"
 
 struct x265_encoder {};
 
@@ -197,10 +198,18 @@
 
     void freeAnalysis(x265_analysis_data* analysis);
 
+    void allocAnalysis2Pass(x265_analysis_2Pass* analysis, int sliceType);
+
+    void freeAnalysis2Pass(x265_analysis_2Pass* analysis, int sliceType);
+
     void readAnalysisFile(x265_analysis_data* analysis, int poc);
 
     void writeAnalysisFile(x265_analysis_data* pic, FrameData &curEncData);
 
+    void readAnalysis2PassFile(x265_analysis_2Pass* analysis2Pass, int poc, int sliceType);
+
+    void writeAnalysis2PassFile(x265_analysis_2Pass* analysis2Pass, FrameData &curEncData);
+
     void finishFrameStats(Frame* pic, FrameEncoder *curEncoder, x265_frame_stats* frameStats, int inPoc);
 
     void calcRefreshInterval(Frame* frameEnc);
diff --git a/source/x265.h b/source/x265.h
--- a/source/x265.h
+++ b/source/x265.h
@@ -115,6 +115,14 @@
     /* All the above values will add up to 100%. */
 } x265_cu_stats;
 
+
+typedef struct x265_analysis_2Pass
+{
+    uint32_t      poc;
+    uint32_t      frameRecordSize;
+    void*         analysisFramedata;
+}x265_analysis_2Pass;
+
 /* Frame level statistics */
 typedef struct x265_frame_stats
 {
@@ -282,6 +290,8 @@
     uint64_t framesize;
 
     int    height;
+
+    x265_analysis_2Pass analysis2Pass;
 } x265_picture;
 
 typedef enum
@@ -1345,6 +1355,11 @@
     /* Optimize CU level QPs to signal consistent deltaQPs in frame for rd level > 4 */
     int        bOptCUDeltaQP;
 
+    /* Refine analysis in multipass ratecontrol based on analysis information stored */
+    int         analysisMultiPassRefine;
+
+    /* Refine analysis in multipass ratecontrol based on distortion data stored */
+    int         analysisMultiPassDistortion;
 } x265_param;
 
 /* x265_param_alloc:
diff --git a/source/x265cli.h b/source/x265cli.h
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -238,6 +238,11 @@
     { "nr-inter",       required_argument, NULL, 0 },
     { "stats",          required_argument, NULL, 0 },
     { "pass",           required_argument, NULL, 0 },
+    { "multi-pass-opt-analysis", no_argument, NULL, 0 },
+    { "no-multi-pass-opt-analysis",    no_argument, NULL, 0 },
+    { "multi-pass-opt-distortion",     no_argument, NULL, 0 },
+    { "no-multi-pass-opt-distortion",  no_argument, NULL, 0 },
+    { "analysis-2Pass-file",           required_argument, NULL, 0 },
     { "slow-firstpass",       no_argument, NULL, 0 },
     { "no-slow-firstpass",    no_argument, NULL, 0 },
     { "multi-pass-opt-rps",   no_argument, NULL, 0 },
@@ -400,6 +405,9 @@
        "                                   - 1 : First pass, creates stats file\n"
        "                                   - 2 : Last pass, does not overwrite stats file\n"
        "                                   - 3 : Nth pass, overwrites stats file\n");
+    H0("   --[no-]multi-pass-opt-analysis   Refine analysis in 2 pass based on analysis information from pass 1\n");
+    H0("   --[no-]multi-pass-opt-distortion Use distortion of CTU from pass 1 to refine qp in 2 pass\n");
+    H0("   --analysis-2Pass-file              File name to dump analysis data in pass 1 and pass 2\n");
     H0("   --stats                       Filename for stats file in multipass pass rate control. Default x265_2pass.log\n");
     H0("   --[no-]analyze-src-pics       Motion estimation uses source frame planes. Default disable\n");
     H0("   --[no-]slow-firstpass         Enable a slow first pass in a multipass rate control mode. Default %s\n", OPT(param->rc.bEnableSlowFirstPass));
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265.patch
Type: text/x-patch
Size: 24982 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20161226/6766fb2b/attachment-0001.bin>


More information about the x265-devel mailing list