[x265] [PATCH] Add real-time VBV fullness based QP tuning in VBV 2 pass
Kirithika Kalirathnam
kirithika at multicorewareinc.com
Wed Sep 9 09:50:48 CEST 2020
>From f83db031a5308bb6bc2ca54dd079e20630fc5701 Mon Sep 17 00:00:00 2001
From: Kirithika <kirithika at multicorewareinc.com>
Date: Fri, 28 Aug 2020 09:20:47 +0530
Subject: [PATCH] Add real-time VBV fullness based QP tuning in VBV 2 pass
This commit enables real-time VBV fullness based 2nd pass QP tuning.
Experimental feature.Default disabled
---
doc/reST/cli.rst | 9 ++++
source/CMakeLists.txt | 2 +-
source/common/param.cpp | 13 +++++
source/encoder/ratecontrol.cpp | 98 +++++++++++++++++++---------------
source/encoder/slicetype.cpp | 14 ++---
source/x265.h | 5 ++
source/x265cli.cpp | 1 +
source/x265cli.h | 2 +
8 files changed, 93 insertions(+), 51 deletions(-)
diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
index e6c628c36..7777ee49e 100755
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -1977,6 +1977,15 @@ Quality, rate control and rate distortion options
**Range of values:** 0 to 10
+.. option:: --vbv-live-multi-pass, --no-vbv-live-multi-pass
+
+ It enables the Qp tuning at frame level based on real time VBV Buffer
fullness
+ in the ratecontrol 2nd pass of multi pass mode to reduce the VBV
violations.
+ It could only be enabled with rate control stat-read encodes with VBV
and ABR
+ rate control mode.
+
+ Default disabled. **Experimental feature**
+
Quantization Options
====================
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index d9ed3983e..5738c861c 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 196)
+set(X265_BUILD 197)
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 845c38bd2..b3001fcf6 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -288,6 +288,7 @@ void x265_param_default(x265_param* param)
param->bResetZoneConfig = 1;
param->reconfigWindowSize = 0;
param->decoderVbvMaxRate = 0;
+ param->bliveVBV2pass = 0;
/* Video Usability Information (VUI) */
param->vui.aspectRatioIdc = 0;
@@ -1375,6 +1376,7 @@ int x265_param_parse(x265_param* p, const char* name,
const char* value)
sscanf(value, "%d,%d,%d", &p->hmeRange[0], &p->hmeRange[1],
&p->hmeRange[2]);
p->bEnableHME = true;
}
+ OPT("vbv-live-multi-pass") p->bliveVBV2pass = atobool(value);
else
return X265_PARAM_BAD_NAME;
}
@@ -1817,6 +1819,15 @@ int x265_check_params(x265_param* param)
CHECK(param->confWinRightOffset < 0, "Conformance Window Right Offset
must be 0 or greater");
CHECK(param->confWinBottomOffset < 0, "Conformance Window Bottom
Offset must be 0 or greater");
CHECK(param->decoderVbvMaxRate < 0, "Invalid Decoder Vbv Maxrate.
Value can not be less than zero");
+ if (param->bliveVBV2pass)
+ {
+ CHECK((param->rc.bStatRead == 0), "Live VBV in multi pass option
requires rate control 2 pass to be enabled");
+ if ((param->rc.vbvMaxBitrate <= 0 || param->rc.vbvBufferSize <= 0))
+ {
+ param->bliveVBV2pass = 0;
+ x265_log(param, X265_LOG_WARNING, "Live VBV enabled without
VBV settings.Disabling live VBV in 2 pass\n");
+ }
+ }
return check_failed;
}
@@ -2238,6 +2249,7 @@ char *x265_param2string(x265_param* p, int padx, int
pady)
s += sprintf(s, " scenecut-window=%d qp-delta-ref=%f
qp-delta-nonref=%f", p->scenecutWindow, p->refQpDelta, p->nonRefQpDelta);
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");
#undef BOOL
return buf;
}
@@ -2593,6 +2605,7 @@ void x265_copy_params(x265_param* dst, x265_param*
src)
dst->confWinRightOffset = src->confWinRightOffset;
dst->confWinBottomOffset = src->confWinBottomOffset;
+ dst->bliveVBV2pass = src->bliveVBV2pass;
#ifdef SVT_HEVC
memcpy(dst->svtHevcParam, src->svtHevcParam,
sizeof(EB_H265_ENC_CONFIGURATION));
#endif
diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp
index 82d7c4f2a..8e9187e8a 100644
--- a/source/encoder/ratecontrol.cpp
+++ b/source/encoder/ratecontrol.cpp
@@ -1755,34 +1755,32 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
g_sliceTypeToChar[m_sliceType],
g_sliceTypeToChar[rce->sliceType]);
}
}
- else
+
+ if ((m_param->bliveVBV2pass && m_param->rc.rateControlMode ==
X265_RC_ABR) || m_isAbr)
{
- if (m_isAbr)
+ int pos = m_sliderPos % s_slidingWindowFrames;
+ int addPos = (pos + s_slidingWindowFrames - 1) %
s_slidingWindowFrames;
+ if (m_sliderPos > s_slidingWindowFrames)
{
- int pos = m_sliderPos % s_slidingWindowFrames;
- int addPos = (pos + s_slidingWindowFrames - 1) %
s_slidingWindowFrames;
- if (m_sliderPos > s_slidingWindowFrames)
- {
- const static double base = pow(0.5, s_slidingWindowFrames
- 1);
- m_movingAvgSum -= m_lastRemovedSatdCost * base;
- m_movingAvgSum *= 0.5;
- m_movingAvgSum += m_satdCostWindow[addPos];
- }
- else if (m_sliderPos == s_slidingWindowFrames)
- {
- m_movingAvgSum += m_satdCostWindow[addPos];
- }
- else if (m_sliderPos > 0)
- {
- m_movingAvgSum += m_satdCostWindow[addPos];
- m_movingAvgSum *= 0.5;
- }
-
- rce->movingAvgSum = m_movingAvgSum;
- m_lastRemovedSatdCost = m_satdCostWindow[pos];
- m_satdCostWindow[pos] = rce->lastSatd;
- m_sliderPos++;
+ const static double base = pow(0.5, s_slidingWindowFrames - 1);
+ m_movingAvgSum -= m_lastRemovedSatdCost * base;
+ m_movingAvgSum *= 0.5;
+ m_movingAvgSum += m_satdCostWindow[addPos];
+ }
+ else if (m_sliderPos == s_slidingWindowFrames)
+ {
+ m_movingAvgSum += m_satdCostWindow[addPos];
}
+ else if (m_sliderPos > 0)
+ {
+ m_movingAvgSum += m_satdCostWindow[addPos];
+ m_movingAvgSum *= 0.5;
+ }
+
+ rce->movingAvgSum = m_movingAvgSum;
+ m_lastRemovedSatdCost = m_satdCostWindow[pos];
+ m_satdCostWindow[pos] = rce->lastSatd;
+ m_sliderPos++;
}
if (m_sliceType == B_SLICE)
@@ -1887,7 +1885,7 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
qScale = x265_clip3(lqmin, lqmax, qScale);
}
- if (!m_2pass)
+ if (!m_2pass || m_param->bliveVBV2pass)
{
/* clip qp to permissible range after vbv-lookahead
estimation to avoid possible
* mispredictions by initial frame size predictors */
@@ -1955,7 +1953,9 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
else
q /= zone->bitrateFactor;
}
- q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) /
abrBuffer);
+ /*Existing ABR conformance check may not be valid with real
time VBV*/
+ if(!m_param->bliveVBV2pass)
+ q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) /
abrBuffer);
if (m_expectedBitsSum > 0)
{
/* Adjust quant based on the difference between
@@ -1988,24 +1988,34 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
if (m_isVbv)
{
- /* Do not overflow vbv */
- double expectedSize = qScale2bits(rce, q);
- double expectedVbv = m_bufferFill + m_bufferRate -
expectedSize;
- double expectedFullness = rce->expectedVbv / m_bufferSize;
- double qmax = q * (2 - expectedFullness);
- double sizeConstraint = 1 + expectedFullness;
- qmax = X265_MAX(qmax, rce->newQScale);
- if (expectedFullness < .05)
- qmax = lmax;
- qmax = X265_MIN(qmax, lmax);
- while (((expectedVbv < rce->expectedVbv/sizeConstraint) &&
(q < qmax)) ||
+ if (!m_param->bliveVBV2pass)
+ {
+ /* Do not overflow vbv */
+ double expectedSize = qScale2bits(rce, q);
+ double expectedVbv = m_bufferFill + m_bufferRate -
expectedSize;
+ double expectedFullness = rce->expectedVbv /
m_bufferSize;
+ double qmax = q * (2 - expectedFullness);
+ double sizeConstraint = 1 + expectedFullness;
+ qmax = X265_MAX(qmax, rce->newQScale);
+ if (expectedFullness < .05)
+ qmax = lmax;
+ qmax = X265_MIN(qmax, lmax);
+ while (((expectedVbv < rce->expectedVbv /
sizeConstraint) && (q < qmax)) ||
((expectedVbv < 0) && (q < lmax)))
+ {
+ q *= 1.05;
+ expectedSize = qScale2bits(rce, q);
+ expectedVbv = m_bufferFill + m_bufferRate -
expectedSize;
+ }
+ }
+ else
{
- q *= 1.05;
- expectedSize = qScale2bits(rce, q);
- expectedVbv = m_bufferFill + m_bufferRate -
expectedSize;
+ /* clip qp to permissible range after
vbv-lookahead estimation to avoid possible
+ * mispredictions by Rate Control pass 1 statistics
analysis */
+ q = clipQscale(curFrame, rce, q);
}
}
+
q = x265_clip3(lmin, lmax, q);
}
else
@@ -2379,7 +2389,7 @@ double RateControl::clipQscale(Frame* curFrame,
RateControlEntry* rce, double q)
}
/* Try to get the buffer not more than 80% filled, but
don't set an impossible goal. */
targetFill = x265_clip3(m_bufferSize * (1 - 0.2 *
finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);
- if (m_isCbr && bufferFillCur > targetFill &&
!m_isSceneTransition)
+ if ((m_isCbr || m_2pass) && bufferFillCur > targetFill
&& !m_isSceneTransition)
{
q /= 1.01;
loopTerminate |= 2;
@@ -2432,7 +2442,7 @@ double RateControl::clipQscale(Frame* curFrame,
RateControlEntry* rce, double q)
* lookahead vbv reduces its qscale by half its value. Be on safer
side and avoid drastic
* qscale reductions for frames high in complexity */
bool mispredCheck = rce->movingAvgSum && m_currentSatd >=
rce->movingAvgSum && q <= q0 / 2;
- if (!m_isCbr || (m_isAbr && mispredCheck))
+ if (!m_isCbr || ((m_isAbr || m_2pass) && mispredCheck))
q = X265_MAX(q0, q);
if (m_rateFactorMaxIncrement)
@@ -2442,7 +2452,7 @@ double RateControl::clipQscale(Frame* curFrame,
RateControlEntry* rce, double q)
return x265_clip3(lmin, qmax, q);
}
}
- if (m_2pass)
+ if (!curFrame && m_2pass)
{
double min = log(lmin);
double max = log(lmax);
diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp
index 4e52e584c..0adb0d0db 100644
--- a/source/encoder/slicetype.cpp
+++ b/source/encoder/slicetype.cpp
@@ -1497,14 +1497,15 @@ void Lookahead::slicetypeDecide()
}
}
- if (m_lastNonB && !m_param->rc.bStatRead &&
+ if (m_lastNonB &&
((m_param->bFrameAdaptive && m_param->bframes) ||
m_param->rc.cuTree || m_param->scenecutThreshold ||
m_param->bHistBasedSceneCut ||
(m_param->lookaheadDepth && m_param->rc.vbvBufferSize)))
{
- slicetypeAnalyse(frames, false);
+ if(!m_param->rc.bStatRead)
+ slicetypeAnalyse(frames, false);
bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
m_param->rc.vbvMaxBitrate > 0;
- if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
+ if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) ||
m_param->bliveVBV2pass)
{
int numFrames;
for (numFrames = 0; numFrames < maxSearch; numFrames++)
@@ -1749,7 +1750,7 @@ void Lookahead::slicetypeDecide()
}
}
- bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
(m_param->rc.vbvBufferSize && m_param->lookaheadDepth)) &&
!m_param->rc.bStatRead;
+ bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
(m_param->rc.vbvBufferSize && m_param->lookaheadDepth));
if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))
{
m_inputLock.acquire();
@@ -1764,9 +1765,10 @@ void Lookahead::slicetypeDecide()
m_inputLock.release();
frames[j + 1] = NULL;
- slicetypeAnalyse(frames, true);
+ if (!m_param->rc.bStatRead)
+ slicetypeAnalyse(frames, true);
bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
m_param->rc.vbvMaxBitrate > 0;
- if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
+ if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) ||
m_param->bliveVBV2pass)
{
int numFrames;
for (numFrames = 0; numFrames < maxSearch; numFrames++)
diff --git a/source/x265.h b/source/x265.h
index 0ffa600b0..3fc464f6d 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -1920,6 +1920,11 @@ typedef struct x265_param
/* Maxrate that could be signaled to the decoder. Default 0. API only.
*/
int decoderVbvMaxRate;
+
+ /*Enables Qp tuning with respect to real time VBV buffer fullness in
rate
+ control 2 pass. Experimental.Default is disabled*/
+ int bliveVBV2pass;
+
} x265_param;
/* x265_param_alloc:
diff --git a/source/x265cli.cpp b/source/x265cli.cpp
index 6e8e0e661..0cf2d815c 100755
--- a/source/x265cli.cpp
+++ b/source/x265cli.cpp
@@ -221,6 +221,7 @@ namespace X265_NS {
" - 3 : Nth pass, overwrites
stats file\n");
H0(" --[no-]multi-pass-opt-analysis Refine analysis in 2 pass
based on analysis information from pass 1\n");
H0(" --[no-]multi-pass-opt-distortion Use distortion of CTU from
pass 1 to refine qp in 2 pass\n");
+ H0(" --[no-]vbv-live-multi-pass Enable realtime VBV in rate
control 2 pass.Default %s\n", OPT(param->bliveVBV2pass));
H0(" --stats Filename for stats file in
multipass pass rate control. Default x265_2pass.log\n");
H0(" --[no-]analyze-src-pics Motion estimation uses source
frame planes. Default disable\n");
H0(" --[no-]slow-firstpass Enable a slow first pass in a
multipass rate control mode. Default %s\n",
OPT(param->rc.bEnableSlowFirstPass));
diff --git a/source/x265cli.h b/source/x265cli.h
index 311f06935..3e2fd5e6d 100644
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -284,6 +284,8 @@ static const struct option long_options[] =
{ "no-multi-pass-opt-analysis", no_argument, NULL, 0 },
{ "multi-pass-opt-distortion", no_argument, NULL, 0 },
{ "no-multi-pass-opt-distortion", no_argument, NULL, 0 },
+ { "vbv-live-multi-pass", no_argument, NULL, 0 },
+ { "no-vbv-live-multi-pass", no_argument, NULL, 0 },
{ "slow-firstpass", no_argument, NULL, 0 },
{ "no-slow-firstpass", no_argument, NULL, 0 },
{ "multi-pass-opt-rps", no_argument, NULL, 0 },
--
2.28.0.windows.1
*Thanks,*
*Kirithika*
On Wed, Sep 9, 2020 at 10:52 AM Kirithika Kalirathnam <
kirithika at multicorewareinc.com> wrote:
> On Mon, Sep 7, 2020 at 6:19 PM Aruna Matheswaran <
> aruna at multicorewareinc.com> wrote:
>
>>
>>
>> On Fri, Sep 4, 2020 at 5:44 PM Kirithika Kalirathnam <
>> kirithika at multicorewareinc.com> wrote:
>>
>>> From f1391f094c9c3c0502624532f751219d126905aa Mon Sep 17 00:00:00 2001
>>> From: Kirithika <kirithika at multicorewareinc.com>
>>> Date: Fri, 28 Aug 2020 09:20:47 +0530
>>> Subject: [PATCH] Add real-time VBV fullness based QP tuning in VBV 2 pass
>>>
>>> This commit enables real-time VBV fullness based 2nd pass QP tuning.
>>> Experimental feature.Default disabled
>>> ---
>>> doc/reST/cli.rst | 9 +++
>>> source/CMakeLists.txt | 2 +-
>>> source/common/param.cpp | 12 ++++
>>> source/encoder/ratecontrol.cpp | 100 ++++++++++++++++++---------------
>>> source/encoder/slicetype.cpp | 14 +++--
>>> source/x265.h | 4 ++
>>> source/x265cli.cpp | 1 +
>>> source/x265cli.h | 2 +
>>> 8 files changed, 92 insertions(+), 52 deletions(-)
>>>
>>> diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
>>> index e6c628c36..2a4b25aca 100755
>>> --- a/doc/reST/cli.rst
>>> +++ b/doc/reST/cli.rst
>>> @@ -1977,6 +1977,15 @@ Quality, rate control and rate distortion options
>>>
>>> **Range of values:** 0 to 10
>>>
>>> +.. option:: --realtime-vbv-2pass, --no-realtime-vbv-2pass
>>>
>> [AM] Can we find a better alternate for the CLI option?
>> --real-time-vbv-2-pass looks a bit long.
>> The term 2pass is a little confusing. Technically it is multi-pass; not
>> just 2pass.
>>
> Ok.I shall update the name to vbv-live-multi-pass,as it is
> self-explanatory though it's a bit longer.
>
>> +
>>> + It enables the Qp tuning at frame level based on real time VBV
>>> Buffer fullness
>>> + in the ratecontrol second pass to reduce the VBV violations.
>>> + It could only be enabled with rate control pass 2 encodes with VBV
>>> and ABR
>>> + rate control mode.
>>> +
>>>
>> [AM] why not for CRF rate-control mode?
>>
> Currently,we have tested the feature only for ABR case.We shall extend
> this to CRF mode also in future.
>
>> + Default disabled. **Experimental feature**
>>> +
>>> Quantization Options
>>> ====================
>>>
>>> diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
>>> index d9ed3983e..5738c861c 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 196)
>>> +set(X265_BUILD 197)
>>> 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 845c38bd2..fc0425905 100755
>>> --- a/source/common/param.cpp
>>> +++ b/source/common/param.cpp
>>> @@ -288,6 +288,7 @@ void x265_param_default(x265_param* param)
>>> param->bResetZoneConfig = 1;
>>> param->reconfigWindowSize = 0;
>>> param->decoderVbvMaxRate = 0;
>>> + param->rc.bRealtimeVBV2pass = 0;
>>>
>>> /* Video Usability Information (VUI) */
>>> param->vui.aspectRatioIdc = 0;
>>> @@ -1375,6 +1376,7 @@ int x265_param_parse(x265_param* p, const char*
>>> name, const char* value)
>>> sscanf(value, "%d,%d,%d", &p->hmeRange[0], &p->hmeRange[1],
>>> &p->hmeRange[2]);
>>> p->bEnableHME = true;
>>> }
>>> + OPT("realtime-vbv-2pass") p->rc.bRealtimeVBV2pass =
>>> atobool(value);
>>> else
>>> return X265_PARAM_BAD_NAME;
>>> }
>>> @@ -1817,6 +1819,15 @@ int x265_check_params(x265_param* param)
>>> CHECK(param->confWinRightOffset < 0, "Conformance Window Right
>>> Offset must be 0 or greater");
>>> CHECK(param->confWinBottomOffset < 0, "Conformance Window Bottom
>>> Offset must be 0 or greater");
>>> CHECK(param->decoderVbvMaxRate < 0, "Invalid Decoder Vbv Maxrate.
>>> Value can not be less than zero");
>>> + if (param->rc.bRealtimeVBV2pass)
>>> + {
>>> + CHECK((param->rc.bStatRead == 0), "Real time VBV in 2 pass
>>> option requires rate control 2 pass to be enabled");
>>> + if ((param->rc.vbvMaxBitrate <= 0 || param->rc.vbvBufferSize <=
>>> 0))
>>> + {
>>> + param->rc.bRealtimeVBV2pass = 0;
>>> + x265_log(param, X265_LOG_WARNING, "Real time VBV enabled
>>> without VBV settings.Disabling real time VBV in 2 pass\n");
>>> + }
>>> + }
>>> return check_failed;
>>> }
>>>
>>> @@ -2593,6 +2604,7 @@ void x265_copy_params(x265_param* dst, x265_param*
>>> src)
>>>
>>> dst->confWinRightOffset = src->confWinRightOffset;
>>> dst->confWinBottomOffset = src->confWinBottomOffset;
>>> + dst->rc.bRealtimeVBV2pass = src->rc.bRealtimeVBV2pass;
>>> #ifdef SVT_HEVC
>>> memcpy(dst->svtHevcParam, src->svtHevcParam,
>>> sizeof(EB_H265_ENC_CONFIGURATION));
>>> #endif
>>> diff --git a/source/encoder/ratecontrol.cpp
>>> b/source/encoder/ratecontrol.cpp
>>> index 82d7c4f2a..ebf374759 100644
>>> --- a/source/encoder/ratecontrol.cpp
>>> +++ b/source/encoder/ratecontrol.cpp
>>> @@ -1755,34 +1755,32 @@ double RateControl::rateEstimateQscale(Frame*
>>> curFrame, RateControlEntry *rce)
>>> g_sliceTypeToChar[m_sliceType],
>>> g_sliceTypeToChar[rce->sliceType]);
>>> }
>>> }
>>> - else
>>> +
>>> + if ((m_param->rc.bRealtimeVBV2pass && m_param->rc.rateControlMode
>>> == X265_RC_ABR) || m_isAbr)
>>> {
>>> - if (m_isAbr)
>>> + int pos = m_sliderPos % s_slidingWindowFrames;
>>> + int addPos = (pos + s_slidingWindowFrames - 1) %
>>> s_slidingWindowFrames;
>>> + if (m_sliderPos > s_slidingWindowFrames)
>>> {
>>> - int pos = m_sliderPos % s_slidingWindowFrames;
>>> - int addPos = (pos + s_slidingWindowFrames - 1) %
>>> s_slidingWindowFrames;
>>> - if (m_sliderPos > s_slidingWindowFrames)
>>> - {
>>> - const static double base = pow(0.5,
>>> s_slidingWindowFrames - 1);
>>> - m_movingAvgSum -= m_lastRemovedSatdCost * base;
>>> - m_movingAvgSum *= 0.5;
>>> - m_movingAvgSum += m_satdCostWindow[addPos];
>>> - }
>>> - else if (m_sliderPos == s_slidingWindowFrames)
>>> - {
>>> - m_movingAvgSum += m_satdCostWindow[addPos];
>>> - }
>>> - else if (m_sliderPos > 0)
>>> - {
>>> - m_movingAvgSum += m_satdCostWindow[addPos];
>>> - m_movingAvgSum *= 0.5;
>>> - }
>>> -
>>> - rce->movingAvgSum = m_movingAvgSum;
>>> - m_lastRemovedSatdCost = m_satdCostWindow[pos];
>>> - m_satdCostWindow[pos] = rce->lastSatd;
>>> - m_sliderPos++;
>>> + const static double base = pow(0.5, s_slidingWindowFrames -
>>> 1);
>>> + m_movingAvgSum -= m_lastRemovedSatdCost * base;
>>> + m_movingAvgSum *= 0.5;
>>> + m_movingAvgSum += m_satdCostWindow[addPos];
>>> + }
>>> + else if (m_sliderPos == s_slidingWindowFrames)
>>> + {
>>> + m_movingAvgSum += m_satdCostWindow[addPos];
>>> }
>>> + else if (m_sliderPos > 0)
>>> + {
>>> + m_movingAvgSum += m_satdCostWindow[addPos];
>>> + m_movingAvgSum *= 0.5;
>>> + }
>>> +
>>> + rce->movingAvgSum = m_movingAvgSum;
>>> + m_lastRemovedSatdCost = m_satdCostWindow[pos];
>>> + m_satdCostWindow[pos] = rce->lastSatd;
>>> + m_sliderPos++;
>>> }
>>>
>>> if (m_sliceType == B_SLICE)
>>> @@ -1887,7 +1885,7 @@ double RateControl::rateEstimateQscale(Frame*
>>> curFrame, RateControlEntry *rce)
>>> qScale = x265_clip3(lqmin, lqmax, qScale);
>>> }
>>>
>>> - if (!m_2pass)
>>> + if (!m_2pass || m_param->rc.bRealtimeVBV2pass)
>>> {
>>> /* clip qp to permissible range after vbv-lookahead
>>> estimation to avoid possible
>>> * mispredictions by initial frame size predictors */
>>> @@ -1955,7 +1953,9 @@ double RateControl::rateEstimateQscale(Frame*
>>> curFrame, RateControlEntry *rce)
>>> else
>>> q /= zone->bitrateFactor;
>>> }
>>> - q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) /
>>> abrBuffer);
>>> + /*Existing ABR conformance check may not be valid with real
>>> time VBV*/
>>> + if(!m_param->rc.bRealtimeVBV2pass)
>>> + q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) /
>>> abrBuffer);
>>> if (m_expectedBitsSum > 0)
>>> {
>>> /* Adjust quant based on the difference between
>>> @@ -1988,24 +1988,34 @@ double RateControl::rateEstimateQscale(Frame*
>>> curFrame, RateControlEntry *rce)
>>>
>>> if (m_isVbv)
>>> {
>>> - /* Do not overflow vbv */
>>> - double expectedSize = qScale2bits(rce, q);
>>> - double expectedVbv = m_bufferFill + m_bufferRate -
>>> expectedSize;
>>> - double expectedFullness = rce->expectedVbv /
>>> m_bufferSize;
>>> - double qmax = q * (2 - expectedFullness);
>>> - double sizeConstraint = 1 + expectedFullness;
>>> - qmax = X265_MAX(qmax, rce->newQScale);
>>> - if (expectedFullness < .05)
>>> - qmax = lmax;
>>> - qmax = X265_MIN(qmax, lmax);
>>> - while (((expectedVbv < rce->expectedVbv/sizeConstraint)
>>> && (q < qmax)) ||
>>> + if (!m_param->rc.bRealtimeVBV2pass)
>>> + {
>>> + /* Do not overflow vbv */
>>> + double expectedSize = qScale2bits(rce, q);
>>> + double expectedVbv = m_bufferFill + m_bufferRate -
>>> expectedSize;
>>> + double expectedFullness = rce->expectedVbv /
>>> m_bufferSize;
>>> + double qmax = q * (2 - expectedFullness);
>>> + double sizeConstraint = 1 + expectedFullness;
>>> + qmax = X265_MAX(qmax, rce->newQScale);
>>> + if (expectedFullness < .05)
>>> + qmax = lmax;
>>> + qmax = X265_MIN(qmax, lmax);
>>> + while (((expectedVbv < rce->expectedVbv /
>>> sizeConstraint) && (q < qmax)) ||
>>> ((expectedVbv < 0) && (q < lmax)))
>>> + {
>>> + q *= 1.05;
>>> + expectedSize = qScale2bits(rce, q);
>>> + expectedVbv = m_bufferFill + m_bufferRate -
>>> expectedSize;
>>> + }
>>> + }
>>> + else
>>> {
>>> - q *= 1.05;
>>> - expectedSize = qScale2bits(rce, q);
>>> - expectedVbv = m_bufferFill + m_bufferRate -
>>> expectedSize;
>>> + /* clip qp to permissible range after
>>> vbv-lookahead estimation to avoid possible
>>> + * mispredictions by Rate Control pass 1
>>> statistics analysis */
>>> + q = clipQscale(curFrame, rce, q);
>>> }
>>> }
>>> +
>>> q = x265_clip3(lmin, lmax, q);
>>> }
>>> else
>>> @@ -2301,7 +2311,7 @@ double RateControl::clipQscale(Frame* curFrame,
>>> RateControlEntry* rce, double q)
>>> double lmin = m_lmin[rce->sliceType];
>>> double lmax = m_lmax[rce->sliceType];
>>> double q0 = q;
>>> - if (m_isVbv && m_currentSatd > 0 && curFrame)
>>> + if ((m_isVbv || m_param->rc.bRealtimeVBV2pass) && curFrame &&
>>> m_currentSatd > 0 )
>>> {
>>>
>> [AM] Do we need to m_param->rc.bRealtimeVBV2pass check here? The call to
>> clipQscale() is guarded by "m_param->rc.bRealtimeVBV2pass" from what I see.
>>
> yeah,the check is redundant and I shall remove it.
>
>> if (m_param->lookaheadDepth || m_param->rc.cuTree ||
>>> (m_param->scenecutThreshold || m_param->bHistBasedSceneCut)
>>> ||
>>> @@ -2379,7 +2389,7 @@ double RateControl::clipQscale(Frame* curFrame,
>>> RateControlEntry* rce, double q)
>>> }
>>> /* Try to get the buffer not more than 80% filled,
>>> but don't set an impossible goal. */
>>> targetFill = x265_clip3(m_bufferSize * (1 - 0.2 *
>>> finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);
>>> - if (m_isCbr && bufferFillCur > targetFill &&
>>> !m_isSceneTransition)
>>> + if ((m_isCbr || m_2pass) && bufferFillCur >
>>> targetFill && !m_isSceneTransition)
>>> {
>>> q /= 1.01;
>>> loopTerminate |= 2;
>>> @@ -2432,7 +2442,7 @@ double RateControl::clipQscale(Frame* curFrame,
>>> RateControlEntry* rce, double q)
>>> * lookahead vbv reduces its qscale by half its value. Be on
>>> safer side and avoid drastic
>>> * qscale reductions for frames high in complexity */
>>> bool mispredCheck = rce->movingAvgSum && m_currentSatd >=
>>> rce->movingAvgSum && q <= q0 / 2;
>>> - if (!m_isCbr || (m_isAbr && mispredCheck))
>>> + if (!m_isCbr || ((m_isAbr || m_2pass) && mispredCheck))
>>>
>> [AM] Same question here.
>>
> m_isAbr is not set with 2 pass encodes.Hence I have added an additional
> check here.
>
>> q = X265_MAX(q0, q);
>>>
>>> if (m_rateFactorMaxIncrement)
>>> @@ -2442,7 +2452,7 @@ double RateControl::clipQscale(Frame* curFrame,
>>> RateControlEntry* rce, double q)
>>> return x265_clip3(lmin, qmax, q);
>>> }
>>> }
>>> - if (m_2pass)
>>> + if (!curFrame && m_2pass)
>>> {
>>> double min = log(lmin);
>>> double max = log(lmax);
>>> diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp
>>> index 4e52e584c..69f3b0ad1 100644
>>> --- a/source/encoder/slicetype.cpp
>>> +++ b/source/encoder/slicetype.cpp
>>> @@ -1497,14 +1497,15 @@ void Lookahead::slicetypeDecide()
>>> }
>>> }
>>>
>>> - if (m_lastNonB && !m_param->rc.bStatRead &&
>>> + if (m_lastNonB &&
>>> ((m_param->bFrameAdaptive && m_param->bframes) ||
>>> m_param->rc.cuTree || m_param->scenecutThreshold ||
>>> m_param->bHistBasedSceneCut ||
>>> (m_param->lookaheadDepth && m_param->rc.vbvBufferSize)))
>>> {
>>> - slicetypeAnalyse(frames, false);
>>> + if(!m_param->rc.bStatRead)
>>> + slicetypeAnalyse(frames, false);
>>> bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
>>> m_param->rc.vbvMaxBitrate > 0;
>>> - if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
>>> + if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
>>> || m_param->rc.bRealtimeVBV2pass)
>>> {
>>> int numFrames;
>>> for (numFrames = 0; numFrames < maxSearch; numFrames++)
>>> @@ -1749,7 +1750,7 @@ void Lookahead::slicetypeDecide()
>>> }
>>> }
>>>
>>> - bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
>>> (m_param->rc.vbvBufferSize && m_param->lookaheadDepth)) &&
>>> !m_param->rc.bStatRead;
>>> + bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
>>> (m_param->rc.vbvBufferSize && m_param->lookaheadDepth));
>>> if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))
>>> {
>>> m_inputLock.acquire();
>>> @@ -1764,9 +1765,10 @@ void Lookahead::slicetypeDecide()
>>> m_inputLock.release();
>>>
>>> frames[j + 1] = NULL;
>>> - slicetypeAnalyse(frames, true);
>>> + if (!m_param->rc.bStatRead)
>>> + slicetypeAnalyse(frames, true);
>>> bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
>>> m_param->rc.vbvMaxBitrate > 0;
>>> - if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
>>> + if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
>>> || m_param->rc.bRealtimeVBV2pass)
>>> {
>>> int numFrames;
>>> for (numFrames = 0; numFrames < maxSearch; numFrames++)
>>> diff --git a/source/x265.h b/source/x265.h
>>> index 0ffa600b0..bcd1d4e58 100644
>>> --- a/source/x265.h
>>> +++ b/source/x265.h
>>> @@ -1486,6 +1486,10 @@ typedef struct x265_param
>>> /* internally enable if tune grain is set */
>>> int bEnableConstVbv;
>>>
>>> + /*Enables Qp tuning with respect to real time VBV buffer
>>> fullness in rate
>>> + control 2 pass. Experimental.Default is disabled*/
>>> + int bRealtimeVBV2pass;
>>> +
>>>
>> [AM] Always add new param options to the end of the structure. Nested
>> structures shall break backward compatibility.
>>
> Ok.I will add the new param at the end of param struct.
>
>> } rc;
>>>
>>> /*== Video Usability Information ==*/
>>> diff --git a/source/x265cli.cpp b/source/x265cli.cpp
>>> index 6e8e0e661..0b17a8d3a 100755
>>> --- a/source/x265cli.cpp
>>> +++ b/source/x265cli.cpp
>>> @@ -221,6 +221,7 @@ namespace X265_NS {
>>> " - 3 : Nth pass,
>>> overwrites stats file\n");
>>> H0(" --[no-]multi-pass-opt-analysis Refine analysis in 2
>>> pass based on analysis information from pass 1\n");
>>> H0(" --[no-]multi-pass-opt-distortion Use distortion of CTU
>>> from pass 1 to refine qp in 2 pass\n");
>>> + H0(" --[no-]realtime-vbv-2pass Enable realtime VBV in
>>> rate control 2 pass.Default %s\n", OPT(param->bLossless));
>>> H0(" --stats Filename for stats file in
>>> multipass pass rate control. Default x265_2pass.log\n");
>>> H0(" --[no-]analyze-src-pics Motion estimation uses
>>> source frame planes. Default disable\n");
>>> H0(" --[no-]slow-firstpass Enable a slow first pass
>>> in a multipass rate control mode. Default %s\n",
>>> OPT(param->rc.bEnableSlowFirstPass));
>>> diff --git a/source/x265cli.h b/source/x265cli.h
>>> index 311f06935..89840d9af 100644
>>> --- a/source/x265cli.h
>>> +++ b/source/x265cli.h
>>> @@ -284,6 +284,8 @@ static const struct option long_options[] =
>>> { "no-multi-pass-opt-analysis", no_argument, NULL, 0 },
>>> { "multi-pass-opt-distortion", no_argument, NULL, 0 },
>>> { "no-multi-pass-opt-distortion", no_argument, NULL, 0 },
>>> + { "realtime-vbv-2pass", no_argument, NULL, 0 },
>>> + { "no-realtime-vbv-2pass", no_argument, NULL, 0 },
>>>
>> [AM] Please add an entry for the new option in x265_param2string(); This
>> will keep the info SEI updated.
>>
> Ok,will update
>
>> { "slow-firstpass", no_argument, NULL, 0 },
>>> { "no-slow-firstpass", no_argument, NULL, 0 },
>>> { "multi-pass-opt-rps", no_argument, NULL, 0 },
>>> --
>>> 2.28.0.windows.1
>>>
>>> *Thanks,*
>>> *Kirithika*
>>> _______________________________________________
>>> x265-devel mailing list
>>> x265-devel at videolan.org
>>> https://mailman.videolan.org/listinfo/x265-devel
>>>
>>
>>
>> --
>> Regards,
>> *Aruna Matheswaran,*
>> Video Codec Engineer,
>> Media & AI analytics BU,
>>
>>
>>
>> _______________________________________________
>> x265-devel mailing list
>> x265-devel at videolan.org
>> https://mailman.videolan.org/listinfo/x265-devel
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20200909/ac10132e/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch-vbv-multi-pass.patch
Type: application/octet-stream
Size: 16276 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20200909/ac10132e/attachment-0001.obj>
More information about the x265-devel
mailing list