3.3.4 H264码表
H264标准中提出了许多新的技术方案,例如为了能够在网络上进行更好的传输,首先要将每帧图像划分为NAL单元,为了提高压缩率及错误处理能力提出了RBSP编码算法。下面对H264标准中NAL、RBSP和SEI的码表进行介绍。
(1)NAL单元语法如下:
nal_unit(NumBytesInNALunit)/*NumBytesInNALunit规定了NAL单元的大小*/ { forbidden_zero_bit/*应该为0*/ nal_ref_idc/*如果不为0,则NUL单元的内容包含一个序列参数集,或一个图像参数集 或一个参考图像条带,或一个参考图像的条带数据分割*/ nal_unit_type/*指明含在NAL单元中的RBSP数据结构的类型*/ NumBytesInRBSP = 0 for(i=1;i<NumBytesInNALunit;i++) { if(i+2<NumBytesInNALunit && next_bits(24)==0x000003) { rbsp_byte[NumBytesInRBSP++]/* 一个RBSP的字节,一个RBSP定义一个字节的有序序列*/ rbsp_byte[NumBytesInRBSP++] i += 2 emulation_prevention_three_byte/*值为0x03的字节,解码器不处理该字节*/ } else rbsp_byte[NumBytesInRBSP++] } } |
(2)RBSP(raw byte sequence payload,原始字节序列载荷)是封装于网络抽象单元中的数据。RBSP共分视频编码数据和控制数据两种,其算法可以应用到不同的对象,主要有序列参数集(Sequence parameter set)的RBSP、序列参数集扩展的RBSP、图像参数集(Picture parameter set)的RBSP、辅助增强信息(Supplemental enhancement information)的RBSP、访问单元分隔符(Slice data partition)的RBSP、填充数据的RBSP、没有分割的条带层的RBSP、条带数据分割块A的RBSP、条带数据分割块B的RBSP、条带数据分割块C的RBSP、条带尾比特的RBSP、尾比特(End of stream)的RBSP。
1序列参数集RBSP 语法如下:
seq_parameter_set_rbsp() { constraint_set0_flag constraint_set1_flag
_flag[i]) if(i<6) scaling_list(ScalingList4x4[i],16, UseDefaultScalingMatrix4x4Flag[i]) else scaling_list( ScalingList8x8[i-6],64, UseDefaultScalingMatrix8x8Flag[i-6]) }//for }//if(profile_idc log2_max_frame_num_minus4/*可以通过计算得到变量MaxFrameNum 的值*/ pic_order_cnt_type/*指解码图像顺序的计数方法*/ if(pic_order_cnt_type==0) log2_max_pic_order_cnt_lsb_minus4/*通过计算得到图像顺序数解码过程中的变量 MaxPicOrderCntLsb的值,log2_max_pic_order_cnt_lsb_minus4的 取值在0到12之间*/ else if(pic_order_cnt_type==1) { delta_pic_order_always_zero_flag/* 指示视频序列的条带头中是否有delta_pic_order_cnt[ 0 ] 和delta_pic_order_cnt[ 1 ] 两个字段*/ offset_for_non_ref_pic/*通过计算得到非参考图像的图像顺序号*/ offset_for_top_to_bottom_field/*通过计算得到一个帧的底场的图像顺序号*/ num_ref_frames_in_pic_order_cnt_cycle/*指示图像顺序号的解码过程*/ for(i=0;i<num_ref_frames_in_pic_order_cnt_cycle;i++) offset_for_ref_frame[i]/* 的图像顺序号的解码过程中使用的一个num_ref_frames_in_ pic_order_cnt_cycle值的列表中的一个元素*/ }//else if num_ref_frames/* 了可能在视频序列中任何图像帧间预测的解码过程中用到的短期参考帧和长期参考 帧、互补参考场对以及不成对的参考场的最大数量*/ gaps_in_frame_num_value_allowed_flag/*指示frame_num 的允许值及解码过程*/ pic_width_in_mbs_minus1/*指示以宏块为单元的每个解码图像的宽度*/ pic_height_in_map_units_minus1/*指示以条带组映射为单位的一个解码帧或场的高度*/ frame_mbs_only_flag/* 如果值为零,表示编码视频序列的编码图像可能是编码场或编码帧,如果值为, 1表示编码视频序列的每个编码图像都是一个仅包含帧宏块的编码帧*/ if(!frame_mbs_only_flag) mb_adaptive_frame_field_flag/*指示在一个图像的帧和场宏块之间是否有交换*/ direct_8x8_inference_flag/* 指示B_Skip、B_Direct_16x16和B_Direct_8x8亮度运动矢量 的计算过程使用的方法*/ frame_cropping_flag/* 如果值为1表示帧剪切偏移参数遵从视频序列参数集中的下一个值。 如果值为0表示不存在帧剪切偏移参数。*/ if(frame_cropping_flag) { frame_crop_left_offset/* 指示从解码过程中输出的编码图像序列中的图像样值以帧坐标中的一个 矩阵区域的形式输出*/ frame_crop_right_offset frame_crop_top_offset frame_crop_bottom_offset } vui_parameters_present_flag if(vui_parameters_present_flag) vui_parameters() rbsp_trailing_bits() } |
2缩放比例列表语法如下:
scaling_list(scalingList,sizeOfScalingList,useDefaultScalingMatrixFlag) { lastScale=8 nextScale=8 for(j=0;j<sizeOfScalingList;j++) { if(nextScale!=0) { delta_scale/*指示缩放比例列表中的第j 个元素的值*/ nextScale=(lastScale+delta_scale+256)%256 useDefaultScalingMatrixFlag=(j==0 && nextScale==0) } scalingList[j]=( nextScale = = 0 ) ? lastScale : nextScale lastScale = scalingList[ j ] } }
|
3序列参数集扩展RBSP语法如下:
seq_parameter_set_extension_rbsp() { seq_parameter_set_id/*标识与序列参数集扩展有关的序列参数*/ aux_format_idc/*设置辅助编码图像信息*/ if(aux_format_idc!=0) { bit_depth_aux_minus8/*指示辅助编码图像的样点队列中样值的比特深度*/ alpha_incr_flag/* 值为0表示为alpha 混合的目的,每个解码辅助编码图像样点值的解释样点值等于 解码辅助编码图像样点的值。值为1表示为alpha 混色的目的,在解码辅助编码图 像样点之后,任何大于Min(alpha_opaque_value, alpha_transparent_value ) 的辅助编码图像样点值应加1 以得到辅助编码图像样点的解释样点值,并且任何 小于等于Min(alpha_opaque_value, alpha_transparent_value )的辅助解码图 像样点值应不改变即可使用,像解码辅助编码图像样点值的解释样点值一样*/ alpha_opaque_value/* 指示一个辅助编码图像样点的解释样点值,并且为alpha 混色的目的该解释样点值 的同一个访问单元的相关的亮度和色度样点认为是不透明的*/ alpha_transparent_value/* 表示一个辅助编码图像样点的解释样点值,并且为alpha 混色的目的该解释样点值 的同一个访问单元的相关的亮度和色度样点认为是透明的*/ } additional_extension_flag/* 等于0表示在RBSP拖尾比特之前的视频序列参数集扩展语法结构中没有跟随额外 的数据。变量additional_extension_flag 的值应等于0。*/ rbsp_trailing_bits() } |
4图像参数集RBSP语法如下:
pic_parameter_set_rbsp() { pic_parameter_set_id/*指示在条带头中提到的图像参数*/ seq_parameter_set_id/*指示活动的序列参数集*/ entropy_coding_mode_flag/*用于选取语法元素的熵编码方式*/ pic_order_present_flag/*指示与图像顺序数有关的语法元素是否出现于条带头中*/ num_slice_groups_minus1/*加1表示一个图像中的条带组数*/ if(num_slice_groups_minus1>0) { slice_group_map_type/* 表示条带组中条带组映射单元的映射是如何编码的,数值为0,表示隔行扫描带组; 数值为1表示分散的条带组映射;数值为2表示一个或多个前景条带组和一个残余条 带组;数值为3、4和5表示变换条带组数值为6表示每个条带组映射单元清楚地分配 一个条带组*/ if(slice_group_map_type==0) for(iGroup=0;iGroup<=num_slice_groups_minus1;iGroup++) run_length_minus1[iGroup]/* 用来指定条带组映射单元的光栅扫描顺序中分配给第i 个条带组的连续条 带组映射单元的数目。*/ else if(slice_group_map_type== 2 ) for(iGroup=0;iGroup<num_slice_groups_minus1;iGroup++) { top_left[iGroup]//表示一个矩形的左上角 bottom_right[ iGroup ]//表示一个矩形的右下角 } else if(slice_group_map_type==3||slice_group_map_type==4|| slice_group_map_type==5 ) { slice_group_change_direction_flag/* 与 slice_group_map_type 一起用来表示当slice_group_map_type的值为 3、4或5时精确的映射类型*/ slice_group_change_rate_minus1/* 设置一个条带组的大小从一个图像到下一个的改变的倍数 以条带组映射单元为单位*/ } else if( slice_group_map_type = = 6 ) { pic_size_in_map_units_minus1//用来指定图像中的条带组映射单元数 for(i=0;i<=pic_size_in_map_units_minus1;i++) slice_group_id[ i ]/* 指示光栅扫描顺序中的第i 个条带组映射单元的一个条带组*/ } } num_ref_idx_l0_active_minus1/*指示参考图像列表0 的最大参考索引号*/ num_ref_idx_l1_active_minus1/*同num_ref_idx_l0_active_minus1*/ weighted_pred_flag/* 值为0表示加权的预测不应用于P和SP条带。值为1表示在P和SP 条带中应使用加权的预测*/ weighted_bipred_idc/*值为0表示B条带应该采用默认的加权预测。值1表示B条带应 该采用具体指明的加权预测。值为2表示B 条带应该采用隐含的加权预测*/ pic_init_qp_minus26/*表示每个条带的SliceQPY 初始值减26*/ pic_init_qs_minus26/*表示在SP或SI条带中的所有宏块的SliceQSY初始值减26*/ chroma_qp_index_offset/* 表示为在QPC 值的表格中寻找Cb色度分量而应加到参数QPY 和 QSY 上的偏移*/ deblocking_filter_control_present_flag/* 值为1表示控制去块效应滤波器的特征的一组语法元素将出现在条带头中。 值为0 表示控制去块效应滤波器的特征的一组语法元素不会出现在条 带头中,并且它们的推定值将会生效*/ constrained_intra_pred_flag/* 值为0表示帧内预测允许使用残余数据,且使用帧内宏块预测模式编码的宏块 的预测可以使用帧间宏块预测模式编码的相邻宏块的解码样值。值为1表示受 限制的帧内预测,在这种情况下,使用帧内宏块预测模式编码的宏块的预测仅 使用残余数据和来自I或SI宏块类型的解码样值。*/ redundant_pic_cnt_present_flag/* 值为0表示redundant_pic_cnt 语法元素不会在条带头、图像参数集中指明 (直接或与相应的数据分割块A关联)的数据分割块B和数据分割块C中出现。 1表示redundant_pic_cnt 语法元素将出现在条带头、图像参数集中指明 (直接或与相应的数据分割块A关联)的数据分割块B和数据分割块C中。*/ if(more_rbsp_data()) { transform_8x8_mode_flag/* 值为1表示8x8 变换解码过程可能正在使用 值为0表示未使用8x8变换解码过程。*/ pic_scaling_matrix_present_flag/* 值为1表示存在用来修改在序列参数集中指定的缩放比例列表的参数。 值为0表示用于该图像中的缩放比例列表应等于那些由序列参数集规定的*/ if(pic_scaling_matrix_present_flag) for(i=0;i<6+2*transform_8x8_mode_flag;i++) { pic_scaling_list_present_flag[i]/* 值为1表示存在缩放比例列表的语法结构并用于指定序号为i 的缩放比例列 表。值为0表示在图像参数集中不存在缩放比例列表,需要根据seq_scaling_ matrix_present_flag的值获取级缩放比例列表*/ if(pic_scaling_list_present_flag[i]) if(i<6) scaling_list(ScalingList4x4[i],16, UseDefaultScalingMatrix4x4Flag[i]) else scaling_list(ScalingList8x8[i-6],64, UseDefaultScalingMatrix8x8Flag[i-6]) }//for second_chroma_qp_index_offset/* 表示为在QPC 值的表格中寻找Cr色度分量而应加到参数QPY和QSY 上的偏移*/ }//if(more_rbsp_data rbsp_trailing_bits( ) } |
5辅助增强信息RBSP语法如下:
sei_rbsp() { do sei_message() while(more_rbsp_data()) rbsp_trailing_bits() } |
6辅助增强信息消息语法如下:
sei_message() { payloadType = 0 while(next_bits(8)==0xFF) { ff_byte payloadType+=255 } last_payload_type_byte/*指示一个SEI消息的载荷类型的最后一个字节*/ payloadType+=last_payload_type_byte payloadSize=0 while(next_bits(8)==0xFF) { ff_byte payloadSize+=255 } last_payload_size_byte/*指示一个SEI消息大小的最后一个字节*/ payloadSize+=last_payload_size_byte sei_payload(payloadType, payloadSize) }
|
7访问单元分隔符RBSP语法如下:
access_unit_delimiter_rbsp() { primary_pic_type/* 指示通过基本编码图像所有条带的slice_type值得到primary_pic_type值*/ rbsp_trailing_bits( ) }
|
8填充数据RBSP语法如下:
filler_data_rbsp() { while(next_bits(8)==0xFF) ff_byte rbsp_trailing_bits() } |
9没有分割的条带层RBSP语法如下:
slice_layer_without_partitioning_rbsp() { slice_header() slice_data() rbsp_slice_trailing_bits() }
|
10条带数据分割块ARBSP语法如下:
slice_data_partition_a_layer_rbsp() { slice_header() slice_id/*标识与数据分割有关的条带*/ slice_data() rbsp_slice_trailing_bits() }
|
11条带数据分割块BRBSP语法如下:
slice_data_partition_b_layer_rbsp() { slice_id if(redundant_pic_cnt_present_flag) redundant_pic_cnt/*对于那些属于基本编码图像的条带和条带数据分割块 应等于0。在冗余编码图像中的编码条带和编码条带数 据分割块的redundant_pic_cnt 的值应大于0。*/ slice_data() rbsp_slice_trailing_bits() } |
12条带数据分割块CRBSP语法如下:
slice_data_partition_c_layer_rbsp() { slice_id if(redundant_pic_cnt_present_flag) redundant_pic_cnt slice_data() rbsp_slice_trailing_bits() } |
13条带尾比特RBSP语法如下:
rbsp_slice_trailing_bits() { rbsp_trailing_bits() if(entropy_coding_mode_flag) while(more_rbsp_trailing_data()) cabac_zero_word/*值是两个等于0x0000的字节的排列*/ } |
14尾比特RBSP语法如下
rbsp_trailing_bits() { rbsp_stop_one_bit/*值应等于1*/ while(!byte_aligned()) rbsp_alignment_zero_bit/*值应等于0*/ } |
(3)SEI是H264标准中一个重要的技术,它主要起补充和增强的作用。它的主要组成部分在上一节已经讲到,下面对各部分的码表进行介绍。
1缓冲周期SEI消息语法如下:
buffering_period(payloadSize) { seq_parameter_set_id/* 表示序列参数集标号,包含序列HRD属性。seq_parameter_set_id的值应与一个主编码 图像引用的图像参数组中的seq_parameter_set_id 的值相等,该主编码图像是与本缓 冲周期SEI 消息相关联的,取值范围在0到31之间*/ if(NalHrdBpPresentFlag) { for(SchedSelIdx=0;SchedSelIdx<=cpb_cnt_minus1;SchedSelIdx++) { initial_cpb_removal_delay[SchedSelIdx]/* 表示在HRD 初始化后的第一个缓冲周期, 第SchedSelIdx 个CPB的时间延迟,这个延迟是从与该缓冲周期SEI 消息相关联的 访问单元中的编码数据的第一个比特到达,到其数据从CPB 中删除的时间间隔*/ initial_cpb_removal_delay_offset[SchedSelIdx]/* 与initial_cpb_removal_ delay[SchedSelIdx]组合用于第SchedSelIdx 个CPB ,表示对CPB的编码 访问单元的初始发送时间。它的语法元素是一个定长码,其比特长度由 initial_cpb_removal_delay_length_minus1+1决定*/ } } if(VclHrdBpPresentFlag) { for(SchedSelIdx=0;SchedSelIdx<=cpb_cnt_minus1; SchedSelIdx++) { initial_cpb_removal_delay[SchedSelIdx] initial_cpb_removal_delay_offset[SchedSelIdx] } } } |
2图像定时SEI消息语法如下:
pic_timing(payloadSize) { if(CpbDpbDelaysPresentFlag) { cpb_removal_delay/* 表示从CPB中删除与最近的一个缓冲周期SEI消息相关的访问单元以后, 到与图像定时SEI 消息相关的访问单元被删除为止,等待的时钟跳动数。 该值还用来计算对HSS 来说进入CPB 的访问单元数据最早可能的到达时 间。它的语法元素是一个定长码,其长度由cpb_removal_delay_length_ minus1 + 1决定*/ dpb_output_delay/*用于计算图像的DPB 输出时间。它表示,从访问单元自 CPB 删除至解码图像自DPB 输出需要等待的时钟记录数*/ } if(pic_struct_present_flag) { pic_struct/*表示一幅图像应显示为一帧还是一场或更多场*/ for(i=0;i<NumClockTS;i++) /* NumClockTS是由pic_struct决定的。对一幅图像,最多可以有NumClockTS 组时戳信息,每组由clock_timestamp_flag[ i ]标识。时戳信息组根据 pic_struct的内容用于关联图像的对应场或帧。*/ { clock_timestamp_flag[i]/* 值为1时表示随后马上有很多时戳语法元素出现。值为0时表示不存 在相关联的时间戳语法元素*/ if(clock_timestamp_flag[i]) { ct_type/*表示源资料的扫描类型*/ nuit_field_based_flag/*计算clockTimestamp的值*/ counting_type/*表示n_frames的值丢弃的方法*/ full_timestamp_flag/*等于1时表示n_frames语法元素后面有 seconds_value,minutes_value,和hours_value。等于0时 表示n_frames语法元素后面只有seconds_flag*/ discontinuity_flag/* 等于0 时表示clockTimestamp 的当前值与按照输出顺序其 前一个时戳计算得到的clockTimestamp 的值的差异,可以 解释为源时间与拍摄关联的帧或场时间之间的时差。 discontinuity_flag 等于1时表示不能做上述解释。 当discontinuity_flag等于0时,clockTimestamp的值应该大 于等于按DPB输出顺序其前图像的所有存在的clockTimestamp值*/ cnt_dropped_flag/* 表示依据counting_type说明的计算方式丢弃n_frames中的一个 或几个值*/ n_frames/*用于计算clockTimestamp的nFrames的值*/ if(full_timestamp_flag){ seconds_value minutes_value hours_value }else{ seconds_flag/* 等于1时表示如果full_timestamp_flag 等于0,seconds_value 和minutes_flag存在。等于0时表示seconds_value 和minutes_flag不存在。*/ if(seconds_flag) { seconds_value minutes_flag/* 表示用于计算clockTimestamp 的sS 值。seconds_value 的值应在0 到59 的范围内。当seconds_value不存在时, 用解码顺序中前一个seconds_value作为sS的值计算 clockTimestamp*/ if(minutes_flag) { minutes_value/* 表示用于计算clockTimestamp 的mM 值。minutes_value 的值应在0 到59 的范围内。当minutes_value不存在时, 用解码顺序中前一个minutes_value作为mM的值 计算clockTimestamp*/ hours_flag/* 等于1时表示如果full_timestamp_flag等于0 且seconds_flag 和minutes_flag 等于 1,hours_value存在*/ if(hours_flag) hours_value/* 表示用于计算clockTimestamp的hH值。hours_value 的值应在0到23的范围内。当hours_value不存在时, 用解码顺序中前一个hours_value作为hH的值计算 clockTimestamp*/ }//if(minutes_flag) }//if(seconds_flag) }//else if(time_offset_length>0) time_offset }//if(clock_timestamp_flag[i]) }//for }//if(pic_struct_present_flag) } |
3泛扫描矩形 SEI 消息语法如下:
Pan_scan_rect(payloadSize) { pan_scan_rect_id/* 包含一个识别号码,用于表示泛扫描矩形的用途(例如表示该矩形是在特定显示 设备上放映的区域,或是含有场景中的特定角色的区域)。用于应用决定的场景*/ pan_scan_rect_cancel_flag/* 等于1 时表示本SEI 消息取消输出顺序中所有在前的泛扫描矩形SEI 消息的存 留。pan_scan_rect_cancel_flag等于0时表示随后是泛扫描矩形信息*/ if(!pan_scan_rect_cancel_flag) { pan_scan_cnt_minus1/* 表示SEI 消息中出现的泛扫描矩形的数量。pan_scan_cnt_minus1 的值应 在0 至2 之间。pan_scan_cnt_minus1等于0表示一个泛扫描矩形用于解码 图像的所有场。pan_scan_cnt_minus1等于1表示有两个泛扫描矩形,第一个 用于输出顺序上图像的第一场,第二个用于输出顺序上图像的第二场。 pan_scan_cnt_minus1等于2表示有三个泛扫描矩形,第一个用于输出顺序上 图像的第一场,第二个用于输出顺序上图像的第二场,第三个重复第一个 用于输出顺序上图像的第三场*/ for(i=0;i<= pan_scan_cnt_minus1;i++) { pan_scan_rect_left_offset[i]/* 表示泛扫描矩形位置的有符号整数值,单位是相对于亮度采样格栅 的1/16 采样间隔*/ pan_scan_rect_right_offset[i] pan_scan_rect_top_offset[i] pan_scan_rect_bottom_offset[i] } pan_scan_rect_repetition_period/* 表示泛扫描矩形SEI 消息的持续性,还可以指定一个图像顺序计数间隔, 在此间隔后,比特流中出现另一个具有相同pan_scan_rect_id 值的泛扫 描矩形SEI 消息,或者到达视频编码序列的末尾。pan_scan_rect_ repetition_period 的值应在0 到16384 的范围内。如果pan_scan_ cnt_minus1 的值大于0,pan_scan_rect_repetition_period的值不能大于1*/ }//if(!pan_scan_rect_cancel_flag) } |
4填充载荷SEI 消息语法如下:
filler_payload(payloadSize) { for(k=0;k<payloadSize;k++) ff_byte/*值为0xFF的字节*/ } |
5ITU-T T.35建议书登记的用户数据的SEI 消息语法如下:
user_data_registered_itu_t_t35(payloadSize) { itu_t_t35_country_code if(itu_t_t35_country_code!=0xFF) i=1 else { Itu_t_t35_country_code_extension_byte i = 2 } do{ itu_t_t35_payload_byte i++ }while(i<payloadSize) }
|
6用户数据未注册SEI语法如下:
User_data_unregistered(payloadSize) { uuid_iso_iec_11578/*应有一个由UUID指定的值*/ for(i=16;i<payloadSize;i++) user_data_payload_byte/* 应为一个字节的数据,其语法和语义由UUID生成器指明*/ } |
7恢复点SEI 消息语法如下:
recovery_point(payloadSize) { recovery_frame_cnt/* 指定输出图像在输出顺序中的恢复点。从参考图像的输出位置以后, 所有输出顺序中的解码图像的内容是正确的或大致正确的,参考图 像的frame_num 等于当前访问单元的VCL NAL 单元的frame_num 加 上recovery_frame_cnt 再对MaxFrameNum 取模运算。recovery_ frame_cnt 的值在0 到MaxFrameNum -1的范围内*/ exact_match_flag/* 表示在与恢复点SEI 消息关联的访问单元处开始的解码过程输出的特 定恢复点之后的解码图像,是否应该是一个与NAL单元流中的前一个 IDR访问单元位置处开始的解码过程生成的图像精确匹配的图像。 值为0表示不一定精确匹配,为1表示精确匹配。*/ broken_link_flag/*表示在恢复点SEI消息处NAL单元流的链接是否出现中断*/ changing_slice_group_idc/* 等于0 表示当主编码图像的所有宏块在变换条带组周期内,也就是从恢 复点SEI消息关联的访问单元到指定恢复点期间被解码时,在输出顺序中 恢复点以后解码图像内容正确或大致正确。当变换条带组周期内任一主 编码图像的num_slice_groups_minus1等于0时, changing_slice_group_idc应等于0*/ } |
8解码参考图像标记重复SEI 消息语法如下:
dec_ref_pic_marking_repetition(payloadSize) { original_idr_flag /* 当解码参考图像标记语法结构最初在一幅IDR 图像中出现时应等于1。 当解码参考图像标记语法结构最初在一幅非IDR图像中出现时, original_idr_flag应等于0。*/ original_frame_num/* 应等于重复的解码参考图像标记语法结构最初出现所属的图像的 frame_num。由original_frame_num 指示的图像是具有指定 frame_num 值的前一幅编码图像。memory_management_control_operation 等于5的图像的original_frame_num的值通常应为0*/ if(!frame_mbs_only_flag) { original_field_pic_flag/* 应等于重复的解码参考图像标记语法结构最初出现所属的图像的field_pic_flag*/ if(original_field_pic_flag) original_bottom_field_flag/* 应等于重复的解码参考图像标记语法结构最初出现所属的图像的 bottom_field_flag*/ } dec_ref_pic_marking()/* 应包含frame_num 为original_frame_num 的图像的解码参考图像标记语法结构的拷 贝。用于规范重复的 dec_ref_pic_marking( ) 语法结构的nal_unit_type应是 frame_num 为original_frame_num的图像的slice header(s)的nal_unit_type*/ } |
9备用图像SEI消息语法如下:
spare_pic(payloadSize) { target_frame_num/*表示目标图像的frame_num*/ spare_field_flag/* 等于0表示目标图像和备用图像是解码帧。spare_field_flag等于1表示目标 图像和备用图像是解码场。*/ if(spare_field_flag) target_bottom_field_flag/*等于0表示目标图像是顶场。 target_bottom_field_flag表示目标图像是底场*/ num_spare_pics_minus1/*表示指定目标图像的备用图像数量。备用图像数等于 num_spare_pics_minus1 + 1。num_spare_pics_minus1 的取值范围是0到15*/ for(i=0;i<num_spare_pics_minus1+1;i++) { delta_spare_frame_num[i]/*指示包含第i 套备用条带组映射单元的备用图像*/ if(spare_field_flag) spare_bottom_field_flag[i]/* 等于0表示第i幅备用图像是顶场。spare_bottom_field_flag[i]等于 1表示第i幅备用图像是底场*/ spare_area_idc[i]/* 表示用来标识在第i 幅备用图像中备用条带组映射单元的方法。 spare_area_idc[i]等于0 表示第i 幅备用图像中的所有条带组映射 单元是备用单元。spare_area_idc[i]等于1 表示用语法元素 spare_unit_flag[i][j]的值标识备用条带组映射单元。 spare_area_idc[i]等于2表示用语法元素zero_run_length[i][j] 导出spareUnitFlagInBoxOutOrder[i][j]*/ if(spare_area_idc[i]==1) for(j=0;j<PicSizeInMapUnits;j++) spare_unit_flag[i][j]/* 等于0 表示第i 幅备用图像的光栅扫描顺序中的第j 个条带 组映射单元是备用单元。spare_unit_flag[i][j]等于1表示 第i幅备用图像的光栅扫描顺序中的第j个条带组映射单元不是 备用单元*/ else if(spare_area_idc[i]==2) { mapUnitCnt = 0 for(j=0;mapUnitCnt<PicSizeInMapUnits;j++) { zero_run_length[i][j]/*在spare_area_idc[i]等于2时用于 导出spareUnitFlagInBoxOutOrder[i][j]的值 mapUnitCnt+=zero_run_length[i][j]+1*/ }//for }//else }//for } |
10场景信息SEI 语法如下:
scene_info(payloadSize) { scene_info_present_flag/* 等于0 表示目标图像所属的场景或场景转换未指定。 scene_info_present_flag 等于1表示目标图像属于同一个场景或场景变换*/ if(scene_info_present_flag) { scene_id 5/*标识目标图像所属的场景*/ scene_transition_type if(scene_transition_type>3) second_scene_id/* 指定目标图像涉及的场景变换(如果存在)的类型*/ } }
|
11子序列信息SEI消息语法如下:
sub_seq_info(payloadSize) { sub_seq_layer_num/* 指明当前图像的子序列层编号,当sub_seq_layer_num 大于0 时,内存管理 控制操作不可以在当前图像的任一条带头中使用。在当前图像属于一个子序 列,该子序列在输出顺序中的第一幅图像是一幅IDR 图像时,sub_seq_layer_ num 应等于0。对一个不成对的参考场,sub_seq_layer_num 应等于0。*/ sub_seq_id/* 指明一个层内的子序列。在当前图像属于一个子序列,该子序列的第一幅图像 是一幅IDR 图像时,sub_seq_id的值应等于IDR图像的idr_pic_id值*/ first_ref_pic_flag/* 等于1 表示当前图像是子序列在解码顺序中的第一幅参考图像。在当前图像 不是子序列在解码顺序中的第一幅参考图像时,first_ref_pic_flag应等于0*/ leading_non_ref_pic_flag/* 等于1表示当前图像是子序列的任一参考图像在解码顺序中的前一幅非参考图像或 者子序列没有参考图像。在当前图像是一幅参考图像或当前图像是子序列的至少 一幅参考图像之后的非参考图像时,leading_non_ref_pic_flag应等于0。*/ last_pic_flag/* 等于1 表示当前图像是子序列在解码顺序中,包括所有参考图像和非参考图像的最 后一幅图像*/ sub_seq_frame_num_flag/* 等于0 表示sub_seq_frame_num 不存在。sub_seq_frame_num_flag 等于1 表示 sub_seq_frame_num存在*/ if(sub_seq_frame_num_flag) sub_seq_frame_num/* 对一个子序列输出顺序中的第一幅参考图像和其后的所有非参考图像应等于0*/ } |
12子序列层特性SEI 消息语法如下:
sub_seq_layer_characteristics(payloadSize) { num_sub_seq_layers_minus1/*加1表示在本序列中的子序列层的编号*/ for(layer=0;layer<=num_sub_seq_layers_minus1;layer++) { accurate_statistics_flag/* 等于1 表示average_bit_rate 和average_frame_rate 的值是统计修正值的舍入。 accurate_statistics_flag等于0表示average_bit_rate和 average_frame_rate的 值是估计值,可能与修正值有些偏差。*/ average_bit_rate/*表示以每秒1000 比特为单位的比特速率*/ average_frame_rate/*表示以帧数/(256秒)为单位的目标子序列的平均帧率*/ } } |
13子序列特性SEI消息语法如下:
sub_seq_characteristics(payloadSize) { sub_seq_layer_num/*指明当前图像的子序列层编号*/ sub_seq_id/*标识目标子序列*/ duration_flag/*等于0表示目标子序列的持续时*/ if(duration_flag) sub_seq_duration/* 表示以90kHz时钟的时钟记录数为单位的目标子序列的持续时间*/ average_rate_flag/*等于0表示目标子序列的平均比特率和平均帧率*/ if(average_rate_flag) { accurate_statistics_flag/* 表示average_bit_rate 和average_frame_rate 的数值的可信度*/ average_bit_rate/*表示以每秒1000 比特为单位的比特速率*/ average_frame_rate/*表示以帧数/(256秒)为单位的目标子序列的平均帧率*/ } num_referenced_subseqs/* 表示包含用于对目标子序列中图像进行内部预测的参考图像的子序列的数量*/ for(n=0;n<num_referenced_subseqs;n++) { ref_sub_seq_layer_num/* 包含用于对目标子序列中图像进行 内部预测的参考图像的子序列*/ ref_sub_seq_id// ref_sub_seq_direction// } } |
14运动受限条带组集SEI消息语法如下:
motion_constrained_slice_group_set(payloadSize) { num_slice_groups_in_set_minus1/*加1 表示条带组集中条带组的数目*/ for(i=0;i<=num_slice_groups_in_set_minus1;i++) slice_group_id[i]/*标识条带组集中的条带组*/ exact_sample_value_match_flag /* 等于0表示,目标图像组内,如果不属于条带组集的宏块未被解码,条带组 集里的每个样点的值不一定严格地与所有宏块被解码后的样值相同。 exact_sample_value_match_flag 等于1 表示,目标图像组内,如果不属于 条带组集的宏块未被解码,条带组集里的每个样点的值应严格地与所有宏块被解 码后的样值相同*/ pan_scan_rect_flag/* 等于0表示pan_scan_rect_id不存在。pan_scan_rect_flag等于1表示 pan_scan_rect_id存在*/ if(pan_scan_rect_flag) pan_scan_rect_id/* 表示指定的条带组集至少覆盖目标图像集内pan_scan_rect_id标示的泛扫描矩形*/ }
|
15胶片颗粒特性SEI消息语法如下:
film_grain_characteristics(payloadSize) { film_grain_characteristics_cancel_flag/* 值为1表示本SEI消息取消输出顺序中之前的胶片颗粒特征SEI消息 的作用。值为0表示其后是胶片颗粒模型信息*/ if(!film_grain_characteristics_cancel_flag) { model_id/*标识胶片颗粒仿真模型*/ separate_colour_description_present_flag/* 值为1表示胶片颗粒特征SEI消息语法结构中存在描述明确的颜色 空间的胶片颗粒特征。值为0表示SEI消息中的胶片颗粒特征的颜色描述 与视频编码序列相同*/ if(separate_colour_description_present_flag) { film_grain_bit_depth_luma_minus8/* 加8 表示在本SEI 消息中用于规定胶片颗粒特征的亮度部分的比特深度*/ film_grain_bit_depth_chroma_minus8/* 加8表示在本SEI消息中用于规定胶片颗粒特征的Cb和Cr部分的比特深度*/ film_grain_full_range_flag//有相同的 film_grain_colour_primaries//有相同的 film_grain_transfer_characteristics //有相同的 film_grain_matrix_coefficients//有相同的 }//if(separate_colour blending_mode_id/*表示将模拟胶片颗粒与解码图像混合的方式*/ log2_scale_factor/*表示用于胶片颗粒特征方程的比例因子*/ for(c=0;c<3;c++) comp_model_present_flag[c]/* 值位0表示胶片颗粒不由第c个颜色部分模拟,c等于0指亮度部分, c等于1指Cb部分,c等于2指Cr部分。值为1表示本SEI消息中存在 为胶片颗粒的第c个颜色部分模拟的语法元素。*/ for(c=0;c<3;c++) if(comp_model_present_flag[c]) { num_intensity_intervals_minus1[c]/* 加1表示对估计的特定的一组模型值的强度间隔的数量*/ num_model_values_minus1[c]/* 加1 表示每个强度间隔中模拟的胶片颗粒出现的模拟值的数量*/ for(i=0;i<=num_intensity_intervals_minus1[c];i++) { intensity_interval_lower_bound[c][i]/* 表示对模拟值组应用的强度级别的间隔i的下限*/ intensity_interval_upper_bound[c][i]/* 表示对模拟值组应用的强度级别的间隔i的上限*/ for(j=0;j<=num_model_values_minus1[c];j++) comp_model_value[c][i][j]/* 表示对颜色部分c和强度间隔i的各个模拟值*/ }//for(i }//if(comp_model_present_flag film_grain_characteristics_repetition_period/* 表示胶片颗粒特征SEI 消息的持续时间,还可以表示一个图像 顺序计数间隔,在其间比特流中出现另一个胶片颗粒特征SEI 消息或视频编码序列结束。*/ }//if(!film_grain_characteristics_cancel_flag) } |
16去块效应滤波器显示优选项SEI消息语法如下:
deblocking_filter_display_preference(payloadSize) { deblocking_display_preference_cancel_flag/* 值为1表示本SEI 消息取消输出顺序中之前的去块效应滤波器显 示参考SEI消息的作用。值为0表示其后有display_prior_to_deblocking_ preferred_flag和deblocking_display_preference_repetition_period*/ if(!deblocking_display_preference_cancel_flag) { display_prior_to_deblocking_preferred_flag/* 指示每幅裁剪输出图像在编码的显示过程中是否使用 去块效应滤波器前图像构建方法的裁剪结果*/ dec_frame_buffering_constraint_flag/* 指示是否对max_dec_frame_buffering 规定的HRD 解码图像缓冲区 (DPB)的帧缓存容量的限制*/ deblocking_display_preference_repetition_period/* 表示去块效应滤波器显示参考SEI 消息的持续时间,还可以表示一个 图像顺序计数间隔,在其间比特流中出现另一个去块效应滤波器显示 参考SEI 消息或视频编码序列结束*/ } } |
17立体视频信息SEI 消息语法如下:
stereo_video_info(payloadSize) { field_views_flag/* 值为1表示当前视频编码序列中的所有图像是场图像,某个特定奇偶性的所有 场是立体视觉内容的左视图,相对奇偶性的所有场是右视图。值为0 示当前 视频编码序列中的所有图像是帧图像,在输出顺序中交替出现的帧各自代表 立体视觉的一个视图。field_views_flag 的值在一个视频编码序列的所有 立体视频信息SEI消息中应相同*/ if(field_views_flag) top_field_is_left_view_flag/* 值为1表示视频编码序列中的顶场代表左视图而底场代表右视图。 值为0表示视频编码序列中的底场代表左视图而顶场代表右视图。如果存在, 在一个视频编码序列中所有立体视频信息SEI消息的 top_field_is_left_view_flag的值应相同*/ else { current_frame_is_left_view_flag/* 值为1表示当前图像是立体视频对的左视图 值为0表示当前图像是立体视频对的右视图*/ next_frame_is_second_view_flag/* 值为1表示当前图像和输出顺序中它的下一幅图像组成一个立体视频对,当前 图像的显示时间应延迟以与其下一幅图像保持一致。值为0 表示当前图像和输 出顺序中它的上一幅图像组成一个立体视频对,当前图像的显示时间不因立体 视频对的原因而延迟*/ } left_view_self_contained_flag/* 值为1表示对视频编码序列中左视图图像的解码过程没有参考右视图图像的内 部预测。值为0表示对视频编码序列中左视图图像的解码过程可能有一些 (也可能没有)参考右视图图像的内部预测。在一个视频编码序列中所有 立体视频信息SEI 消息的left_view_self_contained_flag的值应相同*/ right_view_self_contained_flag/* 值为1表示对视频编码序列中右视图图像的解码过程没有参考左视图图像的 内部预测。值为0表示对视频编码序列中右视图图像的解码过程可能有一些 (也可能没有)参考左视图图像的内部预测。在一个视频编码序列中所有立 体视频信息SEI 消息的right_view_self_contained_flag的值应相同*/ } |
下面介绍H.264关于图像方面的码表。
条带头码表
slice_header( ) { first_mb_in_slice slice_type pic_parameter_set_id frame_num if(!frame_mbs_only_flag) { field_pic_flag if(field_pic_flag) bottom_field_flag } if(nal_unit_type==5) idr_pic_id if(pic_order_cnt_type==0) { pic_order_cnt_lsb if(pic_order_present_flag && !field_pic_flag) delta_pic_order_cnt_bottom } if(pic_order_cnt_type==1 && !delta_pic_order_always_zero_flag) { delta_pic_order_cnt[0] if(pic_order_present_flag && !field_pic_flag) delta_pic_order_cnt[1] } if(redundant_pic_cnt_present_flag) redundant_pic_cnt if(slice_type==B) direct_spatial_mv_pred_flag if(slice_type==P || slice_type==SP || slice_type==B) { num_ref_idx_active_override_flag if(num_ref_idx_active_override_flag) { num_ref_idx_l0_active_minus1 if(slice_type==B) num_ref_idx_l1_active_minus1 } } ref_pic_list_reordering( ) if((weighted_pred_flag && (slice_type==P || slice_type==SP)) || (weighted_bipred_idc==1 && slice_type==B)) pred_weight_table( ) if(nal_ref_idc!=0) dec_ref_pic_marking( ) if(entropy_coding_mode_flag && slice_type != I && slice_type != SI) cabac_init_idc slice_qp_delta if(slice_type==SP || slice_type==SI) { if(slice_type==SP) sp_for_switch_flag slice_qs_delta } if(deblocking_filter_control_present_flag) { disable_deblocking_filter_idc if(disable_deblocking_filter_idc != 1) { slice_alpha_c0_offset_div2 slice_beta_offset_div2 } } if(num_slice_groups_minus1 > 0 && slice_group_map_type >= 3 && slice_group_map_type <= 5) slice_group_change_cycle } |
参考图像列表重排序码表
ref_pic_list_reordering( ) { if(slice_type != I && slice_type != SI) { ref_pic_list_reordering_flag_l0 if(ref_pic_list_reordering_flag_l0) do{ reordering_of_pic_nums_idc if(reordering_of_pic_nums_idc==0 || reordering_of_pic_nums_idc==1) abs_diff_pic_num_minus1 else if(reordering_of_pic_nums_idc==2) long_term_pic_num }while( reordering_of_pic_nums_idc != 3 ) } if(slice_type==B) { ref_pic_list_reordering_flag_l1 if(ref_pic_list_reordering_flag_l1) do{ reordering_of_pic_nums_idc if(reordering_of_pic_nums_idc==0 || reordering_of_pic_nums_idc==1) abs_diff_pic_num_minus1 else if(reordering_of_pic_nums_idc==2) long_term_pic_num } while(reordering_of_pic_nums_idc != 3) } } |
解码的参考图像标识码表
dec_ref_pic_marking( ) { if(nal_unit_type==5) { no_output_of_prior_pics_flag long_term_reference_flag } else { adaptive_ref_pic_marking_mode_flag if(adaptive_ref_pic_marking_mode_flag) do{ memory_management_control_operation if(memory_management_control_operation==1 || memory_management_control_operation==3) difference_of_pic_nums_minus1 if(memory_management_control_operation==2) long_term_pic_num if(memory_management_control_operation==3 || memory_management_control_operation==6) long_term_frame_idx if(memory_management_control_operation==4) 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 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 prevMbSkipped=(mb_skip_run>0) for(i=0;i<mb_skip_run;i++) CurrMbAddr=NextMbAddress(CurrMbAddr) moreDataFlag=more_rbsp_data() } else { mb_skip_flag moreDataFlag=!mb_skip_flag } if(moreDataFlag) { if(MbaffFrameFlag && (CurrMbAddr % 2==0 || (CurrMbAddr % 2==1 && prevMbSkipped))) 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) } |
宏块层码表
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 ) 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 mb_pred( mb_type ) 2 } 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() } } } |
宏块预测码表
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 ] 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] 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] } } |
子宏块预测码表
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]
|