Transform Block
在AV1中,变换编码(Transform Coding)是以块为单位进行的,这个块就称为 Transform Block,我们就姑且叫它“变换块”吧。与前面我提到的Block的概念相比,Transform Block一共包括19种尺寸,与Block的尺寸比起来,可以相同或更小,最大可以达到64x64,最小可以是4x4,源码中对于Transform Block大小的定义是一个名为 TX_SIZE 的枚举变量。
TxSize | Name of TxSize | 含义 |
---|---|---|
0 | TX_4X4 | 4x4 transform |
1 | TX_8X8 | 8x8 transform |
2 | TX_16X16 | 16x16 transform |
3 | TX_32X32 | 32x32 transform |
4 | TX_64X64 | 64x64 transform |
5 | TX_4X8 | 4x8 transform |
6 | TX_8X4 | 8x4 transform |
7 | TX_8X16 | 8x16 transform |
8 | TX_16X8 | 16x8 transform |
9 | TX_16X32 | 16x32 transform |
10 | TX_32X16 | 32x16 transform |
11 | TX_32X64 | 32x64 transform |
12 | TX_64X32 | 64x32 transform |
13 | TX_4X16 | 4x16 transform |
14 | TX_16X4 | 16x4 transform |
15 | TX_8X32 | 8x32 transform |
16 | TX_32X8 | 32x8 transform |
17 | TX_16X64 | 16x64 transform |
18 | TX_64X16 | 64x16 transform |
既然最大的尺寸是64x64,那对于大小超过64的块,例如BLOCK_128x128,BLOCK_128x64,BLOCK_64x128,则需要在内部进行chunk,形成64x64的块后,再进行变换编码运算。
帧内编码的Transform Block划分
Block可以被划分为Transform Block,不同于H.26x系列编码标准,预测编码块与变换编码块,即PU和TU是分开进行划分的,在AV1中,预测编码是以Tranform block为单位进行的,所以做过H.264,HEVC的朋友们,在AV1的源码中,找不到熟悉的PU了 :)
在Intra Prediction的时候,会把块进行划分,最终选择最佳的分块大小,此时的分块大小使用 tx_depth来表示,并且传给解码器,tx_depth的取值范围为[0, 2],其中0为不划分,2为向下划分两级。
可以参考Spec中的 MAX_TX_DEPTH 参数,其值为2
Spec 5.11.15. TX size syntax
read_tx_size( allowSelect ) {
if ( Lossless ) {
TxSize = TX_4X4
return
}
maxRectTxSize = Max_Tx_Size_Rect[ MiSize ]
maxTxDepth = Max_Tx_Depth[ MiSize ]
TxSize = maxRectTxSize
if ( MiSize > BLOCK_4X4 && allowSelect && TxMode == TX_MODE_SELECT ) {
tx_depth // 此处parse出tx_depth
for ( i = 0; i < tx_depth; i++ )
TxSize = Split_Tx_Size[ TxSize ]
}
}
}
tx_depth | 以Block的大小等于64x64为例子,Transform Block大小 |
---|---|
0 | 64x64 |
1 | 32x32 |
2 | 16x16 |
具体的划分情况如下图所示
从上面的图可以看出,随着tx_depth的增大,transform block是逐渐以1/4的变化率在变小。上面的例子只讲了当block为正方形的时候的划分方法,那下面来说说当block的size不是正方形的情况该怎么划分。对于一个32x64的块,下面是一个例子,可以先上下均分为两个32x32的块,然后每个32x32的话可以依据上面例子的方式再次划分为16x16大小的块。
在帧内编码的情况下,变换编码的执行顺序是光栅扫描顺序(Raster scan),所以在编码时,依据从上到下,从左到右的顺序进行。
帧间编码的Transform Block划分
对于帧间编码的情况,其划分情况与帧内编码的相似,也是向下划分最多为两级,同样,也要将划分的级数传递给decoder,只不过syntax的名字不叫tx_depth了,而是txfm_split
在Spec中,函数read_var_tx_size是用来阅读流中的txfm_split的函数(实际代码中,函数调用名和变量名会有所不同)
read_var_tx_size( row, col, txSz, depth) {
if ( row >= MiRows || col >= MiCols )
return
if ( txSz == TX_4X4 || depth == MAX_VARTX_DEPTH ) {
txfm_split = 0
} else {
txfm_split // parsing
}
}
具体的划分图如下
画成树状图更容易理解些。