H264 Direct预测模式

时间:2022-03-28 02:59:37

h.264直接预测

直接预测是B帧上一种独有的预测方式,其中直接预测又分为两种模式: 时域直接模式(temporal direct)、空域直接模式(spatial direct)。

在分析这两种模式之前,有一个前提概念需要了解:共同位置4x4子宏块分割块(co-located 4x4 sub-macroblock partitions),下面简称为co-located。

共同位置4x4子宏块分割块,故名思义,该块大小为4x4。co-located的主要功能是得到出该4x4块的运动向量以及参考帧,以供后面的直接预测做后续处理,如果当前宏块进行的是直接预测,无论时域或空域,都会用到该co-located,因此需要先求出该4x4co-located的具体位置。

 

co-located的定位

1. 定位co-located所在图像

要求co-located的位置,首先需要知道co-located所在的图像colPic的位置,colPic可以确定在当前图像的第一个后向参考图像RefPicList1[ 0 ]内,但是colPic可以为帧或场,这取决于当期图像与参考图像,是以帧图像进行编码,还是以场图像进行编码,或者以互补场对(宏块级帧场自适应)方式进行编码。

H264 Direct预测模式

  • 第一项:field_pic_flag表示当前图像是以帧还是场方式进行编码
  • 第二项:代表RefPicList1[0]的编码方式是帧、场、互补场对(两个场)
  • 第三项:mb_field_decoding_flag代表当前宏块对是以帧、场方式进行编码(前提条件是当前图像是以帧方式进行编码,也只有当前图像选择了帧编码,才能选择宏块对(宏块帧场自适应)的编码方式)
  • 第四项:

    topAbsDiffPOCbottomAbsDiffPOC=|DiffPicOrderCnt(firstRefPicL1Top,CurrPic)|=|DiffPicOrderCnt(firstRefPicL1Bottom,CurrPic)|topAbsDiffPOC=|DiffPicOrderCnt(firstRefPicL1Top,CurrPic)|bottomAbsDiffPOC=|DiffPicOrderCnt(firstRefPicL1Bottom,CurrPic)|

    添加这些条件是为了在采用宏块级帧场自适编码方式时,应选择距离当前图像最近的顶场或底场作为col_Pic

  • 第五项:col_Pic的取值,firstRefPicL1Top 和firstRefPicL1Bottom 分别为RefPicList1[ 0 ]中的顶场和底场

注:其实第二项RefPicList1[ 0 ]是一个被动选项,因为它是根据当前图像的编码方式是帧、场或宏块帧场自适应决定的,如果当前图像是场,那么RefPicList1[ 0 ]就有可能是已解码的场或者以解码帧中的一场;如果当前图像是帧(非MBAFF),那么RefPicList1[ 0 ]就是帧;如果当前宏块是帧并且为MBAFF,那么RefPicList1[ 0 ]就是一个互补场对(两个场可以组成一个帧)

 

2. 得到co-located在colPic内的位置

实际上,如果得到了colPic,就可以通过当前宏块的16个4x4块的绝对位置(以4x4块为单位相对于图像左上角(0,0)的绝对位置( opic_block_x,opic_block_y)),得到co-located在colPic的位置。

  • 如果当前图像为帧,colPic为场,则co-located为(opic_block_x,opic_block_y>>1)
  • 如果当前图像为场,colPic为帧,则co-located为(opic_block_x,opic_block_y<<1)
  • 如果当前图像与colPic同为帧或场,则co-located为(opic_block_x,opic_block_y)

(注:像在jm18.6中,实际计算时,不会出现当前图像为场,colPic为帧的情况,因为场的参考图像都会被分为场后加入参考图像队列,所以最终计算时也会先根据当前场的是顶场或底场挑出参考帧中对应的场作为colPic )

 

在标准中,先定位co-located所在宏块mbAddrCol,然后再定位co-located在该宏块内的地址(xcol,yM)。由于采用了不同于上述的4x4块定位方法,所以计算方式略复杂,但是得到的结果是一样的,最终会定位到同一个co-located

H264 Direct预测模式mbAddrCol1mbAddrCol2mbAddrCol3mbAddrCol4mbAddrCol5mbAddrCol6mbAddrCol7=2×PicWidthInMbs×(CurrMbAddr/PicWidthInMbs)+(CurrMbAddr % PicWidthInMbs)+PicWidthInMbs×(yCol/8)=2×CurrMbAddr+(yCol/8)=2×CurrMbAddr+bottom_field_flag=PicWidthInMbs×(CurrMbAddr/(2×PicWidthInMbs))+(CurrMbAddr % PicWidthInMbs)=CurrMbAddr/2=2×(CurrMbAddr/2)+((topAbsDiffPOC<bottomAbsDiffPOC)?0:1)=2×(CurrMbAddr/2)+(yCol/8)mbAddrCol1=2×PicWidthInMbs×(CurrMbAddr/PicWidthInMbs)+(CurrMbAddr % PicWidthInMbs)+PicWidthInMbs×(yCol/8)mbAddrCol2=2×CurrMbAddr+(yCol/8)mbAddrCol3=2×CurrMbAddr+bottom_field_flagmbAddrCol4=PicWidthInMbs×(CurrMbAddr/(2×PicWidthInMbs))+(CurrMbAddr % PicWidthInMbs)mbAddrCol5=CurrMbAddr/2mbAddrCol6=2×(CurrMbAddr/2)+((topAbsDiffPOC<bottomAbsDiffPOC)?0:1)mbAddrCol7=2×(CurrMbAddr/2)+(yCol/8)

 

(FAQ:为何表中没有FRM与AFRM配对?因为一个sps内只能定义为FRM或者AFRM(MBAFF),在一个序列内两者是不可能共存的;为何表中可以有FRM与FLD共存?因为sps可以定义PAFF(图像帧场自适应))

 

  • 第一项:PicCodingStruct( CurrPic ),当前图像的编码方式
  • 第二项:PicCodingStruct( colPic ),colPic的编码方式
  • 第三项:mbAddrX,当colPic为AFRM(宏块帧场自适应时),该项是用于定位colPic内地址为mbAddrX的宏块对,并用该宏块判断第五项fieldDecodingFlagX,即该宏块对是用场编码还是帧编码方式
  • 第四项:mb_field_decoding_flag,如果当前图像的编码方式是AFRM,该项用于判断当前宏块对是帧编码还是场编码方式
  • 第五项:fieldDecodingFlagX,如果colPic的编码方式是AFRM,该项用于判断mbAddrX所在的宏块对是帧编码还是场编码方式
  • 第六项:mbAddrCol,co-located所在的宏块在colPic内的地址,(注:涉及到AFRM的图像都会被当做互补场对来处理,即AFRM帧,而不是colPic)
  • 第七项:yM,co-located相对于其所在宏块的地址(xCol, yM),单位为像素,即第一个4x4块为(0,0),最后一个为(12,12),(注:当前4x4块相对于其所在宏块的地址为(xCol,yCol))
  • 第八项:VertMvScale,表明CurrPic与colPic的帧场对应关系

 

另外,为了减少计算量,还可以设定direct_8x8_inference_flag等于1,这样会导致每个8x8块共用一个4x4的co-located,共用方式为一个宏块的4个8x8块分别只用该宏块4个角的4x4块作为co-located

H264 Direct预测模式

 

获得co-located的运动向量与参考帧

  • 如果co-located是帧内预测方式编码,那么将无法获得运动向量与参考帧,mvCol = 0,refIdxCol = -1
  • 如果co-located是帧间预测编码方式,并且存在前向参考帧,那么mvCol将是co-located的前向运动向量,refIdxCol是co-located所在的8x8块中的某一个4x4块的前向参考索引
  • 如果co-located是帧间预测编码方式,并且只存在后向参考帧,那么mvCol将是co-located的后向运动向量,refIdxCol是co-located所在的8x8块中的某一个4x4块的后向参考索引

(注:至于如何从8x8块中选取该4x4块并沿用其参考索引,标准中并没有规定,具体可以看本文最后的代码是如何做的)

 

 

时域直接模式(temporal direct)

该模式是基于下图求出当前4x4块的前后向mvL0与mvL1,以及前向参考帧List0 reference的索引

H264 Direct预测模式

已知的变量有:

  1. 后向参考图像List 1 reference (refPicList1[0])及其索引0
  2. 在计算co-located后得到的mvCol(mvCol需要根据VertMvScale进行调整,乘或除2),以及参考图像refColList0[refIdxCol](即List 0 reference)
  3. td与tb为图像之间的POC距离,既然List 0 reference、Current B、List 1 reference 已经知道,那么就容易得出td与tb的值

未知的变量有:

  1. List 0 reference的在当前参考图像列表中的索引
  2. 前后向运动向量mvL0与mvL1

求解方法:

  1. List 0 reference的索引,该索引是参考图像列表中图像List 0 reference所在的最小索引值(这部分由于jm18.6中对mbaff采用了独立互补场对参考列表,所以看起来更简单一点,而标准是从refPicList0参考列表开始,然后结合VertMvScale进行推导,看起来比较繁琐,但其实得到的结果是一样的)。
  2. mvL1 = mvCol/td*(td - tb)
  3. mvL0 = mvCol - mvL1    (忽略mv方向)

由于这些在标准(8.4.1.2.3)中讲的都非常细致,所以这里简要说明一下而已。

 

空域直接模式(spatial direct)

空域模式基于一种假设:当前编码宏块与其相邻宏块都向着同一个方向运动,大家有着类似的运动向量与参考帧(如下图)。在这种假设前提上,空域模式主要思想为采用相邻块来对当前宏块的参考索引以及运动向量进行预测。由于标准中8.4.1.3有非常详细的描述,所以在此略过。

H264 Direct预测模式

但是上述假设也很有可能不成立,有可能当前宏块的相邻块都是运动的,但当前宏块是静止的(如下图)。比如说当前宏块是背景的一部分,而相邻块则是移动着的前景。这时候就需要判断当前宏块是否是运动的,以得到更准确的空域预测,co-located在这里就是用来判断当前宏块是否是运动宏块的。如果co-located的mvCol[0]与mvCol[1]能保证在某个范围之内,则表明当前宏块为静止宏块,那么将把当前宏块的mvL0与mvL1赋值为0,具体在标准8.4.1.2.2中描述得相当详细,不作细述。

H264 Direct预测模式