[x265] [PATCH]Add: Forward and Backward masking

Niranjan Bala niranjan at multicorewareinc.com
Fri Dec 11 09:22:21 CET 2020


>From cf25444e6b0f82de7b751c2436dec22ea94755b9 Mon Sep 17 00:00:00 2001
From: Niranjan Kumar <niranjan at multicorewareinc.com>
Date: Wed, 21 Oct 2020 19:18:14 +0530
Subject: [PATCH] Add: Forward and Backward masking

Enables scenecut-aware-qp in a specified direction
0 - Disabled
1 - Forward masking
2 - Backward masking
3 - Bi-directional masking
---
 doc/reST/cli.rst               | 85 +++++++++++++++++++++++--------
 source/common/param.cpp        | 90 ++++++++++++++++++++++++++-------
 source/encoder/encoder.cpp     |  6 +--
 source/encoder/ratecontrol.cpp | 91 +++++++++++++++++++++++++++-------
 source/encoder/ratecontrol.h   |  1 +
 source/x265.h                  | 32 +++++++++---
 source/x265cli.cpp             | 10 ++--
 source/x265cli.h               |  7 +--
 8 files changed, 244 insertions(+), 78 deletions(-)

diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
index 1a1de9f50..4e20daa90 100755
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -1963,37 +1963,78 @@ Quality, rate control and rate distortion options

  **CLI ONLY**

-.. option:: --scenecut-aware-qp, --no-scenecut-aware-qp
+.. option:: --scenecut-aware-qp <integer>

-   It reduces the bits spent on the inter-frames within the
:option:`--scenecut-window`
+   It reduces the bits spent on the inter-frames within the scenecut window
    before and after a scenecut by increasing their QP in ratecontrol pass2
algorithm
    without any deterioration in visual quality. If a scenecut falls within
the window,
    the QP of the inter-frames after this scenecut will not be modified.
-   :option:`--scenecut-aware-qp` works only with --pass 2. Default
disabled.
+   :option:`--scenecut-aware-qp` works only with --pass 2. Default 0.

-.. option:: --scenecut-window <integer>
-
-   The duration(in milliseconds) for which there is a reduction in the
bits spent
-   on the inter-frames after a scenecut by increasing their QP, when
-   :option:`--scenecut-aware-qp` is enabled. Default 500ms.
+
 +-------+---------------------------------------------------------------+
+ | Mode  | Description                                                   |
+ +=======+===============================================================+
+ | 0     | Disabled.                                                     |
+ +-------+---------------------------------------------------------------+
+ | 1     | Forward masking.                                              |
+ |       | Applies QP modification for frames after the scenecut.        |
+ +-------+---------------------------------------------------------------+
+ | 2     | Backward masking.                                             |
+    |       | Applies QP modification for frames before the scenecut.
  |
+ +-------+---------------------------------------------------------------+
+ | 3     | Bi-directional masking.                                       |
+ |       | Applies QP modification for frames before and after           |
+ |       | the scenecut.                                                 |
+ +-------+---------------------------------------------------------------+

-   **Range of values:** 0 to 1000
+.. option:: --masking-strength <string>

-.. option:: --qp-delta-ref <double>
-
-   The offset by which QP is incremented for inter-frames
-   when :option:`--scenecut-aware-qp` is enabled. Default 5.
+   Comma separated list of values which specifies the duration and offset
+   for the QP increment for inter-frames when
:option:`--scenecut-aware-qp`
+   is enabled.

-   **Range of values:**  0 to 10
+   When :option:`--scenecut-aware-qp` is::
+   * 1 (Forward masking):
+     --masking-strength <fwdWindow,fwdRefQPDelta,fwdNonRefQPDelta>

-.. option:: --qp-delta-nonref <double>
-
-   The offset by which QP is incremented for non-referenced
-   inter-frames when :option:`--scenecut-aware-qp` is enabled.
-   The offset is computed from :option:`--qp-delta-ref` when it
-   is not explicitly specified.
-
-   **Range of values:**  0 to 10
+   * 2 (Backward masking):
+     --masking-strength <bwdWindow,bwdRefQPDelta,bwdNonRefQPDelta>
+
+   * 3 (Bi-directional masking):
+     --masking-strength
<fwdWindow,fwdRefQPDelta,fwdNonRefQPDelta,bwdWindow,bwdRefQPDelta,bwdNonRefQPDelta>
+
+
 +-----------------+---------------------------------------------------------------+
+ | Parameter       | Description
        |
+
+=================+===============================================================+
+ | fwdWindow       | The duration(in milliseconds) for which there is a
reduction  |
+ |                 | in the bits spent on the inter-frames after a
scenecut by     |
+ |      | increasing their QP. Default 500ms.                           |
+    |                 | **Range of values:** 0 to 1000
         |
+
+-----------------+---------------------------------------------------------------+
+ | fwdRefQPDelta   | The offset by which QP is incremented for
inter-frames        |
+ |                 | after a scenecut. Default 5.
         |
+ |                 | **Range of values:** 0 to 10
     |
+
+-----------------+---------------------------------------------------------------+
+ | fwdNonRefQPDelta| The offset by which QP is incremented for
non-referenced      |
+    |                 | inter-frames after a scenecut. The offset is
computed from    |
+ |                 | fwdRefQPDelta when it is not explicitly specified.
         |
+ |                 | **Range of values:** 0 to 10
     |
+
+-----------------+---------------------------------------------------------------+
+ | bwdWindow       | The duration(in milliseconds) for which there is a
reduction  |
+ |                 | in the bits spent on the inter-frames before a
scenecut by    |
+ |      | increasing their QP. Default 100ms.                           |
+ |                 | **Range of values:** 0 to 1000
       |
+
+-----------------+---------------------------------------------------------------+
+ | bwdRefQPDelta   | The offset by which QP is incremented for
inter-frames        |
+ |                 | before a scenecut. The offset is computed from
         |
+ |                 | fwdRefQPDelta when it is not explicitly specified.
         |
+ |                 | **Range of values:** 0 to 10
     |
+
+-----------------+---------------------------------------------------------------+
+ | bwdNonRefQPDelta| The offset by which QP is incremented for
non-referenced      |
+    |                 | inter-frames before a scenecut. The offset is
computed from   |
+ |                 | bwdRefQPDelta when it is not explicitly specified.
         |
+ |                 | **Range of values:** 0 to 10
     |
+
+-----------------+---------------------------------------------------------------+

 .. option:: --vbv-live-multi-pass, --no-vbv-live-multi-pass

diff --git a/source/common/param.cpp b/source/common/param.cpp
index 47a7a7c47..fe038fdf2 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -179,9 +179,12 @@ void x265_param_default(x265_param* param)
     param->bEnableHRDConcatFlag = 0;
     param->bEnableFades = 0;
     param->bEnableSceneCutAwareQp = 0;
-    param->scenecutWindow = 500;
-    param->refQpDelta = 5;
-    param->nonRefQpDelta = param->refQpDelta + (SLICE_TYPE_DELTA *
param->refQpDelta);
+    param->fwdScenecutWindow = 500;
+    param->fwdRefQpDelta = 5;
+    param->fwdNonRefQpDelta = param->fwdRefQpDelta + (SLICE_TYPE_DELTA *
param->fwdRefQpDelta);
+    param->bwdScenecutWindow = 100;
+    param->bwdRefQpDelta = -1;
+    param->bwdNonRefQpDelta = -1;

     /* Intra Coding Tools */
     param->bEnableConstrainedIntra = 0;
@@ -1344,10 +1347,51 @@ int x265_param_parse(x265_param* p, const char*
name, const char* value)
             p->selectiveSAO = atoi(value);
         }
         OPT("fades") p->bEnableFades = atobool(value);
-        OPT("scenecut-aware-qp") p->bEnableSceneCutAwareQp =
atobool(value);
-        OPT("scenecut-window") p->scenecutWindow = atoi(value);
-        OPT("qp-delta-ref") p->refQpDelta = atoi(value);
-        OPT("qp-delta-nonref") p->nonRefQpDelta = atoi(value);
+        OPT("scenecut-aware-qp") p->bEnableSceneCutAwareQp = atoi(value);
+        OPT("masking-strength")
+        {
+            int window1;
+            double refQpDelta1, nonRefQpDelta1;
+
+            if (p->bEnableSceneCutAwareQp == FORWARD)
+            {
+                sscanf(value, "%d,%lf,%lf", &window1, &refQpDelta1,
&nonRefQpDelta1);
+                if (window1 > 0)
+                    p->fwdScenecutWindow = window1;
+                if (refQpDelta1 > 0)
+                    p->fwdRefQpDelta = refQpDelta1;
+                if (nonRefQpDelta1 > 0)
+                    p->fwdNonRefQpDelta = nonRefQpDelta1;
+            }
+            else if (p->bEnableSceneCutAwareQp == BACKWARD)
+            {
+                sscanf(value, "%d,%lf,%lf", &window1, &refQpDelta1,
&nonRefQpDelta1);
+                if (window1 > 0)
+                    p->bwdScenecutWindow = window1;
+                if (refQpDelta1 > 0)
+                    p->bwdRefQpDelta = refQpDelta1;
+                if (nonRefQpDelta1 > 0)
+                    p->bwdNonRefQpDelta = nonRefQpDelta1;
+            }
+            else if (p->bEnableSceneCutAwareQp == BI_DIRECTIONAL)
+            {
+                int window2;
+                double refQpDelta2, nonRefQpDelta2;
+                sscanf(value, "%d,%lf,%lf,%d,%lf,%lf", &window1,
&refQpDelta1, &nonRefQpDelta1, &window2, &refQpDelta2, &nonRefQpDelta2);
+                if (window1 > 0)
+                    p->fwdScenecutWindow = window1;
+                if (refQpDelta1 > 0)
+                    p->fwdRefQpDelta = refQpDelta1;
+                if (nonRefQpDelta1 > 0)
+                    p->fwdNonRefQpDelta = nonRefQpDelta1;
+                if (window2 > 0)
+                    p->bwdScenecutWindow = window2;
+                if (refQpDelta2 > 0)
+                    p->bwdRefQpDelta = refQpDelta2;
+                if (nonRefQpDelta2 > 0)
+                    p->bwdNonRefQpDelta = nonRefQpDelta2;
+            }
+        }
         OPT("field") p->bField = atobool( value );
         OPT("cll") p->bEmitCLL = atobool(value);
         OPT("frame-dup") p->bEnableFrameDuplication = atobool(value);
@@ -1787,12 +1831,19 @@ int x265_check_params(x265_param* param)
         }
         else
         {
-            CHECK(param->scenecutWindow < 0 || param->scenecutWindow >
1000,
-            "Invalid scenecut Window duration. Value must be between 0 and
1000(inclusive)");
-            CHECK(param->refQpDelta < 0 || param->refQpDelta > 10,
-            "Invalid refQpDelta value. Value must be between 0 and 10
(inclusive)");
-            CHECK(param->nonRefQpDelta < 0 || param->nonRefQpDelta > 10,
-            "Invalid nonRefQpDelta value. Value must be between 0 and 10
(inclusive)");
+            CHECK(param->fwdScenecutWindow < 0 || param->fwdScenecutWindow
> 1000,
+            "Invalid forward scenecut Window duration. Value must be
between 0 and 1000(inclusive)");
+            CHECK(param->fwdRefQpDelta < 0 || param->fwdRefQpDelta > 10,
+            "Invalid fwdRefQpDelta value. Value must be between 0 and 10
(inclusive)");
+            CHECK(param->fwdNonRefQpDelta < 0 || param->fwdNonRefQpDelta >
10,
+            "Invalid fwdNonRefQpDelta value. Value must be between 0 and
10 (inclusive)");
+
+            CHECK(param->bwdScenecutWindow < 0 || param->bwdScenecutWindow
> 1000,
+                "Invalid backward scenecut Window duration. Value must be
between 0 and 1000(inclusive)");
+            CHECK(param->bwdRefQpDelta < -1 || param->bwdRefQpDelta > 10,
+                "Invalid bwdRefQpDelta value. Value must be between 0 and
10 (inclusive)");
+            CHECK(param->bwdNonRefQpDelta < -1 || param->bwdNonRefQpDelta
> 10,
+                "Invalid bwdNonRefQpDelta value. Value must be between 0
and 10 (inclusive)");
         }
     }
     if (param->bEnableHME)
@@ -2252,9 +2303,7 @@ char *x265_param2string(x265_param* p, int padx, int
pady)
     BOOL(p->bEnableSvtHevc, "svt");
     BOOL(p->bField, "field");
     s += sprintf(s, " qp-adaptation-range=%.2f", p->rc.qpAdaptationRange);
-    BOOL(p->bEnableSceneCutAwareQp, "scenecut-aware-qp");
-    if (p->bEnableSceneCutAwareQp)
-        s += sprintf(s, " scenecut-window=%d qp-delta-ref=%f
qp-delta-nonref=%f", p->scenecutWindow, p->refQpDelta, p->nonRefQpDelta);
+    s += sprintf(s, " scenecut-aware-qp=%d", p->bEnableSceneCutAwareQp);
     s += sprintf(s, "conformance-window-offsets right=%d bottom=%d",
p->confWinRightOffset, p->confWinBottomOffset);
     s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate);
     BOOL(p->bliveVBV2pass, "vbv-live-multi-pass");
@@ -2608,9 +2657,12 @@ void x265_copy_params(x265_param* dst, x265_param*
src)
     dst->bEnableSvtHevc = src->bEnableSvtHevc;
     dst->bEnableFades = src->bEnableFades;
     dst->bEnableSceneCutAwareQp = src->bEnableSceneCutAwareQp;
-    dst->scenecutWindow = src->scenecutWindow;
-    dst->refQpDelta = src->refQpDelta;
-    dst->nonRefQpDelta = src->nonRefQpDelta;
+    dst->fwdScenecutWindow = src->fwdScenecutWindow;
+    dst->fwdRefQpDelta = src->fwdRefQpDelta;
+    dst->fwdNonRefQpDelta = src->fwdNonRefQpDelta;
+    dst->bwdScenecutWindow = src->bwdScenecutWindow;
+    dst->bwdRefQpDelta = src->bwdRefQpDelta;
+    dst->bwdNonRefQpDelta = src->bwdNonRefQpDelta;
     dst->bField = src->bField;

     dst->confWinRightOffset = src->confWinRightOffset;
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index 1f710e1ce..d880bc62a 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -1810,13 +1810,13 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture* pic_out)
                 inFrame->m_lowres.m_bIsHardScenecut = isHardSC;
         }

-        if (m_param->bEnableSceneCutAwareQp && m_param->rc.bStatRead)
+        if ((m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL ||
m_param->bEnableSceneCutAwareQp == BACKWARD) && m_param->rc.bStatRead)
         {
             RateControlEntry * rcEntry = NULL;
             rcEntry = &(m_rateControl->m_rce2Pass[inFrame->m_poc]);
             if(rcEntry->scenecut)
             {
-                int backwardWindow = X265_MIN(int((p->fpsNum /
p->fpsDenom) / 10), p->lookaheadDepth);
+                int backwardWindow =
X265_MIN(int((m_param->bwdScenecutWindow / 1000.0) * (m_param->fpsNum /
m_param->fpsDenom)), p->lookaheadDepth);
                 for (int i = 1; i <= backwardWindow; i++)
                 {
                     int frameNum = inFrame->m_poc - i;
@@ -2253,7 +2253,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture* pic_out)
                         m_rateControl->m_lastScenecut = frameEnc->m_poc;
                     else
                     {
-                        int maxWindowSize = int((m_param->scenecutWindow /
1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5);
+                        int maxWindowSize =
int((m_param->fwdScenecutWindow / 1000.0) * (m_param->fpsNum /
m_param->fpsDenom) + 0.5);
                         if (frameEnc->m_poc >
(m_rateControl->m_lastScenecut + maxWindowSize))
                             m_rateControl->m_lastScenecut =
frameEnc->m_poc;
                     }
diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp
index 4e7d52419..606c36bf5 100644
--- a/source/encoder/ratecontrol.cpp
+++ b/source/encoder/ratecontrol.cpp
@@ -1854,7 +1854,7 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
             rce->qpNoVbv = q;
         }
         /* Scenecut Aware QP offsets*/
-        if (m_param->bEnableSceneCutAwareQp)
+        if (m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL ||
m_param->bEnableSceneCutAwareQp == FORWARD)
         {
             double lqmin = m_lmin[m_sliceType];
             double lqmax = m_lmax[m_sliceType];
@@ -1863,6 +1863,15 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
             q = x265_qScale2qp(qScale);
             rce->qpNoVbv = q;
         }
+        else if(m_param->bEnableSceneCutAwareQp == BACKWARD)
+        {
+            double lqmin = m_lmin[m_sliceType];
+            double lqmax = m_lmax[m_sliceType];
+            qScale = backwardMasking(curFrame, qScale);
+            qScale = x265_clip3(lqmin, lqmax, qScale);
+            q = x265_qScale2qp(qScale);
+            rce->qpNoVbv = q;
+        }

         if (m_isVbv)
         {
@@ -1977,7 +1986,7 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
             }

             /* Scenecut Aware QP offsets*/
-            if (m_param->bEnableSceneCutAwareQp)
+            if (m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL ||
m_param->bEnableSceneCutAwareQp == FORWARD)
             {
                 double qmin = m_lmin[m_sliceType];
                 double qmax = m_lmax[m_sliceType];
@@ -1985,6 +1994,14 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
                 q = x265_clip3(qmin, qmax, q);
                 rce->qpNoVbv = x265_qScale2qp(q);
             }
+            else if (m_param->bEnableSceneCutAwareQp == BACKWARD)
+            {
+                double qmin = m_lmin[m_sliceType];
+                double qmax = m_lmax[m_sliceType];
+                q = backwardMasking(curFrame, q);
+                q = x265_clip3(qmin, qmax, q);
+                rce->qpNoVbv = x265_qScale2qp(q);
+            }

             if (m_isVbv)
             {
@@ -2141,7 +2158,7 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
                 q = x265_clip3(lqmin, lqmax, q);
             }
             /* Scenecut Aware QP offsets*/
-            if (m_param->bEnableSceneCutAwareQp)
+            if (m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL ||
m_param->bEnableSceneCutAwareQp == FORWARD)
             {
                 double qmin = m_lmin[m_sliceType];
                 double qmax = m_lmax[m_sliceType];
@@ -2149,6 +2166,14 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
                 q = x265_clip3(qmin, qmax, q);
                 rce->qpNoVbv = x265_qScale2qp(q);
             }
+            else if (m_param->bEnableSceneCutAwareQp == BACKWARD)
+            {
+                double qmin = m_lmin[m_sliceType];
+                double qmax = m_lmax[m_sliceType];
+                q = backwardMasking(curFrame, q);
+                q = x265_clip3(qmin, qmax, q);
+                rce->qpNoVbv = x265_qScale2qp(q);
+            }
             q = clipQscale(curFrame, rce, q);

             if (m_2pass)
@@ -3171,15 +3196,17 @@ void RateControl::splitbUsed(char bused[],
RateControlEntry *rce)
 double RateControl::scenecutAwareMasking(Frame* curFrame, double q)
 {
     double qp = x265_qScale2qp(q);
-    uint32_t maxWindowSize = uint32_t((m_param->scenecutWindow / 1000.0) *
(m_param->fpsNum / m_param->fpsDenom) + 0.5);
+    uint32_t maxWindowSize = uint32_t((m_param->fwdScenecutWindow /
1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5);
     uint32_t windowSize = maxWindowSize / 3;
     int lastScenecut = m_top->m_rateControl->m_lastScenecut;
     int lastIFrame = m_top->m_rateControl->m_lastScenecutAwareIFrame;
-    double refQpDelta = double(m_param->refQpDelta);
-    double nonRefQpDelta = double(m_param->nonRefQpDelta);
-    double sliceTypeDelta = SLICE_TYPE_DELTA * refQpDelta;
-    double window2Delta = WINDOW2_DELTA * refQpDelta;
-    double window3Delta = WINDOW3_DELTA * refQpDelta;
+    double fwdRefQpDelta = double(m_param->fwdRefQpDelta);
+    double fwdNonRefQpDelta = double(m_param->fwdNonRefQpDelta);
+    double bwdRefQpDelta = double(m_param->bwdRefQpDelta);
+    double bwdNonRefQpDelta = double(m_param->bwdNonRefQpDelta);
+    double sliceTypeDelta = SLICE_TYPE_DELTA * fwdRefQpDelta;
+    double window2Delta = WINDOW2_DELTA * fwdRefQpDelta;
+    double window3Delta = WINDOW3_DELTA * fwdRefQpDelta;

     if (curFrame->m_poc > lastScenecut && curFrame->m_poc <= (lastScenecut
+ int(maxWindowSize)))
         curFrame->m_isInsideWindow = FORWARD_WINDOW;
@@ -3194,7 +3221,7 @@ double RateControl::scenecutAwareMasking(Frame*
curFrame, double q)
             if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut
+ int(maxWindowSize))
                 && curFrame->m_poc >= lastIFrame))
             {
-                qp += refQpDelta - sliceTypeDelta;
+                qp += fwdRefQpDelta - sliceTypeDelta;
                 if (((curFrame->m_poc) > (lastScenecut + int(windowSize)))
&& ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize))))
                     qp -= window2Delta;
                 else if (curFrame->m_poc > lastScenecut + 2 *
int(windowSize))
@@ -3206,7 +3233,7 @@ double RateControl::scenecutAwareMasking(Frame*
curFrame, double q)
             if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut
+ int(maxWindowSize))
                 && curFrame->m_poc >= lastIFrame))
             {
-                qp += refQpDelta;
+                qp += fwdRefQpDelta;
                 if (((curFrame->m_poc) > (lastScenecut + int(windowSize)))
&& ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize))))
                     qp -= window2Delta;
                 else if (curFrame->m_poc > lastScenecut + 2 *
int(windowSize))
@@ -3218,7 +3245,7 @@ double RateControl::scenecutAwareMasking(Frame*
curFrame, double q)
             if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut
+ int(maxWindowSize))
                 && curFrame->m_poc >= lastIFrame))
             {
-                qp += nonRefQpDelta;
+                qp += fwdNonRefQpDelta;
                 if (((curFrame->m_poc) > (lastScenecut + int(windowSize)))
&& ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize))))
                     qp -= window2Delta;
                 else if (curFrame->m_poc > lastScenecut + 2 *
int(windowSize))
@@ -3228,14 +3255,44 @@ double RateControl::scenecutAwareMasking(Frame*
curFrame, double q)
     }
     else if (curFrame->m_isInsideWindow == BACKWARD_WINDOW)
     {
-        refQpDelta -= window3Delta;
-        nonRefQpDelta -= window3Delta;
+        if (bwdRefQpDelta < 0)
+            bwdRefQpDelta = fwdRefQpDelta - window3Delta;
+        sliceTypeDelta = SLICE_TYPE_DELTA * bwdRefQpDelta;
+        if (bwdNonRefQpDelta < 0)
+            bwdNonRefQpDelta = bwdRefQpDelta + sliceTypeDelta;
+
+        if (curFrame->m_lowres.sliceType == X265_TYPE_P)
+            qp += bwdRefQpDelta - sliceTypeDelta;
+        else if (curFrame->m_lowres.sliceType == X265_TYPE_BREF)
+            qp += bwdRefQpDelta;
+        else if (curFrame->m_lowres.sliceType == X265_TYPE_B)
+            qp += bwdNonRefQpDelta;
+    }
+
+    return x265_qp2qScale(qp);
+}
+double RateControl::backwardMasking(Frame* curFrame, double q)
+{
+    double qp = x265_qScale2qp(q);
+    double fwdRefQpDelta = double(m_param->fwdRefQpDelta);
+    double window3Delta = WINDOW3_DELTA * fwdRefQpDelta;
+    double bwdRefQpDelta = double(m_param->bwdRefQpDelta);
+    double bwdNonRefQpDelta = double(m_param->bwdNonRefQpDelta);
+
+    if (curFrame->m_isInsideWindow == BACKWARD_WINDOW)
+    {
+        if (bwdRefQpDelta < 0)
+            bwdRefQpDelta = fwdRefQpDelta - window3Delta;
+        double sliceTypeDelta = SLICE_TYPE_DELTA * bwdRefQpDelta;
+        if (bwdNonRefQpDelta < 0)
+            bwdNonRefQpDelta = bwdRefQpDelta + sliceTypeDelta;
+
         if (curFrame->m_lowres.sliceType == X265_TYPE_P)
-            qp += refQpDelta - sliceTypeDelta;
+            qp += bwdRefQpDelta - sliceTypeDelta;
         else if (curFrame->m_lowres.sliceType == X265_TYPE_BREF)
-            qp += refQpDelta;
+            qp += bwdRefQpDelta;
         else if (curFrame->m_lowres.sliceType == X265_TYPE_B)
-            qp += nonRefQpDelta;
+            qp += bwdNonRefQpDelta;
     }

     return x265_qp2qScale(qp);
diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h
index 809e0c620..dc4d882a6 100644
--- a/source/encoder/ratecontrol.h
+++ b/source/encoder/ratecontrol.h
@@ -270,6 +270,7 @@ public:
     bool   initPass2();

     double scenecutAwareMasking(Frame* curFrame, double q);
+    double backwardMasking(Frame* curFrame, double q);

 protected:

diff --git a/source/x265.h b/source/x265.h
index f44040ba7..668e9a9c2 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -607,6 +607,9 @@ typedef enum
 #define X265_ANALYSIS_SAVE 1
 #define X265_ANALYSIS_LOAD 2

+#define FORWARD                 1
+#define BACKWARD                2
+#define BI_DIRECTIONAL          3
 #define SLICE_TYPE_DELTA        0.3 /* The offset decremented or
incremented for P-frames or b-frames respectively*/
 #define BACKWARD_WINDOW         1 /* Scenecut window before a scenecut */
 #define FORWARD_WINDOW          2 /* Scenecut window after a scenecut */
@@ -1847,21 +1850,34 @@ typedef struct x265_param
       Default 1 (Enabled). API only. */
     int       bResetZoneConfig;

-    /* It reduces the bits spent on the inter-frames within the
scenecutWindow before and after a scenecut
+    /* It reduces the bits spent on the inter-frames within the
scenecutWindow before and / or after a scenecut
      * by increasing their QP in ratecontrol pass2 algorithm without any
deterioration in visual quality.
-     * Default is disabled. */
+     * 0 - Disabled (default).
+     * 1 - Forward masking.
+     * 2 - Backward masking.
+     * 3 - Bi-directional masking. */
     int       bEnableSceneCutAwareQp;

     /* The duration(in milliseconds) for which there is a reduction in the
bits spent on the inter-frames after a scenecut
-     * by increasing their QP, when bEnableSceneCutAwareQp is set. Default
is 500ms.*/
-    int       scenecutWindow;
+     * by increasing their QP, when bEnableSceneCutAwareQp is 1 or 3.
Default is 500ms.*/
+    int       fwdScenecutWindow;

-    /* The offset by which QP is incremented for inter-frames when
bEnableSceneCutAwareQp is set.
+    /* The offset by which QP is incremented for inter-frames after a
scenecut when bEnableSceneCutAwareQp is 1 or 3.
      * Default is +5. */
-    double       refQpDelta;
+    double    fwdRefQpDelta;

-    /* The offset by which QP is incremented for non-referenced
inter-frames when bEnableSceneCutAwareQp is set. */
-    double       nonRefQpDelta;
+    /* The offset by which QP is incremented for non-referenced
inter-frames after a scenecut when bEnableSceneCutAwareQp is 1 or 3. */
+    double    fwdNonRefQpDelta;
+
+    /* The duration(in milliseconds) for which there is a reduction in the
bits spent on the inter-frames before a scenecut
+     * by increasing their QP, when bEnableSceneCutAwareQp is 2 or 3.
Default is 100ms.*/
+    int       bwdScenecutWindow;
+
+    /* The offset by which QP is incremented for inter-frames before a
scenecut when bEnableSceneCutAwareQp is 2 or 3. */
+    double    bwdRefQpDelta;
+
+    /* The offset by which QP is incremented for non-referenced
inter-frames before a scenecut when bEnableSceneCutAwareQp is 2 or 3. */
+    double    bwdNonRefQpDelta;

     /* A genuine threshold used for histogram based scene cut detection.
      * This threshold determines whether a frame is a scenecut or not
diff --git a/source/x265cli.cpp b/source/x265cli.cpp
index c28dd7f8c..0f50589c1 100755
--- a/source/x265cli.cpp
+++ b/source/x265cli.cpp
@@ -177,10 +177,12 @@ namespace X265_NS {
         H0("   --no-hist-scenecut            Disables histogram based
scene-cut detection using histogram based algorithm.\n");
         H1("   --hist-threshold <0.0..1.0>   Luma Edge histogram's
Normalized SAD threshold for histogram based scenecut detection Default
%.2f\n", param->edgeTransitionThreshold);
         H0("   --[no-]fades                  Enable detection and handling
of fade-in regions. Default %s\n", OPT(param->bEnableFades));
-        H1("   --[no-]scenecut-aware-qp      Enable increasing QP for
frames inside the scenecut window after scenecut. Default %s\n",
OPT(param->bEnableSceneCutAwareQp));
-        H1("   --scenecut-window <0..1000>   QP incremental duration(in
milliseconds) when scenecut-aware-qp is enabled. Default %d\n",
param->scenecutWindow);
-        H1("   --qp-delta-ref <0..10>        QP offset to increment with
base QP for inter-frames. Default %f\n", param->refQpDelta);
-        H1("   --qp-delta-nonref <0..10>     QP offset to increment with
base QP for non-referenced inter-frames. Default %f\n",
param->nonRefQpDelta);
+        H1("   --scenecut-aware-qp <0..3>    Enable increasing QP for
frames inside the scenecut window around scenecut. Default %s\n",
OPT(param->bEnableSceneCutAwareQp));
+        H1("                                 0 - Disabled\n");
+        H1("                                 1 - Forward masking\n");
+        H1("                                 2 - Backward masking\n");
+        H1("                                 3 - Bidirectional masking\n");
+        H1("   --masking-strength <string>   Comma separated values which
specifies the duration and offset for the QP increment for inter-frames");
         H0("   --radl <integer>              Number of RADL pictures
allowed in front of IDR. Default %d\n", param->radl);
         H0("   --intra-refresh               Use Periodic Intra Refresh
instead of IDR frames\n");
         H0("   --rc-lookahead <integer>      Number of frames for
frame-type lookahead (determines encoder latency) Default %d\n",
param->lookaheadDepth);
diff --git a/source/x265cli.h b/source/x265cli.h
index a24d25435..7a2e0a267 100644
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -148,11 +148,8 @@ static const struct option long_options[] =
     { "hist-threshold", required_argument, NULL, 0},
     { "fades",                no_argument, NULL, 0 },
     { "no-fades",             no_argument, NULL, 0 },
-    { "scenecut-aware-qp",    no_argument, NULL, 0 },
-    { "no-scenecut-aware-qp", no_argument, NULL, 0 },
-    { "scenecut-window",required_argument, NULL, 0 },
-    { "qp-delta-ref",   required_argument, NULL, 0 },
-    { "qp-delta-nonref",required_argument, NULL, 0 },
+    { "scenecut-aware-qp", required_argument, NULL, 0 },
+    { "masking-strength",  required_argument, NULL, 0 },
     { "radl",           required_argument, NULL, 0 },
     { "ctu-info",       required_argument, NULL, 0 },
     { "intra-refresh",        no_argument, NULL, 0 },
-- 
2.18.0.windows.1


-- 

Thanks & Regards
*Niranjan Kumar B*
Video Codec Engineer
Media & AI Analytics
+91 958 511 1449
<https://multicorewareinc.com/>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20201211/b1067613/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265.diff
Type: application/octet-stream
Size: 30763 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20201211/b1067613/attachment-0001.obj>


More information about the x265-devel mailing list