x265代码阅读:码率控制(一)

x265中码率控制算法貌似与x264的码率控制算法基本相同,基本上是经验性的,与ITU-T/MPEG各类标准推荐的码率控制算法均不同。
x265的率控应该只是帧级率控,虽然有与CU相关的率控参数,但其实那是块级的率失真优化技术,并非块级率控。x265支持三种率控模式:

/* rate tolerance method */
typedef enum
{
    X265_RC_ABR, // average bit rate
    X265_RC_CQP, // constant QP
    X265_RC_CRF  // constant rate fator
} X265_RC_METHODS;

X265_RC_ABR应该就对应学界的CBR;CQP对应HM不开率控时的配置;X265_RC_CRF是“Quality-controlled VBR”,学界叫做consistent quality的码率控制。在函数x265_param_default中设置的默认的码率控制类型是X265_RC_CRF。在学界,CBR是码率控制研究的重点;在x264/x265中,CRF模式是重点。

在输入参数类型x265_param中定义了一个包含码率控制输入参数的成员rc,rc是一个定义在类型x265_param中的匿名结构体类型的对象。
下面是与计算QP有关的四个主要函数,它们被调用的顺序与下面的列表排列顺序相同:

    // to be called for each curFrame to process RateControl and set QP
    int rateControlStart(Frame* curFrame, RateControlEntry* rce, Encoder* enc);
    // main logic for calculating QP based on ABR
    double rateEstimateQscale(Frame* pic, RateControlEntry *rce);
    /* modify the bitrate curve from pass1 for one frame */
    double getQScale(RateControlEntry *rce, double rateFactor);
    double tuneAbrQScaleFromFeedback(double qScale);

函数rateControlStart中,CQP模式下QP的计算与帧类型有关:

    else // CQP
    {
        if (m_sliceType == B_SLICE && IS_REFERENCED(curFrame))
            m_qp = (m_qpConstant[B_SLICE] + m_qpConstant[P_SLICE]) / 2;
        else
            m_qp = m_qpConstant[m_sliceType];
        curEncData.m_avgQpAq = curEncData.m_avgQpRc = m_qp;

        x265_zone* zone = getZone();
        if (zone)
        {
            if (zone->bForceQp)
                m_qp += zone->qp - m_qpConstant[P_SLICE];
            else
                m_qp -= 6.0 * X265_LOG2(zone->bitrateFactor);
        }
    }

CRF和ABR模式时,B帧的QP由前后两个参考的P帧的QP插值而来,I帧、P帧的QP主要用getQScale中的下面这条语句计算:

    if (m_param->rc.cuTree)
    {
        // Scale and units are obtained from rateNum and rateDenom for videos with fixed frame rates.
        double timescale = (double)m_param->fpsDenom / (2 * m_param->fpsNum);
        q = pow(BASE_FRAME_DURATION / CLIP_DURATION(2 * timescale), 1 - m_param->rc.qCompress);
    }
    else
        q = pow(rce->blurredComplexity, 1 - m_param->rc.qCompress);

上面的rc.qCompress默认是0.6,也就是说量化步长是blurredComplexity的0.4次幂,blurredComplexity越大,量化步长越大。blurredComplexity是图像的预测残差的SATD。
根据图像复杂度初步计算出QScale后,还须除以ratefactor。CRF和ABR调用getQScale时给的rateFactor的参数不同,CBF时是常数,ABR等于m_wantedBitsWindow / m_cplxrSum,使得计算得到的QScale与已编码视频的复杂度成正比。代码如下:

      if (m_param->rc.rateControlMode == X265_RC_CRF)
      {
          q = getQScale(rce, m_rateFactorConstant);
      }
      else
      {
          if (!m_param->rc.bStatRead)
              checkAndResetABR(rce, false);
          double initialQScale = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);
          q = tuneAbrQScaleFromFeedback(initialQScale);
          overflow = q / initialQScale;
      }

变量overflow等于比特误差除以abrBuffer,X265_RC_ABR模式下,getQScale还需要除以overflow;X265_RC_CRF模式下,“no overflow compensation is done”。
x265中的rc.cuTree,类似于x264中的MBTree,不是空域划分的树结构,而是时域的参考树结构,在结构体对象rc中的定义和注释如下:

    struct

    {
    ...
        /* Enable CUTree ratecontrol. This keeps track of the CUs that propagate temporally
         * across frames and assigns more bits to these CUs. Improves encode efficiency.
         * Default: enabled */
        int       cuTree;
        ...
    }

MBTree的百度百科:http://baike.baidu.com/item/Macroblock%20Tree

此外,在ABR模式下还可以设置为二次编码,CRF和CQP模式下不兼容二次编码。设置编码次数的命令如下:

--pass <integer>

客观质量不是他们考虑的因素,他们考虑主观质量,他们认为CBR模式的主观质量最好。

你可能感兴趣的:(H.265)