[x265] [PATCH] Add support for Segment Based Rate Control
Kirithika Kalirathnam
kirithika at multicorewareinc.com
Thu Dec 29 16:29:09 UTC 2022
>From 817342031263956fba544b1aac9f29e814bb1fdf Mon Sep 17 00:00:00 2001
From: Kirithika <kirithika at multicorewareinc.com>
Date: Fri, 9 Dec 2022 12:31:27 +0530
Subject: [PATCH] Add support for Segment Based Rate Control
1.Configure keyframe interval to be 2 seconds
2.Changes frame duration settings with SBRC 3.Reset RateControl (CRF/ABR)
at the GOP beginning
---
source/encoder/encoder.cpp | 10 +++
source/encoder/ratecontrol.cpp | 110 ++++++++++++++++++++-------------
source/encoder/ratecontrol.h | 3 +
3 files changed, 79 insertions(+), 44 deletions(-)
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index 64a4e231c..ad15b984a 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -4396,6 +4396,16 @@ void Encoder::configure(x265_param *p)
if (m_param->searchRange != m_param->hmeRange[2])
m_param->searchRange = m_param->hmeRange[2];
}
+
+ if (m_param->bEnableSBRC && p->bOpenGOP)
+ {
+ x265_log(p, X265_LOG_WARNING, "Segment based RateControl requires
closed gop structure. Enabling closed GOP.\n");
+ m_param->bOpenGOP = 0;
+
+ //Configure GOP to 2s duration
+ p->keyframeMax = 2 * (m_param->fpsNum / m_param->fpsDenom);
+ p->keyframeMin = 2 * (m_param->fpsNum / m_param->fpsDenom);
+ }
}
void Encoder::readAnalysisFile(x265_analysis_data* analysis, int curPoc,
const x265_picture* picIn, int paramBytes)
diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp
index 32399eda6..1c29e4a00 100644
--- a/source/encoder/ratecontrol.cpp
+++ b/source/encoder/ratecontrol.cpp
@@ -392,45 +392,49 @@ bool RateControl::initCUTreeSharedMem()
return true;
}
-bool RateControl::init(const SPS& sps)
+void RateControl::initVBV(const SPS& sps)
{
- if (m_isVbv && !m_initVbv)
+ /* We don't support changing the ABR bitrate right now,
+ * so if the stream starts as CBR, keep it CBR. */
+ if (m_param->rc.vbvBufferSize < (int)(m_param->rc.vbvMaxBitrate /
m_fps))
{
- /* We don't support changing the ABR bitrate right now,
- * so if the stream starts as CBR, keep it CBR. */
- if (m_param->rc.vbvBufferSize < (int)(m_param->rc.vbvMaxBitrate /
m_fps))
- {
- m_param->rc.vbvBufferSize = (int)(m_param->rc.vbvMaxBitrate /
m_fps);
- x265_log(m_param, X265_LOG_WARNING, "VBV buffer size cannot be
smaller than one frame, using %d kbit\n",
- m_param->rc.vbvBufferSize);
- }
- int vbvBufferSize = m_param->rc.vbvBufferSize * 1000;
- int vbvMaxBitrate = m_param->rc.vbvMaxBitrate * 1000;
+ m_param->rc.vbvBufferSize = (int)(m_param->rc.vbvMaxBitrate /
m_fps);
+ x265_log(m_param, X265_LOG_WARNING, "VBV buffer size cannot be
smaller than one frame, using %d kbit\n",
+ m_param->rc.vbvBufferSize);
+ }
+ int vbvBufferSize = m_param->rc.vbvBufferSize * 1000;
+ int vbvMaxBitrate = m_param->rc.vbvMaxBitrate * 1000;
- if (m_param->bEmitHRDSEI && !m_param->decoderVbvMaxRate)
- {
- const HRDInfo* hrd = &sps.vuiParameters.hrdParameters;
- vbvBufferSize = hrd->cpbSizeValue << (hrd->cpbSizeScale +
CPB_SHIFT);
- vbvMaxBitrate = hrd->bitRateValue << (hrd->bitRateScale +
BR_SHIFT);
- }
- m_bufferRate = vbvMaxBitrate / m_fps;
- m_vbvMaxRate = vbvMaxBitrate;
- m_bufferSize = vbvBufferSize;
- m_singleFrameVbv = m_bufferRate * 1.1 > m_bufferSize;
+ if (m_param->bEmitHRDSEI && !m_param->decoderVbvMaxRate)
+ {
+ const HRDInfo* hrd = &sps.vuiParameters.hrdParameters;
+ vbvBufferSize = hrd->cpbSizeValue << (hrd->cpbSizeScale +
CPB_SHIFT);
+ vbvMaxBitrate = hrd->bitRateValue << (hrd->bitRateScale +
BR_SHIFT);
+ }
+ m_bufferRate = vbvMaxBitrate / m_fps;
+ m_vbvMaxRate = vbvMaxBitrate;
+ m_bufferSize = vbvBufferSize;
+ m_singleFrameVbv = m_bufferRate * 1.1 > m_bufferSize;
+
+ if (m_param->rc.vbvBufferInit > 1.)
+ m_param->rc.vbvBufferInit = x265_clip3(0.0, 1.0,
m_param->rc.vbvBufferInit / m_param->rc.vbvBufferSize);
+ if (m_param->vbvBufferEnd > 1.)
+ m_param->vbvBufferEnd = x265_clip3(0.0, 1.0, m_param->vbvBufferEnd
/ m_param->rc.vbvBufferSize);
+ if (m_param->vbvEndFrameAdjust > 1.)
+ m_param->vbvEndFrameAdjust = x265_clip3(0.0, 1.0,
m_param->vbvEndFrameAdjust);
+ m_param->rc.vbvBufferInit = x265_clip3(0.0, 1.0,
X265_MAX(m_param->rc.vbvBufferInit, m_bufferRate / m_bufferSize));
+ m_bufferFillFinal = m_bufferSize * m_param->rc.vbvBufferInit;
+ m_bufferFillActual = m_bufferFillFinal;
+ m_bufferExcess = 0;
+ m_minBufferFill = m_param->minVbvFullness / 100;
+ m_maxBufferFill = 1 - (m_param->maxVbvFullness / 100);
+}
- if (m_param->rc.vbvBufferInit > 1.)
- m_param->rc.vbvBufferInit = x265_clip3(0.0, 1.0,
m_param->rc.vbvBufferInit / m_param->rc.vbvBufferSize);
- if (m_param->vbvBufferEnd > 1.)
- m_param->vbvBufferEnd = x265_clip3(0.0, 1.0,
m_param->vbvBufferEnd / m_param->rc.vbvBufferSize);
- if (m_param->vbvEndFrameAdjust > 1.)
- m_param->vbvEndFrameAdjust = x265_clip3(0.0, 1.0,
m_param->vbvEndFrameAdjust);
- m_param->rc.vbvBufferInit = x265_clip3(0.0, 1.0,
X265_MAX(m_param->rc.vbvBufferInit, m_bufferRate / m_bufferSize));
- m_bufferFillFinal = m_bufferSize * m_param->rc.vbvBufferInit;
- m_bufferFillActual = m_bufferFillFinal;
- m_bufferExcess = 0;
- m_minBufferFill = m_param->minVbvFullness / 100;
- m_maxBufferFill = 1 - (m_param->maxVbvFullness / 100);
- m_initVbv = true;
+bool RateControl::init(const SPS& sps)
+{
+ if (m_isVbv)
+ {
+ initVBV(sps);
}
if (!m_param->bResetZoneConfig && (m_relativeComplexity == NULL))
@@ -477,7 +481,7 @@ bool RateControl::init(const SPS& sps)
/* estimated ratio that produces a reasonable QP for the first I-frame
*/
m_cplxrSum = .01 * pow(7.0e5, m_qCompress) * pow(m_ncu, 0.5) *
tuneCplxFactor;
- m_wantedBitsWindow = m_bitrate * m_frameDuration;
+ m_wantedBitsWindow = (m_param->bEnableSBRC ? (m_bitrate * ( 1.0 /
m_param->keyframeMax )) :m_bitrate * m_frameDuration);
m_accumPNorm = .01;
m_accumPQp = (m_param->rc.rateControlMode == X265_RC_CRF ? CRF_INIT_QP
: ABR_INIT_QP_MIN) * m_accumPNorm;
@@ -1819,7 +1823,8 @@ double RateControl::tuneAbrQScaleFromFeedback(double
qScale)
double abrBuffer = 2 * m_rateTolerance * m_bitrate;
/* use framesDone instead of POC as poc count is not serial with
bframes enabled */
double overflow = 1.0;
- double timeDone = (double)(m_framesDone - m_param->frameNumThreads +
1) * m_frameDuration;
+ double duration = m_param->bEnableSBRC ? (1.0 / m_param->keyframeMax)
: m_frameDuration;
+ double timeDone = (double)(m_framesDone - m_param->frameNumThreads +
1) * duration;
double wantedBits = timeDone * m_bitrate;
int64_t encodedBits = m_totalBits;
if (m_param->totalFrames && m_param->totalFrames <= 2 * m_fps)
@@ -1829,7 +1834,7 @@ double RateControl::tuneAbrQScaleFromFeedback(double
qScale)
}
if (wantedBits > 0 && encodedBits > 0 && (!m_partialResidualFrames ||
- m_param->rc.bStrictCbr || m_isGrainEnabled))
+ m_param->rc.bStrictCbr || m_isGrainEnabled ||
m_param->bEnableSBRC))
{
abrBuffer *= X265_MAX(1, sqrt(timeDone));
overflow = x265_clip3(.5, 2.0, 1.0 + (encodedBits - wantedBits) /
abrBuffer);
@@ -2191,6 +2196,10 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
if (m_param->rc.rateControlMode == X265_RC_CRF)
{
+ if (!m_param->rc.bStatRead && m_param->bEnableSBRC)
+ {
+ checkAndResetCRF(rce);
+ }
q = getQScale(rce, m_rateFactorConstant);
x265_zone* zone = getZone();
if (zone)
@@ -2216,7 +2225,7 @@ double RateControl::rateEstimateQscale(Frame*
curFrame, RateControlEntry *rce)
}
double tunedQScale =
tuneAbrQScaleFromFeedback(initialQScale);
overflow = tunedQScale / initialQScale;
- q = !m_partialResidualFrames? tunedQScale : initialQScale;
+ q = (!m_partialResidualFrames || m_param->bEnableSBRC)?
tunedQScale : initialQScale;
bool isEncodeEnd = (m_param->totalFrames &&
m_framesDone > 0.75 * m_param->totalFrames) ? 1 : 0;
bool isEncodeBeg = m_framesDone < (int)(m_fps + 0.5);
@@ -2385,15 +2394,27 @@ void
RateControl::rateControlUpdateStats(RateControlEntry* rce)
}
}
+
+void RateControl::checkAndResetCRF(RateControlEntry* rce)
+{
+ if(rce->poc % m_param->keyframeMax == 0)
+ {
+ init(*m_curSlice->m_sps);
+ m_shortTermCplxSum = rce->lastSatd /
(CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);
+ m_shortTermCplxCount = 1;
+ rce->blurredComplexity = m_shortTermCplxSum / m_shortTermCplxCount;
+ }
+}
+
void RateControl::checkAndResetABR(RateControlEntry* rce, bool isFrameDone)
{
double abrBuffer = 2 * m_rateTolerance * m_bitrate;
// Check if current Slice is a scene cut that follows low
detailed/blank frames
- if (rce->lastSatd > 4 * rce->movingAvgSum || rce->scenecut ||
rce->isFadeEnd)
+ if (rce->lastSatd > 4 * rce->movingAvgSum || rce->scenecut ||
rce->isFadeEnd || (m_param->bEnableSBRC && (rce->poc % m_param->keyframeMax
== 0)))
{
if (!m_isAbrReset && rce->movingAvgSum > 0
- && (m_isPatternPresent || !m_param->bframes))
+ && (m_isPatternPresent || !m_param->bframes
||(m_param->bEnableSBRC && (rce->poc % m_param->keyframeMax == 0))))
{
int pos = X265_MAX(m_sliderPos - m_param->frameNumThreads, 0);
int64_t shrtTermWantedBits = (int64_t) (X265_MIN(pos,
s_slidingWindowFrames) * m_bitrate * m_frameDuration);
@@ -2403,7 +2424,7 @@ void RateControl::checkAndResetABR(RateControlEntry*
rce, bool isFrameDone)
shrtTermTotalBitsSum += m_encodedBitsWindow[i];
double underflow = (shrtTermTotalBitsSum - shrtTermWantedBits)
/ abrBuffer;
const double epsilon = 0.0001f;
- if ((underflow < epsilon || rce->isFadeEnd) && !isFrameDone)
+ if ((underflow < epsilon || rce->isFadeEnd ||
(m_param->bEnableSBRC && (rce->poc % m_param->keyframeMax == 0))) &&
!isFrameDone)
{
init(*m_curSlice->m_sps);
// Reduce tune complexity factor for scenes that follow
blank frames
@@ -2413,6 +2434,7 @@ void RateControl::checkAndResetABR(RateControlEntry*
rce, bool isFrameDone)
m_shortTermCplxCount = 1;
m_isAbrReset = true;
m_lastAbrResetPoc = rce->poc;
+ rce->blurredComplexity = m_shortTermCplxSum /
m_shortTermCplxCount;
}
}
else if (m_isAbrReset && isFrameDone)
@@ -2487,7 +2509,7 @@ double RateControl::clipQscale(Frame* curFrame,
RateControlEntry* rce, double q)
for (int j = 0; bufferFillCur >= 0 && iter ; j++)
{
int type = curFrame->m_lowres.plannedType[j];
- if (type == X265_TYPE_AUTO || totalDuration >= 1.0)
+ if (type == X265_TYPE_AUTO || totalDuration >= 1.0 ||
(m_param->bEnableSBRC && type == X265_TYPE_IDR))
break;
totalDuration += m_frameDuration;
double wantedFrameSize = m_vbvMaxRate *
m_frameDuration;
@@ -3053,7 +3075,7 @@ int RateControl::rateControlEnd(Frame* curFrame,
int64_t bits, RateControlEntry*
* Not perfectly accurate with B-refs, but good enough. */
m_cplxrSum += (bits * x265_qp2qScale(rce->qpaRc) / (rce->qRceq
* fabs(m_param->rc.pbFactor))) - (rce->rowCplxrSum);
}
- m_wantedBitsWindow += m_frameDuration * m_bitrate;
+ m_wantedBitsWindow += (m_param->bEnableSBRC ? (m_bitrate * (1.0 /
m_param->keyframeMax)) : m_frameDuration * m_bitrate);
m_totalBits += bits - rce->rowTotalBits;
m_encodedBits += actualBits;
int pos = m_sliderPos - m_param->frameNumThreads;
diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h
index e9fd0e182..9c2fe0ed6 100644
--- a/source/encoder/ratecontrol.h
+++ b/source/encoder/ratecontrol.h
@@ -150,6 +150,7 @@ public:
int m_lastScenecutAwareIFrame;
double m_rateTolerance;
double m_frameDuration; /* current frame duration in seconds */
+ double m_frameDurInGOP; /* current frame duration when considered
as a segment */
double m_bitrate;
double m_rateFactorConstant;
double m_bufferSize;
@@ -255,6 +256,7 @@ public:
RateControl(x265_param& p, Encoder *enc);
bool init(const SPS& sps);
void initHRD(SPS& sps);
+ void initVBV(const SPS& sps);
void reconfigureRC();
void setFinalFrameCount(int count);
@@ -315,6 +317,7 @@ protected:
double tuneQScaleForGrain(double rcOverflow);
void splitdeltaPOC(char deltapoc[], RateControlEntry *rce);
void splitbUsed(char deltapoc[], RateControlEntry *rce);
+ void checkAndResetCRF(RateControlEntry* rce);
};
}
#endif // ifndef X265_RATECONTROL_H
--
2.28.0.windows.1
*Thanks,*
*Kirithika*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20221229/6da186a2/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch2.diff
Type: application/octet-stream
Size: 13411 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20221229/6da186a2/attachment-0001.obj>
More information about the x265-devel
mailing list