VTM中的cu、pu和tu在使用时都是作为CodingStructure类的成员变量来使用的,即作为CS中cus、pus和tus数组中的一个变量来使用的,毕竟VTM中的操作都是以CS作为最基本的类来执行的。
VTM不会像JEM中那样将cu、pu和tu区分起来看待:JEM中在划分完cu后,在处理pu时会有8种划分模式,tu也会根据pu的划分方式有自己的划分。VTM则移除了这种对cu、pu和tu的严格区分,只是将cu、pu和tu视为当前块cs的三种类型的数据,CTU划分树得到cu之后不再进行pu和tu的继续划分了(当然tu会因为变换块的大小关系可能划分为小块)
CU、PU和TU的结构体中包含的数据如下:
( 由于VTM3.0中添加了很多的编码工具,所以cu、pu、tu中所保存记录的信息也有相应的添加。)
struct CodingUnit : public UnitArea
{
CodingStructure *cs; //所归属的cs
Slice *slice;
ChannelType chType;
PredMode predMode; //intra、inter
PartSize partSize; //VTM中均为2Nx2N
uint8_t depth; //所有划分模式的depth
uint8_t qtDepth; //QT深度
// a triple split would increase the mtDepth by 1, but the qtDepth by 2 in the first and last part and by 1 in the middle part (because of the 1-2-1 split proportions)
uint8_t btDepth; //BT深度
uint8_t mtDepth; //TT+BT深度
int8_t chromaQpAdj;
int8_t qp; //量化参数
SplitSeries splitSeries; //64位长整数,记录ctu划分树划分到cu时的各个depth的划分模式
bool skip; //是否为skip模式
#if JVET_L0054_MMVD
bool mmvdSkip; //mmvd模式flag
#endif
bool affine; //affine模式flag
int affineType; //affine模式类型,4/6参数
#if JVET_L0124_L0208_TRIANGLE
bool triangle; //三角预测模式flag
#endif
bool transQuantBypass;
bool ipcm; //是否为pcm模式
uint8_t imv; //整数mv
bool rootCbf;
#if HEVC_TILES_WPP
uint32_t tileIdx;
#endif
uint8_t emtFlag;
#if JVET_L0646_GBI
uint8_t GBiIdx; //广义Bi
int refIdxBi[2];
#endif
// needed for fast imv mode decisions
int8_t imvNumCand;
#if JVET_L0293_CPR
bool cpr; //CPR模式flag
#endif
unsigned idx; //cu存储在cs中的cus数组中的idx
CodingUnit *next; //idx表示在数组中位置,nest指向数组中下一个cu
PredictionUnit *firstPU; //cu会记录它的pu和tu
PredictionUnit *lastPU; //cu的pu和tu是cs.pus和cs.tus的一段
TransformUnit *firstTU;
TransformUnit *lastTU;
//.....
};
struct IntraPredictionData //帧内预测数据
{
uint32_t intraDir[MAX_NUM_CHANNEL_TYPE]; //帧内预测亮度和色度模式
#if JVET_L0283_MULTI_REF_LINE
int multiRefIdx; //帧内MRL模式的multiRefIdx
#endif
};
struct IntraPredictionData //帧内预测数据
{
uint32_t intraDir[MAX_NUM_CHANNEL_TYPE]; //帧内预测亮度和色度模式
#if JVET_L0283_MULTI_REF_LINE
int multiRefIdx; //帧内MRL模式的multiRefIdx
#endif
};
struct InterPredictionData //帧间预测数据
{
bool mergeFlag; //是否merge
uint8_t mergeIdx; //mergeidx
#if JVET_L0054_MMVD
bool mmvdMergeFlag; //mmvd模式flag
uint32_t mmvdMergeIdx; //mmvd模式的mergeidx
#endif
uint8_t interDir; //帧间预测方向:1-前向、2-后向、3-双向
uint8_t mvpIdx [NUM_REF_PIC_LIST_01]; //mvp在AMVP列表中的idx
uint8_t mvpNum [NUM_REF_PIC_LIST_01]; //AMVP列表中mvp数目
Mv mvd [NUM_REF_PIC_LIST_01]; //mvd
Mv mv [NUM_REF_PIC_LIST_01]; //mv=mvp+mvd
int16_t refIdx [NUM_REF_PIC_LIST_01]; //参考帧
MergeType mergeType; //merge模式类型
Mv mvdAffi [NUM_REF_PIC_LIST_01][3]; //Affine模式各控制点的mvd
#if JVET_L0694_AFFINE_LINEBUFFER_CLEANUP
Mv mvAffi[NUM_REF_PIC_LIST_01][3]; //Affine模式各控制点的mv
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
bool mhIntraFlag; //CIIP模式flag
#endif
#if JVET_L0293_CPR //CPR模式的mv
Mv bv; // block vector for CPR
Mv bvd; // block vector difference for CPR
#endif
};
struct PredictionUnit : public UnitArea, public IntraPredictionData, public InterPredictionData
{ //pu直接继承了上面帧内和帧间的数据
CodingUnit *cu; //pu所属的cu
CodingStructure *cs; //pu所属的cs
ChannelType chType;
unsigned idx; //pu存储在cs中的pus数组中的idx
PredictionUnit *next; //cs.pus中指向下一个pu
//.....
};
struct TransformUnit : public UnitArea
{
CodingUnit *cu; //tu所属的cu
CodingStructure *cs;
ChannelType chType;
uint8_t depth; //tu如果进行划分时的深度
uint8_t emtIdx;
uint8_t cbf [ MAX_NUM_TBLOCKS ]; //tu是否已经经过变换量化
RDPCMMode rdpcm [ MAX_NUM_TBLOCKS ]; //pcm模式 pcm模式是省去求残差、变换和量化
bool transformSkip[ MAX_NUM_TBLOCKS ]; //transformSkip模式 TS模式是省去变换
int8_t compAlpha [ MAX_NUM_TBLOCKS ];
unsigned idx; //与cu和pu一样,cs.tus中的位置idx
TransformUnit *next;
//.....
private:
TCoeff *m_coeffs[ MAX_NUM_TBLOCKS ]; //其实这里只是记录当前tu的变换系数的存储位置,tu的变换系数数据存储在cs中。参考addTU函数就能理解
Pel *m_pcmbuf[ MAX_NUM_TBLOCKS ]; //pcm模式时的像素buf
};
来源:CSDN
作者:矛盾统一
链接:https://blog.csdn.net/gq0323/article/details/103721014