<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Dec 11, 2020 at 1:53 PM Niranjan Bala <<a href="mailto:niranjan@multicorewareinc.com">niranjan@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">From cf25444e6b0f82de7b751c2436dec22ea94755b9 Mon Sep 17 00:00:00 2001<br>From: Niranjan Kumar <<a href="mailto:niranjan@multicorewareinc.com" target="_blank">niranjan@multicorewareinc.com</a>><br>Date: Wed, 21 Oct 2020 19:18:14 +0530<br>Subject: [PATCH] Add: Forward and Backward masking<br></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><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               | 85 +++++++++++++++++++++++--------<br> source/common/param.cpp        | 90 ++++++++++++++++++++++++++-------<br> source/encoder/encoder.cpp     |  6 +--<br> source/encoder/ratecontrol.cpp | 91 +++++++++++++++++++++++++++-------<br> source/encoder/ratecontrol.h   |  1 +<br> source/x265.h                  | 32 +++++++++---<br> source/x265cli.cpp             | 10 ++--<br> source/x265cli.h               |  7 +--<br> 8 files changed, 244 insertions(+), 78 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index 1a1de9f50..4e20daa90 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -1963,37 +1963,78 @@ Quality, rate control and rate distortion options<br>     <br>     **CLI ONLY**<br> <br>-.. option:: --scenecut-aware-qp, --no-scenecut-aware-qp<br>+.. option:: --scenecut-aware-qp <integer><br>    <br>-   It reduces the bits spent on the inter-frames within the :option:`--scenecut-window`<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 disabled.<br>+   :option:`--scenecut-aware-qp` works only with --pass 2. Default 0.<br>    <br>-.. option:: --scenecut-window <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>+    | 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></div></blockquote><div>[AM] Fix indentation.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">+       +-------+---------------------------------------------------------------+<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 1000<br>+.. option:: --masking-strength <string><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>+   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>-   **Range of values:**  0 to 10<br>+   When :option:`--scenecut-aware-qp` is::<br>+   * 1 (Forward masking):<br>+     --masking-strength <fwdWindow,fwdRefQPDelta,fwdNonRefQPDelta><br>    <br>-.. option:: --qp-delta-nonref <double><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>-   **Range of values:**  0 to 10<br>+   * 2 (Backward masking):<br>+     --masking-strength <bwdWindow,bwdRefQPDelta,bwdNonRefQPDelta><br>+   <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></div></blockquote><div>

[AM] Fix indentation here and in the following section. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">+        +-----------------+---------------------------------------------------------------+<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/common/param.cpp b/source/common/param.cpp<br>index 47a7a7c47..fe038fdf2 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,7 @@ 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>-    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, " scenecut-aware-qp=%d", p->bEnableSceneCutAwareQp);<br></div></blockquote><div>[AM] Update masking strength related params. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">     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 +2657,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..d880bc62a 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></div></blockquote><div>[AM] This conditional check can be simplified. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">         {<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>@@ -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></div></blockquote><div>[AM] This section takes action for all types of bEnableSceneCutAwareQp. Shouldn't this be restricted to FORWARD and BI-DIRECTIONAL types? </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">-                        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..606c36bf5 100644<br>--- a/source/encoder/ratecontrol.cpp<br>+++ b/source/encoder/ratecontrol.cpp<br>@@ -1854,7 +1854,7 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>             rce->qpNoVbv = q;<br>         }<br>         /* Scenecut Aware QP offsets*/<br>-        if (m_param->bEnableSceneCutAwareQp)<br>+        if (m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL || m_param->bEnableSceneCutAwareQp == FORWARD)<br>         {<br>             double lqmin = m_lmin[m_sliceType];<br>             double lqmax = m_lmax[m_sliceType];<br>@@ -1863,6 +1863,15 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>             q = x265_qScale2qp(qScale);<br>             rce->qpNoVbv = q;<br>         }<br>+        else if(m_param->bEnableSceneCutAwareQp == BACKWARD)<br>+        {<br>+            double lqmin = m_lmin[m_sliceType];<br>+            double lqmax = m_lmax[m_sliceType];<br>+            qScale = backwardMasking(curFrame, qScale);<br>+            qScale = x265_clip3(lqmin, lqmax, qScale);<br>+            q = x265_qScale2qp(qScale);<br>+            rce->qpNoVbv = q;<br>+        }<br> <br>         if (m_isVbv)<br>         {<br>@@ -1977,7 +1986,7 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>             }<br> <br>             /* Scenecut Aware QP offsets*/<br>-            if (m_param->bEnableSceneCutAwareQp)<br>+            if (m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL || m_param->bEnableSceneCutAwareQp == FORWARD)<br>             {<br>                 double qmin = m_lmin[m_sliceType];<br>                 double qmax = m_lmax[m_sliceType];<br>@@ -1985,6 +1994,14 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                 q = x265_clip3(qmin, qmax, q);<br>                 rce->qpNoVbv = x265_qScale2qp(q);<br>             }<br>+            else if (m_param->bEnableSceneCutAwareQp == BACKWARD)<br>+            {<br>+                double qmin = m_lmin[m_sliceType];<br>+                double qmax = m_lmax[m_sliceType];<br>+                q = backwardMasking(curFrame, q);<br>+                q = x265_clip3(qmin, qmax, q);<br>+                rce->qpNoVbv = x265_qScale2qp(q);<br>+            }<br> <br>             if (m_isVbv)<br>             {<br>@@ -2141,7 +2158,7 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                 q = x265_clip3(lqmin, lqmax, q);<br>             }<br>             /* Scenecut Aware QP offsets*/<br>-            if (m_param->bEnableSceneCutAwareQp)<br>+            if (m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL || m_param->bEnableSceneCutAwareQp == FORWARD)<br>             {<br>                 double qmin = m_lmin[m_sliceType];<br>                 double qmax = m_lmax[m_sliceType];<br>@@ -2149,6 +2166,14 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                 q = x265_clip3(qmin, qmax, q);<br>                 rce->qpNoVbv = x265_qScale2qp(q);<br>             }<br>+            else if (m_param->bEnableSceneCutAwareQp == BACKWARD)<br>+            {<br>+                double qmin = m_lmin[m_sliceType];<br>+                double qmax = m_lmax[m_sliceType];<br>+                q = backwardMasking(curFrame, q);<br>+                q = x265_clip3(qmin, qmax, q);<br>+                rce->qpNoVbv = x265_qScale2qp(q);<br>+            }<br></div></blockquote><div>[AM] Do not handle BACKWARD in else part. Introduces code duplication.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">             q = clipQscale(curFrame, rce, q);<br> <br>             if (m_2pass)<br>@@ -3171,15 +3196,17 @@ void RateControl::splitbUsed(char bused[], RateControlEntry *rce)<br> double RateControl::scenecutAwareMasking(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 +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 - 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 +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 += 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 +3245,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>@@ -3228,14 +3255,44 @@ double RateControl::scenecutAwareMasking(Frame* curFrame, double q)<br>     }<br>     else if (curFrame->m_isInsideWindow == BACKWARD_WINDOW)<br>     {<br>-        refQpDelta -= window3Delta;<br>-        nonRefQpDelta -= window3Delta;<br>+        if (bwdRefQpDelta < 0)<br>+            bwdRefQpDelta = fwdRefQpDelta - window3Delta;<br>+        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 += bwdRefQpDelta - sliceTypeDelta;<br>+        else if (curFrame->m_lowres.sliceType == X265_TYPE_BREF)<br>+            qp += bwdRefQpDelta;<br>+        else if (curFrame->m_lowres.sliceType == X265_TYPE_B)<br>+            qp += bwdNonRefQpDelta;<br>+    }<br></div></blockquote><div>[AM] Code duplication. Fix the calling point. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">+<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>+        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..dc4d882a6 100644<br>--- a/source/encoder/ratecontrol.h<br>+++ b/source/encoder/ratecontrol.h<br>@@ -270,6 +270,7 @@ public:<br>     bool   initPass2();<br> <br>     double scenecutAwareMasking(Frame* curFrame, double q);<br>+    double backwardMasking(Frame* curFrame, double q);<br> <br> protected:<br> <br>diff --git a/source/x265.h b/source/x265.h<br>index f44040ba7..668e9a9c2 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></div></blockquote><div>[AM] Update X265_BUILD </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"> #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,34 @@ 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>+    /* 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></div></blockquote><div><br></div><div>[AM] Introduce new params at the end of the structure to maintain backward compatibility </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"> <br>     /* A genuine threshold used for histogram based scene cut detection.<br>      * This threshold determines whether a frame is a scenecut or not<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></div></blockquote><div>[AM] Update test command lines. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">2.18.0.windows.1<br><br><div><br></div>-- <br><div dir="ltr"><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>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><font face="georgia, serif">Regards,</font><div><b><font face="georgia, serif">Aruna Matheswaran,</font></b></div><div><font face="georgia, serif">Video Codec Engineer,</font></div><div><font face="georgia, serif">Media & AI analytics BU,</font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" width="96" height="36" style="margin-left: 0px; margin-top: 0px;"></span></span></span><font face="georgia, serif"><br></font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" style="margin-left: 0px; margin-top: 0px;"></span></span></span><font face="georgia, serif"><br></font></div><div><font face="georgia, serif"><br></font></div></div></div></div></div></div></div></div></div></div>