# HG changeset patch
# User xuefeng <xuefeng@multicorewareinc.com>
# Date 1474621021 -28800
# Node ID c785ea65fc84a3c4c2cfcbffdd5efe3d34e27ddc
# Parent  d20b78d6d138de25040a756e7df10b8c45eabba8
Set PPS delta QP with a best value to save bits

diff -r d20b78d6d138 -r c785ea65fc84 source/common/slice.h
--- a/source/common/slice.h	Thu Sep 22 15:54:24 2016 +0530
+++ b/source/common/slice.h	Fri Sep 23 16:57:01 2016 +0800
@@ -347,6 +347,8 @@
     bool        m_sLFaseFlag;      // loop filter boundary flag
     bool        m_colFromL0Flag;   // collocated picture from List0 or List1 flag
 
+    int         m_iPPSQpMinus26;
+	
     Slice()
     {
         m_lastIDR = 0;
@@ -356,6 +358,7 @@
         memset(m_refReconPicList, 0, sizeof(m_refReconPicList));
         memset(m_refPOCList, 0, sizeof(m_refPOCList));
         disableWeights();
+        m_iPPSQpMinus26 = 0;
     }
 
     void disableWeights();
diff -r d20b78d6d138 -r c785ea65fc84 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Thu Sep 22 15:54:24 2016 +0530
+++ b/source/encoder/encoder.cpp	Fri Sep 23 16:57:01 2016 +0800
@@ -74,6 +74,8 @@
     m_threadPool = NULL;
     m_analysisFile = NULL;
     m_offsetEmergency = NULL;
+    m_iFrameNum = 0;
+    m_iPPSQpMinus26 = 0;
     for (int i = 0; i < X265_MAX_FRAME_THREADS; i++)
         m_frameEncoder[i] = NULL;
 
@@ -869,6 +871,36 @@
                 slice->m_endCUAddr = slice->realEndAddress(m_sps.numCUsInFrame * NUM_4x4_PARTITIONS);
             }
 
+            if( frameEnc->m_lowres.bKeyframe && m_param->bRepeatHeaders )
+            {
+                ScopedLock qpLock( m_sliceQpLock );
+                if( m_iFrameNum >= m_param->frameNumThreads )
+                {
+                    //Search the least cost
+                    int64_t iLeastCost = m_iBitsCostSum[0];
+                    int iLeastId = 0;
+                    for( int i = 1; i < QP_MAX_SPEC + 1; i++ )
+                    {
+                        if( iLeastCost > m_iBitsCostSum[i] )
+                        {
+                            iLeastId = i;
+                            iLeastCost = m_iBitsCostSum[i];
+                        }
+                    }
+
+                    m_iPPSQpMinus26 = (iLeastId + 1) - 26;
+
+                    m_iFrameNum = 0;
+                }
+
+                for( int i = 0; i < QP_MAX_SPEC + 1; i++ )
+                {
+                    m_iBitsCostSum[i] = 0;
+                }
+            }
+
+            frameEnc->m_encData->m_slice->m_iPPSQpMinus26 = m_iPPSQpMinus26;
+
             curEncoder->m_rce.encodeOrder = frameEnc->m_encodeOrder = m_encodedFrameNum++;
             if (m_bframeDelay)
             {
@@ -1429,7 +1461,7 @@
     list.serialize(NAL_UNIT_SPS, bs);
 
     bs.resetBits();
-    sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1));
+    sbacCoder.codePPS( m_pps, (m_param->maxSlices <= 1), m_iPPSQpMinus26);
     bs.writeByteAlignment();
     list.serialize(NAL_UNIT_PPS, bs);
 
diff -r d20b78d6d138 -r c785ea65fc84 source/encoder/encoder.h
--- a/source/encoder/encoder.h	Thu Sep 22 15:54:24 2016 +0530
+++ b/source/encoder/encoder.h	Fri Sep 23 16:57:01 2016 +0800
@@ -26,6 +26,7 @@
 
 #include "common.h"
 #include "slice.h"
+#include "threading.h"
 #include "scalinglist.h"
 #include "x265.h"
 #include "nal.h"
@@ -136,6 +137,12 @@
      * one is done. Requires bIntraRefresh to be set.*/
     int                m_bQueuedIntraRefresh;
 
+    /* For optimising slice QP */
+    Lock               m_sliceQpLock;
+    int                m_iFrameNum;
+    int64_t            m_iBitsCostSum[QP_MAX_SPEC + 1];
+    int                m_iPPSQpMinus26;
+
     Encoder();
     ~Encoder() {}
 
diff -r d20b78d6d138 -r c785ea65fc84 source/encoder/entropy.cpp
--- a/source/encoder/entropy.cpp	Thu Sep 22 15:54:24 2016 +0530
+++ b/source/encoder/entropy.cpp	Fri Sep 23 16:57:01 2016 +0800
@@ -324,7 +324,7 @@
     WRITE_FLAG(0, "sps_extension_flag");
 }
 
-void Entropy::codePPS(const PPS& pps, bool filerAcross)
+void Entropy::codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26 )
 {
     WRITE_UVLC(0,                          "pps_pic_parameter_set_id");
     WRITE_UVLC(0,                          "pps_seq_parameter_set_id");
@@ -336,7 +336,7 @@
     WRITE_UVLC(0,                          "num_ref_idx_l0_default_active_minus1");
     WRITE_UVLC(0,                          "num_ref_idx_l1_default_active_minus1");
 
-    WRITE_SVLC(0, "init_qp_minus26");
+    WRITE_SVLC(iPPSInitQpMinus26,         "init_qp_minus26");
     WRITE_FLAG(pps.bConstrainedIntraPred, "constrained_intra_pred_flag");
     WRITE_FLAG(pps.bTransformSkipEnabled, "transform_skip_enabled_flag");
 
@@ -673,7 +673,7 @@
     if (!slice.isIntra())
         WRITE_UVLC(MRG_MAX_NUM_CANDS - slice.m_maxNumMergeCand, "five_minus_max_num_merge_cand");
 
-    int code = sliceQp - 26;
+    int code = sliceQp - (slice.m_iPPSQpMinus26 + 26);
     WRITE_SVLC(code, "slice_qp_delta");
 
     // TODO: Enable when pps_loop_filter_across_slices_enabled_flag==1
diff -r d20b78d6d138 -r c785ea65fc84 source/encoder/entropy.h
--- a/source/encoder/entropy.h	Thu Sep 22 15:54:24 2016 +0530
+++ b/source/encoder/entropy.h	Fri Sep 23 16:57:01 2016 +0800
@@ -142,7 +142,7 @@
 
     void codeVPS(const VPS& vps);
     void codeSPS(const SPS& sps, const ScalingList& scalingList, const ProfileTierLevel& ptl);
-    void codePPS(const PPS& pps, bool filerAcross);
+    void codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26 );
     void codeVUI(const VUI& vui, int maxSubTLayers, bool discardOptionalVUI);
     void codeAUD(const Slice& slice);
     void codeHrdParameters(const HRDInfo& hrd, int maxSubTLayers);
diff -r d20b78d6d138 -r c785ea65fc84 source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp	Thu Sep 22 15:54:24 2016 +0530
+++ b/source/encoder/frameencoder.cpp	Fri Sep 23 16:57:01 2016 +0800
@@ -305,6 +305,19 @@
     weightAnalyse(*frame->m_encData->m_slice, *frame, *master.m_param);
 }
 
+
+uint32_t getBsLength( int32_t code )
+{
+    uint32_t ucode = (code <= 0) ? -code << 1 : (code << 1) - 1;
+
+    ++ucode;
+    unsigned long idx;
+    CLZ( idx, ucode );
+    uint32_t length = (uint32_t)idx * 2 + 1;
+
+    return length;
+}
+
 void FrameEncoder::compressFrame()
 {
     ProfileScopeEvent(frameThread);
@@ -448,6 +461,20 @@
     /* Clip slice QP to 0-51 spec range before encoding */
     slice->m_sliceQp = x265_clip3(-QP_BD_OFFSET, QP_MAX_SPEC, qp);
 
+    if( m_param->bRepeatHeaders )
+    {
+        ScopedLock qpLock( m_top->m_sliceQpLock );
+        for( int i = 0; i < (QP_MAX_SPEC + 1); i++ )
+        {
+            int delta = slice->m_sliceQp - (i + 1);
+            int codeLength = getBsLength( delta );
+
+            m_top->m_iBitsCostSum[i] += codeLength;
+        }
+
+        m_top->m_iFrameNum++;
+    }
+
     m_initSliceContext.resetEntropy(*slice);
 
     m_frameFilter.start(m_frame, m_initSliceContext);
