[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