HEVC代码追踪(二)

R-lambda码率控制模型中的关于帧层,单元层的目标比特分配代码部分。求出各层的目标比特再除以该层的总像素数,得到Bpp用于后续的lambda和Qp的求解。

(1)帧层的目标比特代码部分

Int TEncRCPic::xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP )//估计图像的目标比特数//类中的私有函数的定义
{
  Int targetBits        = 0;
  Int GOPbitsLeft       = encRCGOP->getBitsLeft();//GOP剩余比特数
  Int i;
  Int currPicPosition = encRCGOP->getNumPic()-encRCGOP->getPicLeft();//当前图片的位置
  Int currPicRatio    = encRCSeq->getBitRatio( currPicPosition );//当前图片的比重(当前图像的比重的分配在Void TEncRateCtrl::init中有详细的介绍)
  Int totalPicRatio   = 0;//定义总比重,初始值为0
  for ( i=currPicPosition; i<encRCGOP->getNumPic(); i++ )//for循环累加,求出总比重
  {
    totalPicRatio += encRCSeq->getBitRatio( i );//第一步
  }

  targetBits  = Int( ((Double)GOPbitsLeft) * currPicRatio / totalPicRatio );//图像层的目标比特数(13)第二步

  if ( targetBits < 100 )//默认的目标比特大于100,当比特小于100的时候系统默认分配100比特
  {
    targetBits = 100;   // at least allocate 100 bits for one picture
  }

  if ( m_encRCSeq->getFramesLeft() > 16 )//剩余帧数大于16帧
  {
    targetBits = Int( g_RCWeightPicRargetBitInBuffer * targetBits + g_RCWeightPicTargetBitInGOP * m_encRCGOP->getTargetBitInGOP( currPicPosition ) );//
  }

  return targetBits;
}

这段代码中有几个值得指出的地方

①currPicRatio :这个整型变量相当于提案JCTVC-K0103中的公式(9)中的W,表示当前帧的复杂度(就是一种衡量的标准,可以理解为纹理复杂度)。currPicRatio / totalPicRatio表示当前帧在整个GOP中的比重。

②if ( targetBits < 100 ):就是人为规定了个帧的目标比特数不能小于100。

(2)单元层的目标比特分配

/*
下面这段程序的目的是为了获得LCU层的目标比特数Bpp,那么说先要获得图片层的各单元的总的目标比特数,再除以整个LCU层的总像素数。
分两种情况:I帧和非I帧。
(1)当为I帧时,考虑getLCU(LCUIdx).m_costIntra这个变量,他是表征各索引LCU块的costIntra(我的理解是帧内比重的意思),
在帧内又有两种情况,剩余的总的costIntra>0.1时,就要考虑各个LCU块的比重,并根据比重对各个LCU块分配比特。当剩余的比重小于0.1时,就对
剩余的块平均分配剩余的比特数。
(2)当为非I帧时,使用bitWeight表示各个LCU块的比重,求出各个块的分配到的比特数avgBits 。
两种情况的Bpp都是通过下面的公式求得:bpp = ( Double )avgBits/( Double )m_LCUs[ LCUIdx ].m_numberOfPixel;
*/
Double TEncRCPic::getLCUTargetBpp(SliceType eSliceType)//获得单元层的目标比特分配
{
  Int   LCUIdx    = getLCUCoded();//获得已经编码的单元数
  Double bpp      = -1.0;//为什么初始值为这个?
  Int avgBits     = 0;//平均比特

  if (eSliceType == I_SLICE)//如果编码帧为I帧
  {
    Int noOfLCUsLeft = m_numberOfLCU - LCUIdx + 1;//总单元数-已经编码的单元数+1 =剩余单元数
    Int bitrateWindow = min(4,noOfLCUsLeft);//比特率窗,最小为四,不能小于GOP的值
    Double MAD      = getLCU(LCUIdx).m_costIntra;//编号为LCUIdx的LCU块的比重值为MAD

    if (m_remainingCostIntra > 0.1 )//剩余帧内消耗比重
    {
      Double weightedBitsLeft = (m_bitsLeft*bitrateWindow+(m_bitsLeft-getLCU(LCUIdx).m_targetBitsLeft)*noOfLCUsLeft)/(Double)bitrateWindow;//剩余比特数
      avgBits = Int( MAD*weightedBitsLeft/m_remainingCostIntra );//就是剩余的比特数*当前块在总块中的比重
    }
    else//如果剩余的比重小于0.1
    {
      avgBits = Int( m_bitsLeft / m_LCULeft );//剩余的比特数/剩余的单元数作为当前编码块的平均比特数
    }
    m_remainingCostIntra -= MAD;//每一块的MAD相等,也就是没块的目标比特数相等了,所以剩余的比重就是总的减去上一块的,都相等(都为MAD)。
  }
  else//下面讨论不是帧内的情况
  {
    Double totalWeight = 0;
    for ( Int i=LCUIdx; i<m_numberOfLCU; i++ )
    {
      totalWeight += m_LCUs[i].m_bitWeight;
    }
    Int realInfluenceLCU = min( g_RCLCUSmoothWindowSize, getLCULeft() );//真正有影响的LCU块(平滑窗和剩余块数目的最小值)
    avgBits = (Int)( m_LCUs[LCUIdx].m_bitWeight - ( totalWeight - m_bitsLeft ) / realInfluenceLCU + 0.5 );
  }

  if ( avgBits < 1 )
  {
    avgBits = 1;
  }

  bpp = ( Double )avgBits/( Double )m_LCUs[ LCUIdx ].m_numberOfPixel;//总的比特数/总的像素数(bpp用于后面求lambda)
  m_LCUs[ LCUIdx ].m_targetBits = avgBits;

  return bpp;
}

这段代码中有几个值得指出的地方

①if (eSliceType == I_SLICE)

else//下面讨论不是帧内的情况

首先将整个过程分为两种情况:帧内和非帧内

②MAD = getLCU(LCUIdx).m_costIntra

这是提案JCTVC-K0103中单元层比特分配时用到的一个变量。用MAD的平方来表征当前快的复杂度。但是在代码中我并没有看到相应的MAD的平方用于求目标比特数:

avgBits = Int( MAD*weightedBitsLeft/m_remainingCostIntra );
avgBits = Int( m_bitsLeft / m_LCULeft );

这是I帧的两种情况,都不是我想要的那种代码。

上面是大致的关于帧层和单元层的目标比特代码分析。还有没看懂的地方,后续弄清楚了,再纠正。

时间: 2024-12-27 04:29:19

HEVC代码追踪(二)的相关文章

HEVC代码追踪(四)

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

研磨设计模式解析及python代码实现——(二)外观模式(Facade)

一.外观模式定义 为子系统中的一组接口提供一个一致的界面,使得此子系统更加容易使用. 二.书中python代码实现 1 class AModuleApi: 2 def testA(self): 3 pass 4 class AModuleImpl(AModuleApi): 5 def testA(self): 6 print "Now Call testA in AModule!" 7 class BModuleApi: 8 def testB(self): 9 pass 10 cla

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 一 图库数据管理 Gallery2的数据管理 DataManager(职责:管理数据源)- MediaSource(职责:管理数据集) - MediaSet(职责:管理数据项).DataManager中初始化所有的数据源(LocalSo

AD帐户操作C#示例代码(二)——检查密码将过期的用户

本文接着和大家分享AD帐户操作,这次开发一个简单的检查密码将过期用户的小工具. 首先,新建一个用户实体类,属性是我们要取的用户信息. public class UserInfo { /// <summary> /// sAM帐户名称 /// </summary> public string SamAccountName { get; set; } /// <summary> /// 名称 /// </summary> public string Name {

JavaScript经典代码【二】【javascript判断用户点了鼠标左键还是右键】

IE 下 onMouseDown 事件有个 events.button 可以返回一个数值,根据数值判断取得用户按了那个鼠标键 events.button==0 默认.没有按任何按钮. events.button==1 鼠标左键 events.button==2 鼠标右键 events.button==3 鼠标左右键同时按下 events.button==4 鼠标中键 events.button==5 鼠标左键和中键同时按下 events.button==6 鼠标右键和中键同时按下 events.

java代码解析二维码

java代码解析二维码一般步骤 本文采用的是google的zxing技术进行解析二维码技术,解析二维码的一般步骤如下: 一.下载zxing-core的jar包: 二.创建一个BufferedImageLuminanceSource类继承LuminanceSource,此类在google的源码中有,但是为了使用方便,下面有此类的源码,可以直接复制使用: private final BufferedImage image; private final int left; private final

Eclipse快捷键 之 代码追踪

在使用Java编写复杂一些的程序时,你会不会常常对一层层的继承关系和一次次方法的调用感到迷惘呢?幸亏我们有了Eclipse这么好的IDE可以帮我们理清头绪--这就要使用Eclipse强大的代码追踪功能. 1.用Open Declaration可以查看类.方法和变量的声明.这是最常用的一个功能了,如果在要追踪的对象上点右键,选择Open Declaration,可以跳转到其声明的地方.这个功能有个快捷键是F3,当然你也可以按住Ctrl键,鼠标移过去会变成一个小手,单击就可以了. 2.用Open T

【火炉炼AI】深度学习005-简单几行Keras代码解决二分类问题

[火炉炼AI]深度学习005-简单几行Keras代码解决二分类问题 (本文所使用的Python库和版本号: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2, Keras 2.1.6, Tensorflow 1.9.0) 很多文章和教材都是用MNIST数据集作为深度学习届的"Hello World"程序,但是这个数据集有一个很大的特点:它是一个典型的多分类问题(一共有10个分类),在我们刚刚开始接触深度学习时,我倒是觉得

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

关于图像级别和单元级别的lambda和qp预测计算 这两个级别各两个参数的计算主要考虑的是计算和计算后的平滑参数的设置.都有现成的公式可以参考.同样用到的是HEVC提案JCTVC-K0103(码率控制提案) (一)Double TEncRCPic::estimatePicLambda Double TEncRCPic::estimatePicLambda( list<TEncRCPic*>& listPreviousPictures, SliceType eSliceType)//估计