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

Niranjan Bala niranjan at multicorewareinc.com
Fri Dec 11 15:29:09 CET 2020


>From 775cdc266297f390dab0256a5efa60c3781a3b0d 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                   | 95 +++++++++++++++++++++---------
 source/CMakeLists.txt              |  2 +-
 source/common/param.cpp            | 90 ++++++++++++++++++++++------
 source/encoder/encoder.cpp         |  8 +--
 source/encoder/ratecontrol.cpp     | 68 +++++++++++++++------
 source/encoder/ratecontrol.h       |  3 +-
 source/test/rate-control-tests.txt |  4 +-
 source/x265.h                      | 32 +++++++---
 source/x265cli.cpp                 | 10 ++--
 source/x265cli.h                   |  7 +--
 10 files changed, 229 insertions(+), 90 deletions(-)

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

  **CLI ONLY**

-.. option:: --scenecut-aware-qp, --no-scenecut-aware-qp
-
-   It reduces the bits spent on the inter-frames within the
:option:`--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-window <integer>
+.. option:: --scenecut-aware-qp <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.
-
-   **Range of values:** 0 to 1000
-
-.. option:: --qp-delta-ref <double>
-
-   The offset by which QP is incremented for inter-frames
-   when :option:`--scenecut-aware-qp` is enabled. Default 5.
-
-   **Range of values:**  0 to 10
-
-.. option:: --qp-delta-nonref <double>
+ 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 0.

-   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.
+ +-------+---------------------------------------------------------------+
+ | 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 10
+.. option:: --masking-strength <string>
+
+ 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.
+
+ When :option:`--scenecut-aware-qp` is::
+ * 1 (Forward masking):
+ --masking-strength <fwdWindow,fwdRefQPDelta,fwdNonRefQPDelta>
+ * 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/CMakeLists.txt b/source/CMakeLists.txt
index 67e737512..48ca4af7c 100755
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)
 option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
 mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 198)
+set(X265_BUILD 199)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff --git a/source/common/param.cpp b/source/common/param.cpp
index 47a7a7c47..7a9be18c3 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,9 @@ 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");
+    s += sprintf(s, " scenecut-aware-qp=%d", p->bEnableSceneCutAwareQp);
     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, " 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);
     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 +2659,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..18c3b6788 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;
@@ -2242,7 +2242,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture* pic_out)
             frameEnc = m_lookahead->getDecidedPicture();
         if (frameEnc && !pass && (!m_param->chunkEnd || (m_encodedFrameNum
< m_param->chunkEnd)))
         {
-            if (m_param->bEnableSceneCutAwareQp && m_param->rc.bStatRead)
+            if ((m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL ||
m_param->bEnableSceneCutAwareQp == FORWARD) && m_param->rc.bStatRead)
             {
                 RateControlEntry * rcEntry;
                 rcEntry = &(m_rateControl->m_rce2Pass[frameEnc->m_poc]);
@@ -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..554acfe38 100644
--- a/source/encoder/ratecontrol.cpp
+++ b/source/encoder/ratecontrol.cpp
@@ -1858,7 +1858,10 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
         {
             double lqmin = m_lmin[m_sliceType];
             double lqmax = m_lmax[m_sliceType];
-            qScale = scenecutAwareMasking(curFrame, qScale);
+            if (m_param->bEnableSceneCutAwareQp == FORWARD ||
m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)
+                qScale = forwardMasking(curFrame, qScale);
+            else if (m_param->bEnableSceneCutAwareQp == BACKWARD ||
m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)
+                qScale = backwardMasking(curFrame, qScale);
             qScale = x265_clip3(lqmin, lqmax, qScale);
             q = x265_qScale2qp(qScale);
             rce->qpNoVbv = q;
@@ -1981,7 +1984,12 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
             {
                 double qmin = m_lmin[m_sliceType];
                 double qmax = m_lmax[m_sliceType];
-                q = scenecutAwareMasking(curFrame, q);
+
+                if (m_param->bEnableSceneCutAwareQp == FORWARD ||
m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)
+                    q = forwardMasking(curFrame, q);
+                else if (m_param->bEnableSceneCutAwareQp == BACKWARD ||
m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)
+                    q = backwardMasking(curFrame, q);
+
                 q = x265_clip3(qmin, qmax, q);
                 rce->qpNoVbv = x265_qScale2qp(q);
             }
@@ -2145,7 +2153,12 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
             {
                 double qmin = m_lmin[m_sliceType];
                 double qmax = m_lmax[m_sliceType];
-                q = scenecutAwareMasking(curFrame, q);
+
+                if (m_param->bEnableSceneCutAwareQp == FORWARD ||
m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)
+                    q = forwardMasking(curFrame, q);
+                else if (m_param->bEnableSceneCutAwareQp == BACKWARD ||
m_param->bEnableSceneCutAwareQp == BI_DIRECTIONAL)
+                    q = backwardMasking(curFrame, q);
+
                 q = x265_clip3(qmin, qmax, q);
                 rce->qpNoVbv = x265_qScale2qp(q);
             }
@@ -3168,18 +3181,20 @@ void RateControl::splitbUsed(char bused[],
RateControlEntry *rce)
     }
 }

-double RateControl::scenecutAwareMasking(Frame* curFrame, double q)
+double RateControl::forwardMasking(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 +3209,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 +3221,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 +3233,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))
@@ -3226,16 +3241,31 @@ double RateControl::scenecutAwareMasking(Frame*
curFrame, double q)
             }
         }
     }
-    else if (curFrame->m_isInsideWindow == BACKWARD_WINDOW)
+
+    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)
     {
-        refQpDelta -= window3Delta;
-        nonRefQpDelta -= window3Delta;
+        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..41bbddcf2 100644
--- a/source/encoder/ratecontrol.h
+++ b/source/encoder/ratecontrol.h
@@ -269,7 +269,8 @@ public:
     int writeRateControlFrameStats(Frame* curFrame, RateControlEntry* rce);
     bool   initPass2();

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

 protected:

diff --git a/source/test/rate-control-tests.txt
b/source/test/rate-control-tests.txt
index eed92f809..6c8f10cb6 100644
--- a/source/test/rate-control-tests.txt
+++ b/source/test/rate-control-tests.txt
@@ -44,8 +44,8 @@ CrowdRun_1920x1080_50_10bit_422.yuv,--preset superfast
--bitrate 2500 --pass 1 -
 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
 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
 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
-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
-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
+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
+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

 # multi-pass rate control and analysis
 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
diff --git a/source/x265.h b/source/x265.h
index f44040ba7..b064f67c2 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,24 @@ 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;

     /* A genuine threshold used for histogram based scene cut detection.
      * This threshold determines whether a frame is a scenecut or not
@@ -1932,6 +1938,16 @@ typedef struct x265_param
     /* Maximum VBV fullness to be maintained. Default 80. Keep the buffer
     * at max 80% full */
     double   maxVbvFullness;
+
+    /* 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;
 } x265_param;

 /* x265_param_alloc:
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/513783f2/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265.diff
Type: application/octet-stream
Size: 33799 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20201211/513783f2/attachment-0001.obj>


More information about the x265-devel mailing list