h.264 Mode Decision

Mode Decision(模式选择)决定一个宏块以何种类型进行分割。宏块的分割类型有以下几种:

enum {
//P_Skip and B_Skip(B_Direct) means that nothing need to be encoded ,just use the mv predicted and the residue mb base on such mv
  PSKIP        =  0,       //just use residue of mb coeff but mvc
  BSKIP_DIRECT =  0,       //skip mode on b slice
  P16x16       =  1,       //16x16 on p or b slice
  P16x8        =  2,       //16x8 on p or b slice
  P8x16        =  3,       //8x16 on p or b slice
  SMB8x8       =  4,       //sub macroblock 8x8 on p or b slice
  SMB8x4       =  5,       //sub macroblock 8x4 on p or b slice
  SMB4x8       =  6,       //sub macroblock 4x8 on p or b slice
  SMB4x4       =  7,       //sub macroblock 4x4 on p or b slice
  P8x8         =  8,       //set of sub macroblock modes
  I4MB         =  9,       //4x4 on i slice
  I16MB        = 10,       //16x16 on i slice
  IBLOCK       = 11,       //the same with I4MB
  SI4MB        = 12,       //
  I8MB         = 13,       //8x8 on i slice
  IPCM         = 14,       //PCM mode
  MAXMODE      = 15
} MBModeTypes;

模式选择就是通过某种算法得到最优的宏块分割类型。不同算法在流程、最优分割方式选择上会有区别,但是都遵循h.264的标准。

宏块与子宏块

macroblock_layer( ) {
   mb_type
   if( mb_type  = =  I_PCM ) {
       while( !byte_aligned( ) )
            pcm_alignment_zero_bit
       for( i = 0; i < 256; i++ )
            pcm_sample_luma[ i ]
       for( i = 0; i < 2 * MbWidthC * MbHeightC; i++ )
            pcm_sample_chroma[ i ]
   } else {
       noSubMbPartSizeLessThan8x8Flag = 1
       if( mb_type  !=  I_NxN  &&
           MbPartPredMode( mb_type, 0 )  !=  Intra_16x16  &&
           NumMbPart( mb_type )  = =  4 ) { 

           sub_mb_pred( mb_type )       //子宏块预测
           for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
                if( sub_mb_type[ mbPartIdx ]  !=  B_Direct_8x8 ) {
                     if( NumSubMbPart( sub_mb_type[ mbPartIdx ] )  >  1 )
                          noSubMbPartSizeLessThan8x8Flag = 0
                     } else if( !direct_8x8_inference_flag )
                         noSubMbPartSizeLessThan8x8Flag = 0
       } else {
            if( transform_8x8_mode_flag  &&  mb_type  = =  I_NxN )
                transform_size_8x8_flag
            mb_pred( mb_type )          //宏块预测
       }
       if( MbPartPredMode( mb_type, 0 )  !=  Intra_16x16 ) {
            coded_block_pattern
            if( CodedBlockPatternLuma > 0  &&
                transform_8x8_mode_flag  &&  mb_type  !=  I_NxN  &&
                noSubMbPartSizeLessThan8x8Flag  &&
                ( mb_type  !=  B_Direct_16x16  | |  direct_8x8_inference_flag ) ) 

               transform_size_8x8_flag
       }
       if( CodedBlockPatternLuma > 0  | |  CodedBlockPatternChroma > 0  | |             MbPartPredMode( mb_type, 0 )  = =  Intra_16x16 ) { 

             mb_qp_delta
             residual( )
       }
    }
} 

上面是宏块层的语法,可以看到宏块预测可以分为两大类:宏块预测、子宏块预测,这两类预测是相互独立的。宏块预测包含的宏块类型有:PSKIP, BSKIP_DIRECT, P16x16, P16x8, P8x16, I4MB, I16MB, I8MB。子宏块包含的宏块类型有:SMB8x8, SMB8x4, SMB4x8, SMB4x4。

宏块类型可以再分为三小类:

  1. Skip: PSKIP, BSKIP_DIRECT。这两个分别为P slice与B slice的skip预测类型。Skip采用mvp或者(0,0)作为当前宏块的mv,不编码mvd,只编码像素残差.
  2. Intra: I4MB, I16MB, I8MB.
  3. Inter: P16x16, P16x8, P8x16.

子宏块类型则可以统一为一种类型P8x8,每个宏块有4个P8x8的子宏块,4个子宏块独立进行子宏块预测,每个子宏块都可以为不同的子宏块类型。

Chroma模式选择

Chroma宏块只分为intra与inter两种类型,并不再细分。标准规定了Chroma宏块的预测方式是受到luma的预测方式的制约的。当luma是以intra进行预测时,chroma宏块才会进行intra预测;当luma是以inter进行预测时,chroma宏块进行的是inter预测(Chroma inter预测不会自行预测,而是通过luma预测结果进行缩放处理后得到的Chroma mv)。

宏块预测中,只有I4MB, I16MB, I8MB时Chroma宏块才会采用intra预测:

//只有当luma的预测模式为intra时,才会进行Chroma的intra预测
mb_pred( mb_type ) {
   if( MbPartPredMode( mb_type, 0 )  = =  Intra_4x4  | |
        MbPartPredMode( mb_type, 0 )  = =  Intra_8x8  | |
        MbPartPredMode( mb_type, 0 )  = =  Intra_16x16 ) { 

        if( MbPartPredMode( mb_type, 0 )  = =  Intra_4x4 )
            for( luma4x4BlkIdx=0; luma4x4BlkIdx<16; luma4x4BlkIdx++ ) {
                 prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ]
                 if( !prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ] )
                     rem_intra4x4_pred_mode[ luma4x4BlkIdx ]
            }
        if( MbPartPredMode( mb_type, 0 )  = =  Intra_8x8 )
            for( luma8x8BlkIdx=0; luma8x8BlkIdx<4; luma8x8BlkIdx++ ) {
                 prev_intra8x8_pred_mode_flag[ luma8x8BlkIdx ]
                 if( !prev_intra8x8_pred_mode_flag[ luma8x8BlkIdx ] )
                     rem_intra8x8_pred_mode[ luma8x8BlkIdx ]
            }
         if( chroma_format_idc  !=  0 )
           intra_chroma_pred_mode
   } else if( MbPartPredMode( mb_type, 0 )  !=  Direct ) {
       for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
           if( ( num_ref_idx_l0_active_minus1 > 0  | |
               mb_field_decoding_flag ) &&
          MbPartPredMode( mb_type, mbPartIdx )  !=  Pred_L1 ) 

               ref_idx_l0[ mbPartIdx ]
       for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
            if( ( num_ref_idx_l1_active_minus1  >  0  | |
                     mb_field_decoding_flag ) &&
                 MbPartPredMode( mb_type, mbPartIdx )  !=  Pred_L0 ) 

                 ref_idx_l1[ mbPartIdx ]
       for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
           if( MbPartPredMode ( mb_type, mbPartIdx )  !=  Pred_L1 )
                for( compIdx = 0; compIdx < 2; compIdx++ )
                    mvd_l0[ mbPartIdx ][ 0 ][ compIdx ]
       for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
            if( MbPartPredMode( mb_type, mbPartIdx )  !=  Pred_L0 )
              for( compIdx = 0; compIdx < 2; compIdx++ )
                  mvd_l1[ mbPartIdx ][ 0 ][ compIdx ]
   }
}

子宏块预测中没有Chroma intra预测:

//可以看到子宏块预测时,没有Chroma的intra预测
sub_mb_pred( mb_type ) {
   for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
        sub_mb_type[ mbPartIdx ]
   for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
if( ( num_ref_idx_l0_active_minus1  >  0  | |  mb_field_decoding_flag ) &&
     mb_type  !=  P_8x8ref0  &&
     sub_mb_type[ mbPartIdx ]  !=  B_Direct_8x8  &&
     SubMbPredMode( sub_mb_type[ mbPartIdx ] )  !=  Pred_L1 ) 

            ref_idx_l0[ mbPartIdx ]
   for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
if( (num_ref_idx_l1_active_minus1  >  0  | |  mb_field_decoding_flag ) &&
      sub_mb_type[ mbPartIdx ]  !=  B_Direct_8x8  &&
      SubMbPredMode( sub_mb_type[ mbPartIdx ] )  !=  Pred_L0 ) 

            ref_idx_l1[ mbPartIdx ]
   for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
if( sub_mb_type[ mbPartIdx ]  !=  B_Direct_8x8  &&
     SubMbPredMode( sub_mb_type[ mbPartIdx ] )  !=  Pred_L1 ) 

for( subMbPartIdx = 0;
       subMbPartIdx < NumSubMbPart( sub_mb_type[ mbPartIdx ] );
       subMbPartIdx++) 

                 for( compIdx = 0; compIdx < 2; compIdx++ )
                      mvd_l0[ mbPartIdx ][ subMbPartIdx ][ compIdx ]
   for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
        if( sub_mb_type[ mbPartIdx ]  !=  B_Direct_8x8  &&
             SubMbPredMode( sub_mb_type[ mbPartIdx ] )  !=  Pred_L0 ) 

for( subMbPartIdx = 0;
       subMbPartIdx < NumSubMbPart( sub_mb_type[ mbPartIdx ] );
       subMbPartIdx++) 

                for( compIdx = 0; compIdx < 2; compIdx++ )
                     mvd_l1[ mbPartIdx ][ subMbPartIdx ][ compIdx ]
}

JM18.6中有几种模式选择的算法,下面来分析一下low与high这两种算法的流程。

Mode Decision Low

该过程非常主要的一个特点是Chroma不参与模式选择

简述一下Low的流程:

  1. inter的宏块类型(P16x16, P16x8, P8x16)选择。
  2. inter的子宏块类型(SMB8x8, SMB8x4, SMB4x8, SMB4x4)选择,每个8x8都可以独立选择不同的分割方式;如果8x8变换方式可用的话,则会多进行一次只采用SMB8x8并采用8x8变换的编码方式,由此看出8x8变换在子宏块类型中只用于SMB8x8。
  3. Skip, FindSkipModeMotionVector此处无作用。
  4. Direct
  5. I8MB,在4个8x8子宏块中可以分别选择不同的预测模式,该预测模式与I4MB一样有9种;在mode_decision_for_I8x8_blocks最后会进行残差编码,宏块重建。
  6. I4MB,在16个4x4块中可以分别选择不同的预测模式,预测模式共9种;在mode_decision_for_I4x4_blocks最后会进行残差编码,宏块重建。
  7. I16MB,在residual_transform_quant_luma_16x16最后会进行残差计算,宏块重建。
  8. 上面的步骤已经通过rdcost选择到了最佳的宏块分割模式,这里会进行后续的参数设置,其中最主要的就是非intra模式的残差编码与宏块重建luma_residual_coding。
  9. Chroma,可以注意到,在Low的流程中Chroma一直没有参与到模式选择当中。最后进行Chroma的intra预测,并根据前面luma所得的当前宏块为intra还是inter模式,选择相应的模式进行编码。

Mode Decision High

该过程中chroma宏块也参与模式选择。

简述一下high的流程:

  1. SKIP, 如果是bslice调用Get_Direct_Motion_Vectors,pslice则调用FindSkipModeMotionVector获得运动向量。
  2. inter的宏块类型(P16x16, P16x8, P8x16)选择。
  3. inter的子宏块类型(SMB8x8, SMB8x4, SMB4x8, SMB4x4)选择,每个8x8都可以独立选择不同的分割方式;如果8x8变换方式可用的话,则会多进行一次只采用SMB8x8并采用8x8变换的编码方式,由此看出8x8变换在子宏块类型中只用于SMB8x8。
  4. chroma预测模式,如果指定了FastCrIntraDecision,则挑选出最佳的chroma模式,否则得到的是chroma模式的范围(DC_PRED_8 ~ PLANE_8)。
  5. 根据所得到的chroma模式范围进行循环。
  6. 在所有luma 模式中选择最佳的模式。
  7. compute_mode_RD_cost中首先筛选chroma模式,只有三种情况才可以往下选择最佳luma模式:1. FastCrIntraDecision,表明只有一次chroma循环,并且循环前已经选出了最佳的chroma模式;2.DC_PRED_8,chroma DC模式可以搭配所有的luma模式;3.intra,luma intra模式可以搭配所有的chroma intra模式。
  8. Bslice & P16x16的情况,再次(?)检查forward,backward,both,bi-pred中,哪种方式最佳。
  9. 如果输入参数指定了transform 8x8,那么对transform8x8与transform4x4分别计算残差。
  10. < P8x8,也就是P16x16, P16x8, P8x16的残差编码,宏块重建。
  11. P8x8,也就是SMB8x8, SMB8x4, SMB4x8, SMB4x4宏块重建,他们的残差计算在子宏块预测时已经计算编码过,并且得到了子宏块的重建块,所以这里只是单纯把子宏块的重建块合并起来。
  12. I4MB,在16个4x4块中可以分别选择不同的预测模式,预测模式共9种;在mode_decision_for_I4x4_blocks最后会进行残差编码,宏块重建。
  13. I16MB,在residual_transform_quant_luma_16x16最后会进行残差编码,宏块重建。
  14. I8MB,在4个8x8子宏块中可以分别选择不同的预测模式,该预测模式与I4MB一样有9种;在mode_decision_for_I8x8_blocks最后会进行残差编码,宏块重建。
  15. IPCM,重建块就是编码块。
  16. Chroma残差编码,其实函数内部分别包含了intra与inter的预测。只有luma在intra模式下,才能进行chroma的intra预测。最后进行chroma的残差编码,宏块重建。
  17. 在每个luma模式最后,都计算出rdcost,然后与前面得到的最低rdcost比较,选择最佳的分割模式。

LOW与HIGH的共同点

可以看到他们在inter模式选择时流程大致一样的。先得到宏块的最佳分割模式,然后得到4个子宏块的最佳分割模式。下面大致浏览一下PartitionMotionSearch与SubPartitionMotionSearch的流程。

LOW与HIGH的不同点

不同点大致分为流程上,最优分割模式选择(计算rdcost)的差异。

Low在对每种分割模式预测完后,立刻进行rdcost计算,用得到的rdcost对比前面已经得到的最佳cost,从而得到最佳模式。在得到最佳模式后,再进行残差编码与重建。

High统一把对比cost并得到最佳模式这个过程写到compute_mode_RD_cost里面。在前面进行完成运动预测后,进入该函数对9种分割模式进行残差编码,宏块重建,cost计算与对比。其中4种intra分割模式是在这个函数内部才分别进行预测的。

Low的rdcost计算并不像high的那么严谨,只是简单地算出distortion与残差系数以外的bit数。Low的rdcost不包括chroma所占用的bit。

High的rdcost会计算经由熵编码后得到的bit,并且包含了chroma所占用的bit,因此更加精准。但是也会相应地增加编码时间。

时间: 2024-10-24 18:52:35

h.264 Mode Decision的相关文章

【H.264/AVC视频编解码技术具体解释】十三、熵编码算法(4):H.264使用CAVLC解析宏块的残差数据

<H.264/AVC视频编解码技术具体解释>视频教程已经在"CSDN学院"上线,视频中详述了H.264的背景.标准协议和实现,并通过一个实战project的形式对H.264的标准进行解析和实现,欢迎观看! "纸上得来终觉浅.绝知此事要躬行".仅仅有自己依照标准文档以代码的形式操作一遍,才干对视频压缩编码标准的思想和方法有足够深刻的理解和体会. 链接地址:H.264/AVC视频编解码技术具体解释 GitHub代码地址:点击这里 1. H.264的CAVLC

H.264 / MPEG-4 Part 10 White Paper-翻译

1. Introduction Broadcast(广播) television and home entertainment(娱乐) have been revolutionised(彻底改变) by the advent(出现) of digital TV andDVD-video.(--广播电视和家庭娱乐方式被彻底改变了在数字电视和DVD-Video出现之后--) These applications and many more were made possible by the stan

x264 - 高品质 H.264 编码器

转自:http://www.5i01.cn/topicdetail.php?f=510&t=3735840&r=18&last=48592660 H.264 / MPEG-4 AVC 是优秀的视讯编码格式就目前已成熟的视讯编码格式而言,H.264的压缩率是最佳的.压缩率极高,可以只用很低 bitrate 提供堪用画质. 而 x264 为免费开放原始码的 H.264 / MPEG-4 AVC 编码器,是目前编码效率最高的开放原始码 H.264 编码器. 此文只是基础知识,说明只是大略

H.264官方软件JM源代码简单分析-解码器ldecod

前一阵子看了一下H.264官方参考软件JM的源代码,在这里总结一下它的结构.JM编解码H.264的速度相对于FFmpeg来说是非常慢的,但是它的代码写得清晰易懂,更适合做学术方面的研究.JM包含了视频解码器ldecod和视频编码器lencod.本文记录视频解码器ldecod的结构. 函数调用关系图 JM中的H.264视频解码器ldecod的函数调用关系图如下所示.   单击查看更清晰的大图 下面解释一下图中关键标记的含义. 函数背景色函数在图中以方框的形式表现出来.不同的背景色标志了该函数不同的

(转)H.264中的NAL技术

NAL技术 1.NAL概述NAL全称Network Abstract Layer, 即网络抽象层.在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL).其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输.现实中的传输系统是多样化的,其可靠性,服务质量,封装方式等特征各不相同,NAL这一概念的提出提供了一个视频编码器和传输系统的友好接口,使得编码后的视频数据能够有效地在各种不

H.264学习笔记——相关概念

此处记录学习AVC过程中的一些基本概念,不定时更新. frame:帧,相当于一幅图像,包含一个亮度矩阵和两个色度矩阵. field:场,一帧图像,通过隔行扫描得到奇偶两场,分别称为顶场和底场或奇场和偶场. macroblock/MB:宏块,H.264中处理(预测.变换.量化)的基本单元,大小16*16个像素. slice group:条带组,每一帧/场图像中,按照光栅扫面的顺序,将MB/MB对分成多个条带(slice). I/P/B 宏块:I宏块只能利用所在slice中已编码的像素进行帧内预测.

H.264硬编码&硬解码

Firefly-RK3288拥有强大的VPU(视像处理器),能够流畅实现720P和1080P视频的H.264编解码: 而H.264的压缩率更高,可以更大程度更小视频的空间占用. 详细看视频演示 1. 演示介绍 基于Firefly开发板:视频监控演示: 需要两块开发板:一块开发板摄像头采集+硬编码,网络传输. 另一块开发板 网络接收.硬解码+显示. Demo中采样5GHz Wi-Fi传输,摄像头使用OV13850,或UVC camera 2. H.264技术介绍 H.264是一种高性能视频编解码技

H.264/AVC I/P/B frames

H.264/AVC I/P/B frames GOP: group of I/P/B frames, the first frame in a GOP is I frame. there is only one I frame in a GOP. if there are B frame in a GOP, the last frame is a P frame. I frame: reference frame of P/B frame. P frame: its reference fram

H.264格式,iOS硬编解码 以及 iOS 11对HEVC硬编解码的支持

H.264格式,iOS硬编解码 以及 iOS 11对HEVC硬编解码的支持 1,H.264格式 网络表示层NAL,如图H.264流由一帧一帧的NALU组成: SPS:序列参数集,作用于一系列连续的编码图像: PPS:图像参数集,作用于编码视频序列中一个或多个独立的图像: 这两个帧也是独立的NALU. I-Frame:关键帧,帧内编码后的帧,显示比较完全的一帧: P-Frame:参考前一帧,可能只是对比前一帧的运动估计的变化部分: B-Frame:会参照前后的帧,其他类似P-Frame.B和P F