AVS3编码学习过程中,很重要的一部分是捋清码流结构。通过学习AVS3-P2(FCD 2.0)-20200403_N2805.pdf,博主整理了AVS3的码流结构思维导图,并将编码树、编码单元、变换单元三个重要的结构抽取出来,以C语言的形式进行注释分析。本文中的图片、源码可以到https://download.csdn.net/download/leelitian3/14102746中免费下载。
码流结构导图:uAVS3e_structure
编码树:coding_unit_tree
/* LCU的起始像素,划分次数,划分模式,LCU的大小,是否支持QT划分,划分模式 */
coding_unit_tree(x0, y0, split, width, height, qt, mode)
{
// 判定边界
isBoundary = ((x0 + width) > PicWidthInLuma) || ((y0 + height) > PicHeightInLuma);
rightBoundary = ((x0 + width) > PicWidthInLuma) && ((y0 + height) <= PicHeightInLuma);
bottomBoundary = ((x0 + width) <= PicWidthInLuma) && ((y0 + height) > PicHeightInLuma);
// 允许的划分标志
allowNoSplit = 0;
allowSplitQt = 0;
allowSplitBtVer = 0;
allowSplitBtHor = 0;
allowSplitEqtVer = 0;
allowSplitEqtHor = 0;
// 如果是边界
if (isBoundary)
{
allowNoSplit = 0;
// I帧:128x128
if ((PictureType == 0) && (width > 64) && (height > 64))
{
allowSplitQt = 1; // QT
allowNoSplit = 1; // NO_SPLIT
}
// 64x128,128x64
else if ((width == 64 && height > 64) || (height == 64 && width > 64))
{
allowSplitBtHor = 1; // BT_HOR
allowSplitBtVer = 1; // BT_VER
}
// 右下角的那一块
else if (!rightBoundary && !bottomBoundary)
{
allowSplitQt = 1; // QT
}
// 右边界
else if (rightBoundary)
{
allowSplitBtVer = 1; // BT_VER
}
// 下边界
else if (bottomBoundary)
{
allowSplitBtHor = 1; // BT_HOR
}
}
// 不是边界的情况
else
{
// 64x128,128x64
if (((width == 64) && (height > 64)) || ((height == 64) && (width > 64)))
{
allowSplitBtHor = 1; // BT_HOR
allowSplitBtVer = 1; // BT_VER
allowNoSplit = 1; // NO_SPLIT
}
// 如果划分次数太高了
else if (split >= MaxSplitTimes)
{
allowNoSplit = 1; // NO_SPLIT
}
// I帧:128x128
else if ((PictureType == 0) && (width == 128) && (height == 128))
{
allowSplitQt = 1; // QT
allowNoSplit = 1; // NO_SPLIT
}
else
{
// 当前CU在宽高比8:1的划分范围内
if ((width <= height * MaxPartRatio) && (height <= width * MaxPartRatio))
allowNoSplit = 1; // NO_SPLIT
// 符合QT划分最小尺寸
if ((width > MinQtSize) && qt)
allowSplitQt = 1; // QT
// 在BT划分大小范围内,且划分后宽高比符合要求
if ((width <= MaxBtSize) && (height <= MaxBtSize) && (width > MinBtSize) && (height < MaxPartRatio * width))
allowSplitBtVer = 1; // BT_VER
if ((width <= MaxBtSize) && (height <= MaxBtSize) && (height > MinBtSize) && (width < MaxPartRatio * height))
allowSplitBtHor = 1; // BT_HOR
// 在EQT划分大小范围内,且划分后宽高比符合要求
if ((width <= MaxEqtSize) && (height <= MaxEqtSize) && (height >= MinEqtSize * 2) && (width >= MinEqtSize * 4) && (height * 4 <= MaxPartRatio * width))
allowSplitEqtVer = 1; // EQT_VER
if ((width <= MaxEqtSize) && (height <= MaxEqtSize) && (width >= MinEqtSize * 2) && (height >= MinEqtSize * 4) && (width * 4 <= MaxPartRatio * height))
allowSplitEqtHor = 1; // EQT_HOR
}
}
allowSplitBt = allowSplitBtVer || allowSplitBtHor;
allowSplitEqt = allowSplitEqtVer || allowSplitEqtHor;
// QT && ( NO_SPLIT || BT || EQT )
if (allowSplitQt && (allowNoSplit || allowSplitBt || allowSplitEqt))
{
qt_split_flag; // 是否使用QT划分
}
if (!QtSplitFlag)
{
// NO_SPLIT && ( BT || EQT )
if (allowNoSplit && (allowSplitBt || allowSplitEqt))
{
bet_split_flag; // 是否使用BT/EQT划分
}
if (BetSplitFlag)
{
// BT && EQT
if (allowSplitBt && allowSplitEqt)
bet_split_type_flag; // 0:BT 1:EQT
if ((!BetSplitTypeFlag && allowSplitBtHor && allowSplitBtVer) || (BetSplitTypeFlag && allowSplitEqtHor && allowSplitEqtVer))
bet_split_dir_flag; // 0:HOR 1:VER
}
}
// B/P帧 && [ ( EQT / QT 64pixel ) || ( BT 128pixel ) ]
if ((PictureType != 0) && ((((BetSplitFlag && !BetSplitTypeFlag) || QtSplitFlag) && (width * height == 64)) || (BetSplitTypeFlag && (width * height == 128))))
{
root_cu_mode; // 0: PRED_Intra_Only 1: PRED_Inter_Only
modeChild = root_cu_mode ? 'PRED_Intra_Only' : 'PRED_Inter_Only';
}
else
{
modeChild = mode; // 子编码单元的pred_mode继承父编码单元
}
if (ChildSizeOccur4) // 划分后CU的宽或高为4 ( 详见 AVS3-FCD2.0 P80 )
{
if (Component == 0)
{
LumaWidth = width;
LumaHeight = height;
Component = 1; // 设置为仅编码亮度分量
}
}
// QT划分模式
if (BlockSplitMode == 'SPLIT_QT')
{
// 子CU的大小
QtWidth = width / 2;
QtHeight = height / 2;
// 中间点的像素坐标
x1 = x0 + QtWidth;
y1 = y0 + QtHeight;
// coding_unit_tree:左上角块
coding_unit_tree(x0, y0, split + 1, QtWidth, QtHeight, 1, modeChild);
// 右上角块
if (x1 < PicWidthInLuma)
coding_unit_tree(x1, y0, split + 1, QtWidth, QtHeight, 1, modeChild);
// 左下角块
if (y1 < PicHeightInLuma)
coding_unit_tree(x0, y1, split + 1, QtWidth, QtHeight, 1, modeChild);
// 右下角块
if ((x1 < PicWidthInLuma) && (y1 < PicHeightInLuma))
coding_unit_tree(x1, y1, split + 1, QtWidth, QtHeight, 1, modeChild);
// 若ChildSizeOccur4,则为色度CU编码
if ((LumaWidth == width) && (LumaHeight = height) && ChildSizeOccur4)
{
coding_unit(x0, y0, width, height, 'PRED_No_Constraint', 'COMPONENT_Chroma'); // 以上4块仅编码luma(line134),本块仅编码chroma
Component = 0; // 恢复为编码luma_chroma
}
}
// BT_VER划分模式
else if (BlockSplitMode == 'SPLIT_BT_VER')
{
x1 = x0 + width / 2;
// 左边块
coding_unit_tree(x0, y0, split + 1, width / 2, height, 0, modeChild);
// 右边块
if (x1 < PicWidthInLuma)
coding_unit_tree(x1, y0, split + 1, width / 2, height, 0, modeChild);
// 色度块
if ((LumaWidth == width) && (LumaHeight = height) && ChildSizeOccur4)
{
coding_unit(x0, y0, width, height, 'PRED_No_Constraint', 'COMPONENT_Chroma');
Component = 0;
}
}
// BT_HOR划分模式
else if (BlockSplitMode == 'SPLIT_BT_HOR')
{
y1 = y0 + height / 2;
coding_unit_tree(x0, y0, split + 1, width, height / 2, 0, modeChild);
if (y1 < PicHeightInLuma)
coding_unit_tree(x0, y1, split + 1, width, height / 2, 0, modeChild);
if ((LumaWidth == width) && (LumaHeight = height) && ChildSizeOccur4)
{
coding_unit(x0, y0, width, height, 'PRED_No_Constraint', 'COMPONENT_Chroma');
Component = 0;
}
}
// EQT_VER划分模式
else if (BlockSplitMode == 'SPLIT_EQT_VER')
{
x1 = x0 + width / 4;
x2 = x0 + (3 * width / 4);
y1 = y0 + height / 2;
coding_unit_tree(x0, y0, split + 1, width / 4, height, 0, modeChild);
coding_unit_tree(x1, y0, split + 1, width / 2, height / 2, 0, modeChild);
coding_unit_tree(x1, y1, split + 1, width / 2, height / 2, 0, modeChild);
coding_unit_tree(x2, y0, split + 1, width / 4, height, 0, modeChild);
if ((LumaWidth == width) && (LumaHeight = height) && ChildSizeOccur4)
{
coding_unit(x0, y0, width, height, 'PRED_No_Constraint', 'COMPONENT_Chroma');
Component = 0;
}
}
// EQT_HOR划分模式
else if (BlockSplitMode == 'SPLIT_EQT_HOR')
{
x1 = x0 + width / 2;
y1 = y0 + height / 4;
y2 = y0 + (3 * height / 4);
coding_unit_tree(x0, y0, split + 1, width, height / 4, 0, modeChild);
coding_unit_tree(x0, y1, split + 1, width / 2, height / 2, 0, modeChild);
coding_unit_tree(x1, y1, split + 1, width / 2, height / 2, 0, modeChild);
coding_unit_tree(x0, y2, split + 1, width, height / 4, 0, modeChild);
if ((LumaWidth == width) && (LumaHeight = height) && ChildSizeOccur4)
{
coding_unit(x0, y0, width, height, 'PRED_No_Constraint', 'COMPONENT_Chroma');
Component = 0;
}
}
// NO_SPLIT划分模式
else
{
// 可包含亮度分量和色度分量
if (Component == 0)
{
coding_unit(x0, y0, width, height, mode, 'COMPONENT_LUMACHROMA');
}
// 仅有亮度分量
else if (Component == 1)
{
coding_unit(x0, y0, width, height, mode, 'COMPONENT_LUMA');
}
}
}
编码单元:coding_unit
/* CU的像素坐标,CU大小,预测模式,分量 */
coding_unit(x0, y0, width, height, mode, component)
{
// 色度分量
if (component == 'COMPONENT_Chroma')
{
// priorCuMode:当前色度块对应的亮度块右下角4x4的子块为帧内模式
if ((priorCuMode == 1) && (chroma_format != '00'))
intra_chroma_pred_mode; // 帧内色度预测模式
NumOfTransBlocks = 3;
ctp_y[0] = 0;
CuCtp += ctp_y[0];
// 若色度预测模式不是PCM
if (IntraChromaPredMode != 'Intra_Chroma_PCM')
{
ctp_u;
CuCtp += (ctp_u << 1);
ctp_v;
CuCtp += (ctp_v << 2);
}
// 编码U、V变换块
for (i = NumOfTransBlocks - 2; i < NumOfTransBlocks; i++)
{
IsPcmMode[i] = (IntraChromaPredMode == 'Intra_Chroma_PCM');
IsChroma = 0;
if (i == NumOfTransBlocks - 1 || i == NumOfTransBlocks - 2)
{
IsChroma = 1;
}
// 变换块
block(i, width, height, CuCtp, IsChroma, IsPcmMode[i], component);
}
}
// LUMA或LUMACHROMA
else
{
// 若不是I帧
if (PictureType != 0)
{
if (mode != 'PRED_Intra_Only')
{
skip_flag; // Skip模式标志
}
// Skip模式下:编码umve和affine模式
if (SkipFlag)
{
if (UmveEnableFlag)
umve_flag;
// affine与umve不能共存,且需要宽高都大于16
if (AffineEnableFlag && !UmveFlag && (width >= 16) && (height >= 16))
affine_flag;
}
// 非Skip模式下
if (!SkipFlag)
{
if (mode != 'PRED_Intra_Only')
{
direct_flag; // direct模式标志
}
// Direct模式下:编码umve和affine模式
if (DirectFlag)
{
if (UmveEnableFlag)
umve_flag;
if (AffineEnableFlag && !UmveFlag && (width >= 16) && (height >= 16))
affine_flag;
}
// 非Direct模式下:
if (!DirectFlag && (mode == 'PRED_No_Constraint'))
intra_cu_flag; // 0:帧间模式 1:帧内模式
}
}
PartSize = 'SIZE_2Mx2N';
// 若衍生模式和帧内模式
if (DtEnableFlag && IntraCuFlag)
{
// CU符合DT划分的要求( 其中DtMinSize的值等于16 )
allowDtHorSplit = (height >= DtMinSize) && (height <= DtMaxSize) && (width / height < 4) && (width <= DtMaxSize);
allowDtVerSplit = (width >= DtMinSize) && (width <= DtMaxSize) && (height / width < 4) && (height <= DtMaxSize);
if (allowDtHorSplit || allowDtVerSplit)
{
dt_split_flag; // 是否进行衍生划分
if (DtSplitFlag)
{
if (allowDtHorSplit && allowDtVerSplit)
{
dt_split_dir; // 0:垂直划分 1:水平划分
}
else if (allowDtHorSplit)
{
DtSplitDir = 1;
}
else
{
DtSplitDir = 0;
}
if (DtSplitDir)
{
dt_split_hqt_flag; // 水平四叉划分:0表示不进行,1表示进行
if (!DtSplitHqtFlag)
{
dt_split_hadt_flag; // 水平非对称划分:0表示up,1表示down
}
}
else
{
dt_split_vqt_flag;
if (!DtSplitVqtFlag)
{
dt_split_vadt_flag;
}
}
}
}
}
// umve标识
if (UmveFlag)
{
umve_mv_idx;
umve_step_idx;
umve_dir_idx;
}
// skip/direct前提下的affine
else if ((SkipFlag || DirectFlag) && AffineFlag)
{
cu_affine_cand_idx;
}
// skip/direct
else if (SkipFlag || DirectFlag)
{
cu_subtype_index; // CU子类型索引
}
// 非Skip,非Direct
if (!SkipFlag && !DirectFlag)
{
// 普通inter模式
if (!IntraCuFlag)
{
// affine
if (AffineEnableFlag && (width >= 16) && (height >= 16))
affine_flag;
// amvr
if (AmvrEnableFlag)
{
if (EmvrEnableFlag && !AffineFlag)
{
extend_mvr_flag; // emvr
}
if (AffineFlag)
affine_amvr_index;
else
amvr_index;
}
// B帧预测参考模式:list 0/1/01
if (PictureType == 2)
{
inter_pred_ref_mode;
}
// smvd
if (SmvdEnableFlag && SmvdApplyFlag && !AffineFlag && (InterPredRefMode == 2) && !ExtendMvrFlag)
{
smvd_flag;
}
// MvExistL0:这部分暂时不懂
if (MvExistL0)
{
if (!SmvdFlag && NumRefActive[0] > 1)
pu_reference_index_l0;
mv_diff_x_abs_l0;
if (MvDiffXAbsL0)
mv_diff_x_sign_l0;
mv_diff_y_abs_l0;
if (MvDiffYAbsL0)
mv_diff_y_sign_l0;
if (AffineFlag)
{
mv_diff_x_abs_l0_affine;
if (MvDiffXAbsL0Affine)
mv_diff_x_sign_l0_affine;
mv_diff_y_abs_l0_affine;
if (MvDiffYAbsL0Affine)
mv_diff_y_sign_l0_affine;
}
}
if (MvExistL1 && !SmvdFlag)
{
if (NumRefActive[1] > 1)
pu_reference_index_l1;
mv_diff_x_abs_l1;
if (MvDiffXAbsL1)
mv_diff_x_sign_l1;
mv_diff_y_abs_l1;
if (MvDiffYAbsL1)
mv_diff_y_sign_l1;
if (AffineFlag)
{
mv_diff_x_abs_l1_affine;
if (MvDiffXAbsL1Affine)
mv_diff_x_sign_l1_affine;
mv_diff_y_abs_l1_affine;
if (MvDiffYAbsL1Affine)
mv_diff_y_sign_l1_affine;
}
}
}
// 帧内模式
else
{
TuOrder = 0;
// NumOfIntraPredBlock由衍生模式确定
for (i = 0; i < NumOfIntraPredBlock; i++)
{
intra_luma_pred_mode; // 每个亮度PU的预测模式
}
if (PartSize == 'SIZE_2Mx2N')
{
IsPcmMode[TuOrder] = (IntraLumaPredMode == 'Intra_Luma_PCM');
TuOrder++;
}
else
{
IsPcmMode[0] = 0;
IsPcmMode[1] = 0;
IsPcmMode[2] = 0;
IsPcmMode[3] = 0;
TuOrder = 3;
}
// 若为COMPONENT_LUMACHROMA
if (IntraCuFlag && (chroma_format != '00') && (component == 'COMPONENT_LUMACHROMA'))
{
intra_chroma_pred_mode; // 色度PU的预测模式
IsPcmMode[TuOrder + 1] = (IntraChromaPredMode == 'Intra_Chroma_PCM');
IsPcmMode[TuOrder + 2] = (IntraChromaPredMode == 'Intra_Chroma_PCM');
}
if (IpfEnableFlag && (PartSize == 'SIZE_2Mx2N') && (!IsPcmMode[0]))
{
ipf_flag; // IPF滤波标志
}
}
}
// 非帧内,非Skip
if (!IntraCuFlag && !SkipFlag)
{
if (!DirectFlag && component == 'COMPONENT_LUMACHROMA')
ctp_zero_flag; // 1:变换块系数全为0
CuCtp = 0;
if (!CtpZeroFlag)
{
// 宽高在8~32,宽高比小于4
if (PbtEnableFlag && (width / height < 4) && (height / width < 4) && (width >= 8) && (width <= 32) && (height >= 8) && (height <= 32))
{
pbt_cu_flag; // 基于位置的变换标志
}
// 不使用pbt变换,NumOfTransBlocks = 3
if (!PbtCuFlag)
{
if (component == 'COMPONENT_LUMACHROMA')
{
ctp_u;
ctp_v;
}
CuCtp = ctp_u << (NumOfTransBlocks - 2);
CuCtp += (ctp_v << (NumOfTransBlocks - 1));
if (((ctp_u != 0) || (ctp_v != 0)) || (component != 'COMPONENT_LUMACHROMA'))
{
ctp_y[0];
CuCtp += ctp_y[0];
}
else
{
CuCtp += ctp_y[0];
}
}
// 使用pbt变换,NumOfTransBlocks = 6
else
{
if (component == 'COMPONENT_LUMACHROMA')
{
ctp_u;
ctp_v;
}
CuCtp = ctp_u << (NumOfTransBlocks - 2);
CuCtp += (ctp_v << (NumOfTransBlocks - 1));
for (i = 0; i < NumOfTransBlocks - 2; i++)
{
ctp_y[i];
CuCtp += (ctp_y[i] << i);
}
// 此时CuCtp为 YYYYUV
}
}
}
// 帧内模式
else if (!SkipFlag)
{
CuCtp = 0;
if (!IsPcmMode[0])
{
for (i = 0; i < NumOfTransBlocks - 2; i++)
{
ctp_y[i];
CuCtp += (ctp_y[i] << i);
}
}
if ((component == 'COMPONENT_LUMACHROMA') && (IntraChromaPredMode != 'Intra_Chroma_PCM'))
{
ctp_u;
ctp_v;
}
CuCtp += (ctp_u << (NumOfTransBlocks - 2));
CuCtp += (ctp_v << (NumOfTransBlocks - 1));
}
// 变换块
for (i = 0; i < NumOfTransBlocks; i++)
{
if (i < NumOfTransBlocks)
{
// TransformSplitDirection:0不划分,1pbt,2水平,3垂直
blockWidth = ((TransformSplitDirection == 0) || (TransformSplitDirection == 2)) ? width : (TransformSplitDirection == 1 ? width >> 1 : width >> 2);
blockHeight = ((TransformSplitDirection == 0) || (TransformSplitDirection == 3)) ? height : (TransformSplitDirection == 1 ? height >> 1 : height >> 2);
blockX = x0 + (((TransformSplitDirection == 0) || (TransformSplitDirection == 2)) ? 0 : (TransformSplitDirection == 1 ? ((blockWidth >> 1) * (i % 2)) : ((blockWidth >> 2) * i)));
blockY = y0 + (((TransformSplitDirection == 0) || (TransformSplitDirection == 3)) ? 0 : (TransformSplitDirection == 1 ? ((blockHeight >> 1) * (i / 2)) : ((blockHeight >> 2) * i)))
}
IsChroma = 0;
if (i == NumOfTransBlocks - 1 || i == NumOfTransBlocks - 2)
{
IsChroma = 1;
}
block(i, blockWidth, blockHeight, CuCtp, IsChroma, IsPcmMode[i], component);
}
}
}
变换单元:block
/* 块编号,块大小,该块是否含有编码数据,是否为色度分量,是否使用PCM,分量信息 */
block(i, blockWidth, blockHeight, CuCtp, isChroma, isPcm, component)
{
M1 = blockWidth;
M2 = blockHeight;
// 初始化量化系数矩阵为0
for (x = 0; x < M1; x++)
{
for (y = 0; y < M2; y++)
QuantCoeffMatrix[x][y] = 0;
}
// 非PCM模式
if (!isPcm)
{
// i号块有编码数据
if (CuCtp & (1 << i))
{
blockWidth = isChroma ? blockWidth / 2 : blockWidth;
blockHeight = isChroma ? blockHeight / 2 : blockHeight;
idxW = Log(blockWidth) – 1;
idxH = Log(blockHeight) – 1;
NumOfCoeff = blockWidth * blockHeight;
ScanPosOffset = 0;
do
{
coeff_run; // run
coeff_level_minus1; // level
coeff_sign; // level_sign
AbsLevel = coeff_level_minus1 + 1;
ScanPosOffset = ScanPosOffset + coeff_run;
PosxInBlk = InvScanCoeffInBlk[idxW][idxH][ScanPosOffset][0];
PosyInBlk = InvScanCoeffInBlk[idxW][idxH][ScanPosOffset][1];
QuantCoeffMatrix[PosxInBlk][PosyInBlk] = coeff_sign ? –AbsLevel : AbsLevel;
if (ScanPosOffset >= NumOf Coeff – 1)
{
break;
}
coeff_last; // coeff_last
ScanPosOffset = ScanPosOffset + 1;
} while (!coeff_last)
}
}
// PCM模式
else
{
// 填充位
if ((component != 'COMPONENT_CHROMA' && i == 0) || (component == 'COMPONENT_CHROMA' && i == 1))
{
aec_ipcm_stuffing_bit;
while (!byte_aligned())
{
aec_byte_alignment_bit0;
}
}
// 色度TU大小为一半
M1 = isChroma ? blockWidth / 2 : blockWidth;
M2 = isChroma ? blockHeight / 2 : blockHeight;
xMin = Min(32, M1);
yMin = Min(32, M2);
// 分为32x32的块依次编码
for (yStep = 0; yStep < M2 / yMin; yStep++)
{
for (xStep = 0; xStep < M1 / xMin; xStep++)
{
for (y = 0; y < yMin; y++)
{
for (x = 0; x < xMin; x++)
{
pcm_coeff;
QuantCoeffMatrix[x + xStep * xMin][y + yStep * yMin] = pcm_coeff;
}
}
}
}
}
}
如果文章对您有帮助,记得点个赞哦 o(* ̄▽ ̄*)ブ