[x265] [PATCH] SBRC:Tune Qp based on segment size constraints
Karam Singh
karam.singh at multicorewareinc.com
Wed Apr 3 03:15:26 UTC 2024
Patch pushed to master branch.
Karam Singh
Senior Software (Video Codec) Engineer
MulticoreWare, India
On Thu, Mar 28, 2024 at 11:44 AM Kirithika Kalirathnam <
kirithika at multicorewareinc.com> wrote:
> From 17f2420bbd07db40b618e96a36586da909a26efb Mon Sep 17 00:00:00 2001
> From: Kirithika <kirithika at multicorewareinc.com>
> Date: Sat, 3 Feb 2024 08:28:18 +0530
> Subject: [PATCH] SBRC:Tune Qp based on segment size constraints
>
> This Commit adds support to tune QP for frames based on the segment
> size constraints
> ---
> source/encoder/ratecontrol.cpp | 67 +++++++++++++++++++++++++++++++++-
> source/encoder/ratecontrol.h | 3 ++
> 2 files changed, 69 insertions(+), 1 deletion(-)
>
> diff --git a/source/encoder/ratecontrol.cpp
> b/source/encoder/ratecontrol.cpp
> index 099a03f0a..5c447d8ad 100644
> --- a/source/encoder/ratecontrol.cpp
> +++ b/source/encoder/ratecontrol.cpp
> @@ -260,6 +260,8 @@ RateControl::RateControl(x265_param& p, Encoder *top)
> m_initVbv = false;
> m_singleFrameVbv = 0;
> m_rateTolerance = 1.0;
> + m_encodedSegmentBits = 0;
> + m_segDur = 0;
>
> if (m_param->rc.vbvBufferSize)
> {
> @@ -448,7 +450,9 @@ bool RateControl::init(const SPS& sps)
>
> m_totalBits = 0;
> m_encodedBits = 0;
> + m_encodedSegmentBits = 0;
> m_framesDone = 0;
> + m_segDur = 0;
> m_residualCost = 0;
> m_partialResidualCost = 0;
> m_amortizeFraction = 0.85;
> @@ -1351,6 +1355,16 @@ int RateControl::rateControlStart(Frame* curFrame,
> RateControlEntry* rce, Encode
> m_predType = getPredictorType(curFrame->m_lowres.sliceType,
> m_sliceType);
> rce->poc = m_curSlice->m_poc;
>
> + if (m_param->bEnableSBRC)
> + {
> + if (rce->poc == 0 || (m_framesDone % m_param->keyframeMax == 0))
> + {
> + //Reset SBRC buffer
> + m_encodedSegmentBits = 0;
> + m_segDur = 0;
> + }
> + }
> +
> if (!m_param->bResetZoneConfig && (rce->encodeOrder %
> m_param->reconfigWindowSize == 0))
> {
> int index = m_zoneBufferIdx % m_param->rc.zonefileCount;
> @@ -1974,8 +1988,16 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
> double minScenecutQscale
> =x265_qp2qScale(ABR_SCENECUT_INIT_QP_MIN);
> m_lastQScaleFor[P_SLICE] = X265_MAX(minScenecutQscale,
> m_lastQScaleFor[P_SLICE]);
> }
> +
> double qScale = x265_qp2qScale(q);
> rce->qpNoVbv = q;
> +
> + if (m_param->bEnableSBRC)
> + {
> + qScale = tuneQscaleForSBRC(curFrame, qScale);
> + rce->qpNoVbv = x265_qScale2qp(qScale);
> + }
> +
> double lmin = 0, lmax = 0;
> if (m_isGrainEnabled && m_isFirstMiniGop)
> {
> @@ -2200,7 +2222,8 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
> double rfConstant = m_param->rc.rfConstant;
> if (m_currentSatd < rce->movingAvgSum)
> rfConstant += 2;
> - rfConstant = (rce->sliceType == I_SLICE ? rfConstant
> - m_ipOffset :
> + double ipOffset = (curFrame->m_lowres.bScenecut ?
> m_ipOffset : m_ipOffset / 2.0);
> + rfConstant = (rce->sliceType == I_SLICE ? rfConstant
> - ipOffset :
> (rce->sliceType == B_SLICE ? rfConstant +
> m_pbOffset : rfConstant));
> double mbtree_offset = m_param->rc.cuTree ? (1.0 -
> m_param->rc.qCompress) * 13.5 : 0;
> double qComp = (m_param->rc.cuTree &&
> !m_param->rc.hevcAq) ? 0.99 : m_param->rc.qCompress;
> @@ -2288,6 +2311,9 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
> q = X265_MAX(minScenecutQscale, q);
> m_lastQScaleFor[P_SLICE] = X265_MAX(minScenecutQscale,
> m_lastQScaleFor[P_SLICE]);
> }
> + if (m_param->bEnableSBRC)
> + q = tuneQscaleForSBRC(curFrame, q);
> +
> rce->qpNoVbv = x265_qScale2qp(q);
> if (m_sliceType == P_SLICE)
> {
> @@ -2469,6 +2495,43 @@ double RateControl::predictSize(Predictor *p,
> double q, double var)
> return (p->coeff * var + p->offset) / (q * p->count);
> }
>
> +double RateControl::tuneQscaleForSBRC(Frame* curFrame, double q)
> +{
> + int depth = 0;
> + int framesDoneInSeg = m_framesDone % m_param->keyframeMax;
> + if (framesDoneInSeg + m_param->lookaheadDepth <= m_param->keyframeMax)
> + depth = m_param->lookaheadDepth;
> + else
> + depth = m_param->keyframeMax - framesDoneInSeg;
> + for (int iterations = 0; iterations < 1000; iterations++)
> + {
> + double totalDuration = m_segDur;
> + double frameBitsTotal = m_encodedSegmentBits +
> predictSize(&m_pred[m_predType], q, (double)m_currentSatd);
> + for (int i = 0; i < depth; i++)
> + {
> + int type = curFrame->m_lowres.plannedType[i];
> + if (type == X265_TYPE_AUTO)
> + break;
> + int64_t satd = curFrame->m_lowres.plannedSatd[i] >>
> (X265_DEPTH - 8);
> + type = IS_X265_TYPE_I(curFrame->m_lowres.plannedType[i]) ?
> I_SLICE : IS_X265_TYPE_B(curFrame->m_lowres.plannedType[i]) ? B_SLICE :
> P_SLICE;
> + int predType =
> getPredictorType(curFrame->m_lowres.plannedType[i], type);
> + double curBits = predictSize(&m_pred[predType], q,
> (double)satd);
> + frameBitsTotal += curBits;
> + totalDuration += m_frameDuration;
> + }
> + //Check for segment buffer overflow and adjust QP accordingly
> + double segDur = m_param->keyframeMax / m_fps;
> + double allowedSize = m_vbvMaxRate * segDur;
> + double remDur = segDur - totalDuration;
> + double remainingBits = frameBitsTotal / totalDuration * remDur;
> + if (frameBitsTotal + remainingBits > 0.9 * allowedSize)
> + q = q * 1.01;
> + else
> + break;
> + }
> + return q;
> +}
> +
> double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce,
> double q)
> {
> // B-frames are not directly subject to VBV,
> @@ -3072,6 +3135,8 @@ int RateControl::rateControlEnd(Frame* curFrame,
> int64_t bits, RateControlEntry*
> m_wantedBitsWindow += m_frameDuration * m_bitrate;
> m_totalBits += bits - rce->rowTotalBits;
> m_encodedBits += actualBits;
> + m_encodedSegmentBits += actualBits;
> + m_segDur += m_frameDuration;
> int pos = m_sliderPos - m_param->frameNumThreads;
> if (pos >= 0)
> m_encodedBitsWindow[pos % s_slidingWindowFrames] = actualBits;
> diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h
> index 7c3f60cc7..c3dc0406f 100644
> --- a/source/encoder/ratecontrol.h
> +++ b/source/encoder/ratecontrol.h
> @@ -191,6 +191,8 @@ public:
> double m_qCompress;
> int64_t m_totalBits; /* total bits used for already encoded
> frames (after ammortization) */
> int64_t m_encodedBits; /* bits used for encoded frames (without
> ammortization) */
> + int64_t m_encodedSegmentBits; /* bits used for encoded frames in
> a segment*/
> + double m_segDur;
> double m_fps;
> int64_t m_satdCostWindow[50];
> int64_t m_encodedBitsWindow[50];
> @@ -296,6 +298,7 @@ protected:
> double rateEstimateQscale(Frame* pic, RateControlEntry *rce); // main
> logic for calculating QP based on ABR
> double tuneAbrQScaleFromFeedback(double qScale);
> double tuneQScaleForZone(RateControlEntry *rce, double qScale); //
> Tune qScale to adhere to zone budget
> + double tuneQscaleForSBRC(Frame* curFrame, double q); // Tune qScale
> to adhere to segment budget
> void accumPQpUpdate();
>
> int getPredictorType(int lowresSliceType, int sliceType);
> --
> 2.28.0.windows.1
>
> *Thanks,*
> *Kirithika*
> _______________________________________________
> 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/20240403/6de09db8/attachment.htm>
More information about the x265-devel
mailing list