[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