打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
HEVC码率控制(二):从compressGOP()到compressSlice()

compressGOP()函数要点:

  • 根据iGOPid逐次递增,对一个GOP内的picture依次编码
  • 根据picture level对当前picture进行码率分配
  • 实际中一个Pic就是一个Slice,因此关于slice的循环只执行一次(默认)
  • 根据已经编过的picture,来得到当前picture的lambda
  • 得到当前picture的lambda后,对该picture下每一个CTU进行码率分配
  • 一个picture编完,码流写好了,根据实际编码所用的比特,更新对应level下的lambda参数
compressGOP(){    ...    for(Int iGOPid=0;iGOPid<m_iGopSize;iGOPid++) //GOP内picture循环    {        m_pcSliceEncoder->initEncSlice();        //当前Slice编码参数QP、lambda的默认设置,会在码率控制中进一步被修改        ...        if(m_pcCfg->getUseRateCtrl())        {            m_pcRateCtrl->initRCPic(frameLevel);//根据frame level进行比特分配            ...            lambda=m_pcRateCtrl->getRCPic()->estimatePicLambda();//确定当前picture的lambda            sliceQP = m_pcRateCtrl->getRCPic()->estimatePicQP( lambda,.. );//QP由lambda计算            ...         }        for(UInt nextCtuTsAddr = 0; nextCtuTsAddr < numberOfCtusInFrame; ) //这个循环只执行了一次        {            ...            m_pcSliceEncoder->compressSlice();            ...        }        ...        //编完一帧,开始熵编码,写码流等等        ...        if(m_pcCfg->getUseRateCtrl())        {            ...            updataAfterPicture(); //编完一帧,更新当前picture level对应的lambda参数值(alpha和beta)            ...        }    }//iGOPid loop}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • estimatePicLambda()函数中,在得到lambda之后,对一个picture内所有LCU进行比特分配:
Double TEncRCPic::estimatePicLambda( ){  Double alpha         = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;  Double beta          = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;  //alpha和beta从数组中对应level处取,这两个值在编完前一个相同level的帧后,被设置  Double bpp       = (Double)m_targetBits/(Double)m_numberOfPixel;  Double estLambda;  if (eSliceType == I_SLICE)  {    estLambda = calculateLambdaIntra(alpha, beta, pow(m_totalCostIntra/(Double)m_numberOfPixel, BETA1), bpp);  }  else  {    estLambda = alpha * pow( bpp, beta );  }  Double lastLevelLambda = -1.0;  Double lastPicLambda   = -1.0;  Double lastValidLambda = -1.0;  //对estLambda进行Clip操作  m_estPicLambda = estLambda; //TEncRCPic::m_estPicLambda  Double totalWeight = 0.0;  // initial BU bit allocation weight  for ( Int i=0; i<m_numberOfLCU; i++ )  {    Double alphaLCU, betaLCU;    if ( m_encRCSeq->getUseLCUSeparateModel() )    {      alphaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_alpha;      betaLCU  = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_beta;    }    else    {      alphaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;      betaLCU  = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;    }    m_LCUs[i].m_bitWeight =  m_LCUs[i].m_numberOfPixel * pow( estLambda/alphaLCU, 1.0/betaLCU );    if ( m_LCUs[i].m_bitWeight < 0.01 )    {      m_LCUs[i].m_bitWeight = 0.01;    }    totalWeight += m_LCUs[i].m_bitWeight;  }  for ( Int i=0; i<m_numberOfLCU; i++ )  {    Double BUTargetBits = m_targetBits * m_LCUs[i].m_bitWeight / totalWeight;    m_LCUs[i].m_bitWeight = BUTargetBits;  }  return estLambda;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

m_bitWeight即使每一个CTU对应的比特分配权重

  • 跟新picture level 的alpha和beta函数updateAfterPicture():
void TEncRCPic::updateAfterPicture(){    //计算inputLambda    //计算calLambda        alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha;    Double lnbpp = log( picActualBpp );    lnbpp = Clip3( -5.0, -0.1, lnbpp );    //按照码率控制算法,跟新alpha和beta    TRCParameter rcPara;    rcPara.m_alpha = alpha;    rcPara.m_beta  = beta;    m_encRCSeq->setPicPara( m_frameLevel, rcPara );    //将更新后的alpha和beta保存在数组中}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

compressSlice()函数

  • 按照CTU的先后顺序循环遍历编码
  • 编完一个CTU之后,要更新参数
void TEncSlice::compressSlice(){    ...     xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic );     ...     for( UInt ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ++ctuTsAddr )      //对一个Slice内所有CTU开始循环编码     {         ...          if ( m_pcCfg->getUseRateCtrl() )          {              Int estQP        = pcSlice->getSliceQp();              Double estLambda = -1.0;              Double bpp       = -1.0;          //根据LCU的m_bitWeight这个成员计算当前LCU的比特,再除以LCU内Pixel总数,得到bpp。而m_bitWeight这个成员是得到Pic的lambda之后被赋值。              estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP);          ...            m_pcRdCost->setLambda(estLambda, pcSlice->getSPS()->getBitDepths());         }         m_pcCuEncoder->compressCtu(pCtu);         ...         if(m_pcCfg->getUseRateCtrl())         {             ...             updateAfterCTU();             ...         }         //将CTU的编码结果累加到Picture的统计量之中         m_uiPicTotalBits+=pCtu->getTotalBits();         m_dPicRdcost+=PCtu->getTotalCost();         m_uiPicDist+=PCtu->getTotalDistortion;    }}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
大地坐标系(wgs84)转UTM
R语言弹性网络Elastic Net正则化惩罚回归模型交叉验证可视化
向前向后算法--EM算法及其java实现
[MFC] 将多个坐标点拟合出一条直线,并画出
代码制作分割线
制作分割线
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服