[x265] [PATCH] Modify the crf 2 pass

Alex Giladi alex.giladi at gmail.com
Fri Aug 6 01:00:03 UTC 2021


Hi Mahesh,
What is the actual modification of crf in the patch?
Best,
Alex


On Thu, Aug 5, 2021, 2:15 AM Mahesh Pittala <mahesh at multicorewareinc.com>
wrote:

> From 5065d31b4bfe36e05c94dd79db119cd1fd23aa23 Mon Sep 17 00:00:00 2001
> From: lwWang <liwei at multicorewareinc.com>
> Date: Fri, 25 Jun 2021 17:17:03 +0800
> Subject: [PATCH] Modify the crf 2 pass
>
> Signed-off-by: lwWang <liwei at multicorewareinc.com>
> ---
>  source/common/frame.h          |   1 +
>  source/encoder/encoder.cpp     |   1 +
>  source/encoder/ratecontrol.cpp | 235 ++++++++++++++++-----------------
>  source/encoder/ratecontrol.h   |   3 +
>  4 files changed, 119 insertions(+), 121 deletions(-)
>
> diff --git a/source/common/frame.h b/source/common/frame.h
> index dc5bbacf7..ac1185e81 100644
> --- a/source/common/frame.h
> +++ b/source/common/frame.h
> @@ -70,6 +70,7 @@ struct RcStats
>      double   count[4];
>      double   offset[4];
>      double   bufferFillFinal;
> +    int64_t  currentSatd;
>  };
>
>  class Frame
> diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
> index 003011554..227933e8a 100644
> --- a/source/encoder/encoder.cpp
> +++ b/source/encoder/encoder.cpp
> @@ -2216,6 +2216,7 @@ int Encoder::encode(const x265_picture* pic_in,
> x265_picture* pic_out)
>                  outFrame->m_rcData->iCuCount =
> outFrame->m_encData->m_frameStats.percent8x8Intra * m_rateControl->m_ncu;
>                  outFrame->m_rcData->pCuCount =
> outFrame->m_encData->m_frameStats.percent8x8Inter * m_rateControl->m_ncu;
>                  outFrame->m_rcData->skipCuCount =
> outFrame->m_encData->m_frameStats.percent8x8Skip  * m_rateControl->m_ncu;
> +                outFrame->m_rcData->currentSatd =
> curEncoder->m_rce.coeffBits;
>              }
>
>              /* Allow this frame to be recycled if no frame encoders are
> using it for reference */
> diff --git a/source/encoder/ratecontrol.cpp
> b/source/encoder/ratecontrol.cpp
> index e9ceccc24..28345a1e9 100644
> --- a/source/encoder/ratecontrol.cpp
> +++ b/source/encoder/ratecontrol.cpp
> @@ -1116,123 +1116,106 @@ bool RateControl::initPass2()
>      uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. *
> m_numEntries * m_frameDuration);
>      int startIndex, framesCount, endIndex;
>      int fps = X265_MIN(m_param->keyframeMax, (int)(m_fps + 0.5));
> +    int distance = fps << 1;
> +    distance = distance > m_param->keyframeMax ? (m_param->keyframeMax <<
> 1) : m_param->keyframeMax;
>      startIndex = endIndex = framesCount = 0;
> -    int diffQp = 0;
>      double targetBits = 0;
>      double expectedBits = 0;
> -    for (startIndex = m_start, endIndex = m_start; endIndex <
> m_numEntries; endIndex++)
> +    double targetBits2 = 0;
> +    double expectedBits2 = 0;
> +    double cpxSum = 0;
> +    double cpxSum2 = 0;
> +
> +    if (m_param->rc.rateControlMode == X265_RC_ABR)
>      {
> -        allConstBits += m_rce2Pass[endIndex].miscBits;
> -        allCodedBits += m_rce2Pass[endIndex].coeffBits +
> m_rce2Pass[endIndex].mvBits;
> -        if (m_param->rc.rateControlMode == X265_RC_CRF)
> +        for (startIndex = m_start, endIndex = m_start; endIndex <
> m_numEntries; endIndex++)
>          {
> -            framesCount = endIndex - startIndex + 1;
> -            diffQp += int (m_rce2Pass[endIndex].qpaRc -
> m_rce2Pass[endIndex].qpNoVbv);
> -            if (framesCount > fps)
> -                diffQp -= int (m_rce2Pass[endIndex - fps].qpaRc -
> m_rce2Pass[endIndex - fps].qpNoVbv);
> -            if (framesCount >= fps)
> -            {
> -                if (diffQp >= 1)
> -                {
> -                    if (!m_isQpModified && endIndex > fps)
> -                    {
> -                        double factor = 2;
> -                        double step = 0;
> -                        if (endIndex + fps >= m_numEntries)
> -                        {
> -                            m_start = endIndex - (endIndex % fps);
> -                            return true;
> -                        }
> -                        for (int start = endIndex + 1; start <= endIndex
> + fps && start < m_numEntries; start++)
> -                        {
> -                            RateControlEntry *rce = &m_rce2Pass[start];
> -                            targetBits += qScale2bits(rce,
> x265_qp2qScale(rce->qpNoVbv));
> -                            expectedBits += qScale2bits(rce, rce->qScale);
> -                        }
> -                        if (expectedBits < 0.95 * targetBits)
> -                        {
> -                            m_isQpModified = true;
> -                            m_isGopReEncoded = true;
> -                            while (endIndex + fps < m_numEntries)
> -                            {
> -                                step = pow(2, factor / 6.0);
> -                                expectedBits = 0;
> -                                for (int start = endIndex + 1; start <=
> endIndex + fps; start++)
> -                                {
> -                                    RateControlEntry *rce =
> &m_rce2Pass[start];
> -                                    rce->newQScale = rce->qScale / step;
> -                                    X265_CHECK(rce->newQScale >= 0, "new
> Qscale is negative\n");
> -                                    expectedBits += qScale2bits(rce,
> rce->newQScale);
> -                                    rce->newQp =
> x265_qScale2qp(rce->newQScale);
> -                                }
> -                                if (expectedBits >= targetBits && step >
> 1)
> -                                    factor *= 0.90;
> -                                else
> -                                    break;
> -                            }
> -
> -                            if (m_isVbv && endIndex + fps < m_numEntries)
> -                                if (!vbv2Pass((uint64_t)targetBits,
> endIndex + fps, endIndex + 1))
> -                                    return false;
> -
> -                            targetBits = 0;
> -                            expectedBits = 0;
> -
> -                            for (int start = endIndex - fps + 1; start <=
> endIndex; start++)
> -                            {
> -                                RateControlEntry *rce =
> &m_rce2Pass[start];
> -                                targetBits += qScale2bits(rce,
> x265_qp2qScale(rce->qpNoVbv));
> -                            }
> -                            while (1)
> -                            {
> -                                step = pow(2, factor / 6.0);
> -                                expectedBits = 0;
> -                                for (int start = endIndex - fps + 1;
> start <= endIndex; start++)
> -                                {
> -                                    RateControlEntry *rce =
> &m_rce2Pass[start];
> -                                    rce->newQScale = rce->qScale * step;
> -                                    X265_CHECK(rce->newQScale >= 0, "new
> Qscale is negative\n");
> -                                    expectedBits += qScale2bits(rce,
> rce->newQScale);
> -                                    rce->newQp =
> x265_qScale2qp(rce->newQScale);
> -                                }
> -                                if (expectedBits > targetBits && step > 1)
> -                                    factor *= 1.1;
> -                                else
> -                                     break;
> -                            }
> -                            if (m_isVbv)
> -                                if (!vbv2Pass((uint64_t)targetBits,
> endIndex, endIndex - fps + 1))
> -                                    return false;
> -                            diffQp = 0;
> -                            m_reencode = endIndex - fps + 1;
> -                            endIndex = endIndex + fps;
> -                            startIndex = endIndex + 1;
> -                            m_start = startIndex;
> -                            targetBits = expectedBits = 0;
> -                        }
> -                        else
> -                            targetBits = expectedBits = 0;
> -                    }
> -                }
> -                else
> -                    m_isQpModified = false;
> -            }
> +            allConstBits += m_rce2Pass[endIndex].miscBits;
> +            allCodedBits += m_rce2Pass[endIndex].coeffBits +
> m_rce2Pass[endIndex].mvBits;
>          }
> -    }
>
> -    if (m_param->rc.rateControlMode == X265_RC_ABR)
> -    {
>          if (allAvailableBits < allConstBits)
>          {
>              x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too
> low. estimated minimum is %d kbps\n",
> -                     (int)(allConstBits * m_fps / framesCount * 1000.));
> +                (int)(allConstBits * m_fps / framesCount * 1000.));
>              return false;
>          }
>          if (!analyseABR2Pass(allAvailableBits))
>              return false;
> +
> +        return true;
>      }
>
> -    m_start = X265_MAX(m_start, endIndex - fps);
> +    if (m_param->rc.rateControlMode != X265_RC_CRF)
> +    {
> +        return true;
> +    }
> +
> +    if (m_isQpModified)
> +    {
> +        return true;
> +    }
> +
> +    if (m_start + (fps << 1) > m_numEntries)
> +    {
> +        return true;
> +    }
> +
> +    for (startIndex = m_start, endIndex = m_numEntries - 1; startIndex <
> endIndex; startIndex++, endIndex--)
> +    {
> +        cpxSum += m_rce2Pass[startIndex].qScale /
> m_rce2Pass[startIndex].coeffBits;
> +        cpxSum2 += m_rce2Pass[endIndex].qScale /
> m_rce2Pass[endIndex].coeffBits;
> +
> +        RateControlEntry *rce = &m_rce2Pass[startIndex];
> +        targetBits += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv));
> +        expectedBits += qScale2bits(rce, rce->qScale);
> +
> +        rce = &m_rce2Pass[endIndex];
> +        targetBits2 += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv));
> +        expectedBits2 += qScale2bits(rce, rce->qScale);
> +    }
> +
> +    if (expectedBits < 0.95 * targetBits || expectedBits2 < 0.95 *
> targetBits2)
> +    {
> +        if (cpxSum/cpxSum2 < 0.95 || cpxSum2 / cpxSum < 0.95)
> +        {
> +            m_isQpModified = true;
> +            m_isGopReEncoded = true;
> +
> +            m_shortTermCplxSum = 0;
> +            m_shortTermCplxCount = 0;
> +            m_framesDone = m_start;
> +
> +            for (startIndex = m_start; startIndex < m_numEntries;
> startIndex++)
> +            {
> +                m_shortTermCplxSum *= 0.5;
> +                m_shortTermCplxCount *= 0.5;
> +                m_shortTermCplxSum += m_rce2Pass[startIndex].currentSatd
> / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);
> +                m_shortTermCplxCount++;
> +            }
> +
> +            m_bufferFill = m_rce2Pass[m_start - 1].bufferFill;
> +            m_bufferFillFinal = m_rce2Pass[m_start - 1].bufferFillFinal;
> +            m_bufferFillActual = m_rce2Pass[m_start - 1].bufferFillActual;
> +
> +            m_reencode = m_start;
> +            m_start = m_numEntries;
> +        }
> +        else
> +        {
> +
> +            m_isQpModified = false;
> +            m_isGopReEncoded = false;
> +        }
> +    }
> +    else
> +    {
> +
> +        m_isQpModified = false;
> +        m_isGopReEncoded = false;
> +    }
> +
> +    m_start = X265_MAX(m_start, m_numEntries - distance +
> m_param->keyframeMax);
>
>      return true;
>  }
> @@ -1505,15 +1488,34 @@ int RateControl::rateControlStart(Frame* curFrame,
> RateControlEntry* rce, Encode
>              rce->frameSizeMaximum *= m_param->maxAUSizeFactor;
>          }
>      }
> +
> +    ///< regenerate the qp
>      if (!m_isAbr && m_2pass && m_param->rc.rateControlMode == X265_RC_CRF)
>      {
> -        rce->qpPrev = x265_qScale2qp(rce->qScale);
> -        rce->qScale = rce->newQScale;
> -        rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq =
> x265_qScale2qp(rce->newQScale);
> -        m_qp = int(rce->qpaRc + 0.5);
> -        rce->frameSizePlanned = qScale2bits(rce, rce->qScale);
> -        m_framesDone++;
> -        return m_qp;
> +        int index = m_encOrder[rce->poc];
> +        index++;
> +        double totalDuration = m_frameDuration;
> +        for (int j = 0; totalDuration < 1.0; j++)
> +        {
> +            switch (m_rce2Pass[index].sliceType)
> +            {
> +            case B_SLICE:
> +                curFrame->m_lowres.plannedType[j] =
> m_rce2Pass[index].keptAsRef ? X265_TYPE_BREF : X265_TYPE_B;
> +                break;
> +            case P_SLICE:
> +                curFrame->m_lowres.plannedType[j] = X265_TYPE_P;
> +                break;
> +            case I_SLICE:
> +                curFrame->m_lowres.plannedType[j] = m_param->bOpenGOP ?
> X265_TYPE_I : X265_TYPE_IDR;
> +                break;
> +            default:
> +                break;
> +            }
> +
> +            curFrame->m_lowres.plannedSatd[j] =
> m_rce2Pass[index].currentSatd;
> +            totalDuration += m_frameDuration;
> +            index++;
> +        }
>      }
>
>      if (m_isAbr || m_2pass) // ABR,CRF
> @@ -2019,7 +2021,7 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>                  qScale = x265_clip3(lqmin, lqmax, qScale);
>              }
>
> -            if (!m_2pass || m_param->bliveVBV2pass)
> +            if (!m_2pass || m_param->bliveVBV2pass || (m_2pass &&
> m_param->rc.rateControlMode == X265_RC_CRF))
>              {
>                  /* clip qp to permissible range after vbv-lookahead
> estimation to avoid possible
>                   * mispredictions by initial frame size predictors */
> @@ -2056,7 +2058,7 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>      else
>      {
>          double abrBuffer = 2 * m_rateTolerance * m_bitrate;
> -        if (m_2pass)
> +        if (m_2pass && m_param->rc.rateControlMode != X265_RC_CRF)
>          {
>              double lmin = m_lmin[m_sliceType];
>              double lmax = m_lmax[m_sliceType];
> @@ -2947,7 +2949,7 @@ int RateControl::rateControlEnd(Frame* curFrame,
> int64_t bits, RateControlEntry*
>
>      if (m_param->rc.aqMode || m_isVbv || m_param->bAQMotion ||
> bEnableDistOffset)
>      {
> -        if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode ==
> X265_RC_CRF))
> +        if (m_isVbv)
>          {
>              double avgQpRc = 0;
>              /* determine avg QP decided by VBV rate control */
> @@ -2981,16 +2983,7 @@ int RateControl::rateControlEnd(Frame* curFrame,
> int64_t bits, RateControlEntry*
>      if (m_param->rc.rateControlMode == X265_RC_CRF)
>      {
>          double crfVal, qpRef = curEncData.m_avgQpRc;
> -        bool is2passCrfChange = false;
> -        if (m_2pass)
> -        {
> -            if (fabs(curEncData.m_avgQpRc - rce->qpPrev) > 0.1)
> -            {
> -                qpRef = rce->qpPrev;
> -                is2passCrfChange = true;
> -            }
> -        }
> -        if (is2passCrfChange || fabs(qpRef - rce->qpNoVbv) > 0.5)
> +        if (fabs(qpRef - rce->qpNoVbv) > 0.5)
>          {
>              double crfFactor = rce->qRceq /x265_qp2qScale(qpRef);
>              double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);
> diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h
> index a0b555f8a..666025823 100644
> --- a/source/encoder/ratecontrol.h
> +++ b/source/encoder/ratecontrol.h
> @@ -74,6 +74,7 @@ struct RateControlEntry
>      Predictor  rowPreds[3][2];
>      Predictor* rowPred[2];
>
> +    int64_t currentSatd;
>      int64_t lastSatd;      /* Contains the picture cost of the previous
> frame, required for resetAbr and VBV */
>      int64_t leadingNoBSatd;
>      int64_t rowTotalBits;  /* update cplxrsum and totalbits at the end of
> 2 rows */
> @@ -88,6 +89,8 @@ struct RateControlEntry
>      double  rowCplxrSum;
>      double  qpNoVbv;
>      double  bufferFill;
> +    double  bufferFillFinal;
> +    double  bufferFillActual;
>      double  targetFill;
>      bool    vbvEndAdj;
>      double  frameDuration;
> --
> 2.22.0.windows.1
>
> _______________________________________________
> 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/20210805/a09dd28f/attachment-0001.html>


More information about the x265-devel mailing list