帧内预测过程会以相邻块的像素值做参考,来预测当前块的像素值。以Intra_4x4为例,如下图所示,需要用到的13个相邻像素值,那么如何获取这13个像素值?
本文要主要说明如何获取帧内预测所用到的相邻像素。
获取相邻像素的流程如下:
- 找到当前块(可以为4x4、8x8、16x16大小)的左、上、右上、左上相邻块
- 找到左、上、右上、左上相邻块所在宏块
- 根据当前宏块以及相邻块所在宏块确定相邻像素
在此之前需要先知道宏块地址是否可用,如果宏块地址不可用,则在该宏块的相邻像素也都不可用。
1.宏块地址可用性推导
宏块不可用主要有以下三种情况:
- mbAddr<0,此时该宏块不存在
- mbAddr>CurrMbAddr,也就是在当前解码宏块之后的宏块,显然后面的宏块还为解码,不可用做预测
- mbAddr和CurrMbAddr属于不同slice
2.相邻宏块地址及其可用性的推导
分为两种情况:
- MbaffFlag=0
- MBaffFlag=1
2.1 非MBAFF宏块(帧宏块或场宏块)
mbAddrA:表示当前宏块左侧宏块的地址和可用性状态。
mbAddrB:表示当前宏块上侧宏块的地址和可用性状态。
mbAddrC:表示当前宏块右上侧宏块的地址和可用性状态。
mbAddrD:表示当前宏块左上侧宏块的地址和可用性状态。
下图表示当前宏块和四个相邻宏块的空间位置
2.2 MBAFF宏块
对于MBAFF格式,是以宏块对方式成对出现,一个宏块对包含顶宏块和底宏块。
帧宏块对和场宏块对数据存放方式也有差异。
一个宏块对亮度分量有32行数据,如果当前宏块对为帧宏块,则顶帧宏块由1-16行数据组成,底帧宏块由17-32行数据组成;
如果当前宏块对为场宏块,则顶场宏块为奇数行数据组成,底场宏块为偶数行数据组成。
mbAddrA:表示当前宏块左侧宏块对中顶宏块的地址和可用性状态。
mbAddrB:表示当前宏块上侧宏块对中顶宏块的地址和可用性状态。
mbAddrC:表示当前宏块右上侧宏块对中顶宏块的地址和可用性状态。
mbAddrD:表示当前宏块左上侧宏块对中顶宏块的地址和可用性状态。
下图表示当前宏块和四个相邻宏块的空间位置,不管当前宏块是顶宏块还是底宏块,四个相邻宏块都是相同的。
3.相邻宏块、块的推导过程
帧内预测所用的块大小有三种情况(16x16、8x8、4x4)。
以8x8块为例,如下图所示,当前宏块分为4个8x8块。
idx=0的8x8块,左相邻块为mbAddrA中idx为1的8x8块,如果mbAddrA不可用,则左相邻块也不可用,
上相邻块为mbAddrB中idx为2的8x8块,
左上相邻块为mbAddrD中idx为3的8x8块。
idx=3的8x8块,左相邻块为当前宏块中idx为2的8x8块,
上相邻块为当前宏块中idx为1的8x8块,
左上相邻块为当前宏块中idx为0的8x8块。
因此,相邻块的推导过程,需要先找到相邻块所在宏块,确定宏块是否可用。
4.相邻像素推导过程
本过程的输入为相对于当前宏块左上角样点位置的亮度或色度位置(xN,yN)。
本过程的输出为:
mbAddrN:等于CurrMbAddr或等于包含(xN,yN)的相邻宏块的地址,及其可用性,
( xW, yW ):表示与宏块mbAddrN左上角的相对(不是相对于当前宏块左上角)位置(xN,yN)。
比如xN=-1,yN=-1,表示获取当前宏块左上角相邻像素,显然(xN,yN)像素所在宏块为左上角宏块mbAddrD,( xW, yW )=(15, 15).
相邻像素推导根据当前宏块是否为MBAFF分为两种情况。
4.1场和非MBAFF帧中相邻像素
MbaffFlag=0时,相对简单相邻像素的推导如下表所示。
4.2 MBAFF帧中相邻像素
MbaffFlag=1时,要根据当前宏块帧/场属性、顶/底场属性以及相邻块帧/场属性、顶/底场属性做不同的处理,相对复杂。
以xN=-1,yN=-1为例,也就是得到左上相邻像素。
其相邻像素可以由下表获得:
currMbFrameFlag,表示当前宏块是否为帧宏块
mbIsTopMbFlag,表示当前宏块为顶宏块还是底宏块
mbAddrX,表示相邻宏块对,还不能确定最终相邻宏块是使用顶宏块还是底宏块
mbAddrXFrameFlag,表示相邻宏块是否为帧宏块
mbAddrN,表示最终的相邻宏块
相邻像素推导可分为四个步骤:
- 根据currMbFrameFlag和mbIsTopMbFlag确定当前宏块左上角像素在帧图像中对应的像素点;
- 根据当前宏块的属性来确定相邻像素点;
- 确定相邻像素点所属宏块对mbAddrX;
- 根据相邻宏块对的属性mbAddrXFrameFlag来确定相邻像素点所属宏块mbAddrN;
根据当前宏块帧、场格式以及顶、底属性分四种情况分析
1.当 currMbFrameFlag = 1,mbIsTopMbFlag = 1,也就是当前宏块为帧宏块,并且为顶宏块
- 确定当前宏块左上角像素在帧图像中对应的像素点:
currMbFrameFlag = 1,mbIsTopMbFlag = 1:当前宏块为顶帧宏块,其左上角像素的对应像素点为 c - 根据当前宏块的属性来确定相邻像素点:
因为当前宏块为顶帧宏块,所以 c 的左上角相邻像素点为 a - 确定相邻像素点所属宏块对:
因为宏块对是用顶宏块的地址表示,所以像素点 a 所属宏块对为 mbAddrD,因此 mbAddrX = mbAddrD - 根据相邻宏块对的属性来确定相邻像素点所属宏块:
(1)、如果 mbAddrX 是帧宏块对(即mbAddrXFrameFlag = 1),像素点 a 属于宏块 mbAddrD+1,所以mbAddrN = mbAddrD+1
(2)、如果 mbAddrX 是场宏块对(即mbAddrXFrameFlag = 0),像素点 a 在场图像时(即进行隔行抽取后)属于宏块mbAddrD+1
,因此mbAddrN = mbAddrD+1
2. 当 currMbFrameFlag = 1,mbIsTopMbFlag = 0,也就是当前宏块为帧宏块,并且为底宏块
- 确定当前宏块左上角像素在帧图像中对应的像素点:
currMbFrameFlag = 1,mbIsTopMbFlag = 0:当前宏块为低帧宏块,其左上角像素的对应像素点为 f - 根据当前宏块的属性来确定相邻像素点:
因为当前宏块为底帧宏块,所以 f 的左上角相邻像素点为 e - 确定相邻像素点所属宏块对:
因为宏块对是用顶宏块的地址表示,所以像素点 e 所属宏块对为 mbAddrA,因此表 6-4 中 mbAddrX = mbAddrA - 根据相邻宏块对的属性来确定相邻像素点所属宏块:
(1)、如果 mbAddrX 是帧宏块对(即mbAddrXFrameFlag = 1),像素点 e 属于宏块 mbAddrA,因此mbAddrN = mbAddrA
(2)、如果 mbAddrX 是场宏块对(即mbAddrXFrameFlag = 0),像素点 e 在图像的偶数行,属于底场宏块 mbAddrA+1,因此mbAddrN = mbAddrA+1
3.当 currMbFrameFlag = 0,mbIsTopMbFlag = 1,当前宏块为顶场宏块
1、确定当前宏块左上角像素在帧图像中对应的像素点:
currMbFrameFlag = 0,mbIsTopMbFlag = 1:当前宏块为顶场宏块,其左上角像素的对应像素点为 c
2、根据当前宏块对的属性来确定相邻像素点:
因为当前宏块为顶场宏块,所以 c 的左上角相邻像素点为 b
3、确定相邻像素点所属宏块对:
因为宏块对是用顶宏块的地址表示,所以像素点 b 所属宏块对为 mbAddrD,因此 mbAddrX = mbAddrD
4、根据相邻宏块对的属性来确定相邻像素点所属宏块:
(1)、如果 mbAddrX 是帧宏块对(即mbAddrXFrameFlag = 1),像素点 b 属于宏块 mbAddrD+1,因此mbAddrN = mbAddrD+1
(2)、如果 mbAddrX 是场宏块对(即mbAddrXFrameFlag = 0),像素点 b 在场图像奇数行,属于顶场宏块 mbAddrD,因此mbAddrN = mbAddrD
4.当 currMbFrameFlag = 0,mbIsTopMbFlag = 0,当前宏块为底场宏块
1、确定当前宏块左上角像素在帧图像中对应的像素点:
currMbFrameFlag = 0,mbIsTopMbFlag = 0:当前宏块为低场宏块,其左上角像素的对应像素点为 d
2、根据当前宏块对的属性来确定相邻像素点:
因为当前宏块为低场宏块,所以 d 的左上角相邻像素点为 a
3、确定相邻像素点所属宏块对:
因为宏块对是用顶宏块的地址表示,所以像素点 a 所属宏块对为 mbAddrD,因此表 6-4 中 mbAddrX = mbAddrD
4、根据相邻宏块对的属性来确定相邻像素点所属宏块:
无论 mbAddrX 是帧宏块对还是场宏块对(即无论mbAddrXFrameFlag 值为多少),像素点 a 都属于宏块 mbAddrD+1
(1)、如果 mbAddrX 是帧宏块对(即mbAddrXFrameFlag = 1),像素点 a 属于宏块 mbAddrD+1,因此mbAddrN = mbAddrD+1
(2)、如果 mbAddrX 是场宏块对(即mbAddrXFrameFlag = 0),像素点 a 在场图像偶数行,属于底场宏块 mbAddrD+1,因此mbAddrN = mbAddrD+1