<div dir="ltr"><br clear="all"><div>From 775cdc266297f390dab0256a5efa60c3781a3b0d Mon Sep 17 00:00:00 2001<br>From: Niranjan Kumar <<a href="mailto:niranjan@multicorewareinc.com">niranjan@multicorewareinc.com</a>><br>Date: Wed, 21 Oct 2020 19:18:14 +0530<br>Subject: [PATCH] Add: Forward and Backward masking<br><br>Enables scenecut-aware-qp in a specified direction<br>0 - Disabled<br>1 - Forward masking<br>2 - Backward masking<br>3 - Bi-directional masking<br>---<br> doc/reST/cli.rst                   | 95 +++++++++++++++++++++---------<br> source/CMakeLists.txt              |  2 +-<br> source/common/param.cpp            | 90 ++++++++++++++++++++++------<br> source/encoder/encoder.cpp         |  8 +--<br> source/encoder/ratecontrol.cpp     | 68 +++++++++++++++------<br> source/encoder/ratecontrol.h       |  3 +-<br> source/test/rate-control-tests.txt |  4 +-<br> source/x265.h                      | 32 +++++++---<br> source/x265cli.cpp                 | 10 ++--<br> source/x265cli.h                   |  7 +--<br> 10 files changed, 229 insertions(+), 90 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index 1a1de9f50..e6acc7785 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -1963,37 +1963,76 @@ Quality, rate control and rate distortion options<br>  <br>     **CLI ONLY**<br> <br>-.. option:: --scenecut-aware-qp, --no-scenecut-aware-qp<br>-   <br>-   It reduces the bits spent on the inter-frames within the :option:`--scenecut-window`<br>-   before and after a scenecut by increasing their QP in ratecontrol pass2 algorithm<br>-   without any deterioration in visual quality. If a scenecut falls within the window,<br>-   the QP of the inter-frames after this scenecut will not be modified. <br>-   :option:`--scenecut-aware-qp` works only with --pass 2. Default disabled.<br>-   <br>-.. option:: --scenecut-window <integer><br>+.. option:: --scenecut-aware-qp <integer><br> <br>-   The duration(in milliseconds) for which there is a reduction in the bits spent<br>-   on the inter-frames after a scenecut by increasing their QP, when<br>-   :option:`--scenecut-aware-qp` is enabled. Default 500ms.<br>-   <br>-   **Range of values:** 0 to 1000<br>-   <br>-.. option:: --qp-delta-ref <double><br>-<br>-   The offset by which QP is incremented for inter-frames<br>-   when :option:`--scenecut-aware-qp` is enabled. Default 5.<br>-   <br>-   **Range of values:**  0 to 10<br>-   <br>-.. option:: --qp-delta-nonref <double><br>+ It reduces the bits spent on the inter-frames within the scenecut window<br>+     before and after a scenecut by increasing their QP in ratecontrol pass2 algorithm<br>+    without any deterioration in visual quality. If a scenecut falls within the window,<br>+  the QP of the inter-frames after this scenecut will not be modified.<br>+ :option:`--scenecut-aware-qp` works only with --pass 2. Default 0.<br> <br>-   The offset by which QP is incremented for non-referenced<br>-   inter-frames when :option:`--scenecut-aware-qp` is enabled.<br>-   The offset is computed from :option:`--qp-delta-ref` when it<br>-   is not explicitly specified.<br>+        +-------+---------------------------------------------------------------+<br>+    | Mode  | Description                                                   |<br>+  +=======+===============================================================+<br>+    | 0     | Disabled.                                                     |<br>+        +-------+---------------------------------------------------------------+<br>+    | 1     | Forward masking.                                              |<br>+   |       | Applies QP modification for frames after the scenecut.        |<br>+     +-------+---------------------------------------------------------------+<br>+    | 2     | Backward masking.                                             |<br>+    |       | Applies QP modification for frames before the scenecut.       |<br>+      +-------+---------------------------------------------------------------+<br>+    | 3     | Bi-directional masking.                                       |<br>+       |       | Applies QP modification for frames before and after           |<br>+    |       | the scenecut.                                                 |<br>+ +-------+---------------------------------------------------------------+<br> <br>-   **Range of values:**  0 to 10<br>+.. option:: --masking-strength <string><br>+<br>+        Comma separated list of values which specifies the duration and offset<br>+       for the QP increment for inter-frames when :option:`--scenecut-aware-qp`<br>+     is enabled.<br>+<br>+       When :option:`--scenecut-aware-qp` is::<br>+      * 1 (Forward masking):<br>+       --masking-strength <fwdWindow,fwdRefQPDelta,fwdNonRefQPDelta><br>+  * 2 (Backward masking):<br>+      --masking-strength <bwdWindow,bwdRefQPDelta,bwdNonRefQPDelta><br>+  * 3 (Bi-directional masking):<br>+        --masking-strength <fwdWindow,fwdRefQPDelta,fwdNonRefQPDelta,bwdWindow,bwdRefQPDelta,bwdNonRefQPDelta><br>+<br>+      +-----------------+---------------------------------------------------------------+<br>+  | Parameter       | Description                                                   |<br>+      +=================+===============================================================+<br>+  | fwdWindow       | The duration(in milliseconds) for which there is a reduction  |<br>+      |                 | in the bits spent on the inter-frames after a scenecut by     |<br>+        |                 | increasing their QP. Default 500ms.                           |<br>+     |                 | **Range of values:** 0 to 1000                                |<br>+  +-----------------+---------------------------------------------------------------+<br>+  | fwdRefQPDelta   | The offset by which QP is incremented for inter-frames        |<br>+     |                 | after a scenecut. Default 5.                                  |<br>+ |                 | **Range of values:** 0 to 10                                  |<br>+ +-----------------+---------------------------------------------------------------+<br>+  | fwdNonRefQPDelta| The offset by which QP is incremented for non-referenced      |<br>+       |                 | inter-frames after a scenecut. The offset is computed from    |<br>+        |                 | fwdRefQPDelta when it is not explicitly specified.            |<br>+    |                 | **Range of values:** 0 to 10                                  |<br>+ +-----------------+---------------------------------------------------------------+<br>+  | bwdWindow       | The duration(in milliseconds) for which there is a reduction  |<br>+      |                 | in the bits spent on the inter-frames before a scenecut by    |<br>+        |                 | increasing their QP. Default 100ms.                           |<br>+     |                 | **Range of values:** 0 to 1000                                |<br>+  +-----------------+---------------------------------------------------------------+<br>+  | bwdRefQPDelta   | The offset by which QP is incremented for inter-frames        |<br>+     |                 | before a scenecut. The offset is computed from                |<br>+  |                 | fwdRefQPDelta when it is not explicitly specified.            |<br>+    |                 | **Range of values:** 0 to 10                                  |<br>+ +-----------------+---------------------------------------------------------------+<br>+  | bwdNonRefQPDelta| The offset by which QP is incremented for non-referenced      |<br>+       |                 | inter-frames before a scenecut. The offset is computed from   |<br>+ |                 | bwdRefQPDelta when it is not explicitly specified.            |<br>+    |                 | **Range of values:** 0 to 10                                  |<br>+ +-----------------+---------------------------------------------------------------+<br> <br> .. option:: --vbv-live-multi-pass, --no-vbv-live-multi-pass<br> <br>diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt<br>index 67e737512..48ca4af7c 100755<br>--- a/source/CMakeLists.txt<br>+++ b/source/CMakeLists.txt<br>@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)<br> option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br> # X265_BUILD must be incremented each time the public API is changed<br>-set(X265_BUILD 198)<br>+set(X265_BUILD 199)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in">x265.def.in</a>"<br>                "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in">x265_config.h.in</a>"<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index 47a7a7c47..7a9be18c3 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -179,9 +179,12 @@ void x265_param_default(x265_param* param)<br>     param->bEnableHRDConcatFlag = 0;<br>     param->bEnableFades = 0;<br>     param->bEnableSceneCutAwareQp = 0;<br>-    param->scenecutWindow = 500;<br>-    param->refQpDelta = 5;<br>-    param->nonRefQpDelta = param->refQpDelta + (SLICE_TYPE_DELTA * param->refQpDelta);<br>+    param->fwdScenecutWindow = 500;<br>+    param->fwdRefQpDelta = 5;<br>+    param->fwdNonRefQpDelta = param->fwdRefQpDelta + (SLICE_TYPE_DELTA * param->fwdRefQpDelta);<br>+    param->bwdScenecutWindow = 100;<br>+    param->bwdRefQpDelta = -1;<br>+    param->bwdNonRefQpDelta = -1;<br> <br>     /* Intra Coding Tools */<br>     param->bEnableConstrainedIntra = 0;<br>@@ -1344,10 +1347,51 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br>             p->selectiveSAO = atoi(value);<br>         }<br>         OPT("fades") p->bEnableFades = atobool(value);<br>-        OPT("scenecut-aware-qp") p->bEnableSceneCutAwareQp = atobool(value);<br>-        OPT("scenecut-window") p->scenecutWindow = atoi(value);<br>-        OPT("qp-delta-ref") p->refQpDelta = atoi(value);<br>-        OPT("qp-delta-nonref") p->nonRefQpDelta = atoi(value);<br>+        OPT("scenecut-aware-qp") p->bEnableSceneCutAwareQp = atoi(value);<br>+        OPT("masking-strength")<br>+        {<br>+            int window1;<br>+            double refQpDelta1, nonRefQpDelta1;<br>+<br>+            if (p->bEnableSceneCutAwareQp == FORWARD)<br>+            {<br>+                sscanf(value, "%d,%lf,%lf", &window1, &refQpDelta1, &nonRefQpDelta1);<br>+                if (window1 > 0)<br>+                    p->fwdScenecutWindow = window1;<br>+                if (refQpDelta1 > 0)<br>+                    p->fwdRefQpDelta = refQpDelta1;<br>+                if (nonRefQpDelta1 > 0)<br>+                    p->fwdNonRefQpDelta = nonRefQpDelta1;<br>+            }<br>+            else if (p->bEnableSceneCutAwareQp == BACKWARD)<br>+            {<br>+                sscanf(value, "%d,%lf,%lf", &window1, &refQpDelta1, &nonRefQpDelta1);<br>+                if (window1 > 0)<br>+                    p->bwdScenecutWindow = window1;<br>+                if (refQpDelta1 > 0)<br>+                    p->bwdRefQpDelta = refQpDelta1;<br>+                if (nonRefQpDelta1 > 0)<br>+                    p->bwdNonRefQpDelta = nonRefQpDelta1;<br>+            }<br>+            else if (p->bEnableSceneCutAwareQp == BI_DIRECTIONAL)<br>+            {<br>+                int window2;<br>+                double refQpDelta2, nonRefQpDelta2;<br>+                sscanf(value, "%d,%lf,%lf,%d,%lf,%lf", &window1, &refQpDelta1, &nonRefQpDelta1, &window2, &refQpDelta2, &nonRefQpDelta2);<br>+                if (window1 > 0)<br>+                    p->fwdScenecutWindow = window1;<br>+                if (refQpDelta1 > 0)<br>+                    p->fwdRefQpDelta = refQpDelta1;<br>+                if (nonRefQpDelta1 > 0)<br>+                    p->fwdNonRefQpDelta = nonRefQpDelta1;<br>+                if (window2 > 0)<br>+                    p->bwdScenecutWindow = window2;<br>+                if (refQpDelta2 > 0)<br>+                    p->bwdRefQpDelta = refQpDelta2;<br>+                if (nonRefQpDelta2 > 0)<br>+                    p->bwdNonRefQpDelta = nonRefQpDelta2;<br>+            }<br>+        }<br>         OPT("field") p->bField = atobool( value );<br>         OPT("cll") p->bEmitCLL = atobool(value);<br>         OPT("frame-dup") p->bEnableFrameDuplication = atobool(value);<br>@@ -1787,12 +1831,19 @@ int x265_check_params(x265_param* param)<br>         }<br>         else<br>         {<br>-            CHECK(param->scenecutWindow < 0 || param->scenecutWindow > 1000,<br>-            "Invalid scenecut Window duration. Value must be between 0 and 1000(inclusive)");<br>-            CHECK(param->refQpDelta < 0 || param->refQpDelta > 10,<br>-            "Invalid refQpDelta value. Value must be between 0 and 10 (inclusive)");<br>-            CHECK(param->nonRefQpDelta < 0 || param->nonRefQpDelta > 10,<br>-            "Invalid nonRefQpDelta value. Value must be between 0 and 10 (inclusive)");<br>+            CHECK(param->fwdScenecutWindow < 0 || param->fwdScenecutWindow > 1000,<br>+            "Invalid forward scenecut Window duration. Value must be between 0 and 1000(inclusive)");<br>+            CHECK(param->fwdRefQpDelta < 0 || param->fwdRefQpDelta > 10,<br>+            "Invalid fwdRefQpDelta value. Value must be between 0 and 10 (inclusive)");<br>+            CHECK(param->fwdNonRefQpDelta < 0 || param->fwdNonRefQpDelta > 10,<br>+            "Invalid fwdNonRefQpDelta value. Value must be between 0 and 10 (inclusive)");<br>+<br>+            CHECK(param->bwdScenecutWindow < 0 || param->bwdScenecutWindow > 1000,<br>+                "Invalid backward scenecut Window duration. Value must be between 0 and 1000(inclusive)");<br>+            CHECK(param->bwdRefQpDelta < -1 || param->bwdRefQpDelta > 10,<br>+                "Invalid bwdRefQpDelta value. Value must be between 0 and 10 (inclusive)");<br>+            CHECK(param->bwdNonRefQpDelta < -1 || param->bwdNonRefQpDelta > 10,<br>+                "Invalid bwdNonRefQpDelta value. Value must be between 0 and 10 (inclusive)");<br>         }<br>     }<br>     if (param->bEnableHME)<br>@@ -2252,9 +2303,9 @@ char *x265_param2string(x265_param* p, int padx, int pady)<br>     BOOL(p->bEnableSvtHevc, "svt");<br>     BOOL(p->bField, "field");<br>     s += sprintf(s, " qp-adaptation-range=%.2f", p->rc.qpAdaptationRange);<br>-    BOOL(p->bEnableSceneCutAwareQp, "scenecut-aware-qp");<br>+    s += sprintf(s, " scenecut-aware-qp=%d", p->bEnableSceneCutAwareQp);<br>     if (p->bEnableSceneCutAwareQp)<br>-        s += sprintf(s, " scenecut-window=%d qp-delta-ref=%f qp-delta-nonref=%f", p->scenecutWindow, p->refQpDelta, p->nonRefQpDelta);<br>+        s += sprintf(s, " fwd-scenecut-window=%d fwd-ref-qp-delta=%f fwd-nonref-qp-delta=%f bwd-scenecut-window=%d bwd-ref-qp-delta=%f bwd-nonref-qp-delta=%f", p->fwdScenecutWindow, p->fwdRefQpDelta, p->fwdNonRefQpDelta, p->bwdScenecutWindow, p->bwdRefQpDelta, p->bwdNonRefQpDelta);<br>     s += sprintf(s, "conformance-window-offsets right=%d bottom=%d", p->confWinRightOffset, p->confWinBottomOffset);<br>     s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate);<br>     BOOL(p->bliveVBV2pass, "vbv-live-multi-pass");<br>@@ -2608,9 +2659,12 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br>     dst->bEnableSvtHevc = src->bEnableSvtHevc;<br>     dst->bEnableFades = src->bEnableFades;<br>     dst->bEnableSceneCutAwareQp = src->bEnableSceneCutAwareQp;<br>-    dst->scenecutWindow = src->scenecutWindow;<br>-    dst->refQpDelta = src->refQpDelta;<br>-    dst->nonRefQpDelta = src->nonRefQpDelta;<br>+    dst->fwdScenecutWindow = src->fwdScenecutWindow;<br>+    dst->fwdRefQpDelta = src->fwdRefQpDelta;<br>+    dst->fwdNonRefQpDelta = src->fwdNonRefQpDelta;<br>+    dst->bwdScenecutWindow = src->bwdScenecutWindow;<br>+    dst->bwdRefQpDelta = src->bwdRefQpDelta;<br>+    dst->bwdNonRefQpDelta = src->bwdNonRefQpDelta;<br>     dst->bField = src->bField;<br> <br>     dst->confWinRightOffset = src->confWinRightOffset;<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 1f710e1ce..18c3b6788 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -1810,13 +1810,13 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                 inFrame->m_lowres.m_bIsHardScenecut = isHardSC;<br>         }<br> <br>-        if (m_param->bEnableSceneCutAwareQp && m_param->rc.bStatRead)<br>+        if ((m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL || m_param->bEnableSceneCutAwareQp == BACKWARD) && m_param->rc.bStatRead)<br>         {<br>             RateControlEntry * rcEntry = NULL;<br>             rcEntry = &(m_rateControl->m_rce2Pass[inFrame->m_poc]);<br>             if(rcEntry->scenecut)<br>             {<br>-                int backwardWindow = X265_MIN(int((p->fpsNum / p->fpsDenom) / 10), p->lookaheadDepth);<br>+                int backwardWindow = X265_MIN(int((m_param->bwdScenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom)), p->lookaheadDepth);<br>                 for (int i = 1; i <= backwardWindow; i++)<br>                 {<br>                     int frameNum = inFrame->m_poc - i;<br>@@ -2242,7 +2242,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>             frameEnc = m_lookahead->getDecidedPicture();<br>         if (frameEnc && !pass && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd)))<br>         {<br>-            if (m_param->bEnableSceneCutAwareQp && m_param->rc.bStatRead)<br>+            if ((m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL || m_param->bEnableSceneCutAwareQp == FORWARD) && m_param->rc.bStatRead)<br>             {<br>                 RateControlEntry * rcEntry;<br>                 rcEntry = &(m_rateControl->m_rce2Pass[frameEnc->m_poc]);<br>@@ -2253,7 +2253,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                         m_rateControl->m_lastScenecut = frameEnc->m_poc;<br>                     else<br>                     {<br>-                        int maxWindowSize = int((m_param->scenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5);<br>+                        int maxWindowSize = int((m_param->fwdScenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5);<br>                         if (frameEnc->m_poc > (m_rateControl->m_lastScenecut + maxWindowSize))<br>                             m_rateControl->m_lastScenecut = frameEnc->m_poc;<br>                     }<br>diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp<br>index 4e7d52419..554acfe38 100644<br>--- a/source/encoder/ratecontrol.cpp<br>+++ b/source/encoder/ratecontrol.cpp<br>@@ -1858,7 +1858,10 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>         {<br>             double lqmin = m_lmin[m_sliceType];<br>             double lqmax = m_lmax[m_sliceType];<br>-            qScale = scenecutAwareMasking(curFrame, qScale);<br>+            if (m_param->bEnableSceneCutAwareQp == FORWARD || m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)<br>+                qScale = forwardMasking(curFrame, qScale);<br>+            else if (m_param->bEnableSceneCutAwareQp == BACKWARD || m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)<br>+                qScale = backwardMasking(curFrame, qScale);<br>             qScale = x265_clip3(lqmin, lqmax, qScale);<br>             q = x265_qScale2qp(qScale);<br>             rce->qpNoVbv = q;<br>@@ -1981,7 +1984,12 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>             {<br>                 double qmin = m_lmin[m_sliceType];<br>                 double qmax = m_lmax[m_sliceType];<br>-                q = scenecutAwareMasking(curFrame, q);<br>+<br>+                if (m_param->bEnableSceneCutAwareQp == FORWARD || m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)<br>+                    q = forwardMasking(curFrame, q);<br>+                else if (m_param->bEnableSceneCutAwareQp == BACKWARD || m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)<br>+                    q = backwardMasking(curFrame, q);<br>+<br>                 q = x265_clip3(qmin, qmax, q);<br>                 rce->qpNoVbv = x265_qScale2qp(q);<br>             }<br>@@ -2145,7 +2153,12 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>             {<br>                 double qmin = m_lmin[m_sliceType];<br>                 double qmax = m_lmax[m_sliceType];<br>-                q = scenecutAwareMasking(curFrame, q);<br>+<br>+                if (m_param->bEnableSceneCutAwareQp == FORWARD || m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)<br>+                    q = forwardMasking(curFrame, q);<br>+                else if (m_param->bEnableSceneCutAwareQp == BACKWARD || m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)<br>+                    q = backwardMasking(curFrame, q);<br>+<br>                 q = x265_clip3(qmin, qmax, q);<br>                 rce->qpNoVbv = x265_qScale2qp(q);<br>             }<br>@@ -3168,18 +3181,20 @@ void RateControl::splitbUsed(char bused[], RateControlEntry *rce)<br>     }<br> }<br> <br>-double RateControl::scenecutAwareMasking(Frame* curFrame, double q)<br>+double RateControl::forwardMasking(Frame* curFrame, double q)<br> {<br>     double qp = x265_qScale2qp(q);<br>-    uint32_t maxWindowSize = uint32_t((m_param->scenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5);<br>+    uint32_t maxWindowSize = uint32_t((m_param->fwdScenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5);<br>     uint32_t windowSize = maxWindowSize / 3;<br>     int lastScenecut = m_top->m_rateControl->m_lastScenecut;<br>     int lastIFrame = m_top->m_rateControl->m_lastScenecutAwareIFrame;<br>-    double refQpDelta = double(m_param->refQpDelta);<br>-    double nonRefQpDelta = double(m_param->nonRefQpDelta);<br>-    double sliceTypeDelta = SLICE_TYPE_DELTA * refQpDelta;<br>-    double window2Delta = WINDOW2_DELTA * refQpDelta;<br>-    double window3Delta = WINDOW3_DELTA * refQpDelta;<br>+    double fwdRefQpDelta = double(m_param->fwdRefQpDelta);<br>+    double fwdNonRefQpDelta = double(m_param->fwdNonRefQpDelta);<br>+    double bwdRefQpDelta = double(m_param->bwdRefQpDelta);<br>+    double bwdNonRefQpDelta = double(m_param->bwdNonRefQpDelta);<br>+    double sliceTypeDelta = SLICE_TYPE_DELTA * fwdRefQpDelta;<br>+    double window2Delta = WINDOW2_DELTA * fwdRefQpDelta;<br>+    double window3Delta = WINDOW3_DELTA * fwdRefQpDelta;<br> <br>     if (curFrame->m_poc > lastScenecut && curFrame->m_poc <= (lastScenecut + int(maxWindowSize)))<br>         curFrame->m_isInsideWindow = FORWARD_WINDOW;<br>@@ -3194,7 +3209,7 @@ double RateControl::scenecutAwareMasking(Frame* curFrame, double q)<br>             if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut + int(maxWindowSize))<br>                 && curFrame->m_poc >= lastIFrame))<br>             {<br>-                qp += refQpDelta - sliceTypeDelta;<br>+                qp += fwdRefQpDelta - sliceTypeDelta;<br>                 if (((curFrame->m_poc) > (lastScenecut + int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize))))<br>                     qp -= window2Delta;<br>                 else if (curFrame->m_poc > lastScenecut + 2 * int(windowSize))<br>@@ -3206,7 +3221,7 @@ double RateControl::scenecutAwareMasking(Frame* curFrame, double q)<br>             if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut + int(maxWindowSize))<br>                 && curFrame->m_poc >= lastIFrame))<br>             {<br>-                qp += refQpDelta;<br>+                qp += fwdRefQpDelta;<br>                 if (((curFrame->m_poc) > (lastScenecut + int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize))))<br>                     qp -= window2Delta;<br>                 else if (curFrame->m_poc > lastScenecut + 2 * int(windowSize))<br>@@ -3218,7 +3233,7 @@ double RateControl::scenecutAwareMasking(Frame* curFrame, double q)<br>             if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut + int(maxWindowSize))<br>                 && curFrame->m_poc >= lastIFrame))<br>             {<br>-                qp += nonRefQpDelta;<br>+                qp += fwdNonRefQpDelta;<br>                 if (((curFrame->m_poc) > (lastScenecut + int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize))))<br>                     qp -= window2Delta;<br>                 else if (curFrame->m_poc > lastScenecut + 2 * int(windowSize))<br>@@ -3226,16 +3241,31 @@ double RateControl::scenecutAwareMasking(Frame* curFrame, double q)<br>             }<br>         }<br>     }<br>-    else if (curFrame->m_isInsideWindow == BACKWARD_WINDOW)<br>+<br>+    return x265_qp2qScale(qp);<br>+}<br>+double RateControl::backwardMasking(Frame* curFrame, double q)<br>+{<br>+    double qp = x265_qScale2qp(q);<br>+    double fwdRefQpDelta = double(m_param->fwdRefQpDelta);<br>+    double window3Delta = WINDOW3_DELTA * fwdRefQpDelta;<br>+    double bwdRefQpDelta = double(m_param->bwdRefQpDelta);<br>+    double bwdNonRefQpDelta = double(m_param->bwdNonRefQpDelta);<br>+<br>+    if (curFrame->m_isInsideWindow == BACKWARD_WINDOW)<br>     {<br>-        refQpDelta -= window3Delta;<br>-        nonRefQpDelta -= window3Delta;<br>+        if (bwdRefQpDelta < 0)<br>+            bwdRefQpDelta = fwdRefQpDelta - window3Delta;<br>+        double sliceTypeDelta = SLICE_TYPE_DELTA * bwdRefQpDelta;<br>+        if (bwdNonRefQpDelta < 0)<br>+            bwdNonRefQpDelta = bwdRefQpDelta + sliceTypeDelta;<br>+<br>         if (curFrame->m_lowres.sliceType == X265_TYPE_P)<br>-            qp += refQpDelta - sliceTypeDelta;<br>+            qp += bwdRefQpDelta - sliceTypeDelta;<br>         else if (curFrame->m_lowres.sliceType == X265_TYPE_BREF)<br>-            qp += refQpDelta;<br>+            qp += bwdRefQpDelta;<br>         else if (curFrame->m_lowres.sliceType == X265_TYPE_B)<br>-            qp += nonRefQpDelta;<br>+            qp += bwdNonRefQpDelta;<br>     }<br> <br>     return x265_qp2qScale(qp);<br>diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h<br>index 809e0c620..41bbddcf2 100644<br>--- a/source/encoder/ratecontrol.h<br>+++ b/source/encoder/ratecontrol.h<br>@@ -269,7 +269,8 @@ public:<br>     int writeRateControlFrameStats(Frame* curFrame, RateControlEntry* rce);<br>     bool   initPass2();<br> <br>-    double scenecutAwareMasking(Frame* curFrame, double q);<br>+    double forwardMasking(Frame* curFrame, double q);<br>+    double backwardMasking(Frame* curFrame, double q);<br> <br> protected:<br> <br>diff --git a/source/test/rate-control-tests.txt b/source/test/rate-control-tests.txt<br>index eed92f809..6c8f10cb6 100644<br>--- a/source/test/rate-control-tests.txt<br>+++ b/source/test/rate-control-tests.txt<br>@@ -44,8 +44,8 @@ CrowdRun_1920x1080_50_10bit_422.yuv,--preset superfast --bitrate 2500 --pass 1 -<br> RaceHorses_416x240_30_10bit.yuv,--preset medium --crf 26 --vbv-maxrate 1000 --vbv-bufsize 1000 --pass 1::--preset fast --bitrate 1000  --vbv-maxrate 1000 --vbv-bufsize 700 --pass 3 -F4::--preset slow --bitrate 500 --vbv-maxrate 500  --vbv-bufsize 700 --pass 2 -F4<br> sita_1920x1080_30.yuv, --preset ultrafast --crf 20 --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 1 --vbv-bufsize 7000 --vbv-maxrate 5000:: --preset ultrafast --crf 20 --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 2 --vbv-bufsize 7000 --vbv-maxrate 5000 --repeat-headers<br> sita_1920x1080_30.yuv, --preset medium --crf 20 --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 1 --vbv-bufsize 7000 --vbv-maxrate 5000 --repeat-headers --multi-pass-opt-rps:: --preset medium --crf 20 --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 2 --vbv-bufsize 7000 --vbv-maxrate 5000 --repeat-headers --multi-pass-opt-rps<br>-sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --pass 1::--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --pass 2 --scenecut-aware-qp<br>-sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --hist-scenecut --pass 1::--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --hist-scenecut --pass 2 --scenecut-aware-qp --qp-delta-nonref 8<br>+sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --pass 1::--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --pass 2 --scenecut-aware-qp 1<br>+sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --hist-scenecut --pass 1::--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --hist-scenecut --pass 2 --scenecut-aware-qp 3 --masking-strength 300,-1,7,100,2,3<br> <br> # multi-pass rate control and analysis<br> ducks_take_off_1080p50.y4m,--bitrate 6000 --pass 1  --multi-pass-opt-analysis  --hash 1 --ssim --psnr:: --bitrate 6000 --pass 2  --multi-pass-opt-analysis  --hash 1 --ssim --psnr<br>diff --git a/source/x265.h b/source/x265.h<br>index f44040ba7..b064f67c2 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -607,6 +607,9 @@ typedef enum<br> #define X265_ANALYSIS_SAVE 1<br> #define X265_ANALYSIS_LOAD 2<br> <br>+#define FORWARD                 1<br>+#define BACKWARD                2<br>+#define BI_DIRECTIONAL          3<br> #define SLICE_TYPE_DELTA        0.3 /* The offset decremented or incremented for P-frames or b-frames respectively*/<br> #define BACKWARD_WINDOW         1 /* Scenecut window before a scenecut */<br> #define FORWARD_WINDOW          2 /* Scenecut window after a scenecut */<br>@@ -1847,21 +1850,24 @@ typedef struct x265_param<br>       Default 1 (Enabled). API only. */<br>     int       bResetZoneConfig;<br> <br>-    /* It reduces the bits spent on the inter-frames within the scenecutWindow before and after a scenecut<br>+    /* It reduces the bits spent on the inter-frames within the scenecutWindow before and / or after a scenecut<br>      * by increasing their QP in ratecontrol pass2 algorithm without any deterioration in visual quality.<br>-     * Default is disabled. */<br>+     * 0 - Disabled (default).<br>+     * 1 - Forward masking.<br>+     * 2 - Backward masking.<br>+     * 3 - Bi-directional masking. */<br>     int       bEnableSceneCutAwareQp;<br> <br>     /* The duration(in milliseconds) for which there is a reduction in the bits spent on the inter-frames after a scenecut<br>-     * by increasing their QP, when bEnableSceneCutAwareQp is set. Default is 500ms.*/<br>-    int       scenecutWindow;<br>+     * by increasing their QP, when bEnableSceneCutAwareQp is 1 or 3. Default is 500ms.*/<br>+    int       fwdScenecutWindow;<br> <br>-    /* The offset by which QP is incremented for inter-frames when bEnableSceneCutAwareQp is set.<br>+    /* The offset by which QP is incremented for inter-frames after a scenecut when bEnableSceneCutAwareQp is 1 or 3.<br>      * Default is +5. */<br>-    double       refQpDelta;<br>+    double    fwdRefQpDelta;<br> <br>-    /* The offset by which QP is incremented for non-referenced inter-frames when bEnableSceneCutAwareQp is set. */<br>-    double       nonRefQpDelta;<br>+    /* The offset by which QP is incremented for non-referenced inter-frames after a scenecut when bEnableSceneCutAwareQp is 1 or 3. */<br>+    double    fwdNonRefQpDelta;<br> <br>     /* A genuine threshold used for histogram based scene cut detection.<br>      * This threshold determines whether a frame is a scenecut or not<br>@@ -1932,6 +1938,16 @@ typedef struct x265_param<br>     /* Maximum VBV fullness to be maintained. Default 80. Keep the buffer<br>     * at max 80% full */<br>     double   maxVbvFullness;<br>+<br>+    /* The duration(in milliseconds) for which there is a reduction in the bits spent on the inter-frames before a scenecut<br>+     * by increasing their QP, when bEnableSceneCutAwareQp is 2 or 3. Default is 100ms.*/<br>+    int       bwdScenecutWindow;<br>+<br>+    /* The offset by which QP is incremented for inter-frames before a scenecut when bEnableSceneCutAwareQp is 2 or 3. */<br>+    double    bwdRefQpDelta;<br>+<br>+    /* The offset by which QP is incremented for non-referenced inter-frames before a scenecut when bEnableSceneCutAwareQp is 2 or 3. */<br>+    double    bwdNonRefQpDelta;<br> } x265_param;<br> <br> /* x265_param_alloc:<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index c28dd7f8c..0f50589c1 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -177,10 +177,12 @@ namespace X265_NS {<br>         H0("   --no-hist-scenecut            Disables histogram based scene-cut detection using histogram based algorithm.\n");<br>         H1("   --hist-threshold <0.0..1.0>   Luma Edge histogram's Normalized SAD threshold for histogram based scenecut detection Default %.2f\n", param->edgeTransitionThreshold);<br>         H0("   --[no-]fades                  Enable detection and handling of fade-in regions. Default %s\n", OPT(param->bEnableFades));<br>-        H1("   --[no-]scenecut-aware-qp      Enable increasing QP for frames inside the scenecut window after scenecut. Default %s\n", OPT(param->bEnableSceneCutAwareQp));<br>-        H1("   --scenecut-window <0..1000>   QP incremental duration(in milliseconds) when scenecut-aware-qp is enabled. Default %d\n", param->scenecutWindow);<br>-        H1("   --qp-delta-ref <0..10>        QP offset to increment with base QP for inter-frames. Default %f\n", param->refQpDelta);<br>-        H1("   --qp-delta-nonref <0..10>     QP offset to increment with base QP for non-referenced inter-frames. Default %f\n", param->nonRefQpDelta);<br>+        H1("   --scenecut-aware-qp <0..3>    Enable increasing QP for frames inside the scenecut window around scenecut. Default %s\n", OPT(param->bEnableSceneCutAwareQp));<br>+        H1("                                 0 - Disabled\n");<br>+        H1("                                 1 - Forward masking\n");<br>+        H1("                                 2 - Backward masking\n");<br>+        H1("                                 3 - Bidirectional masking\n");<br>+        H1("   --masking-strength <string>   Comma separated values which specifies the duration and offset for the QP increment for inter-frames");<br>         H0("   --radl <integer>              Number of RADL pictures allowed in front of IDR. Default %d\n", param->radl);<br>         H0("   --intra-refresh               Use Periodic Intra Refresh instead of IDR frames\n");<br>         H0("   --rc-lookahead <integer>      Number of frames for frame-type lookahead (determines encoder latency) Default %d\n", param->lookaheadDepth);<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index a24d25435..7a2e0a267 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -148,11 +148,8 @@ static const struct option long_options[] =<br>     { "hist-threshold", required_argument, NULL, 0},<br>     { "fades",                no_argument, NULL, 0 },<br>     { "no-fades",             no_argument, NULL, 0 },<br>-    { "scenecut-aware-qp",    no_argument, NULL, 0 },<br>-    { "no-scenecut-aware-qp", no_argument, NULL, 0 },<br>-    { "scenecut-window",required_argument, NULL, 0 },<br>-    { "qp-delta-ref",   required_argument, NULL, 0 },<br>-    { "qp-delta-nonref",required_argument, NULL, 0 },<br>+    { "scenecut-aware-qp", required_argument, NULL, 0 },<br>+    { "masking-strength",  required_argument, NULL, 0 },<br>     { "radl",           required_argument, NULL, 0 },<br>     { "ctu-info",       required_argument, NULL, 0 },<br>     { "intra-refresh",        no_argument, NULL, 0 },<br>-- <br>2.18.0.windows.1<br><br></div>-- <br><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div dir="ltr"><font color="#0c343d" face="verdana, sans-serif"><br></font></div><div dir="ltr"><font color="#0c343d" face="verdana, sans-serif">Thanks & Regards</font><div><font color="#0c343d" face="verdana, sans-serif"><b>Niranjan Kumar B</b></font></div><div><font size="1" color="#0c343d" face="verdana, sans-serif">Video Codec Engineer </font></div><div><font size="1" color="#0c343d" face="verdana, sans-serif">Media & AI Analytics</font></div><div><font face="trebuchet ms, sans-serif" color="#0c343d">+91 958 511 1449</font></div><div><a href="https://multicorewareinc.com/" style="color:rgb(17,85,204)" target="_blank"><img src="https://docs.google.com/uc?export=download&id=1kc3RJu9M8bnIf6Xa5rUw2d-eEVUsPBE5&revid=0B7tw9XJBmynaemR1VUpQUi9DVytRVW5SVkRwVTFjb1hBMUcwPQ"></a></div></div></div></div></div></div></div></div>