TEncRateCtrl类是码率控制的总类,后续的序列,GOP,帧都是基于该基础

码率控制的总流程为

1、在TEncTop::create中,定义了TEncRateCtrl的码率控制初始化,其中序列级别的码率控制也在TEncRateCtrl::init中

if ( m_RCEnableRateControl )
    {
        // 码率控制器初始化
        m_cRateCtrl.init( m_framesToBeEncoded, m_RCTargetBitrate, m_iFrameRate, m_iGOPSize, m_iSourceWidth, m_iSourceHeight,
            g_uiMaxCUWidth, g_uiMaxCUHeight, m_RCKeepHierarchicalBit, m_RCUseLCUSeparateModel, m_GOPList );
    }

2、在TEncTop::encode中,定义了GOP级别的码率控制

if ( m_RCEnableRateControl )
    {
        m_cRateCtrl.initRCGOP( m_iNumPicRcvd );
    }

3、在TEncGOP::compressGOP,定义了帧级别的码率控制

m_pcRateCtrl->initRCPic( frameLevel );

在CompressSlice中进行CTU级别的码率控制

先开看看成员属性

分别是序列,GOP和帧三个控制类,list<TEncRCPic*> m_listRCPictures中模板是TEncRCPic类,意思是已经编码完的帧放进list中

构造函数和析构函数就是对接下来的三个类进行初始化和销毁

再来看看主要的成员方法:

init函数就是输入cfg文件中的配置

cfg文件中keepHierBits有三种选择,选0 是等比例分配,也就是各帧的比重相同,如果是1就是按比例分类,2是自适应比特分类

KeepHierarchicalBit                 : 2                # Rate control: 0: equal bit allocation; 1: fixed ratio bit allocation; 2: adaptive ratio bit allocation

接着在

这里是低延时配置下GOPsize=4比重的取值,参考下表

GOPSIZE=4,如果是自适应比特分配,将adaptiveBit置为1,否则是0.

GOPsize=8,随机介入的情况,如果是自适应比特分配,将adaptiveBit置为2,否则是0.

GOPID2level ,根据 GOP中ID确定其分级,HEVC测试序列采用分级算法,这里的分级和后续的CTU层比重计算有关

可以看到GOP大小为4时,GOPlevel最大为3

当GOP大小为8时,GOPlevel最大为4

TEncRateCtrl::init的作用就是先把分级,GOP中不同帧的一些参数先给确定了,然后创建序列的实例,初始化G该视频序列seq中以GOP为单位的各帧的比重,以及各帧的Level,还有帧级的阿尔法和贝塔参数,如果开启了LCU的分割,还初始化LCU的阿尔法和贝塔参数

创建序列级实例,然后把cfg的配置文件参数传给该类,把上面确定的帧分级和GOP中各帧所占比重传给序列级别,初始化各帧的阿尔法和贝塔参数,如果采用了useLCUSeparateModel,这个是指LCU层的lambda算法,还需初始化LCU层的阿尔法和贝塔参数

1428行是采用了目标位饱和法进行速率控制,看到这个才发现看到的很多文献注水有多么严重

#if U0132_TARGET_BITS_SATURATIONBool       m_CpbSaturationEnabled;    // Enable target bits saturation to avoid CPB overflow and underflowInt        m_cpbState;                // CPB State UInt       m_cpbSize;                 // CPB sizeUInt       m_bufferingRate;           // Buffering rate
#endif
#if U0132_TARGET_BITS_SATURATIONm_CpbSaturationEnabled = true;m_cpbSize              = targetBitrate;m_cpbState             = (UInt)(m_cpbSize*0.5f);m_bufferingRate        = (Int)(targetBitrate / frameRate);

把 m_CpbSaturationEnabled由默认false改为true就开启了目标位饱和法进行速率控制算法

缓冲区大小为目标码率,即可以缓冲一秒的图像,初始缓冲区状态为缓冲区的一半,bufferRate就是码率/帧率。

具体算法原理参考

码率控制(五):流体流量模型 - 掘金 (juejin.cn)https://juejin.cn/post/6956881425610047524

#if U0132_TARGET_BITS_SATURATIONif (m_pcRateCtrl->getCpbSaturationEnabled() && frameLevel != 0){Int estimatedCpbFullness = m_pcRateCtrl->getCpbState() + m_pcRateCtrl->getBufferingRate();
​// prevent overflowif (estimatedCpbFullness - estimatedBits > (Int)(m_pcRateCtrl->getCpbSize()*0.9f)){estimatedBits = estimatedCpbFullness - (Int)(m_pcRateCtrl->getCpbSize()*0.9f);}
​estimatedCpbFullness -= m_pcRateCtrl->getBufferingRate();// prevent underflow
#if V0078_ADAPTIVE_LOWER_BOUNDif (estimatedCpbFullness - estimatedBits < m_pcRateCtrl->getRCPic()->getLowerBound()){estimatedBits = max(200, estimatedCpbFullness - m_pcRateCtrl->getRCPic()->getLowerBound());}
#elseif (estimatedCpbFullness - estimatedBits < (Int)(m_pcRateCtrl->getCpbSize()*0.1f)){estimatedBits = max(200, estimatedCpbFullness - (Int)(m_pcRateCtrl->getCpbSize()*0.1f));}
#endif
​m_pcRateCtrl->getRCPic()->setTargetBits(estimatedBits);}
#endif

updateCpbState函数

编码完一帧后更新缓冲区状态,cpbstate用完判断缓冲区是上溢还是下溢出

#if U0132_TARGET_BITS_SATURATION
Int  TEncRateCtrl::updateCpbState(Int actualBits)
{Int cpbState = 1;m_cpbState -= actualBits;if (m_cpbState < 0){cpbState = -1;}m_cpbState += m_bufferingRate;if (m_cpbState > m_cpbSize){cpbState = 0;}return cpbState;
}

如图所示,我编码了三帧,码率是20000bps,fps =30,bufferRate=666

初始缓冲区大小为10000,第一帧为14432bits,10000+666-14432 =-3766,缓冲区下溢

initRCGOP函数

initRCPIC函数

可以看到在GOP创建时传了seq和该GOP的大小,在pic创建时传入了seq,GOP还有该帧的level。

这里有个注意点,initRCGOP传参numberofpictures并不一定等于GOPsize,经过断点调试后发现,假如我设置只编码三帧,IPPP结构,GOPsize=4,会调用两次initRCGOP函数,第一次numberofpictures=1.为I帧,第二次numberofpictures=2,是剩下的两帧。对于第一帧I帧而言,GOPsize=1,对于2,3帧GOPsize依旧等于4,原因后面讲。

HEVC码率控制算法1TEncRateCtrl相关推荐

  1. VCIP2020:面向机器视觉的HEVC码率控制

    本文来自VCIP2020文章<A Novel Visual Analysis Oriented Rate Control Scheme for HEVC> 深度学习的发展使得计算机视觉任务 ...

  2. H.264的码率控制算法

    H.264的码率控制算法采用了多种技术,其中包括自适应基本单元层(Adaptive Basic Unit Layer).流量往返模型(Fluid Traffic Model).线性MAD模型.二次率失 ...

  3. HEVC码率控制介绍(R-Lamda)

    本来是不想贴出相应的代码的,但是还是贴出来大概的模块吧,这样才能不纸上谈兵! R-lamda模型提出到优化已有2年,从近几年的文章来看,大体归为以下几类:一类是帧内的码率控制算法,一类是模型参数更新, ...

  4. JM编码器码率控制算法笔记:以JVT-G012r1为例

    应用率失真优化需要三个算法/模型 根据信源输入及选择的编码框架,建立合适的R-D模型(通常是R-Q.D-Q关系): 根据给定的码率R以及缓冲区状态,为每个编码单元分配比特并带入R-D模型求解Q,并在编 ...

  5. H.264码率控制算法研究及JM相应代码分析(二)

    在前一篇文章的基础上,现在先看一下MPEG4 编码标准中应用的码率控制算法,总结起来,各大算法都是在解决两个问题:RD 率失真的优化以及避免缓冲区的上溢下溢. MPEG-4 VM8 码率控制算法 在这 ...

  6. x264 码率控制算法原理

    x264 的码率控制是如何实现的 ? 本文介绍 x264 码率控制算法的数学原理,和基本框架. 1.理论假设 有助于往下阅读,可以暂时跳过. 设变量:      qscale = 拉格朗日常数 lam ...

  7. HEVC码率控制资料整理

    本篇博客主要记录项目过程中参考过.写得比较好的博客. 下载 HEVC项目 YUV视频文件 安装与使用 https://lin-lz.blog.csdn.net/article/details/5277 ...

  8. HEVC码率控制TEncRCPic

    TEncRCPic帧级别码率控制 先开看成员属性 补充:m_totalCostIntra是指该帧(I帧)的帧内所有LCU的代价总和,该值通过TEncSlice::calCostSliceI函数赋值,同 ...

  9. HEVC码率控制代码分析

    参考阅读https://blog.csdn.net/HEVC_CJL/article/details/10982699和https://blog.csdn.net/NB_vol_1/article/d ...

最新文章

  1. IoT 、5G与边缘计算将会擦出怎样的火花?
  2. 如何通过 macOS 恢复功能重新安装 macOS
  3. (转)利用Ant与Proguard混淆引用的子工程项目jar包及打war包
  4. mysql增删查操作
  5. POJ - 3322 Bloxorz I(bfs+状态设计)
  6. linux服务器上svn的log_Linux服务器上搭建svn服务器
  7. java从url下载文件_Java从URL下载文件
  8. 队列消息在html中怎么排列,Redis实现消息队列
  9. 难以置信,MySQL也可以无损自由切换
  10. C++基础教程之函数重载,什么是C++函数重载?
  11. Java 学习如逆水行舟,不进则退,100 本 java 电子书推荐
  12. Vue电商网站项目开发总结
  13. 仿羊了个羊H5游戏源码
  14. matlab画航线图,【图文详解】如何画出华丽丽的全球航线图
  15. python滑稽脸程序
  16. 3. Git与TortoiseGit基本操作
  17. 学计算机基础知识的app,电脑基础知识零基础入门版-电脑基础知识APP手机大全v1.0 安卓版-007游戏网...
  18. team explorer_Team Explorer 2017独立安装程序的退还
  19. 软件版本A.B.C这些数字分别代表什么意思
  20. 电脑技巧——用键盘控制光标

热门文章

  1. 简单聊天室客户端界面的实现(ChatClient.java)
  2. 目标管理的S.M.A.R.T.理念
  3. OpenCV——角点检测原理分析(Harris,Shi-Tomasi、亚像素级角点检测)
  4. 多视图几何笔记(二)射影变换
  5. OCR文字识别之CTC原理和实现
  6. 【读书笔记】《偷影子的人》[法]马克·李维 —— 不想被叫醒的梦
  7. 联想昭阳E47A无线网卡指示灯不亮,搜不到无线信号,解决办法
  8. labview 添加自定义Lib
  9. eclipse在资源管理器中打开文件
  10. 单元测试实践篇:Mock