[x265-commits] [x265] Improved sao implementation by limiting sao types

Ashok Kumar Mishra ashok at multicorewareinc.com
Tue Apr 11 01:03:03 CEST 2017


details:   http://hg.videolan.org/x265/rev/c7b7c736696f
branches:  
changeset: 11735:c7b7c736696f
user:      Ashok Kumar Mishra <ashok at multicorewareinc.com>
date:      Mon Apr 10 11:42:20 2017 +0530
description:
Improved sao implementation by limiting sao types

diffstat:

 doc/reST/cli.rst            |    6 +-
 source/CMakeLists.txt       |    2 +-
 source/common/param.cpp     |    6 +-
 source/encoder/encoder.cpp  |    2 +-
 source/encoder/sao.cpp      |  217 ++++++++++++++++++++++++++-----------------
 source/encoder/sao.h        |    4 +-
 source/test/smoke-tests.txt |    2 +-
 source/x265.h               |   27 ++---
 source/x265cli.h            |    3 +
 9 files changed, 155 insertions(+), 114 deletions(-)

diffs (truncated from 524 to 300 lines):

diff -r 3c26e29120aa -r c7b7c736696f doc/reST/cli.rst
--- a/doc/reST/cli.rst	Wed Feb 22 15:24:25 2017 +0530
+++ b/doc/reST/cli.rst	Mon Apr 10 11:42:20 2017 +0530
@@ -1689,10 +1689,14 @@ Loop filters
 	When enabled, non-deblocked pixels are used for SAO analysis. When
 	disabled, SAO analysis skips the right/bottom boundary areas.
 	Default disabled
+.. option:: --limit-sao, --no-limit-sao
+    Limit SAO filter computation by early terminating SAO process based
+    on inter prediction mode, CTU spatial-domain correlations, and relations
+    between luma and chroma.
+    Default disabled
 
 VUI (Video Usability Information) options
 =========================================
-
 x265 emits a VUI with only the timing info by default. If the SAR is
 specified (or read from a Y4M header) it is also included.  All other
 VUI fields must be manually specified.
diff -r 3c26e29120aa -r c7b7c736696f source/CMakeLists.txt
--- a/source/CMakeLists.txt	Wed Feb 22 15:24:25 2017 +0530
+++ b/source/CMakeLists.txt	Mon Apr 10 11:42:20 2017 +0530
@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CP
 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 113)
+set(X265_BUILD 114)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r 3c26e29120aa -r c7b7c736696f source/common/param.cpp
--- a/source/common/param.cpp	Wed Feb 22 15:24:25 2017 +0530
+++ b/source/common/param.cpp	Mon Apr 10 11:42:20 2017 +0530
@@ -187,7 +187,7 @@ void x265_param_default(x265_param* para
     /* SAO Loop Filter */
     param->bEnableSAO = 1;
     param->bSaoNonDeblocked = 0;
-
+    param->bLimitSAO = 0;
     /* Coding Quality */
     param->cbQpOffset = 0;
     param->crQpOffset = 0;
@@ -272,9 +272,7 @@ void x265_param_default(x265_param* para
     param->bAQMotion = 0;
     param->bHDROpt = 0;
     param->analysisRefineLevel = 5;
-
 }
-
 int x265_param_default_preset(x265_param* param, const char* preset, const char* tune)
 {
 #if EXPORT_C_API
@@ -949,6 +947,7 @@ int x265_param_parse(x265_param* p, cons
         }
         OPT("hdr") p->bEmitHDRSEI = atobool(value);
         OPT("hdr-opt") p->bHDROpt = atobool(value);
+        OPT("limit-sao") p->bLimitSAO = atobool(value);
         else
             return X265_PARAM_BAD_NAME;
     }
@@ -1658,6 +1657,7 @@ char *x265_param2string(x265_param* p, i
     BOOL(p->bEmitHDRSEI, "hdr");
     BOOL(p->bHDROpt, "hdr-opt");
     s += sprintf(s, " refine-level=%d", p->analysisRefineLevel);
+    BOOL(p->bLimitSAO, "limit-sao");
 #undef BOOL
     return buf;
 }
diff -r 3c26e29120aa -r c7b7c736696f source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Wed Feb 22 15:24:25 2017 +0530
+++ b/source/encoder/encoder.cpp	Mon Apr 10 11:42:20 2017 +0530
@@ -2140,7 +2140,7 @@ void Encoder::configure(x265_param *p)
     /* some options make no sense if others are disabled */
     p->bSaoNonDeblocked &= p->bEnableSAO;
     p->bEnableTSkipFast &= p->bEnableTransformSkip;
-
+    p->bLimitSAO &= p->bEnableSAO;
     /* initialize the conformance window */
     m_conformanceWindow.bEnabled = false;
     m_conformanceWindow.rightOffset = 0;
diff -r 3c26e29120aa -r c7b7c736696f source/encoder/sao.cpp
--- a/source/encoder/sao.cpp	Wed Feb 22 15:24:25 2017 +0530
+++ b/source/encoder/sao.cpp	Mon Apr 10 11:42:20 2017 +0530
@@ -734,6 +734,7 @@ void SAO::generateChromaOffsets(SaoCtuPa
 /* Calculate SAO statistics for current CTU without non-crossing slice */
 void SAO::calcSaoStatsCTU(int addr, int plane)
 {
+    Slice* slice = m_frame->m_encData->m_slice;
     const PicYuv* reconPic = m_frame->m_reconPic;
     const CUData* cu = m_frame->m_encData->getPicCTU(addr);
     const pixel* fenc0 = m_frame->m_fencPic->getPlaneAddr(plane, addr);
@@ -857,60 +858,60 @@ void SAO::calcSaoStatsCTU(int addr, int 
 
             primitives.saoCuStatsE1(diff + startY * MAX_CU_SIZE, rec0 + startY * stride, stride, upBuff1, endX, endY - startY, m_offsetOrg[plane][SAO_EO_1], m_count[plane][SAO_EO_1]);
         }
+        if (!m_param->bLimitSAO || ((slice->m_sliceType == P_SLICE && !cu->isSkipped(0)) ||
+            (slice->m_sliceType != B_SLICE)))
+        {
+            // SAO_EO_2: // dir: 135
+            {
+                if (m_param->bSaoNonDeblocked)
+                {
+                    skipB = 4;
+                    skipR = 5;
+                }
 
-        // SAO_EO_2: // dir: 135
-        {
-            if (m_param->bSaoNonDeblocked)
+                fenc = fenc0;
+                rec  = rec0;
+
+                startX = !lpelx;
+                endX   = (rpelx == picWidth) ? ctuWidth - 1 : ctuWidth - skipR + plane_offset;
+
+                startY = bAboveUnavail;
+                endY   = (bpely == picHeight) ? ctuHeight - 1 : ctuHeight - skipB + plane_offset;
+                if (startY)
+                {
+                    fenc += stride;
+                    rec += stride;
+                }
+
+                primitives.sign(upBuff1, &rec[startX], &rec[startX - stride - 1], (endX - startX));
+
+                primitives.saoCuStatsE2(diff + startX + startY * MAX_CU_SIZE, rec0  + startX + startY * stride, stride, upBuff1, upBufft, endX - startX, endY - startY, m_offsetOrg[plane][SAO_EO_2], m_count[plane][SAO_EO_2]);
+            }
+            // SAO_EO_3: // dir: 45
             {
-                skipB = 4;
-                skipR = 5;
+                if (m_param->bSaoNonDeblocked)
+                {
+                    skipB = 4;
+                    skipR = 5;
+                }
+                fenc = fenc0;
+                rec  = rec0;
+                startX = !lpelx;
+                endX   = (rpelx == picWidth) ? ctuWidth - 1 : ctuWidth - skipR + plane_offset;
+
+                startY = bAboveUnavail;
+                endY   = (bpely == picHeight) ? ctuHeight - 1 : ctuHeight - skipB + plane_offset;
+
+                if (startY)
+                {
+                    fenc += stride;
+                    rec += stride;
+                }
+
+                primitives.sign(upBuff1, &rec[startX - 1], &rec[startX - 1 - stride + 1], (endX - startX + 1));
+
+                primitives.saoCuStatsE3(diff + startX + startY * MAX_CU_SIZE, rec0  + startX + startY * stride, stride, upBuff1 + 1, endX - startX, endY - startY, m_offsetOrg[plane][SAO_EO_3], m_count[plane][SAO_EO_3]);
             }
-
-            fenc = fenc0;
-            rec  = rec0;
-
-            startX = !lpelx;
-            endX   = (rpelx == picWidth) ? ctuWidth - 1 : ctuWidth - skipR + plane_offset;
-
-            startY = bAboveUnavail;
-            endY   = (bpely == picHeight) ? ctuHeight - 1 : ctuHeight - skipB + plane_offset;
-            if (startY)
-            {
-                fenc += stride;
-                rec += stride;
-            }
-
-            primitives.sign(upBuff1, &rec[startX], &rec[startX - stride - 1], (endX - startX));
-
-            primitives.saoCuStatsE2(diff + startX + startY * MAX_CU_SIZE, rec0  + startX + startY * stride, stride, upBuff1, upBufft, endX - startX, endY - startY, m_offsetOrg[plane][SAO_EO_2], m_count[plane][SAO_EO_2]);
-        }
-
-        // SAO_EO_3: // dir: 45
-        {
-            if (m_param->bSaoNonDeblocked)
-            {
-                skipB = 4;
-                skipR = 5;
-            }
-
-            fenc = fenc0;
-            rec  = rec0;
-
-            startX = !lpelx;
-            endX   = (rpelx == picWidth) ? ctuWidth - 1 : ctuWidth - skipR + plane_offset;
-
-            startY = bAboveUnavail;
-            endY   = (bpely == picHeight) ? ctuHeight - 1 : ctuHeight - skipB + plane_offset;
-
-            if (startY)
-            {
-                fenc += stride;
-                rec += stride;
-            }
-
-            primitives.sign(upBuff1, &rec[startX - 1], &rec[startX - 1 - stride + 1], (endX - startX + 1));
-
-            primitives.saoCuStatsE3(diff + startX + startY * MAX_CU_SIZE, rec0  + startX + startY * stride, stride, upBuff1 + 1, endX - startX, endY - startY, m_offsetOrg[plane][SAO_EO_3], m_count[plane][SAO_EO_3]);
         }
     }
 }
@@ -1224,10 +1225,8 @@ void SAO::rdoSaoUnitRowEnd(const SAOPara
 void SAO::rdoSaoUnitCu(SAOParam* saoParam, int rowBaseAddr, int idxX, int addr)
 {
     Slice* slice = m_frame->m_encData->m_slice;
-//    int qp = slice->m_sliceQp;
     const CUData* cu = m_frame->m_encData->getPicCTU(addr);
     int qp = cu->m_qp[0];
-
     int64_t lambda[2] = { 0 };
 
     int qpCb = qp + slice->m_pps->chromaQpOffset[0] + slice->m_chromaQpOffset[0];
@@ -1262,18 +1261,6 @@ void SAO::rdoSaoUnitCu(SAOParam* saoPara
 
     for (int i = 0; i < planes; i++)
         saoParam->ctuParam[i][addr].reset();
-
-    if (saoParam->bSaoFlag[0])
-        calcSaoStatsCTU(addr, 0);
-
-    if (saoParam->bSaoFlag[1])
-    {
-        calcSaoStatsCTU(addr, 1);
-        calcSaoStatsCTU(addr, 2);
-    }
-
-    saoStatsInitialOffset(planes);
-
     // SAO distortion calculation
     m_entropyCoder.load(m_rdContexts.cur);
     m_entropyCoder.resetBits();
@@ -1282,15 +1269,44 @@ void SAO::rdoSaoUnitCu(SAOParam* saoPara
     if (allowMerge[1])
         m_entropyCoder.codeSaoMerge(0);
     m_entropyCoder.store(m_rdContexts.temp);
+    memset(m_offset, 0, sizeof(m_offset));
+    int64_t bestCost = 0;
+    int64_t rateDist = 0;
+
+    bool bAboveLeftAvail = true;
+    for (int mergeIdx = 0; mergeIdx < 2; ++mergeIdx)
+    {
+        if (!allowMerge[mergeIdx])
+            continue;
+
+        SaoCtuParam* mergeSrcParam = &(saoParam->ctuParam[0][addrMerge[mergeIdx]]);
+        bAboveLeftAvail = bAboveLeftAvail && (mergeSrcParam->typeIdx == -1);
+    }
+    // Don't apply sao if ctu is skipped or ajacent ctus are sao off
+    bool bSaoOff = (slice->m_sliceType == B_SLICE) && (cu->isSkipped(0) || bAboveLeftAvail);
 
     // Estimate distortion and cost of new SAO params
-    int64_t bestCost = 0;
-    int64_t rateDist = 0;
-    // Estimate distortion and cost of new SAO params
-    saoLumaComponentParamDist(saoParam, addr, rateDist, lambda, bestCost);
-    if (chroma)
-        saoChromaComponentParamDist(saoParam, addr, rateDist, lambda, bestCost);
+    if (saoParam->bSaoFlag[0])
+    {
+        if (!m_param->bLimitSAO || !bSaoOff)
+        {
+            calcSaoStatsCTU(addr, 0);
+            saoStatsInitialOffset(addr, 0);
+            saoLumaComponentParamDist(saoParam, addr, rateDist, lambda, bestCost);
+        }
+    }
 
+    SaoCtuParam* lclCtuParam = &saoParam->ctuParam[0][addr];
+    if (saoParam->bSaoFlag[1])
+    {
+        if (!m_param->bLimitSAO || ((lclCtuParam->typeIdx != -1) && !bSaoOff))
+        {
+            calcSaoStatsCTU(addr, 1);
+            calcSaoStatsCTU(addr, 2);
+            saoStatsInitialOffset(addr, 1);
+            saoChromaComponentParamDist(saoParam, addr, rateDist, lambda, bestCost);
+        }
+    }
     if (saoParam->bSaoFlag[0] || saoParam->bSaoFlag[1])
     {
         // Cost of merge left or Up
@@ -1357,17 +1373,27 @@ void SAO::rdoSaoUnitCu(SAOParam* saoPara
     }
 }
 
-
 // Rounds the division of initial offsets by the number of samples in
 // each of the statistics table entries.
-void SAO::saoStatsInitialOffset(int planes)
+void SAO::saoStatsInitialOffset(int addr, int planes)
 {
-    memset(m_offset, 0, sizeof(m_offset));
+    Slice* slice = m_frame->m_encData->m_slice;
+    const CUData* cu = m_frame->m_encData->getPicCTU(addr);
 
+    int maxSaoType;


More information about the x265-commits mailing list