HEVC码率控制代码追踪(三)

关于图像级别和单元级别的lambda和qp预测计算

这两个级别各两个参数的计算主要考虑的是计算和计算后的平滑参数的设置。都有现成的公式可以参考。同样用到的是HEVC提案JCTVC-K0103(码率控制提案)

(一)Double TEncRCPic::estimatePicLambda

Double TEncRCPic::estimatePicLambda( list<TEncRCPic*>& listPreviousPictures, SliceType eSliceType)//估计图片级别的lambda
{
  Double alpha         = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;
  Double beta          = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;
  Double bpp       = (Double)m_targetBits/(Double)m_numberOfPixel;//前面求得的bpp用于这里来获得lambda
  Double estLambda;
  if (eSliceType == I_SLICE)//I片有自己的lambda算法
  {
    estLambda = calculateLambdaIntra(alpha, beta, pow(m_totalCostIntra/(Double)m_numberOfPixel, BETA1), bpp);
  }
  else
  {
    estLambda = alpha * pow( bpp, beta );//非I帧的计算公式,提案中常用的公式
  }
  /*到这里当前帧的lambda已经求得,但是还需要对数据进行处理才能正式用于编码当中,用约束条件进行约束,使其值有限定范围*/
 //下面这段程序是对Lambda的平滑,保证前后帧之间的参数不变化太大。
  Double lastLevelLambda = -1.0;//上一个级别???
  Double lastPicLambda   = -1.0;//上一帧的lambda
  Double lastValidLambda = -1.0;
  list<TEncRCPic*>::iterator it;
  for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ )
  {
    if ( (*it)->getFrameLevel() == m_frameLevel )
    {
      lastLevelLambda = (*it)->getPicActualLambda();
    }
    lastPicLambda     = (*it)->getPicActualLambda();

    if ( lastPicLambda > 0.0 )
    {
      lastValidLambda = lastPicLambda;
    }
  }

  if ( lastLevelLambda > 0.0 )
  {
    lastLevelLambda = Clip3( 0.1, 10000.0, lastLevelLambda );
    estLambda = Clip3( lastLevelLambda * pow( 2.0, -3.0/3.0 ), lastLevelLambda * pow( 2.0, 3.0/3.0 ), estLambda );
  }

  if ( lastPicLambda > 0.0 )
  {
    lastPicLambda = Clip3( 0.1, 2000.0, lastPicLambda );
    estLambda = Clip3( lastPicLambda * pow( 2.0, -10.0/3.0 ), lastPicLambda * pow( 2.0, 10.0/3.0 ), estLambda );
  }
  else if ( lastValidLambda > 0.0 )
  {
    lastValidLambda = Clip3( 0.1, 2000.0, lastValidLambda );
    estLambda = Clip3( lastValidLambda * pow(2.0, -10.0/3.0), lastValidLambda * pow(2.0, 10.0/3.0), estLambda );
  }
  else
  {
    estLambda = Clip3( 0.1, 10000.0, estLambda );
  }

  if ( estLambda < 0.1 )//最终的预测lambda不能小于0.1
  {
    estLambda = 0.1;
  }

  m_estPicLambda = estLambda;

  Double totalWeight = 0.0;
  // initial BU bit allocation weight      初始化BU比特分配比重
  for ( Int i=0; i<m_numberOfLCU; i++ )//遍历整个LCU的数目
  {
    Double alphaLCU, betaLCU;
    if ( m_encRCSeq->getUseLCUSeparateModel() )//启用LCU的分层模式,同一个图片层的不同LCU的参数是不同的,所以要遍历整个图像层的所有LCU ,分配不同的参数。。
    {
      alphaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_alpha;
      betaLCU  = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_beta;
    }
    else//如果没有启用LCU的层的不同模式,则整个picture使用个相同的参数,就不需要分各个不同的LCU考虑了
    {
      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;
}

(二)TEncRCPic::estimatePicQP

Int TEncRCPic::estimatePicQP( Double lambda, list<TEncRCPic*>& listPreviousPictures )
{
  Int QP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 );//加0.5为了四舍五入(上面一个函数已经给出了lambda的计算,所以由公式可以知道,直接计算出QP的值)
  /*将下面三个参数都赋值相同,什么意思?*/
  Int lastLevelQP = g_RCInvalidQPValue;//上一层?
  Int lastPicQP   = g_RCInvalidQPValue;
  Int lastValidQP = g_RCInvalidQPValue;//前一帧的有效的合法的QP,也就是经过平滑之后的QP
  list<TEncRCPic*>::iterator it;
  for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ )
  {
    if ( (*it)->getFrameLevel() == m_frameLevel )
    {
      lastLevelQP = (*it)->getPicActualQP();
    }
    lastPicQP = (*it)->getPicActualQP();
    if ( lastPicQP > g_RCInvalidQPValue )
    {
      lastValidQP = lastPicQP;
    }
  }

  if ( lastLevelQP > g_RCInvalidQPValue )
  {
    QP = Clip3( lastLevelQP - 3, lastLevelQP + 3, QP );
  }

  if( lastPicQP > g_RCInvalidQPValue )
  {
    QP = Clip3( lastPicQP - 10, lastPicQP + 10, QP );
  }
  else if( lastValidQP > g_RCInvalidQPValue )
  {
      QP = Clip3(lastValidQP - 10, lastValidQP + 10, QP);//当前的QP受限于前一帧的合法QP值
  }

  return QP;
}

上面两个函数完成了图片级的lambda和QP的求解。下面将对单元层的参数进行分析

(一)

Double TEncRCPic::getLCUEstLambda( Double bpp )//LCU层的λ预测
{
  Int   LCUIdx = getLCUCoded();
  Double alpha;
  Double beta;
  if ( m_encRCSeq->getUseLCUSeparateModel() )//每个LCU使用的不同的alpha和beta
  {
    alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha;//这些值由LCU的编号决定
    beta  = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta;
  }
  else//使用相同的
  {
    alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;//这些值直接由帧号决定
    beta  = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;
  }

  Double estLambda = alpha * pow( bpp, beta );
  //for Lambda clip, picture level clip
  Double clipPicLambda = m_estPicLambda;

  //for Lambda clip, LCU level clip
  Double clipNeighbourLambda = -1.0;
  for ( Int i=LCUIdx - 1; i>=0; i-- )
  {
    if ( m_LCUs[i].m_lambda > 0 )
    {
      clipNeighbourLambda = m_LCUs[i].m_lambda;
      break;
    }
  }

  if ( clipNeighbourLambda > 0.0 )
  {
    estLambda = Clip3( clipNeighbourLambda * pow( 2.0, -1.0/3.0 ), clipNeighbourLambda * pow( 2.0, 1.0/3.0 ), estLambda );
  }

  if ( clipPicLambda > 0.0 )
  {
    estLambda = Clip3( clipPicLambda * pow( 2.0, -2.0/3.0 ), clipPicLambda * pow( 2.0, 2.0/3.0 ), estLambda );
  }
  else
  {
    estLambda = Clip3( 10.0, 1000.0, estLambda );
  }

  if ( estLambda < 0.1 )
  {
    estLambda = 0.1;
  }

  return estLambda;
}

(二)

Int TEncRCPic::getLCUEstQP( Double lambda, Int clipPicQP )//LCU层的QP估计
{
  Int LCUIdx = getLCUCoded();
  Int estQP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 );//0.5的作用是四舍五入

  //for Lambda clip, LCU level clip
  Int clipNeighbourQP = g_RCInvalidQPValue;
  for ( Int i=LCUIdx - 1; i>=0; i-- )
  {
    if ( (getLCU(i)).m_QP > g_RCInvalidQPValue )
    {
      clipNeighbourQP = getLCU(i).m_QP;
      break;
    }
  }

  if ( clipNeighbourQP > g_RCInvalidQPValue )
  {
    estQP = Clip3( clipNeighbourQP - 1, clipNeighbourQP + 1, estQP );
  }

  estQP = Clip3( clipPicQP - 2, clipPicQP + 2, estQP );

  return estQP;
}

在求这两个参数的时候,前面有一个函数(TEncRCPic::getLCUTargetBpp)是用来求出单元层的bpp的。由bpp求出lambda,lambda求出QP。

时间: 2024-08-25 07:01:16

HEVC码率控制代码追踪(三)的相关文章

HEVC码率控制简介(R-lamda)

HEVC码率控制介绍 R-lamda模型提出到优化已有2年,从近几年的文章来看,大体归为类:一是帧内的码率的码率控制算法,一是模型参数更新,一是考虑感知 第一类:K0103码率控制算法主要是在P/B帧上提出的,I帧没有做,体现在I帧中LCU编码时用的还是帧层的QP,而帧层的QP是由配置文件(即*.cfg中QP: 32 # Quantization parameter(0-51)  这里的32我们可以更改一般设置为22.27.32.37),如果码率控制开启,实际上配置文件中#======== Qu

X264码率控制总结1

1.  X264显式支持的一趟码率控制方法有:ABR, CQP, CRF. 缺省方法是CRF.这三种方式的优先级是ABR > CQP > CRF. if ( bitrate ) rc_method = ABR; else if ( qp || qp_constant ) rc_method = CQP; else rc_method = CRF; bitrate和QP都没有缺省值,一旦设置他们就表示要按照相应的码率控制方法进行编码,CRF有缺省值23,没有任何关于编码控制的设置时就按照CRF缺

X264码率控制总结1——ABR,CQP,CRF

1.  X264显式支持的一趟码率控制方法有:ABR, CQP, CRF. 缺省方法是CRF.这三种方式的优先级是ABR > CQP > CRF. if ( bitrate ) rc_method = ABR; else if ( qp || qp_constant ) rc_method = CQP; else rc_method = CRF;     bitrate和QP都没有缺省值,一旦设置他们就表示要按照相应的码率控制方法进行编码,CRF有缺省值23,没有任何关于编码控制的设置时就按照

HEVC码率控制算法研究与HM相应代码分析(三)——算法及代码分析

在前两篇文章中,首先介绍了HEVC标准和编码流程,然后介绍了在HEVC中采用的全新的R-λ模型,本文将基于前面的内容和相应代码对码率控制算法进行详细的分析. 下面基于JCTVC-K0103提案详细介绍一下HEVC中基于R-λ模型的码率控制方法.同时基于HM-10对码率控制部分的代码做一个简要分析,相比于JM,HM中更多的使用了面向对象技术,结构更加清楚明了,码率控制相关代码的基本调用层次如下,纵向上即层层调用的关系,横向上是对几个比较重要的函数的内部调用情况列了出来. 跟以前的方法类似,码率控制

HEVC代码追踪(二)

R-lambda码率控制模型中的关于帧层,单元层的目标比特分配代码部分.求出各层的目标比特再除以该层的总像素数,得到Bpp用于后续的lambda和Qp的求解. (1)帧层的目标比特代码部分 Int TEncRCPic::xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP )//估计图像的目标比特数//类中的私有函数的定义 { Int targetBits = 0; Int GOPbitsLeft = encRCGOP->getB

HEVC代码追踪(四)

该图为码率控制的一个大致流程图,给出了绝大部分有关码率控制的功能函数的调用流程,调用函数.这有助于更清晰的对码率控制的实现流程的掌握.同时在后续代码改动的时候,也可以清楚的找到所涉及的所有模块.

ffmpeg码率控制

一.VBR与CBR的含义和区别 VBR是动态码率.CBR是静态码率. VBR(Variable Bitrate)动态比特率.也就是没有固定的比特率,压缩软件在压缩时根据音频数据即时确定使用什么比特率,这是以质量为前提兼顾文件大小的方式. VBR也称为动态比特率编码,使用这个方式时,你可以选择从最差音质/最大压缩比到最好音质/最低压缩比之间的种种过渡级数,在MP3文件编码之时,程序 会尝试保持所选定的整个文件的品质,将选择适合音乐文件的不同部分的比特率来编码.主要优点是可以让整首歌都能大致达到我们

FFMpeg的码率控制

mediaxyz是一位研究ffmpeg有三年的高人了,这几天一直在折腾ffmpeg中的x264,就是不知道该如何控制码率,主要是参数太多,也不知道该如何设置,在google上search了一下,这方面的介绍为0,那就找mediaxyz请教请教吧,这些可都是经验,非常宝贵! 以下是与mediaxyz在QQ上聊天的记录,只有一部分,因为QQ把之前的谈话删除了,但基本上精髓都可这里了. mediaxyz 23:40:26 你说的qsable是c->global_quality吧 Leon 23:40:

x264码率控制总结3——码率控制参数详解

x264码率控制参数详解 -q, --qp <integer>          Force constant QP (0-51, 0=lossless) 默认:无 说明:三种可选的码率控制方法(bitrate, CQP,CRF)之一.设置x264使用固定QP模式.设定的QP将被作为P帧的量化参数,I帧和B帧的量化参数由–ipratio and –pbratio参数进一步算出.CQP模式使用固定的QP,这意味着最终的文件大小是不可知的.设置为0将产出无损输出.相同视觉质量时,CQP模式编码输出