[x265] [PATCH 2 of 3] cuDeltaQP: raise QP of CUs that are far off the meanQP to minimize deltaQP fluctuations

kavitha at multicorewareinc.com kavitha at multicorewareinc.com
Thu Dec 22 10:59:19 CET 2016


# HG changeset patch
# User Kavitha Sampath <kavitha at multicorewareinc.com>
# Date 1482058180 -19800
#      Sun Dec 18 16:19:40 2016 +0530
# Node ID f1b91c4f65a3a5069d326d422134080a5484d540
# Parent  62f0c309ca7057dcdc3e604f74fad58ff885c740
cuDeltaQP: raise QP of CUs that are far off the meanQP to minimize deltaQP fluctuations

diff -r 62f0c309ca70 -r f1b91c4f65a3 source/common/cudata.h
--- a/source/common/cudata.h	Wed Dec 21 15:46:09 2016 +0530
+++ b/source/common/cudata.h	Sun Dec 18 16:19:40 2016 +0530
@@ -216,6 +216,7 @@
     const CUData* m_cuAboveRight;     // pointer to above-right neighbor CTU
     const CUData* m_cuAbove;          // pointer to above neighbor CTU
     const CUData* m_cuLeft;           // pointer to left neighbor CTU
+    double m_meanQP;
 
     CUData();
 
diff -r 62f0c309ca70 -r f1b91c4f65a3 source/encoder/analysis.cpp
--- a/source/encoder/analysis.cpp	Wed Dec 21 15:46:09 2016 +0530
+++ b/source/encoder/analysis.cpp	Sun Dec 18 16:19:40 2016 +0530
@@ -142,6 +142,7 @@
     ctu.setQPSubParts((int8_t)qp, 0, 0);
 
     m_rqt[0].cur.load(initialContext);
+    ctu.m_meanQP = initialContext.m_meanQP;
     m_modeDepth[0].fencYuv.copyFromPicYuv(*m_frame->m_fencPic, ctu.m_cuAddr, 0);
 
     uint32_t numPartition = ctu.m_numPartitions;
@@ -197,7 +198,7 @@
             compressInterCU_rd5_6(ctu, cuGeom, qp);
     }
 
-    if (m_param->bEnableRdRefine)
+    if (m_param->bEnableRdRefine || m_param->bOptCUDeltaQP)
         qprdRefine(ctu, cuGeom, qp, qp);
 
     return *m_modeDepth[0].bestMode;
@@ -299,8 +300,13 @@
         int cuIdx = (cuGeom.childOffset - 1) / 3;
         bestCUCost = origCUCost = cacheCost[cuIdx];
 
-        for (int dir = 2; dir >= -2; dir -= 4)
+        int direction = m_param->bOptCUDeltaQP ? 1 : 2;
+
+        for (int dir = direction; dir >= -direction; dir -= (direction * 2))
         {
+            if (m_param->bOptCUDeltaQP && ((dir != 1) || ((qp + 3) >= (int32_t)parentCTU.m_meanQP)))
+                break;
+
             int threshold = 1;
             int failure = 0;
             cuPrevCost = origCUCost;
@@ -308,6 +314,9 @@
             int modCUQP = qp + dir;
             while (modCUQP >= m_param->rc.qpMin && modCUQP <= QP_MAX_SPEC)
             {
+                if (m_param->bOptCUDeltaQP && modCUQP > (int32_t)parentCTU.m_meanQP)
+                    break;
+
                 recodeCU(parentCTU, cuGeom, modCUQP, qp);
                 cuCost = md.bestMode->rdCost;
 
diff -r 62f0c309ca70 -r f1b91c4f65a3 source/encoder/entropy.cpp
--- a/source/encoder/entropy.cpp	Wed Dec 21 15:46:09 2016 +0530
+++ b/source/encoder/entropy.cpp	Sun Dec 18 16:19:40 2016 +0530
@@ -226,6 +226,7 @@
     markValid();
     m_fracBits = 0;
     m_pad = 0;
+    m_meanQP = 0;
     X265_CHECK(sizeof(m_contextState) >= sizeof(m_contextState[0]) * MAX_OFF_CTX_MOD, "context state table is too small\n");
 }
 
diff -r 62f0c309ca70 -r f1b91c4f65a3 source/encoder/entropy.h
--- a/source/encoder/entropy.h	Wed Dec 21 15:46:09 2016 +0530
+++ b/source/encoder/entropy.h	Sun Dec 18 16:19:40 2016 +0530
@@ -111,6 +111,7 @@
     int           m_bitsLeft;
     uint64_t      m_fracBits;
     EstBitsSbac   m_estBitsSbac;
+    double        m_meanQP;
 
     Entropy();
 
diff -r 62f0c309ca70 -r f1b91c4f65a3 source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp	Wed Dec 21 15:46:09 2016 +0530
+++ b/source/encoder/frameencoder.cpp	Sun Dec 18 16:19:40 2016 +0530
@@ -1182,6 +1182,65 @@
         //m_rows[row - 1].bufferedEntropy.loadContexts(m_initSliceContext);
     }
 
+    // calculate mean QP for consistent deltaQP signalling calculation
+    if (m_param->bOptCUDeltaQP)
+    {
+        ScopedLock self(curRow.lock);
+        if (!curRow.avgQPComputed)
+        {
+            if (m_param->bEnableWavefront || !row)
+            {
+                double meanQPOff = 0;
+                uint32_t loopIncr, count = 0;
+                bool isReferenced = IS_REFERENCED(m_frame);
+                double *qpoffs = (isReferenced && m_param->rc.cuTree) ? m_frame->m_lowres.qpCuTreeOffset : m_frame->m_lowres.qpAqOffset;
+                if (qpoffs)
+                {
+                    if (m_param->rc.qgSize == 8)
+                        loopIncr = 8;
+                    else
+                        loopIncr = 16;
+                    uint32_t cuYStart = 0, height = m_frame->m_fencPic->m_picHeight;
+                    if (m_param->bEnableWavefront)
+                    {
+                        cuYStart = intRow * m_param->maxCUSize;
+                        height = cuYStart + m_param->maxCUSize;
+                    }
+
+                    uint32_t qgSize = m_param->rc.qgSize, width = m_frame->m_fencPic->m_picWidth;
+                    uint32_t maxOffsetCols = (m_frame->m_fencPic->m_picWidth + (loopIncr - 1)) / loopIncr;
+                    for (uint32_t cuY = cuYStart; cuY < height && (cuY < m_frame->m_fencPic->m_picHeight); cuY += qgSize)
+                    {
+                        for (uint32_t cuX = 0; cuX < width; cuX += qgSize)
+                        {
+                            double qp_offset = 0;
+                            uint32_t cnt = 0;
+
+                            for (uint32_t block_yy = cuY; block_yy < cuY + qgSize && block_yy < m_frame->m_fencPic->m_picHeight; block_yy += loopIncr)
+                            {
+                                for (uint32_t block_xx = cuX; block_xx < cuX + qgSize && block_xx < width; block_xx += loopIncr)
+                                {
+                                    int idx = ((block_yy / loopIncr) * (maxOffsetCols)) + (block_xx / loopIncr);
+                                    qp_offset += qpoffs[idx];
+                                    cnt++;
+                                }
+                            }
+                            qp_offset /= cnt;
+                            meanQPOff += qp_offset;
+                            count++;
+                        }
+                    }
+                    meanQPOff /= count;
+                }
+                rowCoder.m_meanQP = slice->m_sliceQp + meanQPOff;
+            }
+            else
+            {
+                rowCoder.m_meanQP = m_rows[0].rowGoOnCoder.m_meanQP;
+            }
+            curRow.avgQPComputed = 1;
+        }
+    }
 
     // TODO: specially case handle on first and last row
 
diff -r 62f0c309ca70 -r f1b91c4f65a3 source/encoder/frameencoder.h
--- a/source/encoder/frameencoder.h	Wed Dec 21 15:46:09 2016 +0530
+++ b/source/encoder/frameencoder.h	Sun Dec 18 16:19:40 2016 +0530
@@ -95,6 +95,7 @@
 
     /* count of completed CUs in this row */
     volatile uint32_t completed;
+    volatile uint32_t avgQPComputed;
 
     /* called at the start of each frame to initialize state */
     void init(Entropy& initContext, unsigned int sid)
@@ -102,6 +103,7 @@
         active = false;
         busy = false;
         completed = 0;
+        avgQPComputed = 0;
         sliceId = sid;
         memset(&rowStats, 0, sizeof(rowStats));
         rowGoOnCoder.load(initContext);


More information about the x265-devel mailing list