HEVCe轻量级帧内编码器阅读

看了一篇大佬写的文章,里面实现了一个轻量级的帧内编码器,感觉用来学习编码器基础非常好,本文是一些自己的理解。大佬文章:H.265/HEVC 帧内编码详解:CU/TU层次结构、预测、变换、量化、编码、编码端整体流程 - 知乎

整体流程:

1.参数解析,输入文件 输出文件 QP  [重构文件]。

2.加载PGM文件,loadPGMfile(),把数据存入char img [8192*8192](二维图片往一维数组存),并且得到图片的宽xsz和高ysz。

3.开始压缩HEVCImageEncoder(),这个函数返回HEVC码流长度,保存码流到pbuffer,保存重构文件img_rcon。

HEVCImageEncoder()

[

1)初始化CABAC编码器,初始化tCtxs上下文参数集,填充高和宽成为CTU的倍数(CTU固定32x32大小)。初始化所有CU大小为CTU大小,所有帧内预测模式为PMODE_DC。

2)putHeaderToBuffer()将头文件信息插入HEVC码流(VPS,SPS,PPS)

3)从左至右、从上到下一个一个CTU的开始编码

for (y=0; y<yszn; y+=CTU_SZ) {

for (x=0; x<xszn; x+=CTU_SZ) {

……参数、重构处理

processCURecurs() 编码一个CTU

……重构处理

写终止位,CABAC缓存区写出到输出缓存区

}

保留上一行CTU的信息可以给下一行做参考

}

]

processCURecurs()

参数:(blk_orig  [][CTU_SZ]原始像素块,blk_rcon   [][1+CTU_SZ*2]重构像素块

Ctxs、CABAC以及一系列的边框检查标志)

[

一系列初始化,以及获取邻近CU的信息,构造子块信息。

第一步:尝试划分成4个CU

putSplitCUflag()设置划分标志

四个子块再次递归调用processCURecurs(),计算Rdcost(基于SSE的cost),备份重构块。

第二步:CU不划分,对每个帧内预测方向尝试part2Nx2N (no splitting to 4 PUs)模式。

for (pmode=0; pmode<PMODE_COUNT; pmode++) {

predicttransformquantizedeQuantizetransform系列函数

逆转换后的块存入重构块

设置不划分标志

对blk_quat系数块进行putCU_Part2Nx2N_noTUsplit()编码CU,计算RDcost

更新最佳RDcost,选择最佳帧内预测方向  }

第三步:CU不划分,对每个帧内预测方向尝试part2Nx2N (no splitting to 4 PUs),but splitting to 4 TUs模式,循环同第二步类似,调用putCU_Part2Nx2N_TUsplit()编码CU

第四步:CU大小正好等于8x8时。partNxN (splitting to 4 PUs)模式

循环同第二步类似,这里直接调用putCoef()对四个子PU处理

再给四个PU的Ctx赋值,再调用putCU_PartNxN()编码

最后一步:将最佳重构CU写入blk_rcon

}

]

predictBLK_SUBtransform0quantizedeQuantizetransform1系列函数

predict:根据预测角度得到预测块blk_tmp1

35个角度(Planar、DC、HOR、VER、2~9、11~25、27~34)

BLK_SUB:blk_orig- blk_tmp1得到残差块blk_tmp2

transform0:对残差块blk_tmp2进行转换(DCT or 4x4 DST)

DST4_MAT, DCT8_MAT, DCT16_MAT, DCT32_MAT四个预设好的转换矩阵,根据TU大小来选择矩阵。矩阵相乘函数matMul()。

quantize:简化率失真优化量化(RDOQ),对转换后的blk_tmp2进行量化得到blk_quat块

循环对每个CG块(4x4系数块)进行量化

for (yc=0; yc<sz; yc+=CG_SZ) {

for (xc=0; xc<sz; xc+=CG_SZ) {

……

   对一个CG块进行率失真优化得到最优CG块

for (y=yc; y<yc+CG_SZ; y++) {

    for (x=xc; x<xc+CG_SZ; x++){

  I32  level     = COEF_CLIP( (dlevel+add) >> sft );

I32  min_level = MAX(0, level-2);

在这两个范围内寻找最优CG

 }}

……if this CG is too weak,clear all items in CG,系数矩阵太弱就直接全部置0

}}

deQuantize:反量化,由blk_quat得到blk_tmp2

transform1:逆转换blk_tmp2

BLK_ADD_CLIP_TO_PIX:把逆回来的blk_tmp2直接存入重构块

后续对量化得到的blk_quat块进行编码

putCU_Part2Nx2N_noTUsplitputCU_Part2Nx2N_TusplitputCU_PartNxN三个编码函数

putCU_Part2Nx2N_noTUsplit()put a CU to HEVC stream, where part_type = part2Nx2N , no splitting to 4 Tus。

系列函数:putPartSize、putYpmode、putUVpmode、putSplitTUflag、putQtCbf(U、V、Y)以及putCoef()均调用CABACputBin()函数来CABAC编码写入码流

putCU_Part2Nx2N_TUsplit()

putCU_Part2Nx2N_noTUsplit()类似,额外对四个TU进行putCoef()系数编码

putCU_PartNxN()

同上面两个类似,标志位不同,并且对四个TU系数编码

putCoef()

把一个系数块编进码流

调用getScanOrder获得扫描顺序表,调用一系列CABACputBins()进行CABAC编码

附:

作者的码流分析CU、PU、TU层次编码划分

HEVC的35中帧内预测模式

整体流程图:

// 作者分析的编码器搜索一个 CTU 的最优方案的过程日志 -------------------------------------------------------------------------

ProcessCU开始: CU(y= 0 x= 0 size=32)  初始化设置最优RDcost=99999

      ProcessCU开始: CU(y= 0 x= 0 size=16)  初始化设置最优RDcost=99999

            ProcessCU开始: CU(y= 0 x= 0 size= 8)  初始化设置最优RDcost=99999

               把 CU(y= 0 x= 0 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=369), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y= 0 x= 0 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 1 (RDcost=748), 不小于之前最优RDcost (369)

               把 CU(y= 0 x= 0 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={ 0,19,31,18}, RDcost=801, 不小于之前最优RDcost (369)

            ProcessCU结束: CU(y= 0 x= 0 size= 8), 最终 RDcost=369

            ProcessCU开始: CU(y= 0 x= 8 size= 8)  初始化设置最优RDcost=99999

               把 CU(y= 0 x= 8 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 4 (RDcost=238), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y= 0 x= 8 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 2 (RDcost=270), 不小于之前最优RDcost (238)

               把 CU(y= 0 x= 8 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={ 3, 2,34, 3}, RDcost=309, 不小于之前最优RDcost (238)

            ProcessCU结束: CU(y= 0 x= 8 size= 8), 最终 RDcost=238

            ProcessCU开始: CU(y= 8 x= 0 size= 8)  初始化设置最优RDcost=99999

               把 CU(y= 8 x= 0 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是26 (RDcost=217), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y= 8 x= 0 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是26 (RDcost=232), 不小于之前最优RDcost (217)

               把 CU(y= 8 x= 0 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={25,17,22,20}, RDcost=291, 不小于之前最优RDcost (217)

            ProcessCU结束: CU(y= 8 x= 0 size= 8), 最终 RDcost=217

            ProcessCU开始: CU(y= 8 x= 8 size= 8)  初始化设置最优RDcost=99999

               把 CU(y= 8 x= 8 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=225), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y= 8 x= 8 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是10 (RDcost=269), 不小于之前最优RDcost (225)

               把 CU(y= 8 x= 8 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={26,24,17, 7}, RDcost=282, 不小于之前最优RDcost (225)

            ProcessCU结束: CU(y= 8 x= 8 size= 8), 最终 RDcost=225

         已尝试把 CU(y= 0 x= 0 size=16) 拆分成4个CU, 总 RDcost=369+238+217+225=1049  暂时以该方案作为当前最优方案

         把 CU(y= 0 x= 0 size=16) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=818), 小于之前最优RDcost (1049), 更新为当前最优方案

         把 CU(y= 0 x= 0 size=16) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 2 (RDcost=951), 不小于之前最优RDcost (818)

      ProcessCU结束: CU(y= 0 x= 0 size=16), 最终 RDcost=818

      ProcessCU开始: CU(y= 0 x=16 size=16)  初始化设置最优RDcost=99999

            ProcessCU开始: CU(y= 0 x=16 size= 8)  初始化设置最优RDcost=99999

               把 CU(y= 0 x=16 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 1 (RDcost=214), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y= 0 x=16 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=237), 不小于之前最优RDcost (214)

               把 CU(y= 0 x=16 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={ 2, 3,14,17}, RDcost=370, 不小于之前最优RDcost (214)

            ProcessCU结束: CU(y= 0 x=16 size= 8), 最终 RDcost=214

            ProcessCU开始: CU(y= 0 x=24 size= 8)  初始化设置最优RDcost=99999

               把 CU(y= 0 x=24 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是26 (RDcost=416), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y= 0 x=24 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=503), 不小于之前最优RDcost (416)

               把 CU(y= 0 x=24 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={ 1,16,19,21}, RDcost=525, 不小于之前最优RDcost (416)

            ProcessCU结束: CU(y= 0 x=24 size= 8), 最终 RDcost=416

            ProcessCU开始: CU(y= 8 x=16 size= 8)  初始化设置最优RDcost=99999

               把 CU(y= 8 x=16 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=216), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y= 8 x=16 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=247), 不小于之前最优RDcost (216)

               把 CU(y= 8 x=16 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={ 0,26, 7,19}, RDcost=223, 不小于之前最优RDcost (216)

            ProcessCU结束: CU(y= 8 x=16 size= 8), 最终 RDcost=216

            ProcessCU开始: CU(y= 8 x=24 size= 8)  初始化设置最优RDcost=99999

               把 CU(y= 8 x=24 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 8 (RDcost=1986), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y= 8 x=24 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 3 (RDcost=1404), 小于之前最优RDcost (1986), 更新为当前最优方案

               把 CU(y= 8 x=24 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={ 0,16,23, 3}, RDcost=1345, 小于当前最优RDcost (1404), 更新为当前最优方案

            ProcessCU结束: CU(y= 8 x=24 size= 8), 最终 RDcost=1345

         已尝试把 CU(y= 0 x=16 size=16) 拆分成4个CU, 总 RDcost=214+416+216+1345=2192  暂时以该方案作为当前最优方案

         把 CU(y= 0 x=16 size=16) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 3 (RDcost=5377), 不小于之前最优RDcost (2192)

         把 CU(y= 0 x=16 size=16) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是15 (RDcost=2717), 不小于之前最优RDcost (2192)

      ProcessCU结束: CU(y= 0 x=16 size=16), 最终 RDcost=2192

      ProcessCU开始: CU(y=16 x= 0 size=16)  初始化设置最优RDcost=99999

            ProcessCU开始: CU(y=16 x= 0 size= 8)  初始化设置最优RDcost=99999

               把 CU(y=16 x= 0 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 1 (RDcost=219), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y=16 x= 0 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是17 (RDcost=289), 不小于之前最优RDcost (219)

               把 CU(y=16 x= 0 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={ 1,16,22,12}, RDcost=344, 不小于之前最优RDcost (219)

            ProcessCU结束: CU(y=16 x= 0 size= 8), 最终 RDcost=219

            ProcessCU开始: CU(y=16 x= 8 size= 8)  初始化设置最优RDcost=99999

               把 CU(y=16 x= 8 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是24 (RDcost=1300), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y=16 x= 8 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=654), 小于之前最优RDcost (1300), 更新为当前最优方案

               把 CU(y=16 x= 8 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={17,31,19,22}, RDcost=649, 小于当前最优RDcost (654), 更新为当前最优方案

            ProcessCU结束: CU(y=16 x= 8 size= 8), 最终 RDcost=649

            ProcessCU开始: CU(y=24 x= 0 size= 8)  初始化设置最优RDcost=99999

               把 CU(y=24 x= 0 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是26 (RDcost=181), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y=24 x= 0 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=221), 不小于之前最优RDcost (181)

               把 CU(y=24 x= 0 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={31,26,19,29}, RDcost=306, 不小于之前最优RDcost (181)

            ProcessCU结束: CU(y=24 x= 0 size= 8), 最终 RDcost=181

            ProcessCU开始: CU(y=24 x= 8 size= 8)  初始化设置最优RDcost=99999

               把 CU(y=24 x= 8 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是28 (RDcost=1302), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y=24 x= 8 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是27 (RDcost=907), 小于之前最优RDcost (1302), 更新为当前最优方案

               把 CU(y=24 x= 8 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={29,28,23,27}, RDcost=937, 不小于之前最优RDcost (907)

            ProcessCU结束: CU(y=24 x= 8 size= 8), 最终 RDcost=907

         已尝试把 CU(y=16 x= 0 size=16) 拆分成4个CU, 总 RDcost=219+649+181+907=1958  暂时以该方案作为当前最优方案

         把 CU(y=16 x= 0 size=16) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是14 (RDcost=4343), 不小于之前最优RDcost (1958)

         把 CU(y=16 x= 0 size=16) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是28 (RDcost=3091), 不小于之前最优RDcost (1958)

      ProcessCU结束: CU(y=16 x= 0 size=16), 最终 RDcost=1958

      ProcessCU开始: CU(y=16 x=16 size=16)  初始化设置最优RDcost=99999

            ProcessCU开始: CU(y=16 x=16 size= 8)  初始化设置最优RDcost=99999

               把 CU(y=16 x=16 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 3 (RDcost=1641), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y=16 x=16 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 4 (RDcost=1332), 小于之前最优RDcost (1641), 更新为当前最优方案

               把 CU(y=16 x=16 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={ 4, 5, 3, 0}, RDcost=1254, 小于当前最优RDcost (1332), 更新为当前最优方案

            ProcessCU结束: CU(y=16 x=16 size= 8), 最终 RDcost=1254

            ProcessCU开始: CU(y=16 x=24 size= 8)  初始化设置最优RDcost=99999

               把 CU(y=16 x=24 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是33 (RDcost=1670), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y=16 x=24 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=875), 小于之前最优RDcost (1670), 更新为当前最优方案

               把 CU(y=16 x=24 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={34,31, 6, 0}, RDcost=919, 不小于之前最优RDcost (875)

            ProcessCU结束: CU(y=16 x=24 size= 8), 最终 RDcost=875

            ProcessCU开始: CU(y=24 x=16 size= 8)  初始化设置最优RDcost=99999

               把 CU(y=24 x=16 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=322), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y=24 x=16 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是27 (RDcost=395), 不小于之前最优RDcost (322)

               把 CU(y=24 x=16 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={34,29, 1,28}, RDcost=421, 不小于之前最优RDcost (322)

            ProcessCU结束: CU(y=24 x=16 size= 8), 最终 RDcost=322

            ProcessCU开始: CU(y=24 x=24 size= 8)  初始化设置最优RDcost=99999

               把 CU(y=24 x=24 size= 8) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是26 (RDcost=359), 小于之前最优RDcost (99999), 更新为当前最优方案

               把 CU(y=24 x=24 size= 8) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是26 (RDcost=335), 小于之前最优RDcost (359), 更新为当前最优方案

               把 CU(y=24 x=24 size= 8) 分成4个PU, 对每个PU分别尝试35种预测模式, 4个最佳的预测模式={24,27,24,26}, RDcost=415, 不小于之前最优RDcost (335)

            ProcessCU结束: CU(y=24 x=24 size= 8), 最终 RDcost=335

         已尝试把 CU(y=16 x=16 size=16) 拆分成4个CU, 总 RDcost=1254+875+322+335=2787  暂时以该方案作为当前最优方案

         把 CU(y=16 x=16 size=16) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 5 (RDcost=5745), 不小于之前最优RDcost (2787)

         把 CU(y=16 x=16 size=16) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=4150), 不小于之前最优RDcost (2787)

      ProcessCU结束: CU(y=16 x=16 size=16), 最终 RDcost=2787

   已尝试把 CU(y= 0 x= 0 size=32) 拆分成4个CU, 总 RDcost=818+2192+1958+2787=7754  暂时以该方案作为当前最优方案

   把 CU(y= 0 x= 0 size=32) 当作1个TU, 尝试35种预测模式, 其中最佳预测模式是 0 (RDcost=20321), 不小于之前最优RDcost (7754)

   把 CU(y= 0 x= 0 size=32) 分成4个TU, 尝试35种预测模式, 其中最佳预测模式是 3 (RDcost=15969), 不小于之前最优RDcost (7754)

ProcessCU结束: CU(y= 0 x= 0 size=32), 最终 RDcost=7754

  • 50
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值