上一篇文章主要讨论了RC的总体框架,本文开始分析具体的代码实现细节。分析的顺序按照总体框架来,即初始化-->更新。

(1)m_cRateCtrl.init()

#if M0036_RC_IMPROVEMENT
Void TEncRateCtrl::init( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int keepHierBits, Bool useLCUSeparateModel, GOPEntry GOPList[MAX_GOP] )
#else
Void TEncRateCtrl::init( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Bool keepHierBits, Bool useLCUSeparateModel, GOPEntry GOPList[MAX_GOP] )
#endif
{
destroy(); Bool isLowdelay = true;
for ( Int i=0; i<GOPSize-1; i++ )
{
if ( GOPList[i].m_POC > GOPList[i+1].m_POC ) //!< 判断是否为lowdelay配置
{
isLowdelay = false;
break;
}
} Int numberOfLevel = 1;
#if M0036_RC_IMPROVEMENT
Int adaptiveBit = 0;
if ( keepHierBits > 0 )
#else
if ( keepHierBits ) //!< hierarchical structure
#endif
{
numberOfLevel = Int( log((Double)GOPSize)/log(2.0) + 0.5 ) + 1;
}
if ( !isLowdelay && GOPSize == 8 )
{
numberOfLevel = Int( log((Double)GOPSize)/log(2.0) + 0.5 ) + 1;
}
numberOfLevel++; // intra picture
numberOfLevel++; // non-reference picture Int* bitsRatio; //!< 每一幅picture的权值
bitsRatio = new Int[ GOPSize ];
for ( Int i=0; i<GOPSize; i++ )
{
bitsRatio[i] = 10;
if ( !GOPList[i].m_refPic )
{
bitsRatio[i] = 2;
}
} #if M0036_RC_IMPROVEMENT
if ( keepHierBits > 0 )
#else
if ( keepHierBits )
#endif
{
Double bpp = (Double)( targetBitrate / (Double)( frameRate*picWidth*picHeight ) ); //!< K0103 式子(3)
if ( GOPSize == 4 && isLowdelay ) //!< K0103 Table 1
{
if ( bpp > 0.2 )
{
bitsRatio[0] = 2;
bitsRatio[1] = 3;
bitsRatio[2] = 2;
bitsRatio[3] = 6;
}
else if( bpp > 0.1 )
{
bitsRatio[0] = 2;
bitsRatio[1] = 3;
bitsRatio[2] = 2;
bitsRatio[3] = 10;
}
else if ( bpp > 0.05 )
{
bitsRatio[0] = 2;
bitsRatio[1] = 3;
bitsRatio[2] = 2;
bitsRatio[3] = 12;
}
else
{
bitsRatio[0] = 2;
bitsRatio[1] = 3;
bitsRatio[2] = 2;
bitsRatio[3] = 14;
}
#if M0036_RC_IMPROVEMENT
if ( keepHierBits == 2 )
{
adaptiveBit = 1;
}
#endif
}
else if ( GOPSize == 8 && !isLowdelay ) //!< K0103 Table 2
{
if ( bpp > 0.2 )
{
bitsRatio[0] = 15;
bitsRatio[1] = 5;
bitsRatio[2] = 4;
bitsRatio[3] = 1;
bitsRatio[4] = 1;
bitsRatio[5] = 4;
bitsRatio[6] = 1;
bitsRatio[7] = 1;
}
else if ( bpp > 0.1 )
{
bitsRatio[0] = 20;
bitsRatio[1] = 6;
bitsRatio[2] = 4;
bitsRatio[3] = 1;
bitsRatio[4] = 1;
bitsRatio[5] = 4;
bitsRatio[6] = 1;
bitsRatio[7] = 1;
}
else if ( bpp > 0.05 )
{
bitsRatio[0] = 25;
bitsRatio[1] = 7;
bitsRatio[2] = 4;
bitsRatio[3] = 1;
bitsRatio[4] = 1;
bitsRatio[5] = 4;
bitsRatio[6] = 1;
bitsRatio[7] = 1;
}
else
{
bitsRatio[0] = 30;
bitsRatio[1] = 8;
bitsRatio[2] = 4;
bitsRatio[3] = 1;
bitsRatio[4] = 1;
bitsRatio[5] = 4;
bitsRatio[6] = 1;
bitsRatio[7] = 1;
}
#if M0036_RC_IMPROVEMENT
if ( keepHierBits == 2 )
{
adaptiveBit = 2;
}
#endif
}
else
{
#if M0036_RC_IMPROVEMENT
printf( "\n hierarchical bit allocation is not support for the specified coding structure currently.\n" );
#else
printf( "\n hierarchical bit allocation is not support for the specified coding structure currently." );
#endif
}
} Int* GOPID2Level = new int[ GOPSize ]; //!< 根据在GOP中的id确定所属的分层
for ( int i=0; i<GOPSize; i++ )
{
GOPID2Level[i] = 1;
if ( !GOPList[i].m_refPic )
{
GOPID2Level[i] = 2;
}
}
#if M0036_RC_IMPROVEMENT
if ( keepHierBits > 0 )
#else
if ( keepHierBits )
#endif
{
if ( GOPSize == 4 && isLowdelay )
{
GOPID2Level[0] = 3;
GOPID2Level[1] = 2;
GOPID2Level[2] = 3;
GOPID2Level[3] = 1;
}
else if ( GOPSize == 8 && !isLowdelay )
{
GOPID2Level[0] = 1;
GOPID2Level[1] = 2;
GOPID2Level[2] = 3;
GOPID2Level[3] = 4;
GOPID2Level[4] = 4;
GOPID2Level[5] = 3;
GOPID2Level[6] = 4;
GOPID2Level[7] = 4;
}
} if ( !isLowdelay && GOPSize == 8 )
{
GOPID2Level[0] = 1;
GOPID2Level[1] = 2;
GOPID2Level[2] = 3;
GOPID2Level[3] = 4;
GOPID2Level[4] = 4;
GOPID2Level[5] = 3;
GOPID2Level[6] = 4;
GOPID2Level[7] = 4;
} m_encRCSeq = new TEncRCSeq;
#if M0036_RC_IMPROVEMENT
m_encRCSeq->create( totalFrames, targetBitrate, frameRate, GOPSize, picWidth, picHeight, LCUWidth, LCUHeight, numberOfLevel, useLCUSeparateModel, adaptiveBit );
#else //!< 序列级RC参数的初始化
m_encRCSeq->create( totalFrames, targetBitrate, frameRate, GOPSize, picWidth, picHeight, LCUWidth, LCUHeight, numberOfLevel, useLCUSeparateModel );
#endif
m_encRCSeq->initBitsRatio( bitsRatio ); //!< 每幅picture的权值
m_encRCSeq->initGOPID2Level( GOPID2Level );
m_encRCSeq->initPicPara(/*TRCParameter* picPara = NULL*/); //!< alpha, beta
if ( useLCUSeparateModel )
{
m_encRCSeq->initLCUPara(); //!< alpha,beta初始化
} delete[] bitsRatio;
delete[] GOPID2Level;
}

分析该函数中调用的比较重要的若干个子函数:

m_encRCSeq->create()

#if M0036_RC_IMPROVEMENT
Void TEncRCSeq::create( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int numberOfLevel, Bool useLCUSeparateModel, Int adaptiveBit )
#else
Void TEncRCSeq::create( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int numberOfLevel, Bool useLCUSeparateModel )
#endif
{
destroy();
m_totalFrames = totalFrames;
m_targetRate = targetBitrate;
m_frameRate = frameRate;
m_GOPSize = GOPSize;
m_picWidth = picWidth;
m_picHeight = picHeight;
m_LCUWidth = LCUWidth;
m_LCUHeight = LCUHeight;
m_numberOfLevel = numberOfLevel;
m_useLCUSeparateModel = useLCUSeparateModel; m_numberOfPixel = m_picWidth * m_picHeight;
m_targetBits = (Int64)m_totalFrames * (Int64)m_targetRate / (Int64)m_frameRate; //!< 序列总码率(输出码流总大小)
m_seqTargetBpp = (Double)m_targetRate / (Double)m_frameRate / (Double)m_numberOfPixel; //!< m_targetRate--bps //!< m_alphaUpdata和m_betaUpdate这两个变量用于在接下来更新lamda的参数值
if ( m_seqTargetBpp < 0.03 ) //!< (..., 0.03)
{
m_alphaUpdate = 0.01;
m_betaUpdate = 0.005;
}
else if ( m_seqTargetBpp < 0.08 ) //!< [0.03, 0.08)
{
m_alphaUpdate = 0.05;
m_betaUpdate = 0.025;
}
#if M0036_RC_IMPROVEMENT
else if ( m_seqTargetBpp < 0.2 )
{
m_alphaUpdate = 0.1;
m_betaUpdate = 0.05;
}
else if ( m_seqTargetBpp < 0.5 )
{
m_alphaUpdate = 0.2;
m_betaUpdate = 0.1;
}
else
{
m_alphaUpdate = 0.4;
m_betaUpdate = 0.2;
}
#else
else //!< [0.08, ...]
{
m_alphaUpdate = 0.1;
m_betaUpdate = 0.05;
}
#endif
m_averageBits = (Int)(m_targetBits / totalFrames); //!< 平均每帧占用的比特数
Int picWidthInBU = ( m_picWidth % m_LCUWidth ) == 0 ? m_picWidth / m_LCUWidth : m_picWidth / m_LCUWidth + 1;
Int picHeightInBU = ( m_picHeight % m_LCUHeight ) == 0 ? m_picHeight / m_LCUHeight : m_picHeight / m_LCUHeight + 1;
m_numberOfLCU = picWidthInBU * picHeightInBU; //!< 一帧picture中包含的LCU数目 m_bitsRatio = new Int[m_GOPSize];
for ( Int i=0; i<m_GOPSize; i++ )
{
m_bitsRatio[i] = 1;
} m_GOPID2Level = new Int[m_GOPSize];
for ( Int i=0; i<m_GOPSize; i++ )
{
m_GOPID2Level[i] = 1;
} m_picPara = new TRCParameter[m_numberOfLevel];
for ( Int i=0; i<m_numberOfLevel; i++ )
{
m_picPara[i].m_alpha = 0.0;
m_picPara[i].m_beta = 0.0;
} if ( m_useLCUSeparateModel ) //!< 每个LCU的alpha和beta都有各自的值
{
m_LCUPara = new TRCParameter*[m_numberOfLevel];
for ( Int i=0; i<m_numberOfLevel; i++ )
{
m_LCUPara[i] = new TRCParameter[m_numberOfLCU];
for ( Int j=0; j<m_numberOfLCU; j++)
{
m_LCUPara[i][j].m_alpha = 0.0;
m_LCUPara[i][j].m_beta = 0.0;
}
}
} m_framesLeft = m_totalFrames; //!< 剩余的待编码帧数
m_bitsLeft = m_targetBits; //!< 剩余可用的比特数
#if M0036_RC_IMPROVEMENT
m_adaptiveBit = adaptiveBit;
m_lastLambda = 0.0;
#endif
}

m_encRCSeq->initPicPara()

Void TEncRCSeq::initPicPara( TRCParameter* picPara )
{
assert( m_picPara != NULL ); if ( picPara == NULL ) //!< K0103 式子(10)
{
for ( Int i=0; i<m_numberOfLevel; i++ )
{
#if RATE_CONTROL_INTRA
if (i>0)
{
m_picPara[i].m_alpha = 3.2003;
m_picPara[i].m_beta = -1.367;
}
else
{
m_picPara[i].m_alpha = ALPHA;
m_picPara[i].m_beta = BETA2;
}
#else //!< 第一帧图像的参数初始化
m_picPara[i].m_alpha = 3.2003;
m_picPara[i].m_beta = -1.367;
#endif
}
}
else
{
for ( Int i=0; i<m_numberOfLevel; i++ )
{
m_picPara[i] = picPara[i];
}
}
}

(2)m_cRateCtrl.initRCGOP()

Void TEncRateCtrl::initRCGOP( Int numberOfPictures )
{
m_encRCGOP = new TEncRCGOP;
m_encRCGOP->create( m_encRCSeq, numberOfPictures );
}
Void TEncRCGOP::create( TEncRCSeq* encRCSeq, Int numPic )
{
destroy();
Int targetBits = xEstGOPTargetBits( encRCSeq, numPic ); //!< GOP level bit allocation #if M0036_RC_IMPROVEMENT
if ( encRCSeq->getAdaptiveBits() > 0 && encRCSeq->getLastLambda() > 0.1 )
{
Double targetBpp = (Double)targetBits / encRCSeq->getNumPixel();
Double basicLambda = 0.0;
Double* lambdaRatio = new Double[encRCSeq->getGOPSize()];
Double* equaCoeffA = new Double[encRCSeq->getGOPSize()];
Double* equaCoeffB = new Double[encRCSeq->getGOPSize()]; if ( encRCSeq->getAdaptiveBits() == 1 ) // for GOP size =4, low delay case
{
if ( encRCSeq->getLastLambda() < 120.0 )
{
lambdaRatio[1] = 0.725 * log( encRCSeq->getLastLambda() ) + 0.5793;
lambdaRatio[0] = 1.3 * lambdaRatio[1];
lambdaRatio[2] = 1.3 * lambdaRatio[1];
lambdaRatio[3] = 1.0;
}
else
{
lambdaRatio[0] = 5.0;
lambdaRatio[1] = 4.0;
lambdaRatio[2] = 5.0;
lambdaRatio[3] = 1.0;
}
}
else if ( encRCSeq->getAdaptiveBits() == 2 ) // for GOP size = 8, random access case
{
if ( encRCSeq->getLastLambda() < 90.0 )
{
lambdaRatio[0] = 1.0;
lambdaRatio[1] = 0.725 * log( encRCSeq->getLastLambda() ) + 0.7963;
lambdaRatio[2] = 1.3 * lambdaRatio[1];
lambdaRatio[3] = 3.25 * lambdaRatio[1];
lambdaRatio[4] = 3.25 * lambdaRatio[1];
lambdaRatio[5] = 1.3 * lambdaRatio[1];
lambdaRatio[6] = 3.25 * lambdaRatio[1];
lambdaRatio[7] = 3.25 * lambdaRatio[1];
}
else
{
lambdaRatio[0] = 1.0;
lambdaRatio[1] = 4.0;
lambdaRatio[2] = 5.0;
lambdaRatio[3] = 12.3;
lambdaRatio[4] = 12.3;
lambdaRatio[5] = 5.0;
lambdaRatio[6] = 12.3;
lambdaRatio[7] = 12.3;
}
} xCalEquaCoeff( encRCSeq, lambdaRatio, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() );
basicLambda = xSolveEqua( targetBpp, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() );
encRCSeq->setAllBitRatio( basicLambda, equaCoeffA, equaCoeffB ); delete []lambdaRatio;
delete []equaCoeffA;
delete []equaCoeffB;
}
#endif m_picTargetBitInGOP = new Int[numPic]; //!< 用于保存当前GOP中每幅picture对应的目标码率
Int i;
Int totalPicRatio = 0;
Int currPicRatio = 0;
for ( i=0; i<numPic; i++ )
{
totalPicRatio += encRCSeq->getBitRatio( i ); //!< 总权值
}
for ( i=0; i<numPic; i++ )
{
currPicRatio = encRCSeq->getBitRatio( i ); //!< 当前picture的权值
#if M0036_RC_IMPROVEMENT
m_picTargetBitInGOP[i] = (Int)( ((Double)targetBits) * currPicRatio / totalPicRatio );
#else
m_picTargetBitInGOP[i] = targetBits * currPicRatio / totalPicRatio; //!< K0103 式子(9),注意:由于是初始化,式子中的CodedGOP等于0
#endif
} m_encRCSeq = encRCSeq;
m_numPic = numPic;
m_targetBits = targetBits;
m_picLeft = m_numPic;
m_bitsLeft = m_targetBits;
}
Int TEncRCGOP::xEstGOPTargetBits( TEncRCSeq* encRCSeq, Int GOPSize )
{
Int realInfluencePicture = min( g_RCSmoothWindowSize, encRCSeq->getFramesLeft() ); //!< 获得实际的平滑窗口大小
Int averageTargetBitsPerPic = (Int)( encRCSeq->getTargetBits() / encRCSeq->getTotalFrames() ); //!< RPicArg
Int currentTargetBitsPerPic = (Int)( ( encRCSeq->getBitsLeft() - averageTargetBitsPerPic * (encRCSeq->getFramesLeft() - realInfluencePicture) ) / realInfluencePicture ); //!< TAvgPic,计算方法跟K0103不同,这里利用left的思路计算,而K0103利用coded的思路计算,但结果是一样的
Int targetBits = currentTargetBitsPerPic * GOPSize; //!< TGOP if ( targetBits < 200 )
{
targetBits = 200; // at least allocate 200 bits for one GOP
} return targetBits;
}

(未完待续...)

HEVC码率控制浅析——HM代码阅读之二的更多相关文章

  1. HEVC码率控制浅析——HM代码阅读之一

    HM的码率控制提案主要参考如下三篇:K0103,M0036,M0257.本文及后续文章将基于HM12.0进行讨论,且首先仅讨论K0103对应的代码,之后再陆续补充M0036,M0257对应的代码分析, ...

  2. HEVC码率控制浅析——HM代码阅读之四

    继续分析第一篇提到的compressSlice中对LCU的RC参数初始化: #if RATE_CONTROL_LAMBDA_DOMAIN Double oldLambda = m_pcRdCost-& ...

  3. Bleve代码阅读(二)——Index Mapping

    引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...

  4. <<梦断代码>>阅读笔记二

    这是第二篇读书笔记,这本书我已经读了有一大半了,感觉书中所描述的人都是疯子,一群有创造力,却又耐得住寂寞的疯子. 我从书中发现几点我比较感兴趣的内容. 第一个,乐高之梦.将程序用乐高积木一样拼接起来. ...

  5. 最近调试HEVC中码率控制, 发现HM里面一个重大bug

    最近调试HEVC中码率控制, 发现里面一个重大bug! 码率控制中有这么一个函数: Int TEncRCGOP::xEstGOPTargetBits( TEncRCSeq* encRCSeq, Int ...

  6. MediaInfo代码阅读

      MediaInfo是一个用来分析媒体文件的开源工具. 支持的文件非常全面,基本上支持所有的媒体文件. 最近是在做HEVC开发,所以比较关注MediaInfo中关于HEVC的分析与处理. 从Meid ...

  7. FFMpeg的码率控制

    mediaxyz是一位研究ffmpeg有三年的高人了,这几天一直在折腾ffmpeg中的x264,就是不知道该如何控制码率,主要是参数太多,也不知道该如何设置,在google上search了一下,这方面 ...

  8. [转载] FFMpeg的码率控制

    mediaxyz是一位研究ffmpeg有三年的高人了,这几天一直在折腾ffmpeg中的x264,就是不知道该如何控制码率,主要是参数太多,也不知道该如何设置,在google上search了一下,这方面 ...

  9. [置顶] Linux协议栈代码阅读笔记(一)

    Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, int p ...

随机推荐

  1. 基于TCP/IP协议的C++网络编程(API函数版)

    源代码:http://download.csdn.net/detail/nuptboyzhb/4169959 基于TCP/IP协议的网络编程 定义变量——获得WINSOCK版本——加载WINSOCK库 ...

  2. <转载>如何解决子级用float浮动父级div高度不能自适应的问题

    转载:http://www.kwstu.com/ArticleView/divcss_2013101582430202 解决子级对象使用css float浮动 而父级div不能自适应高度,不能被父级内 ...

  3. FZU 1894 (双端队列)

    Problem 1894 志愿者选拔 Accept: 1166    Submit: 3683 Time Limit: 1500 mSec    Memory Limit : 32768 KB  Pr ...

  4. CentOS6.4 安装Mysql

    虽说,新版的数据包可能会带上一些新特性,但是数据库对我而言,还是稳定版优先.因为新特性不一定我会用到.. 下载安装: yum list | grep mysql 因为是准备搞开发用的,所以只要安装my ...

  5. IOS UITableView单条刷新,数据不刷新解决方案

    在使用 UITableView 进行某设置页面的设计时,由于设计页面有固定的section个数和row个数,而数据又需要根据用户的修改情况进行改变,所以我们往往不会为每个cell单独写一个类,而是直接 ...

  6. ORACLE 五种表的优缺点总结

    ORACLE 五种表的优缺点总结: 1.普通表(heap table):适合大部分设计场景,有长处也有缺点. 长处: a,语法简单方便 b,适合大部分场景 缺点: a,更新日志开销较大 b,Delet ...

  7. [Machine Learning (Andrew NG courses)]IV.Linear Regression with Multiple Variables

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenFoXzE5OTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...

  8. OSX: 使用命令行对FileVault2分区恢复

    FileVault 2必须有Recovery HD分区,因为它依赖于它作为系统初启动.如果今后什么时候或者误操作删除了Recovery HD分区,那么你的机器就无法启动鸟. 是否使用苹果的办法重新获得 ...

  9. MFC 用gdi绘制填充多边形区域

    MFC 用gdi绘制填充多边形区域 这里的代码是实现一个三角形的绘制,并用刷子填充颜色 在OnPaint()函数里面 运用的是给定的三角形的三个点,很多个点可以绘制多边形 CBrush br(RGB( ...

  10. jar包生制作几种方法,jar包导出三种方法:eclipse导出、jar命令、FatJar插件

    Eclipse将引用了第三方jar包的Java项目打包成jar文件的两种方法 方案一:用Eclipse自带的Export功能 步骤1:准备主清单文件 “MANIFEST.MF”, 由于是打包引用了第三 ...