Network Abstraction Layer,简称NAL。
h.264把原始的yuv文件编码成码流文件,生成的码流文件就是NAL单元流(NAL unit Stream)。而NAL单元流,就是NAL单元组成的。
标准的Annex B规定了NAL单元组成NAL单元流的方式,下面描述了如何将一个NAL单元打包起来,而多个NAL单元进行组合则形成了NAL单元流。
byte_stream_nal_unit( NumBytesInNALunit ) { C Descriptor
while( next_bits( 24 ) != 0x000001 &&
next_bits( 32 ) != 0x00000001 )
leading_zero_8bits /* equal to 0x00 */ f(8)
if( next_bits( 24 ) != 0x000001 )
zero_byte /* equal to 0x00 */ f(8)
start_code_prefix_one_3bytes /* equal to 0x000001 */ f(24)
nal_unit( NumBytesInNALunit )
while( more_data_in_byte_stream( ) &&
next_bits( 24 ) != 0x000001 &&
next_bits( 32 ) != 0x00000001 )
trailing_zero_8bits /* equal to 0x00 */ f(8)
}
语法元素
NAL单元是对RBSP进行打包生成的,NAL单元有如下语法
nal_unit( NumBytesInNALunit ) { C Descriptor
forbidden_zero_bit All f(1)
nal_ref_idc All u(2)
nal_unit_type All u(5)
NumBytesInRBSP = 0
nalUnitHeaderBytes = 1
if( nal_unit_type = = 14 | | nal_unit_type = = 20 | |
nal_unit_type = = 21 ) {
if( nal_unit_type ! = 21 )
svc_extension_flag All u(1)
else
avc_3d_extension_flag All u(1)
if( svc_extension_flag ) {
nal_unit_header_svc_extension( ) /* specified in Annex G */ All
nalUnitHeaderBytes += 3
} else if( avc_3d_extension_flag ) {
nal_unit_header_3davc_extension( ) /* specified in Annex J */
nalUnitHeaderBytes += 2
} else {
nal_unit_header_mvc_extension( ) /* specified in Annex H */ All
nalUnitHeaderBytes += 3
}
}
for( i = nalUnitHeaderBytes; i < NumBytesInNALunit; i++ ) {
if( i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {
rbsp_byte[ NumBytesInRBSP++ ] All b(8)
rbsp_byte[ NumBytesInRBSP++ ] All b(8)
i += 2
emulation_prevention_three_byte /* equal to 0x03 */ All f(8)
} else
rbsp_byte[ NumBytesInRBSP++ ] All b(8)
}
}
语法元素
0x000000 => 0x00000300
0x000001 => 0x00000301
0x000002 => 0x00000302
0x000003 => 0x00000303
……
Raw Byte Sequence Payload,原始字节序列载荷。
跟据nal_unit_type可以分成以下表格
| nal_unit_type |
Content of NAL unit and RBSP |
Catogary |
| 0 |
Unspecified |
|
| 1 |
Coded slice of a non-IDR picture |
2,3,4 |
| 2 |
Coded slice data partition A |
2 |
| 3 |
Coded slice data partition B |
3 |
| 4 |
Coded slice data partition C |
4 |
| 5 |
Coded slice of an IDR picture |
2,3 |
| 6 |
Supplemental enhancement information |
5 |
| 7 |
Sequence parameter set |
0 |
| 8 |
Picture parameter set |
1 |
| 9 |
Access unit delimiter |
6 |
|
10 |
End of sequence |
7 |
|
11 |
End of stream |
8 |
|
12 |
Filler data |
9 |
|
13 |
Sequence parameter set extension |
10 |
|
14 |
Prefix NAL unit |
2 |
|
15 |
Subset sequence parameter set |
0 |
|
16…18 |
Reserved |
|
|
19 |
Coded slice of an auxiliary coded |
2,3,4 |
|
20 |
Coded slice extension |
2,3,4 |
|
21 |
Coded slice extension for a depth view |
2,3,4 |
|
22…23 |
Reserved |
|
| 24…31 |
Unspecified |
第一列代表当前NAL的类型;第二列是该类型对应的描述以及RBSP语法结构名称;第三列列出了当前NAL类型中可能出现的语法元素种类,(Category)种类在所有语法结构中的语法元素后面都有标明。
标准中描述了很多种的RBSP结构并且通过语法表现出来,RBSP语法主要规定了该结构由什么成员组成,各个成员如何组合,成员会占用几个bit。不过虽然RBSP结构有很多种,但是他们也有一个共同点:都有一个RBSP尾部。
RBSP尾部的语法如下:
rbsp_trailing_bits( ) { C Descriptor
rbsp_stop_one_bit /* equal to 1 */ All f(1)
while( !byte_aligned( ) )
rbsp_alignment_zero_bit /* equal to 0 */ All f(1)
}
语法元素
有一种特殊情况:如果采用的熵编码方式为CABAC,而且当前是实际图像内容相关的RBSP(名称包含slice的RBSP结构),那么会在RBSP尾部的后面添加1个或多个0x0000。语法表示如下:
rbsp_slice_trailing_bits( ) { C Descriptor
rbsp_trailing_bits( ) All
if( entropy_coding_mode_flag )
while( more_rbsp_trailing_data( ) )
cabac_zero_word /* equal to 0x0000 */ All f(16)
}
语法元素
RBSP中除了rbsp_trailing_bits以及rbsp_slice_trailing_bits,其余部分被统称为SODB(String Of Data Bits)。
这是SPS RBSP的名称,它的结构如下
seq_parameter_set_rbsp( ) { C Descriptor
seq_parameter_set_data( ) 0
rbsp_trailing_bits( ) 0
}
如前面所说,RBSP都有一个rbsp_trailing_bits的尾部。而SPS的结构被包含在了seq_parameter_set_data里面
seq_parameter_set_data( ) { C Descriptor
profile_idc 0 u(8)
constraint_set0_flag 0 u(1)
constraint_set1_flag 0 u(1)
constraint_set2_flag 0 u(1)
constraint_set3_flag 0 u(1)
constraint_set4_flag 0 u(1)
constraint_set5_flag 0 u(1)
reserved_zero_2bits /* equal to 0 */ 0 u(2)
level_idc 0 u(8)
seq_parameter_set_id 0 ue(v)
if( profile_idc = = 100 | | profile_idc = = 110 | |
profile_idc = = 122 | | profile_idc = = 244 | | profile_idc = = 44 | |
profile_idc = = 83 | | profile_idc = = 86 | | profile_idc = = 118 | |
profile_idc = = 128 | | profile_idc = = 138 | | profile_idc = = 139 | |
profile_idc = = 134 ) {
chroma_format_idc 0 ue(v)
if( chroma_format_idc = = 3 )
separate_colour_plane_flag 0 u(1)
bit_depth_luma_minus8 0 ue(v)
bit_depth_chroma_minus8 0 ue(v)
qpprime_y_zero_transform_bypass_flag 0 u(1)
seq_scaling_matrix_present_flag 0 u(1)
if( seq_scaling_matrix_present_flag )
for( i = 0; i < ( ( chroma_format_idc != 3 ) ? 8 : 12 ); i++ ) {
seq_scaling_list_present_flag[ i ] 0 u(1)
if( seq_scaling_list_present_flag[ i ] )
if( i < 6 )
scaling_list( ScalingList4x4[ i ], 16,
UseDefaultScalingMatrix4x4Flag[ i ]) 0
else
scaling_list( ScalingList8x8[ i − 6 ], 64,
UseDefaultScalingMatrix8x8Flag[ i − 6 ] ) 0
}
}
log2_max_frame_num_minus4 0 ue(v)
pic_order_cnt_type 0 ue(v)
if( pic_order_cnt_type = = 0 )
log2_max_pic_order_cnt_lsb_minus4 0 ue(v)
else if( pic_order_cnt_type = = 1 ) {
delta_pic_order_always_zero_flag 0 u(1)
offset_for_non_ref_pic 0 se(v)
offset_for_top_to_bottom_field 0 se(v)
num_ref_frames_in_pic_order_cnt_cycle 0 ue(v)
for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
offset_for_ref_frame[ i ] 0 se(v)
}
max_num_ref_frames
gaps_in_frame_num_value_allowed_flag 0 u(1)
pic_width_in_mbs_minus1 0 ue(v)
pic_height_in_map_units_minus1 0 ue(v)
frame_mbs_only_flag 0 u(1)
if( !frame_mbs_only_flag )
mb_adaptive_frame_field_flag 0 u(1)
direct_8x8_inference_flag 0 u(1)
frame_cropping_flag 0 u(1)
if( frame_cropping_flag ) {
frame_crop_left_offset 0 ue(v)
frame_crop_right_offset 0 ue(v)
frame_crop_top_offset 0 ue(v)
frame_crop_bottom_offset 0 ue(v)
}
vui_parameters_present_flag 0 u(1)
if( vui_parameters_present_flag )
vui_parameters( ) 0
}
语法元素
如前面所说,RBSP都有一个rbsp_trailing_bits的尾部。PPS RBSP结构如下
pic_parameter_set_rbsp( ) { C Descriptor
pic_parameter_set_id 1 ue(v)
seq_parameter_set_id 1 ue(v)
entropy_coding_mode_flag 1 u(1)
bottom_field_pic_order_in_frame_present_flag 1 u(1)
num_slice_groups_minus1 1 ue(v)
if( num_slice_groups_minus1 > 0 ) {
slice_group_map_type 1 ue(v)
if( slice_group_map_type = = 0 )
for( iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++ )
run_length_minus1[ iGroup ] 1 ue(v)
else if( slice_group_map_type = = 2 )
for( iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++ ) {
top_left[ iGroup ] 1 ue(v)
bottom_right[ iGroup ] 1 ue(v)
}
else if( slice_group_map_type = = 3 | |
slice_group_map_type = = 4 | |
slice_group_map_type = = 5 ) {
slice_group_change_direction_flag 1 u(1)
slice_group_change_rate_minus1 1 ue(v)
} else if( slice_group_map_type = = 6 ) {
pic_size_in_map_units_minus1 1 ue(v)
for( i = 0; i <= pic_size_in_map_units_minus1; i++ )
slice_group_id[ i ] 1 u(v)
}
}
num_ref_idx_l0_default_active_minus1 1 ue(v)
num_ref_idx_l1_default_active_minus1 1 ue(v)
weighted_pred_flag 1 u(1)
weighted_bipred_idc 1 u(2)
pic_init_qp_minus26 /* relative to 26 */ 1 se(v)
pic_init_qs_minus26 /* relative to 26 */ 1 se(v)
chroma_qp_index_offset 1 se(v)
deblocking_filter_control_present_flag 1 u(1)
constrained_intra_pred_flag 1 u(1)
redundant_pic_cnt_present_flag 1 u(1)
if( more_rbsp_data( ) ) {
transform_8x8_mode_flag 1 u(1)
pic_scaling_matrix_present_flag 1 u(1)
if( pic_scaling_matrix_present_flag )
for( i = 0; i < 6 +
( ( chroma_format_idc != 3 ) ? 2 : 6 ) * transform_8x8_mode_flag;
i++ ) {
pic_scaling_list_present_flag[ i ] 1 u(1)
if( pic_scaling_list_present_flag[ i ] )
if( i < 6 )
scaling_list( ScalingList4x4[ i ], 16,
UseDefaultScalingMatrix4x4Flag[ i ] ) 1
else
scaling_list( ScalingList8x8[ i − 6 ], 64,
UseDefaultScalingMatrix8x8Flag[ i − 6 ] ) 1
}
second_chroma_qp_index_offset 1 se(v)
}
rbsp_trailing_bits( ) 1
}
语法元素
如果当前slice不采用slice data partition的RBSP结构的话,就会是这个RBSP结构,编码时一般都会采用的这个RBSP结构。
我们知道编码是以slice为单位的,这个结构内包含的就是视频中编码的主要内容,视频图像进行编码后就会包含在这个结构内,也就是说编码后的码流中,大多数都是以这个结构的RBSP打包成的NAL unit。
语法结构如下
slice_layer_without_partitioning_rbsp( ) { C Descriptor
slice_header( ) 2
slice_data( ) /* all categories of slice_data( ) syntax */ 2 | 3 | 4
rbsp_slice_trailing_bits( ) 2
}
其中分成slice_header,slice_data两部分,最后是RBSP尾部。
slice_header
slice_header就是slice的头部,其中包含的是本slice的相关参数,语法结构如下
slice_header( ) { C Descriptor
first_mb_in_slice 2 ue(v)
slice_type 2 ue(v)
pic_parameter_set_id 2 ue(v)
if( separate_colour_plane_flag = = 1 )
colour_plane_id 2 u(2)
frame_num 2 u(v)
if( !frame_mbs_only_flag ) {
field_pic_flag 2 u(1)
if( field_pic_flag )
bottom_field_flag 2 u(1)
}
if( IdrPicFlag )
idr_pic_id 2 ue(v)
if( pic_order_cnt_type = = 0 ) {
pic_order_cnt_lsb 2 u(v)
if( bottom_field_pic_order_in_frame_present_flag && !field_pic_flag )
delta_pic_order_cnt_bottom 2 se(v)
}
if( pic_order_cnt_type = = 1 && !delta_pic_order_always_zero_flag ) {
delta_pic_order_cnt[ 0 ] 2 se(v)
if( bottom_field_pic_order_in_frame_present_flag && !field_pic_flag )
delta_pic_order_cnt[ 1 ] 2 se(v)
}
if( redundant_pic_cnt_present_flag )
redundant_pic_cnt 2 ue(v)
if( slice_type = = B )
direct_spatial_mv_pred_flag 2 u(1)
if( slice_type = = P | | slice_type = = SP | | slice_type = = B ) {
num_ref_idx_active_override_flag 2 u(1)
if( num_ref_idx_active_override_flag ) {
num_ref_idx_l0_active_minus1 2 ue(v)
if( slice_type = = B )
num_ref_idx_l1_active_minus1 2 ue(v)
}
}
if( nal_unit_type = = 20 | | nal_unit_type = = 21 )
ref_pic_list_mvc_modification( ) /* specified in Annex H */ 2
else
ref_pic_list_modification( ) 2
if( ( weighted_pred_flag && ( slice_type = = P | | slice_type = = SP ) ) | |
( weighted_bipred_idc = = 1 && slice_type = = B ) )
pred_weight_table( ) 2
if( nal_ref_idc != 0 )
dec_ref_pic_marking( ) 2
if( entropy_coding_mode_flag && slice_type != I && slice_type != SI )
cabac_init_idc 2 ue(v)
slice_qp_delta 2 se(v)
if( slice_type = = SP | | slice_type = = SI ) {
if( slice_type = = SP )
sp_for_switch_flag 2 u(1)
slice_qs_delta 2 se(v)
}
if( deblocking_filter_control_present_flag ) {
disable_deblocking_filter_idc 2 ue(v)
if( disable_deblocking_filter_idc != 1 ) {
slice_alpha_c0_offset_div2 2 se(v)
slice_beta_offset_div2 2 se(v)
}
}
if( num_slice_groups_minus1 > 0 &&
slice_group_map_type >= 3 && slice_group_map_type <= 5)
slice_group_change_cycle 2 u(v)
}
语法元素
| slice_type | Nane of slice_type |
| 0 | P(P slice) |
| 1 | B(B slice) |
| 2 | I(I slice) |
| 3 | SP(SP slice) |
| 4 | SI(SI slice) |
| 5 | P(P slice) |
| 6 | B(B slice) |
| 7 | I(I slice) |
| 8 | SP(SP slice) |
| 9 | SI(SI slice) |
slice_data
slice_data是slice的主体部分,当前slice内的宏块编码后的信息都在其中。
语法结构如下
slice_data( ) { C Descriptor
if( entropy_coding_mode_flag )
while( !byte_aligned( ) )
cabac_alignment_one_bit 2 f(1)
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 2 ue(v)
prevMbSkipped = ( mb_skip_run > 0 )
for( i=0; i<mb_skip_run; i++ )
CurrMbAddr = NextMbAddress( CurrMbAddr )
if( mb_skip_run > 0 )
moreDataFlag = more_rbsp_data( )
} else {
mb_skip_flag 2 ae(v)
moreDataFlag = !mb_skip_flag
}
if( moreDataFlag ) {
if( MbaffFrameFlag && ( CurrMbAddr % 2 = = 0 | |
( CurrMbAddr % 2 = = 1 && prevMbSkipped ) ) )
mb_field_decoding_flag 2 u(1) | ae(v)
macroblock_layer( ) 2 | 3 | 4
}
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 2 ae(v)
moreDataFlag = !end_of_slice_flag
}
}
CurrMbAddr = NextMbAddress( CurrMbAddr )
} while( moreDataFlag )
}
可以注意到slice_data内头部的对齐外,它由宏块信息循环组合而成。
语法元素
macroblock_layer
如前面所说,这里面的是宏块编码数据,语法结构如下
macroblock_layer( ) { C Descriptor
mb_type 2 ue(v) | ae(v)
if( mb_type = = I_PCM ) {
while( !byte_aligned( ) )
pcm_alignment_zero_bit 3 f(1)
for( i = 0; i < 256; i++ )
pcm_sample_luma[ i ] 3 u(v)
for( i = 0; i < 2 * MbWidthC * MbHeightC; i++ )
pcm_sample_chroma[ i ] 3 u(v)
} else {
noSubMbPartSizeLessThan8x8Flag = 1
if( mb_type != I_NxN &&
MbPartPredMode( mb_type, 0 ) != Intra_16x16 &&
NumMbPart( mb_type ) = = 4 ) {
sub_mb_pred( mb_type ) 2
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 2 u(1) | ae(v)
mb_pred( mb_type ) 2
}
if( MbPartPredMode( mb_type, 0 ) != Intra_16x16 ) {
coded_block_pattern 2 me(v) | ae(v)
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 2 u(1) | ae(v)
}
if( CodedBlockPatternLuma > 0 | | CodedBlockPatternChroma > 0 | |
MbPartPredMode( mb_type, 0 ) = = Intra_16x16 ) {
mb_qp_delta 2 se(v) | ae(v)
residual( 0, 15 ) 3 | 4
}
}
}
语法元素
| CodedBlockPatternChroma | Description |
| 0 | All chroma transform coefficient levels are equal to 0. |
| 1 |
One or more chroma DC transform coefficient levels shall be non-zero valued. |
| 2 |
Zero or more chroma DC transform coefficient levels are non-zero valued. |
按照macroblock_layer的语法结构上看,宏块能粗略分成三种结构:PCM、sub_mb_pred(子宏块预测)、mb_pred(宏块预测)。另外,虽然skip宏块并不在macroblock内描述,它也是宏块的一种结构。
mb_perd
语法结构如下
mb_pred( mb_type ) { C Descriptor
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 ] 2 u(1) | ae(v)
if( !prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ] )
rem_intra4x4_pred_mode[ luma4x4BlkIdx ] 2 u(3) | ae(v)
}
if( MbPartPredMode( mb_type, 0 ) = = Intra_8x8 )
for( luma8x8BlkIdx=0; luma8x8BlkIdx<4; luma8x8BlkIdx++ ) {
prev_intra8x8_pred_mode_flag[ luma8x8BlkIdx ] 2 u(1) | ae(v)
if( !prev_intra8x8_pred_mode_flag[ luma8x8BlkIdx ] )
rem_intra8x8_pred_mode[ luma8x8BlkIdx ] 2 u(3) | ae(v)
}
if( ChromaArrayType = = 1 | | ChromaArrayType = = 2 )
intra_chroma_pred_mode 2 ue(v) | ae(v)
} 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 != field_pic_flag ) &&
MbPartPredMode( mb_type, mbPartIdx ) != Pred_L1 )
ref_idx_l0[ mbPartIdx ] 2 te(v) | ae(v)
for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
if( ( num_ref_idx_l1_active_minus1 > 0 | |
mb_field_decoding_flag != field_pic_flag ) &&
MbPartPredMode( mb_type, mbPartIdx ) != Pred_L0 )
ref_idx_l1[ mbPartIdx ] 2 te(v) | ae(v)
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 ] 2 se(v) | ae(v)
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 ] 2 se(v) | ae(v)
}
}
语法元素
下图是几个mb_pred结构的例子
sub_mb_pred
语法结构如下
sub_mb_pred( mb_type ) { C Descriptor
for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
sub_mb_type[ mbPartIdx ] 2 ue(v) | ae(v)
for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
if( ( num_ref_idx_l0_active_minus1 > 0 | |
mb_field_decoding_flag != field_pic_flag ) &&
mb_type != P_8x8ref0 &&
sub_mb_type[ mbPartIdx ] != B_Direct_8x8 &&
SubMbPredMode( sub_mb_type[ mbPartIdx ] ) != Pred_L1 )
ref_idx_l0[ mbPartIdx ] 2 te(v) | ae(v)
for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
if( ( num_ref_idx_l1_active_minus1 > 0 | |
mb_field_decoding_flag != field_pic_flag ) &&
sub_mb_type[ mbPartIdx ] != B_Direct_8x8 &&
SubMbPredMode( sub_mb_type[ mbPartIdx ] ) != Pred_L0 )
ref_idx_l1[ mbPartIdx ] 2 te(v) | ae(v)
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 ] 2 se(v) | ae(v)
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 ] 2 se(v) | ae(v)
}
语法元素
下面是一个sub_mb_pred语法结构的例子,左边的表格分别代表四个子宏块的模式,他们按照顺序被写在sub_mb_pred的头部。图例中,结构上面的数字代表了该语法元素所属的子宏块。
residual,residual_luma
像素残差进行变换、量化后的系数的语法结构。
residual( startIdx, endIdx ) { C Descriptor
if( !entropy_coding_mode_flag )
residual_block = residual_block_cavlc
else
residual_block = residual_block_cabac
residual_luma( i16x16DClevel, i16x16AClevel, level4x4, level8x8,
startIdx, endIdx ) 3 | 4
Intra16x16DCLevel = i16x16DClevel
Intra16x16ACLevel = i16x16AClevel
LumaLevel4x4 = level4x4
LumaLevel8x8 = level8x8
if( ChromaArrayType = = 1 | | ChromaArrayType = = 2 ) {
NumC8x8 = 4 / ( SubWidthC * SubHeightC )
for( iCbCr = 0; iCbCr < 2; iCbCr++ )
if( ( CodedBlockPatternChroma & 3 ) && startIdx = = 0 )
/* chroma DC residual present */
residual_block( ChromaDCLevel[ iCbCr ], 0, 4 * NumC8x8 − 1,
4 * NumC8x8 ) 3 | 4
else
for( i = 0; i < 4 * NumC8x8; i++ )
ChromaDCLevel[ iCbCr ][ i ] = 0
for( iCbCr = 0; iCbCr < 2; iCbCr++ )
for( i8x8 = 0; i8x8 < NumC8x8; i8x8++ )
for( i4x4 = 0; i4x4 < 4; i4x4++ )
if( CodedBlockPatternChroma & 2 )
/* chroma AC residual present */
residual_block( ChromaACLevel[ iCbCr ][ i8x8*4+i4x4 ],
Max( 0, startIdx − 1 ), endIdx − 1, 15) 3 | 4
else
for( i = 0; i < 15; i++ )
ChromaACLevel[ iCbCr ][ i8x8*4+i4x4 ][ i ] = 0
} else if( ChromaArrayType = = 3 ) {
residual_luma( i16x16DClevel, i16x16AClevel, level4x4, level8x8,
startIdx, endIdx ) 3 | 4
CbIntra16x16DCLevel = i16x16DClevel
CbIntra16x16ACLevel = i16x16AClevel
CbLevel4x4 = level4x4
CbLevel8x8 = level8x8
residual_luma( i16x16DClevel, i16x16AClevel, level4x4, level8x8,
startIdx, endIdx ) 3 | 4
CrIntra16x16DCLevel = i16x16DClevel
CrIntra16x16ACLevel = i16x16AClevel
CrLevel4x4 = level4x4
CrLevel8x8 = level8x8
}
}
residual内部首先会根据entropy_coding_mode_flag来选择CAVLC或者CABAC的熵编码方式,然后在下面进行level的处理。level处理部分先包含了residual_luma,也就是先进行luma level的处理,然后用residual_block对chroma level进行处理。
chroma level一般采用的yuv格式都是4:2:0,也就是ChromaArrayType=1。
residual_luma( i16x16DClevel, i16x16AClevel, level4x4, level8x8,
startIdx, endIdx ) { C Descriptor
if( startIdx = = 0 && MbPartPredMode( mb_type, 0 ) = = Intra_16x16 )
residual_block( i16x16DClevel, 0, 15, 16 ) 3
for( i8x8 = 0; i8x8 < 4; i8x8++ )
if( !transform_size_8x8_flag | | !entropy_coding_mode_flag )
for( i4x4 = 0; i4x4 < 4; i4x4++ ) {
if( CodedBlockPatternLuma & ( 1 << i8x8 ) )
if( MbPartPredMode( mb_type, 0 ) = = Intra_16x16 )
residual_block( i16x16AClevel[i8x8*4+ i4x4],
Max( 0, startIdx − 1 ), endIdx − 1, 15) 3
else
residual_block( level4x4[ i8x8 * 4 + i4x4 ],
startIdx, endIdx, 16) 3 | 4
else if( MbPartPredMode( mb_type, 0 ) = = Intra_16x16 )
for( i = 0; i < 15; i++ )
i16x16AClevel[ i8x8 * 4 + i4x4 ][ i ] = 0
else
for( i = 0; i < 16; i++ )
level4x4[ i8x8 * 4 + i4x4 ][ i ] = 0
if( !entropy_coding_mode_flag && transform_size_8x8_flag )
for( i = 0; i < 16; i++ )
level8x8[ i8x8 ][ 4 * i + i4x4 ] = level4x4[ i8x8 * 4 + i4x4 ][ i ]
}
else if( CodedBlockPatternLuma & ( 1 << i8x8 ) )
residual_block( level8x8[ i8x8 ], 4 * startIdx, 4 * endIdx + 3, 64 ) 3 | 4
else
for( i = 0; i < 64; i++ )
level8x8[ i8x8 ][ i ] = 0
}
传递给residual_luma的luma level分为几种,如下面的语法元素i16x16DClevel, i16x16AClevel, level4x4, level8x8,需要根据不同情况分开处理,residual_luma做的工作就是针对不同的类型的level,为下面的熵编码语法结构residual_block传递不同的参数。
语法元素
如果没有宏块CBP上的bit全都不为0的话,它的residual就会是如下的样子
原文:http://www.cnblogs.com/TaigaCon/p/5215448.html