[x265] [PATCH] Store commonly-used RPS in SPS in 2 pass mode

ayacc564 at 163.com ayacc564 at 163.com
Tue Oct 25 10:14:46 CEST 2016


# HG changeset patch
# User ZhengWang <zheng at multicorewareinc.com>
# Date 1477292081 -28800
#      一 10月 24 14:54:41 2016 +0800
# Node ID 19d3c5ea8bc10d3728ba2ae06190d188fe6093a3
# Parent  0e9e5264054606a38a3fe6c87272a1737b340b1a
Store commonly-used RPS in SPS  in 2 pass mode.
Add new param --[no]-multi-pass-opt-rps to control it, default disabled.

diff -r 0e9e52640546 -r 19d3c5ea8bc1 doc/reST/cli.rst
--- a/doc/reST/cli.rst	三 10月 12 17:58:49 2016 +0530
+++ b/doc/reST/cli.rst	一 10月 24 14:54:41 2016 +0800
@@ -1852,6 +1852,10 @@
 	Discard optional VUI HRD info from bitstream. Default enabled when
 	:option:`--hrd` is enabled.
 
+.. option:: --[no]-multi-pass-opt-rps
+
+	Enable storing commonly RPS in SPS in multi pass mode. Default disabled.
+
 
 Debugging options
 =================
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/CMakeLists.txt
--- a/source/CMakeLists.txt	三 10月 12 17:58:49 2016 +0530
+++ b/source/CMakeLists.txt	一 10月 24 14:54:41 2016 +0800
@@ -30,7 +30,7 @@
 mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
 
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 98)
+set(X265_BUILD 99)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/common/common.h
--- a/source/common/common.h	三 10月 12 17:58:49 2016 +0530
+++ b/source/common/common.h	一 10月 24 14:54:41 2016 +0800
@@ -312,6 +312,7 @@
 
 #define MAX_NUM_REF_PICS            16 // max. number of pictures used for reference
 #define MAX_NUM_REF                 16 // max. number of entries in picture reference list
+#define MAX_NUM_SHORT_TERM_RPS      64 // max. number of short term reference picture set in SPS
 
 #define REF_NOT_VALID               -1
 
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/common/framedata.cpp
--- a/source/common/framedata.cpp	三 10月 12 17:58:49 2016 +0530
+++ b/source/common/framedata.cpp	一 10月 24 14:54:41 2016 +0800
@@ -37,6 +37,9 @@
     m_slice  = new Slice;
     m_picCTU = new CUData[sps.numCUsInFrame];
     m_picCsp = csp;
+    m_spsrpsIdx = -1;
+    if (param.rc.bStatWrite)
+        m_spsrps = const_cast<RPS*>(sps.spsrps);
 
     m_cuMemPool.create(0, param.internalCsp, sps.numCUsInFrame);
     for (uint32_t ctuAddr = 0; ctuAddr < sps.numCUsInFrame; ctuAddr++)
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/common/framedata.h
--- a/source/common/framedata.h	三 10月 12 17:58:49 2016 +0530
+++ b/source/common/framedata.h	一 10月 24 14:54:41 2016 +0800
@@ -106,6 +106,9 @@
     CUDataMemPool  m_cuMemPool;
     CUData*        m_picCTU;
 
+    RPS*           m_spsrps;
+    int            m_spsrpsIdx;
+
     /* Rate control data used during encode and by references */
     struct RCStatCU
     {
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/common/param.cpp
--- a/source/common/param.cpp	三 10月 12 17:58:49 2016 +0530
+++ b/source/common/param.cpp	一 10月 24 14:54:41 2016 +0800
@@ -198,6 +198,7 @@
     param->bCULossless = 0;
     param->bEnableTemporalSubLayers = 0;
     param->bEnableRdRefine = 0;
+    param->bMultiPassOptRPS = 0;
 
     /* Rate control options */
     param->rc.vbvMaxBitrate = 0;
@@ -915,6 +916,8 @@
         OPT("limit-tu") p->limitTU = atoi(value);
         OPT("opt-qp-pps") p->bOptQpPPS = atobool(value);
         OPT("opt-ref-list-length-pps") p->bOptRefListLengthPPS = atobool(value);
+        OPT("multi-pass-opt-rps") p->bMultiPassOptRPS = atobool(value);
+
         else
             return X265_PARAM_BAD_NAME;
     }
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/common/slice.h
--- a/source/common/slice.h	三 10月 12 17:58:49 2016 +0530
+++ b/source/common/slice.h	一 10月 24 14:54:41 2016 +0800
@@ -239,6 +239,10 @@
     uint32_t maxLatencyIncrease;
     int      numReorderPics;
 
+    RPS      spsrps[MAX_NUM_SHORT_TERM_RPS];
+    int      spsrpsNum;
+    int      numGOPBegin;
+
     bool     bUseSAO; // use param
     bool     bUseAMP; // use param
     bool     bUseStrongIntraSmoothing; // use param
@@ -337,6 +341,7 @@
     int         m_sliceQp;
     int         m_poc;
     int         m_lastIDR;
+    int         m_rpsIdx;
 
     uint32_t    m_colRefIdx;       // never modified
 
@@ -352,6 +357,7 @@
 
     int         m_iPPSQpMinus26;
     int         numRefIdxDefault[2];
+    int         m_iNumRPSInSPS;
 
     Slice()
     {
@@ -365,6 +371,7 @@
         m_iPPSQpMinus26 = 0;
         numRefIdxDefault[0] = 1;
         numRefIdxDefault[1] = 1;
+        m_rpsIdx = -1;
     }
 
     void disableWeights();
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/encoder/api.cpp
--- a/source/encoder/api.cpp	三 10月 12 17:58:49 2016 +0530
+++ b/source/encoder/api.cpp	一 10月 24 14:54:41 2016 +0800
@@ -141,6 +141,11 @@
         Encoder *encoder = static_cast<Encoder*>(enc);
         Entropy sbacCoder;
         Bitstream bs;
+        if (encoder->m_param->rc.bStatRead && encoder->m_param->bMultiPassOptRPS)
+        {
+            if (!encoder->computeSPSRPSIndex())
+                return -1;
+        }
         encoder->getStreamHeaders(encoder->m_nalList, sbacCoder, bs);
         *pp_nal = &encoder->m_nalList.m_nal[0];
         if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	三 10月 12 17:58:49 2016 +0530
+++ b/source/encoder/encoder.cpp	一 10月 24 14:54:41 2016 +0800
@@ -77,6 +77,7 @@
     m_iFrameNum = 0;
     m_iPPSQpMinus26 = 0;
     m_iLastSliceQp = 0;
+    m_rpsInSpsCount = 0;
     for (int i = 0; i < X265_MAX_FRAME_THREADS; i++)
         m_frameEncoder[i] = NULL;
 
@@ -905,6 +906,7 @@
             frameEnc->m_encData->m_slice->m_iPPSQpMinus26 = m_iPPSQpMinus26;
             frameEnc->m_encData->m_slice->numRefIdxDefault[0] = m_pps.numRefIdxDefault[0];
             frameEnc->m_encData->m_slice->numRefIdxDefault[1] = m_pps.numRefIdxDefault[1];
+            frameEnc->m_encData->m_slice->m_iNumRPSInSPS = m_sps.spsrpsNum;
 
             curEncoder->m_rce.encodeOrder = frameEnc->m_encodeOrder = m_encodedFrameNum++;
             if (m_bframeDelay)
@@ -1068,6 +1070,13 @@
 
         x265_log(m_param, X265_LOG_INFO, "lossless compression ratio %.2f::1\n", uncompressed / m_analyzeAll.m_accBits);
     }
+    if (m_param->bMultiPassOptRPS && m_param->rc.bStatRead)
+    {
+        x265_log(m_param, X265_LOG_INFO, "RPS in SPS: %d frames (%.2f%%), RPS not in SPS: %d frames (%.2f%%)\n", 
+            m_rpsInSpsCount, (float)100.0 * m_rpsInSpsCount / m_rateControl->m_numEntries, 
+            m_rateControl->m_numEntries - m_rpsInSpsCount, 
+            (float)100.0 * (m_rateControl->m_numEntries - m_rpsInSpsCount) / m_rateControl->m_numEntries);
+    }
 
     if (m_analyzeAll.m_numPics)
     {
@@ -2433,3 +2442,203 @@
     TOOLCMP(oldParam->maxNumMergeCand, newParam->maxNumMergeCand, "max-merge=%d to %d\n");
     TOOLCMP(oldParam->bIntraInBFrames, newParam->bIntraInBFrames, "b-intra=%d to %d\n");
 }
+
+bool Encoder::computeSPSRPSIndex()
+{
+    RPS* rpsInSPS = m_sps.spsrps;
+    int* rpsNumInPSP = &m_sps.spsrpsNum;
+    int  beginNum = m_sps.numGOPBegin;
+    int  endNum;
+    RPS* rpsInRec;
+    RPS* rpsInIdxList;
+    RPS* thisRpsInSPS;
+    RPS* thisRpsInList;
+    RPSListNode* headRpsIdxList = NULL;
+    RPSListNode* tailRpsIdxList = NULL;
+    RPSListNode* rpsIdxListIter = NULL;
+    RateControlEntry *rce2Pass = m_rateControl->m_rce2Pass;
+    int numEntries = m_rateControl->m_numEntries;
+    RateControlEntry *rce;
+    int idx = 0;
+    int pos = 0;
+    int resultIdx[64];
+    memset(rpsInSPS, 0, sizeof(RPS) * MAX_NUM_SHORT_TERM_RPS);
+
+    // find out all RPS date in current GOP
+    beginNum++;
+    endNum = beginNum;
+    if (!m_param->bRepeatHeaders)
+    {
+        endNum = numEntries;
+    }
+    else
+    {
+        while (endNum < numEntries)
+        {
+            rce = &rce2Pass[endNum];
+            if (rce->sliceType == I_SLICE)
+            {
+                break;
+            }
+            endNum++;
+        }
+    }
+    m_sps.numGOPBegin = endNum;
+
+    // find out all kinds of RPS
+    for (int i = beginNum; i < endNum; i++)
+    {
+        rce = &rce2Pass[i];
+        rpsInRec = &rce->rpsData;
+        rpsIdxListIter = headRpsIdxList;
+        // i frame don't recode RPS info
+        if (rce->sliceType != I_SLICE)
+        {
+            while (rpsIdxListIter)
+            {
+                rpsInIdxList = rpsIdxListIter->rps;
+                if (rpsInRec->numberOfPictures == rpsInIdxList->numberOfPictures
+                    && rpsInRec->numberOfNegativePictures == rpsInIdxList->numberOfNegativePictures
+                    && rpsInRec->numberOfPositivePictures == rpsInIdxList->numberOfPositivePictures)
+                {
+                    for (pos = 0; pos < rpsInRec->numberOfPictures; pos++)
+                    {
+                        if (rpsInRec->deltaPOC[pos] != rpsInIdxList->deltaPOC[pos]
+                            || rpsInRec->bUsed[pos] != rpsInIdxList->bUsed[pos])
+                            break;
+                    }
+                    if (pos == rpsInRec->numberOfPictures)    // if this type of RPS has exist
+                    {
+                        rce->rpsIdx = rpsIdxListIter->idx;
+                        rpsIdxListIter->count++;
+                        // sort RPS type link after reset RPS type count.
+                        RPSListNode* next = rpsIdxListIter->next;
+                        RPSListNode* prior = rpsIdxListIter->prior;
+                        RPSListNode* iter = prior;
+                        if (iter)
+                        {
+                            while (iter)
+                            {
+                                if (iter->count > rpsIdxListIter->count)
+                                    break;
+                                iter = iter->prior;
+                            }
+                            if (iter)
+                            {
+                                prior->next = next;
+                                if (next)
+                                    next->prior = prior;
+                                else
+                                    tailRpsIdxList = prior;
+                                rpsIdxListIter->next = iter->next;
+                                rpsIdxListIter->prior = iter;
+                                iter->next->prior = rpsIdxListIter;
+                                iter->next = rpsIdxListIter;
+                            }
+                            else
+                            {
+                                prior->next = next;
+                                if (next)
+                                    next->prior = prior;
+                                else
+                                    tailRpsIdxList = prior;
+                                headRpsIdxList->prior = rpsIdxListIter;
+                                rpsIdxListIter->next = headRpsIdxList;
+                                rpsIdxListIter->prior = NULL;
+                                headRpsIdxList = rpsIdxListIter;
+                            }
+                        }
+                        break;
+                    }
+                }
+                rpsIdxListIter = rpsIdxListIter->next;
+            }
+            if (!rpsIdxListIter)  // add new type of RPS
+            {
+                RPSListNode* newIdxNode = new RPSListNode();
+                if (newIdxNode == NULL)
+                    goto fail;
+                newIdxNode->rps = rpsInRec;
+                newIdxNode->idx = idx++;
+                newIdxNode->count = 1;
+                newIdxNode->next = NULL;
+                newIdxNode->prior = NULL;
+                if (!tailRpsIdxList)
+                    tailRpsIdxList = headRpsIdxList = newIdxNode;
+                else
+                {
+                    tailRpsIdxList->next = newIdxNode;
+                    newIdxNode->prior = tailRpsIdxList;
+                    tailRpsIdxList = newIdxNode;
+                }
+                rce->rpsIdx = newIdxNode->idx;
+            }
+        }
+        else
+        {
+            rce->rpsIdx = -1;
+        }
+    }
+
+    // get commonly RPS set
+    memset(resultIdx, 0, sizeof(resultIdx));
+    if (idx > MAX_NUM_SHORT_TERM_RPS)
+        idx = MAX_NUM_SHORT_TERM_RPS;
+
+    *rpsNumInPSP = idx;
+    rpsIdxListIter = headRpsIdxList;
+    for (int i = 0; i < idx; i++)
+    {
+        resultIdx[i] = rpsIdxListIter->idx;
+        m_rpsInSpsCount += rpsIdxListIter->count;
+        thisRpsInSPS = rpsInSPS + i;
+        thisRpsInList = rpsIdxListIter->rps;
+        thisRpsInSPS->numberOfPictures = thisRpsInList->numberOfPictures;
+        thisRpsInSPS->numberOfNegativePictures = thisRpsInList->numberOfNegativePictures;
+        thisRpsInSPS->numberOfPositivePictures = thisRpsInList->numberOfPositivePictures;
+        for (pos = 0; pos < thisRpsInList->numberOfPictures; pos++)
+        {
+            thisRpsInSPS->deltaPOC[pos] = thisRpsInList->deltaPOC[pos];
+            thisRpsInSPS->bUsed[pos] = thisRpsInList->bUsed[pos];
+        }
+        rpsIdxListIter = rpsIdxListIter->next;
+    }
+
+    //reset every frame's RPS index
+    for (int i = beginNum; i < endNum; i++)
+    {
+        int j;
+        rce = &rce2Pass[i];
+        for (j = 0; j < idx; j++)
+        {
+            if (rce->rpsIdx == resultIdx[j])
+            {
+                rce->rpsIdx = j;
+                break;
+            }
+        }
+
+        if (j == idx)
+            rce->rpsIdx = -1;
+    }
+
+    rpsIdxListIter = headRpsIdxList;
+    while (rpsIdxListIter)
+    {
+        RPSListNode* freeIndex = rpsIdxListIter;
+        rpsIdxListIter = rpsIdxListIter->next;
+        delete freeIndex;
+    }
+    return true;
+
+fail:
+    rpsIdxListIter = headRpsIdxList;
+    while (rpsIdxListIter)
+    {
+        RPSListNode* freeIndex = rpsIdxListIter;
+        rpsIdxListIter = rpsIdxListIter->next;
+        delete freeIndex;
+    }
+    return false;
+}
+
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/encoder/encoder.h
--- a/source/encoder/encoder.h	三 10月 12 17:58:49 2016 +0530
+++ b/source/encoder/encoder.h	一 10月 24 14:54:41 2016 +0800
@@ -79,6 +79,15 @@
     int numRefIdxl1[MAX_NUM_REF_IDX];
 };
 
+struct RPSListNode
+{
+    int idx;
+    int count;
+    RPS* rps;
+    RPSListNode* next;
+    RPSListNode* prior;
+};
+
 class FrameEncoder;
 class DPB;
 class Lookahead;
@@ -156,6 +165,9 @@
     Lock               m_sliceRefIdxLock;
     RefIdxLastGOP      m_refIdxLastGOP;
 
+    Lock               m_rpsInSpsLock;
+    int                m_rpsInSpsCount;
+
     Encoder();
     ~Encoder() {}
 
@@ -196,6 +208,7 @@
     void initRefIdx();
     void analyseRefIdx(int *numRefIdx);
     void updateRefIdx();
+    bool computeSPSRPSIndex();
 
 protected:
 
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/encoder/entropy.cpp
--- a/source/encoder/entropy.cpp	三 10月 12 17:58:49 2016 +0530
+++ b/source/encoder/entropy.cpp	一 10月 24 14:54:41 2016 +0800
@@ -312,7 +312,9 @@
     WRITE_FLAG(sps.bUseSAO, "sample_adaptive_offset_enabled_flag");
 
     WRITE_FLAG(0, "pcm_enabled_flag");
-    WRITE_UVLC(0, "num_short_term_ref_pic_sets");
+    WRITE_UVLC(sps.spsrpsNum, "num_short_term_ref_pic_sets");
+    for (int i = 0; i < sps.spsrpsNum; i++)
+        codeShortTermRefPicSet(sps.spsrps[i], i);
     WRITE_FLAG(0, "long_term_ref_pics_present_flag");
 
     WRITE_FLAG(sps.bTemporalMVPEnabled, "sps_temporal_mvp_enable_flag");
@@ -614,8 +616,21 @@
             }
 #endif
 
-        WRITE_FLAG(0, "short_term_ref_pic_set_sps_flag");
-        codeShortTermRefPicSet(slice.m_rps);
+        if (slice.m_rpsIdx < 0)
+        {
+            WRITE_FLAG(0, "short_term_ref_pic_set_sps_flag");
+            codeShortTermRefPicSet(slice.m_rps, slice.m_sps->spsrpsNum);
+        }
+        else
+        {
+            WRITE_FLAG(1, "short_term_ref_pic_set_sps_flag");
+            int numBits = 0;
+            while ((1 << numBits) < slice.m_iNumRPSInSPS)
+                numBits++;
+
+            if (numBits > 0)
+                WRITE_CODE(slice.m_rpsIdx, numBits, "short_term_ref_pic_set_idx");
+        }
 
         if (slice.m_sps->bTemporalMVPEnabled)
             WRITE_FLAG(1, "slice_temporal_mvp_enable_flag");
@@ -707,8 +722,11 @@
         WRITE_CODE(substreamSizes[i] - 1, offsetLen, "entry_point_offset_minus1");
 }
 
-void Entropy::codeShortTermRefPicSet(const RPS& rps)
+void Entropy::codeShortTermRefPicSet(const RPS& rps, int idx)
 {
+    if (idx > 0)
+        WRITE_FLAG(0, "inter_ref_pic_set_prediction_flag");
+
     WRITE_UVLC(rps.numberOfNegativePictures, "num_negative_pics");
     WRITE_UVLC(rps.numberOfPositivePictures, "num_positive_pics");
     int prev = 0;
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/encoder/entropy.h
--- a/source/encoder/entropy.h	三 10月 12 17:58:49 2016 +0530
+++ b/source/encoder/entropy.h	一 10月 24 14:54:41 2016 +0800
@@ -149,7 +149,7 @@
 
     void codeSliceHeader(const Slice& slice, FrameData& encData, uint32_t slice_addr, uint32_t slice_addr_bits, int sliceQp);
     void codeSliceHeaderWPPEntryPoints(const uint32_t *substreamSizes, uint32_t numSubStreams, uint32_t maxOffset);
-    void codeShortTermRefPicSet(const RPS& rps);
+    void codeShortTermRefPicSet(const RPS& rps, int idx);
     void finishSlice()                 { encodeBinTrm(1); finish(); dynamic_cast<Bitstream*>(m_bitIf)->writeByteAlignment(); }
 
     void encodeCTU(const CUData& cu, const CUGeom& cuGeom);
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp	三 10月 12 17:58:49 2016 +0530
+++ b/source/encoder/frameencoder.cpp	一 10月 24 14:54:41 2016 +0800
@@ -359,9 +359,23 @@
             ScopedLock refIdxLock(m_top->m_sliceRefIdxLock);
             m_top->updateRefIdx();
         }
-        m_top->getStreamHeaders(m_nalList, m_entropyCoder, m_bs);
+        if (m_top->m_param->rc.bStatRead  && m_top->m_param->bMultiPassOptRPS)
+        {
+            ScopedLock refIdxLock(m_top->m_rpsInSpsLock);
+            if (!m_top->computeSPSRPSIndex())
+            {
+                x265_log(m_param, X265_LOG_ERROR, "compute commonly RPS failed!\n");
+                m_top->m_aborted = true;
+            }
+            m_top->getStreamHeaders(m_nalList, m_entropyCoder, m_bs);
+        }
+        else
+            m_top->getStreamHeaders(m_nalList, m_entropyCoder, m_bs);
     }
 
+    if (m_top->m_param->rc.bStatRead && m_top->m_param->bMultiPassOptRPS)
+        m_frame->m_encData->m_slice->m_rpsIdx = (m_top->m_rateControl->m_rce2Pass + m_frame->m_encodeOrder)->rpsIdx;
+
     // Weighted Prediction parameters estimation.
     bool bUseWeightP = slice->m_sliceType == P_SLICE && slice->m_pps->bUseWeightPred;
     bool bUseWeightB = slice->m_sliceType == B_SLICE && slice->m_pps->bUseWeightedBiPred;
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	三 10月 12 17:58:49 2016 +0530
+++ b/source/encoder/ratecontrol.cpp	一 10月 24 14:54:41 2016 +0800
@@ -544,10 +544,27 @@
                 }
                 rce = &m_rce2Pass[encodeOrder];
                 m_encOrder[frameNumber] = encodeOrder;
-                e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",
-                       &picType, &qpRc, &qpAq, &qNoVbv, &qRceq, &rce->coeffBits,
-                       &rce->mvBits, &rce->miscBits, &rce->iCuCount, &rce->pCuCount,
-                       &rce->skipCuCount);
+                if (!m_param->bMultiPassOptRPS)
+                {
+                    e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",
+                        &picType, &qpRc, &qpAq, &qNoVbv, &qRceq, &rce->coeffBits,
+                        &rce->mvBits, &rce->miscBits, &rce->iCuCount, &rce->pCuCount,
+                        &rce->skipCuCount);
+                }
+                else
+                {
+                    char deltaPOC[128];
+                    char bUsed[40];
+                    memset(deltaPOC, 0, sizeof(deltaPOC));
+                    memset(bUsed, 0, sizeof(bUsed));
+                    e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf nump:%d numnegp:%d numposp:%d deltapoc:%s bused:%s",
+                        &picType, &qpRc, &qpAq, &qNoVbv, &qRceq, &rce->coeffBits,
+                        &rce->mvBits, &rce->miscBits, &rce->iCuCount, &rce->pCuCount,
+                        &rce->skipCuCount, &rce->rpsData.numberOfPictures, &rce->rpsData.numberOfNegativePictures, &rce->rpsData.numberOfPositivePictures, deltaPOC, bUsed);
+                    splitdeltaPOC(deltaPOC, rce);
+                    splitbUsed(bUsed, rce);
+                    rce->rpsIdx = -1;
+                }
                 rce->keptAsRef = true;
                 rce->isIdr = false;
                 if (picType == 'b' || picType == 'p')
@@ -2632,18 +2649,55 @@
     char cType = rce->sliceType == I_SLICE ? (curFrame->m_lowres.sliceType == X265_TYPE_IDR ? 'I' : 'i')
         : rce->sliceType == P_SLICE ? 'P'
         : IS_REFERENCED(curFrame) ? 'B' : 'b';
-    if (fprintf(m_statFileOut,
-                "in:%d out:%d type:%c q:%.2f q-aq:%.2f q-noVbv:%.2f q-Rceq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f ;\n",
-                rce->poc, rce->encodeOrder,
-                cType, curEncData.m_avgQpRc, curEncData.m_avgQpAq,
-                rce->qpNoVbv, rce->qRceq,
-                curFrame->m_encData->m_frameStats.coeffBits,
-                curFrame->m_encData->m_frameStats.mvBits,
-                curFrame->m_encData->m_frameStats.miscBits,
-                curFrame->m_encData->m_frameStats.percent8x8Intra * m_ncu,
-                curFrame->m_encData->m_frameStats.percent8x8Inter * m_ncu,
-                curFrame->m_encData->m_frameStats.percent8x8Skip  * m_ncu) < 0)
-        goto writeFailure;
+    
+    if (!curEncData.m_param->bMultiPassOptRPS)
+    {
+        if (fprintf(m_statFileOut,
+            "in:%d out:%d type:%c q:%.2f q-aq:%.2f q-noVbv:%.2f q-Rceq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f ;\n",
+            rce->poc, rce->encodeOrder,
+            cType, curEncData.m_avgQpRc, curEncData.m_avgQpAq,
+            rce->qpNoVbv, rce->qRceq,
+            curFrame->m_encData->m_frameStats.coeffBits,
+            curFrame->m_encData->m_frameStats.mvBits,
+            curFrame->m_encData->m_frameStats.miscBits,
+            curFrame->m_encData->m_frameStats.percent8x8Intra * m_ncu,
+            curFrame->m_encData->m_frameStats.percent8x8Inter * m_ncu,
+            curFrame->m_encData->m_frameStats.percent8x8Skip  * m_ncu) < 0)
+            goto writeFailure;
+    }
+    else{
+        RPS* rpsWriter = &curFrame->m_encData->m_slice->m_rps;
+        int i, num = rpsWriter->numberOfPictures;
+        char deltaPOC[128];
+        char bUsed[40];
+        memset(deltaPOC, 0, sizeof(deltaPOC));
+        memset(bUsed, 0, sizeof(bUsed));
+        sprintf(deltaPOC, "deltapoc:~");
+        sprintf(bUsed, "bused:~");
+
+        for (i = 0; i < num; i++)
+        {
+            sprintf(deltaPOC, "%s%d~", deltaPOC, rpsWriter->deltaPOC[i]);
+            sprintf(bUsed, "%s%d~", bUsed, rpsWriter->bUsed[i]);
+        }
+
+        if (fprintf(m_statFileOut,
+            "in:%d out:%d type:%c q:%.2f q-aq:%.2f q-noVbv:%.2f q-Rceq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f nump:%d numnegp:%d numposp:%d %s %s ;\n",
+            rce->poc, rce->encodeOrder,
+            cType, curEncData.m_avgQpRc, curEncData.m_avgQpAq,
+            rce->qpNoVbv, rce->qRceq,
+            curFrame->m_encData->m_frameStats.coeffBits,
+            curFrame->m_encData->m_frameStats.mvBits,
+            curFrame->m_encData->m_frameStats.miscBits,
+            curFrame->m_encData->m_frameStats.percent8x8Intra * m_ncu,
+            curFrame->m_encData->m_frameStats.percent8x8Inter * m_ncu,
+            curFrame->m_encData->m_frameStats.percent8x8Skip  * m_ncu,
+            rpsWriter->numberOfPictures,
+            rpsWriter->numberOfNegativePictures,
+            rpsWriter->numberOfPositivePictures,
+            deltaPOC, bUsed) < 0)
+            goto writeFailure;
+    }
     /* Don't re-write the data in multi-pass mode. */
     if (m_param->rc.cuTree && IS_REFERENCED(curFrame) && !m_param->rc.bStatRead)
     {
@@ -2736,3 +2790,48 @@
     X265_FREE(m_param->rc.zones);
 }
 
+void RateControl::splitdeltaPOC(char deltapoc[], RateControlEntry *rce)
+{
+    int idx = 0, length = 0;
+    char tmpStr[128];
+    char* src = deltapoc;
+    char* buf = strstr(src, "~");
+    while (buf)
+    {
+        memset(tmpStr, 0, sizeof(tmpStr));
+        length = (int)(buf - src);
+        if (length != 0)
+        {
+            strncpy(tmpStr, src, length);
+            rce->rpsData.deltaPOC[idx] = atoi(tmpStr);
+            idx++;
+            if (idx == rce->rpsData.numberOfPictures)
+                break;
+        }
+        src += (length + 1);
+        buf = strstr(src, "~");
+    }
+}
+
+void RateControl::splitbUsed(char bused[], RateControlEntry *rce)
+{
+    int idx = 0, length = 0;
+    char tmpStr[128];
+    char* src = bused;
+    char* buf = strstr(src, "~");
+    while (buf)
+    {
+        memset(tmpStr, 0, sizeof(tmpStr));
+        length = (int)(buf - src);
+        if (length != 0)
+        {
+            strncpy(tmpStr, src, length);
+            rce->rpsData.bUsed[idx] = atoi(tmpStr) > 0;
+            idx++;
+            if (idx == rce->rpsData.numberOfPictures)
+                break;
+        }
+        src += (length + 1);
+        buf = strstr(src, "~");
+    }
+}
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h	三 10月 12 17:58:49 2016 +0530
+++ b/source/encoder/ratecontrol.h	一 10月 24 14:54:41 2016 +0800
@@ -111,6 +111,8 @@
     bool     isIdr;
     SEIPictureTiming *picTimingSEI;
     HRDTiming        *hrdTiming;
+    int      rpsIdx;
+    RPS      rpsData;
 };
 
 class RateControl
@@ -282,6 +284,8 @@
     bool   findUnderflow(double *fills, int *t0, int *t1, int over, int framesCount);
     bool   fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax);
     double tuneQScaleForGrain(double rcOverflow);
+    void   splitdeltaPOC(char deltapoc[], RateControlEntry *rce);
+    void   splitbUsed(char deltapoc[], RateControlEntry *rce);
 };
 }
 #endif // ifndef X265_RATECONTROL_H
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/x265.h
--- a/source/x265.h	三 10月 12 17:58:49 2016 +0530
+++ b/source/x265.h	一 10月 24 14:54:41 2016 +0800
@@ -1323,6 +1323,9 @@
     /* Opitmize ref list length in PPS based on stats from previous GOP*/
     int bOptRefListLengthPPS;
 
+    /* Enable storing commonly RPS in SPS in multi pass mode */
+    int       bMultiPassOptRPS;
+
 } x265_param;
 
 /* x265_param_alloc:
diff -r 0e9e52640546 -r 19d3c5ea8bc1 source/x265cli.h
--- a/source/x265cli.h	三 10月 12 17:58:49 2016 +0530
+++ b/source/x265cli.h	一 10月 24 14:54:41 2016 +0800
@@ -236,6 +236,8 @@
     { "pass",           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 },
+    { "no-multi-pass-opt-rps", no_argument, NULL, 0 },
     { "analysis-mode",  required_argument, NULL, 0 },
     { "analysis-file",  required_argument, NULL, 0 },
     { "strict-cbr",           no_argument, NULL, 0 },
@@ -460,6 +462,7 @@
     H0("   --[no-]vui-hrd-info           Discard optional HRD timing information from the bistream. Default %s\n", OPT(param->bEmitVUIHRDInfo));
     H0("   --[no-]opt-qp-pps             Discard optional HRD timing information from the bistream. Default %s\n", OPT(param->bOptQpPPS));
     H0("   --[no-]opt-ref-list-length-pps  Discard optional HRD timing information from the bistream. Default %s\n", OPT(param->bOptRefListLengthPPS));
+    H0("   --[no-]multi-pass-opt-rps     Enable storing commonly RPS in SPS in multi pass mode. Default %s\n", OPT(param->bMultiPassOptRPS));
     H1("\nReconstructed video options (debugging):\n");
     H1("-r/--recon <filename>            Reconstructed raw image YUV or Y4M output file name\n");
     H1("   --recon-depth <integer>       Bit-depth of reconstructed raw image file. Defaults to input bit depth, or 8 if Y4M\n");
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265.patch
Type: text/x-patch
Size: 28689 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20161025/6ce7ff2b/attachment-0001.bin>


More information about the x265-devel mailing list