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 ]
}
}
}
重排序(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 ]
}
}