此系列是为了记录自己学习VTM10.0的过程和锻炼表达能力,主要是从解码端进行入手。由于本人水平有限,出现的错误恳请大家指正,欢迎与大家一起交流进步。
上一篇博客(VTM10.0代码学习4)讲述了将语法元素的处理从CTU级划分到CU级,并在其2.5节提到coding_unit()这个函数。我原本以为能用一篇博客讲述完coding_unit(),但实际需要两篇,错估了自己的能力(真不想承认啊,这是我太过年轻而犯下的错)。CU级语法元素处理的主要部分可以分为预测模式的参数和变换残差,本篇博客先讲述coding_unit()这个函数,然后再详解一下如何从码流获取预测模式的参数,至于变换残差的部分就留到下一篇博客中。
1. coding_unit()
在这里画了一张流程图,希望能帮大家更好地理解
CodingStructure& cs = *cu.cs;
PredictionUnit& pu = cs.addPU(cu, partitioner.chType);//向cs类加入当前PU
addPU:与先前提到的addCU类似,但稍微有些不同,函数的写法允许一个CU对应多个PU。但是在H.266中并不需要一个CU划分成多个PU,即使有基于子块的帧间预测,但是在语法元素传输中,一个CU还是对应一个PU就够了。
// skip flag
// 在当前CU存在亮度分量的前提下,满足当前slice不是I slice或所在CLVS允许开启IBC
if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag()) && cu.Y().valid())
{
cu_skip_flag( cu );//获取cu_skip_flag和skip情况下的pred_mode_ibc_flag的获取
}
// skip data
if( cu.skip )
{
cu.colorTransform = false;
cs.addEmptyTUs( partitioner );//向cs类加入空的TU
MergeCtx mrgCtx;
prediction_unit ( pu, mrgCtx );//在这种情况下只执行了prediction_unit()里面的merge_data()函数
end_of_ctu( cu, cuCtx );
return;
}
第一个分支:主要解析了语法元素cu_skip_flag和在cu_skip_flag为1情况下的语法元素pred_mode_ibc_flag。前者表示当前CU是否开启skip模式,后者表示当前CU的预测模式是否是IBC。
如果当前CU开启skip模式:
- 如果当前解码过程处于P slice或B slice,之后只可能解析语法元素pred_mode_ibc_flag和语法结构merge_data()
- 如果当前解码过程处于I slice,之后只可能解析语法元素merge_idx
第二个分支:里面的语句之后还会遇到,目前只需要知道:在这种情况下调用prediction_unit(),只执行了里面的merge_data()函数。并跳过之后的语法元素解析。
pred_mode ( cu );//获得CU的预测模式
if (CU::isIntra(cu))
{
adaptive_color_transform(cu);//解析语法元素cu_act_enabled_flag
}
pred_mode():获取当前CU的预测模式,预测模式一共有四种:传统帧内,帧间,IBC和PLT。IBC和PLT本质上也是种帧内预测,但在语法元素传输中,将其与传统帧内区分开。
分支:解析语法元素cu_act_enabled_flag,表示当前CU是否开启ACT
//解析PLT的语法元素
if (CU::isPLT(cu))
{
cu.colorTransform = false;
cs.addTU(cu, partitioner.chType);//向cs类加入TU
if (cu.isSepTree())
{
if (isLuma(partitioner.chType))
{
cu_palette_info(cu, COMPONENT_Y, 1, cuCtx);//具体参考JVET-S2001 7.3.11.6 P121,不想跟进去看= =
}
if (cu.chromaFormat != CHROMA_400 && (partitioner.chType == CHANNEL_TYPE_CHROMA))
{
cu_palette_info(cu, COMPONENT_Cb, 2, cuCtx);
}
}
else
{
if( cu.chromaFormat != CHROMA_400 )
{