H264源码分析(三)

原文出自http://blog.csdn.net/xfding/article/details/5477351(收集转载)

(七)加权预测句法

pred_weight_table( ) {  
  
// luma_log2_weight_denom    给出参考帧列表中参考图像所有亮度的加权系数,是个初始值luma_log2_weight_denom  值的范围是  0 to 7。 
    luma_log2_weight_denom   
    // chroma_log2_weight_denom  给出参考帧列表中参考图像所有色度的加权系数,是个初始值chroma_log2_weight_denom  值的范围是  0 to 7。 
    chroma_log2_weight_denom   
    for( i = 0; i <= num_ref_idx_l0_active_minus1; i++ ) {       
        // luma_weight_l0_flag  等于 1  时,指的是在参考序列 0 中的亮度的加权系数存在;等于 0 时,在参考序列 0 中的亮度的加权系数不存在。   
        luma_weight_l0_flag   
        if( luma_weight_l0_flag ) {          
            // luma_weight_l0[ i ]  用参考序列 0 预测亮度值时,所用的加权系数。如果  luma_weight_l0_flag is = 0, luma_weight_l0[ i ] = pow(2, luma_log2_weight_denom )
            luma_weight_l0[ i ]  
            // luma_offset_l0[ i ]  用参考序列 0 预测亮度值时,所用的加权系数的额外的偏移。luma_offset_l0[ i ]  值的范围–128 to 127。如果  luma_weight_l0_flag is = 0, luma_offset_l0[ i ] = 0  
            luma_offset_l0[ i ]   
        }         
        chroma_weight_l0_flag   
        if( chroma_weight_l0_flag )         
            for( j =0; j < 2; j++ ) {         
                chroma_weight_l0[ i ][ j ]   
                chroma_offset_l0[ i ][ j ]  
            }         
    }         
    if( slice_type    = =    B )         
        for( i = 0; i <= num_ref_idx_l1_active_minus1; i++ ) {         
            luma_weight_l1_flag  
            if( luma_weight_l1_flag ) {         
                luma_weight_l1[ i ]  
                luma_offset_l1[ i ] 
            }         
            chroma_weight_l1_flag   
            if( chroma_weight_l1_flag )         
                for( j = 0; j < 2; j++ ) {         
                    chroma_weight_l1[ i ][ j ]  
                    chroma_offset_l1[ i ][ j ]  
                }         
        }         
}

 

(八)参考图像序列标记 (marking)操作的语义

重排序(reordering)操作是对参考帧队列重新排序,而标记(marking)操作负责将参考图像移入或移出参考帧队列。

dec_ref_pic_marking( ) { 
    if( nal_unit_type    = =    5 ) {           
        // no_output_of_prior_pics_flag  仅在当前图像是 IDR 图像时出现这个句法元素,指明是否要将前面已解码的图像全部输出。 
        no_output_of_prior_pics_flag  
       
// long_term_reference_flag    与上个图像一样,仅在当前图像是 IDR 图像时出现这一句法元素。这个句法元素指明是否使用长期参考这个机制。如果取值为 1,表明使用长期参考,并且每个 IDR 图像被解码后自动成为长期参考帧,否则(取值为 0),IDR 图像被解码后自动成为短期参考帧。 
        long_term_reference_flag
   
    } else {          
        // adaptive_ref_pic_marking_mode_flag         指明标记(marking)操作的模式,
           adaptive_ref_pic_marking_mode_flag         标记(marking)模式
           0                                                                  先入先出(FIFO):使用滑动窗的机制,先入先出,在这种模式
                                                                               下没有办法对长期参考帧进行操作。
           1                                                                  自适应标记(marking):后续码流中会有一系列句法元素显式指
                                                                               明操作的步骤。自适应是指编码器可根据情况随机灵活地作出决策。 
        adaptive_ref_pic_marking_mode_flag   
        if( adaptive_ref_pic_marking_mode_flag )          
            do {          
                /* memory_management_control_operation  在自适应标记(marking)模式中,指明本次操作的具体内容
                memory_management_control_operation           标记(marking)操作
                0                                                                          结束循环,退出标记(marding)操作。 
                1                                                                          将一个短期参考图像标记为非参考图像,也
                                                                                            即将一个短期参考图像移出参考帧队列。
                2                                                                          将一个长期参考图像标记为非参考图像,也
                                                                                            即将一个长期参考图像移出参考帧队列。
                3                                                                          将一个短期参考图像转为长期参考图像。
                4                                                                          指明长期参考帧的最大数目。
                5                                                                          清空参考帧队列,将所有参考图像移出参考
                                                                                            帧队列,并禁用长期参考机制
                6                                                                          将当前图像存为一个长期参考帧。 */

               memory_management_control_operation  
                if( memory_management_control_operation    = =    1    | |
                    memory_management_control_operation    = =    3 )
                    // difference_of_pic_nums_minus1    当 memory_management_control_operation 等于 3  或 1 时,由  这个
句法元素可以计算得到需要操作的图像在短期参考队列中的序号。参考帧队列中必须存在这个图像。
                    difference_of_pic_nums_minus1  
                if(memory_management_control_operation    = =    2    )         
                    // long_term_pic_num    当 memory_management_control_operation 等于 2 时,  从此句法元素得到所要
操作的长期参考图像的序号。
   
                    long_term_pic_num   
                if( memory_management_control_operation    = =    3    | |
                    memory_management_control_operation    = =    6 )
                    // long_term_frame_idx    当  memory_management_control_operation 等于 3 或 6  ,分配一个长期参考
帧的序号给一个图像。 
                    long_term_frame_idx   
                if( memory_management_control_operation    = =    4 )         
                   // max_long_term_frame_idx_plus1  此句法元素减1, 指明长期参考队列的最大数目 。max_long_term_frame_idx_plus1 值的范围  0 to num_ref_frames。   
                    max_long_term_frame_idx_plus1   
            } while( memory_management_control_operation    !=    0 )          
    }          
}

 

(九)片层数据句法

slice_data( ) {  
    if( entropy_coding_mode_flag )            
        while( !byte_aligned( ) )             
            // cabac_alignment_one_bit    当熵编码模式是CABAC 时,此时要求数据字节对齐,即数据从下一个字节的第一个比特开始,如果还没有字节对齐将出现若干个 cabac_alignment_one_bit 作为填充。 
           cabac_alignment_one_bit  
    CurrMbAddr = first_mb_in_slice * ( 1 + MbaffFrameFlag )            
    moreDataFlag = 1            
    prevMbSkipped = 0            
    do {            
        if( slice_type    !=    I    &&    slice_type    !=    SI )            
            if( !entropy_coding_mode_flag ) { 
                // mb_skip_run    当图像采用帧间预测编码时,H.264 允许在图像平坦的区域使用“跳跃”块,“跳跃”块本身不携带任何数据,解码器通过周围已重建的宏块的数据来恢复“跳跃”块。当熵编码为 CAVLC 或 CABAC 时,“跳跃”块的表示方法不同。当 entropy_coding_mode_flag为1,即熵编码为CABAC时 ,是每个“ 跳 跃 ”块都会有句法元素mb_skip_flag指明,而entropy_coding_mode_flag 等于 0,即熵编码为CAVLC时,用一种行程的方法给出紧连着的“跳跃”块的数目,即句法元素 mb_skip_run。mb_skip_run 值的范围 0 to PicSizeInMbs – CurrMbAddr  。            
                mb_skip_run   
                prevMbSkipped = ( mb_skip_run > 0 )            
                for( i=0; i<MB_SKIP_RUN; i++ )            
                    CurrMbAddr = NextMbAddress( CurrMbAddr )            
                moreDataFlag = more_rbsp_data( )            
            } else {            
                // mb_skip_flag  指明当前宏块是否是跳跃编码模式的宏块
                mb_skip_flag   
                moreDataFlag = !mb_skip_flag            
            }            
        if( moreDataFlag ) {            
            if( MbaffFrameFlag && ( CurrMbAddr % 2    = =    0    | |    
                ( CurrMbAddr % 2    = =    1    &&    prevMbSkipped ) ) )
                // mb_field_decoding_flag  在帧场自适应图像中,指明当前宏块所属的宏块对是帧模式还是场模式。0 帧模式;1 场模式。如果一个宏块对的两个宏块句法结构中都没有出现这个句法元素,即它们都是“跳跃”块时,本句法元素由以下决定:
                    -  如果这个宏块对与相邻的、左边的宏块对属于同一个片时,这个宏块对的 mb_field_decoding_flag的值等于左边的宏块对的 mb_field_decoding_flag 的值。
                    -   否则,这个宏块对的 mb_field_decoding_flag   的值等于上边同属于一个片的宏块对的mb_field_decoding_flag 的值。 -  如果这个宏块对既没有相邻的、上边同属于一个片的宏块对;也没有相邻的、左边同属于一个片的宏块对,这个宏块对的 mb_field_decoding_flag 的值等于 0,即帧模式。 end_of_slice_flag  指明是否到了片的结尾。
                mb_field_decoding_flag   
            macroblock_layer( )       
        }            
        if( !entropy_coding_mode_flag )            
            moreDataFlag = more_rbsp_data( )            
        else {            
            if( slice_type    !=    I    &&    slice_type    !=    SI )            
                prevMbSkipped = mb_skip_flag            
            if( MbaffFrameFlag    &&    CurrMbAddr % 2    = =    0 )            
                moreDataFlag = 1            
            else {            
                end_of_slice_flag  
                moreDataFlag = !end_of_slice_flag            
            }
        }            
        CurrMbAddr = NextMbAddress( CurrMbAddr )            
    } while( moreDataFlag )            
}

(十)宏块层句法(无)

十一)宏块层预测句法

mb_pred( mb_type ) {  
    if( MbPartPredMode( mb_type, 0 )    = =    Intra_4x4    | |    
        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 ] rem_intra4x4_pred_mode[ luma4x4BlkIdx ] 帧内预测的模式也是需要预测的,  prev_intra4x4_pred_mode_flag 用来指明帧内预测时,亮度分量的预测模式的预测值是否就是真实预测模式,如果是,就不需另外再传预测模式。如果不是,就由 rem_intra4x4_pred_mode 指定真实预测模式。       
                prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ]  
                if( !prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ] )        
                   rem_intra4x4_pred_mode[ luma4x4BlkIdx ]  
            }        
   
    // intra_chroma_pred_mode  在帧内预测时指定色度的预测模式,
            intra_chroma_pred_mode        预测模式
            0                                               DC
            1                                               Horizontal
            2                                               Vertical            
            3                                               Plane
 
       
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]用参考帧队列 L0 进行预测,即前向预测时,参考图像在参考帧队列中的序号。其中 mbPartIdx 是宏块分区的序号。 如 果 当 前 宏 块 是非场宏块 ,  则ref_idx_l0[ mbPartIdx ] 值的范围是0到 num_ref_idx_l0_active_minus1。 否则,如果当前宏块是场宏块,(宏块所在图像是场,当图像是帧场自适应时当前宏块处于场编码的宏块对),ref_idx_l0[ mbPartIdx]值的范围是 0  到 2*num_ref_idx_l0_active_minus1 + 1,如前所述,此时参考帧队列的帧都将拆成场,故参考队列长度加倍。
                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 ]  运动矢量的预测值和实际值之间的差。mbPartIdx  是宏块分区的序号。CompIdx = 0 时水平运动矢量;  CompIdx = 1 垂直运动矢量。 
                    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 ]   
    }        
}

你可能感兴趣的:(视频,嵌入式,h264,编解码)