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

来源:互联网 发布:大数据和云计算的关系 编辑:程序博客网 时间:2024/06/01 22:52

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}
  • 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;}

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保存在数组中}

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;    }}
0 0
原创粉丝点击