在上一篇文章中介绍了AV1帧内预测的各个工具,本文进一步介绍其中的相关细节。
参考像素准备
帧内预测是利用当前帧已重建的像素预测当前块,和HEVC一样,AV1的帧内预测参考像素来自当前块上方和左侧的重建像素。
对于尺寸为wxh的块,其参考像素获取过程如下:
上方参考像素AboveRow[ i ] ,i=0,1...w+h-1获取过程:
-
如果上方相邻像素无效但是左侧相邻像素有效,AboveRow[ i ]=CurrFrame[ plane ][ y ][ x - 1]。
-
如果上方和左侧相邻像素都无效,AboveRow[ i ]=( 1 << ( BitDepth -1 ) ) - 1。
-
否则:AboveRow[ i ]=CurrFrame[ plane ][ y-1 ][ Min(aboveLimit, x+i) ]。
其中aboveLimit=Min( maxX, x + ( haveAboveRight ? 2 * w : w ) - 1 )防止超出图像右边界。
左侧参考像素LeftCol[ i ] ,i=0,1...w+h-1获取过程:
-
如果上方相邻像素有效但是左侧相邻像素无效,LeftCol[ i ]=CurrFrame[ plane ][ y - 1 ][ x ]。
-
如果上方和左侧相邻像素都无效,LeftCol[ i ]=( 1 << ( BitDepth -1 ) ) - 1。
-
否则:LeftCol[ i ]=CurrFrame[ plane ][ Min(leftLimit, y+i) ][ x-1 ]。
其中leftLimit=Min( maxY, y + ( haveBelowLeft ? 2 * h : h ) - 1 )防止超出图像下边界。
左上角像素AboveRow[ -1 ]获取过程:
-
如果上方和左侧相邻像素都有效,AboveRow[ -1 ]=CurrFrame[ plane ][ y-1 ][ x-1 ]。
-
否则,如果上方相邻像素有效AboveRow[ -1 ]=CurrFrame[ plane ][ y-1 ][ x ]。
-
否则,如果左侧相邻像素有效AboveRow[ -1 ]=CurrFrame[ plane ][ y ][ x-1 ]。
-
否则,AboveRow[ -1 ]=( 1 << ( BitDepth -1 ) ) - 1。
DC预测模式
DC模式是常用的一种帧内预测模式,主要用于内容平坦的块,它利用参考像素的均值作为当前块的预测值,具体预测像素计算方法如下:
-
如果上方和左侧参考像素都有效,则计算所有参考像素的均值作为当前块所有像素的预测值:
-
如果仅左侧参考像素有效:
-
如果仅上方参考像素有效:
-
如果左侧和上方参考像素都无效:预测值为1 << ( BitDepth - 1 )
PAETH_PRED模式
PAETH_PRED模式类似于HEVC中的Planar模式,
每个位置的预测值就是使上面式子最小的值。
参考像素滤波
语法元素enable_intra_edge_filter表示是否开启对参考像素滤波和上采样过程,
参考像素滤波
对于非90度和180度的角度模式需要对参考像素滤波,过程如下:
1、左上角参考像素滤波,如果pAngle>90且pAngle<180且(w+h)>=24对左上角参考像素用一个3抽头滤波器滤波:
LeftCol[-1]=AboveRow[-1]=LeftCol[ 0 ] * 5 + AboveRow[ -1 ] * 6 + AboveRow[ 0 ] * 5
2、滤波类型计算,这个过程得到filterType ,当上方或左侧使用smooth模式则filterType =1,
3、滤波强度srength计算,它的范围是0到3,由块尺寸、filterType、角度等决定:
strength = 0
if ( filterType == 0 ) {
if ( blkWh <= 8 ) {
if ( d >= 56 ) strength = 1
} else if ( blkWh <= 12 ) {
if ( d >= 40 ) strength = 1
} else if ( blkWh <= 16 ) {
if ( d >= 40 ) strength = 1
} else if ( blkWh <= 24 ) {
if ( d >= 8 ) strength = 1
if ( d >= 16 ) strength = 2
if ( d >= 32 ) strength = 3
} else if ( blkWh <= 32 ) {
strength = 1
if ( d >= 4 ) strength = 2
if ( d >= 32 ) strength = 3
} else {
strength = 3
}
} else {
if ( blkWh <= 8 ) {
if ( d >= 40 ) strength = 1
if ( d >= 64 ) strength = 2
} else if ( blkWh <= 16 ) {
if ( d >= 20 ) strength = 1
if ( d >= 48 ) strength = 2
} else if ( blkWh <= 24 ) {
if ( d >= 4 ) strength = 3
} else {
strength = 3
}
}
其中blkWh =w+h,d是角度差值,如果pAngle<180且haveAbove =1,d=abs(pAngle-90),如果pAngle>90且haveLeft=1,d=abs(pAngle-180)。
4、滤波操作,若srength=0则无需滤波否则需要进行滤波,标准定义了3个5抽头滤波器分别对应3个强度。
Intra_Edge_Kernel[INTRA_EDGE_KERNELS][INTRA_EDGE_TAPS] = {
{ 0, 4, 8, 4, 0 }, //strength=1
{ 0, 5, 6, 5, 0 }, //strength=2
{ 2, 4, 4, 4, 2 } //strength=3
}
5、上采样,对于有的模式还需要对参考像素进行上采样,首先根据角度和滤波类型判断是否需要上采样
if ( d <= 0 || d >= 40 ) {
useUpsample = 0
} else if ( filterType == 0 ) {
useUpsample = (blkWh <= 16)
} else {
useUpsample = (blkWh <= 8)
}
d和blkWh跟滤波强度计算中的定义一样
如果useUpsample=1则需要进行上采样,上采样过程是2倍上采样,首先需要对参考像素长度加倍
dup[ 0 ] = buf[ -1 ]
for ( i = -1; i < numPx; i++ ) {
dup[ i + 2 ] = buf[ i ]
}
dup[ numPx + 2 ] = buf[ numPx - 1 ]
然后对半像素位置插值
buf[-2] = dup[0]
for ( i = 0; i < numPx; i++ ) {
s = -dup[i] + (9 * dup[i + 1]) + (9 * dup[i + 2]) - dup[i + 3]
s = Clip1( Round2(s, 4) )
buf[ 2 * i - 1 ] = s
buf[ 2 * i ] = dup[i + 2]
}
预测值计算
前面得到参考像素并完成滤波后就可以利用对各种角度模式计算预测值,预测块尺寸wxh,对于i=0...h-1,j=0...w-1计算pred[i][j]。
Dr_Intra_Derivative[ 90 ] = {
0, 0, 0, 1023, 0, 0, 547, 0, 0, 372, 0, 0, 0, 0,
273, 0, 0, 215, 0, 0, 178, 0, 0, 151, 0, 0, 132, 0, 0,
116, 0, 0, 102, 0, 0, 0, 90, 0, 0, 80, 0, 0, 71, 0, 0,
64, 0, 0, 57, 0, 0, 51, 0, 0, 45, 0, 0, 0, 40, 0, 0,
35, 0, 0, 31, 0, 0, 27, 0, 0, 23, 0, 0, 19, 0, 0,
15, 0, 0, 0, 0, 11, 0, 0, 7, 0, 0, 3, 0, 0
}
如果pAngle<90,按以下方式生成pred[i][j]:
如果90<pAngle<180,按以下方式生成pred[i][j]:
如果pAngle>180,按以下方式生成pred[i][j]:
如果pAngle=90,则pred[i][j]=AboveRow[j],j=0..w-1,i=0..h-1。
如果pAngle=180,则pred[i][j]=Leftcol[i],j=0..w-1,i=0..h-1。