1.引言
前面我们学会了指数哥伦布解码,翻翻白皮书,依靠这个知识,基本上我们就能一口气解码完SPS,PPS,SEI,Slice Header了。在Slice Data里会出现一些ae(v)类型的熵编码,这个我们后面再看 。
接下来的重点就是,认真的看一下解码出来的每个参数的作用。这些参数在后续的计算YUV的过程中都会起到对应的作用。
首先,我们从SPS开始。
2. SPS
SPS,即sequence parameter set,序列参数集合。
在H264中,具体的图像数据在宏块中传输,但是这些图像所依赖的一些参数,会被汇总到SPS、PPS中,并被赋予较高的优先级,优先保证这些数据包的完整和准确。
基本的参考流程就是,
宏块参考slice数据,slice参考slice头,slice头参考PPS,PPS依赖SPS。
我们可以依次收到多份SPS数据,并按照SPS id将他们保存下来,在后面的参考过程中,如果有参考SPS的id匹配上的,即可以获取对应的数据。
下面我们来翻到白皮书《Rec. ITU-T H.264 (03/2010)》的43页,章节为7.3.2.1.1 Sequence parameter set data syntax, 如下图:
可以看出来,在白皮书中,不仅把每个参数的格式列出来,连伪代码都写好了,像是if,for等逻辑全都在。如果不是优化效率,只是要实现功能的需求,基本上按照这个流程往下解参数就可以了。
每个参数的解析方法在上一章,指数哥伦布里已经介绍了,本章我们主要介绍一下SPS 中各个参数的作用。
3. 参数解析
- profile_idc: profile 级别,大体分为base,main,extend,high四大类。对应不同的功能组合。包含有没有使用CABAC,有没有使用B帧,YUV的格式等等。
具体对照表格看 这里 的图表.
profile的对应值如下:
profile_idc | 含义 | 重要特征 |
---|---|---|
66 | baseline profile | I/P帧,progressive(无交错),CAVLC |
77 | main profile | I/P/B/SP/SI帧,progressive(无交错) , CAVLC |
88 | extended profile | I/P/B帧,progressive(无交错) + interlaced(交错),CAVLC + CABAC |
100 | High | |
110 | High 10 | |
122 | High 4:2:2 | |
144 | High 4:4:4 |
-
constraint_set0_flag:强制使用Baseline profile进行编码
-
constraint_set1_flag:强制使用Main profile进行编码
-
constraint_set2_flag:强制使用Extended profile进行编码
-
constraint_set3_flag:配合profile_idc一起控制一些功能的开关
-
constraint_set4_flag:配合profile_idc一起控制一些功能的开关
-
constraint_set5_flag :配合profile_idc一起控制一些功能的开关
-
level_idc:level级别,告知解码器当前码流所需要的资源级别,比如size,帧率在一个什么级别。个人感觉是用于解码器预先分配解码资源(比如开多少内存,开多少线程等等)。
部分级别说明如下:
-
seq_parameter_set_id:本组SPS的id,范围[0,31],用于PPS索引到这组参数。
-
chroma_format_idc :YUV格式,范围[0,3],默认1:yuv420。只有profile达到High422,High444,才支持YUV422和YUV444的格式。
如下表,从左往右依次是:baseline, extend,mail,high,high10, high422,high444
-
separate_colour_plane_flag:针对YUV444使用,把Y,U,V当做三个独立的图像进行编码。
chroma_format_idc | separate_colour_plane_flag | Chroma Format | SubWidthC | SubHeightC |
---|---|---|---|---|
0 | 0 | monochrome | - | - |
1 | 0 | YUV420 | 2 | 2 |
2 | 0 | YUV422 | 2 | 1 |
3 | 0 | YUV444 | 1 | 1 |
3 | 1 | YUV444 | - | - |
-
bit_depth_luma_minus8:针对high模式,允许设置图像深度大于8bit的情况。
非high的时候,都是一个字节8bit(0~255)表示一个像素的亮度或色度。
-
bit_depth_chroma_minus8:同上
-
qpprime_y_zero_transform_bypass_flag: 这个用的不多,用于指定 变换系数解码时的 旁路操作 是否要在 去块效应滤波之前执行。理解不深,直接上图:
-
seq_scaling_matrix_present_flag
-
seq_scaling_list_present_flag : 这两个参数也理解不深。后面有理解了再来写,目前先上图。
-
log2_max_frame_num_minus4:取值范围[0,12], log2和minus2都是计算方式的前后缀。关键在于 max_frame_num。很明显看出这个表示的是frame_num的max最大值。frame_num使我们在解码过程中会使用到的一个重要变量,表明了解码顺序。
-
pic_order_cnt_type:指定计算pic_order_cnt 的 方式,pic_order_cnt 是图像播放的顺序,也是真实录制的顺序,可以理解为真正的时间轴,不过是一个相对值。pic_order_cnt 有3种计算方式。具体计算方式可以参加毕厚杰《新一代视频压缩编码标准 第二版》7.3节(P181)的流程。
-
log2_max_pic_order_cnt_lsb_minus4:log2和minus4的前后缀是计算方式,主要含义就是 pic_order_cnt的max最大值的lsb,msb是需要解码器自己算的。这个涉及到POC的计算方法。
-
delta_pic_order_always_zero_flag:用于计算POC
-
offset_for_non_ref_pic:取值范围int, 用于计算非参考帧的POC
-
offset_for_top_to_bottom_field,用于计算场的POC
-
num_ref_frames_in_pic_order_cnt_cycle,范围[0,255],用于计算POC
-
offset_for_ref_frame,范围int,用于计算POC
-
max_num_ref_frames : reference frame 的最大值。一般参考图像范围0~MaxDpbSize.
-
gaps_in_frame_num_value_allowed_flag:允许码流中 frame num是不连续的。
-
pic_width_in_mbs_minus1:minus1是后缀,指明图像宽有多少个MB(每个MB是16x16)。这样很容算出图像亮度宽度 = (pic_width_in_mbs_minus1 + 1)* 16。
-
pic_height_in_map_units_minus1:minus1是后缀,指明图像高有多少个map unit(每个map unit是16x16 或 16x32),所以图像高度 = (pic_height_in_map_units_minus1 + 1)* 16或者32。
-
frame_mbs_only_flag:表明是否存在图像场,0代表存在,有场处理起来就比较麻烦。但是从main profile开始就加入了interlace的交错场功能,也算支持比较早。虽然现在用的不多了。
-
mb_adaptive_frame_field_flag:表明是图像帧还是图像场还是帧场自适应。
以上两个参数配合,可以推断出图像的帧场属性
frame_mbs_only_flag = 0 | frame_mbs_only_flag = 1 | |
---|---|---|
mb_adaptive_frame_field_flag 不存在 | - | 图像全是帧 |
mb_adaptive_frame_field_flag = 0 | 图像是 场 和 帧 | - |
mb_adaptive_frame_field_flag = 1 | 图像是 场 和 帧场自适应 | - |
没有帧和帧场自适应共存的模式。
- direct_8x8_inference_flag,计算B_SKIP, B_direct等宏块的运动矢量使用。
- frame_cropping_flag:图像是否需要crop,因为宏块都是16x16的,但是真实的图形不能都是16对齐的,所以有这个标志用来切除多余的边。为0时表示不需要切。
- frame_crop_left_offset:裁边的参数
- frame_crop_right_offset:裁边的参数
- frame_crop_top_offset:裁边的参数
- frame_crop_bottom_offset:裁边的参数
4. 伪代码分析
SPS的解析过程分支不多,我们按照流程来过一遍。
解析 profile_idc,
解析constraint_set0/1/2/3/4/5_flag
reserved_zero_2bits 用0补齐
|
解析level_idc
|
解析seq_parameter_set_id
|
if (profile_idc 等于 100/110/122/244/44/83/86/118/128) 说明high profile功能,开启了部分扩展功能 {
解析 chroma_format_idc, YUV格式是420,mono,422,还是444
if (YUV 格式是 YUV444) {
读取separate_colour_plane_flag 值,
}
读取亮度和色度的位宽参数
读取缩放参数
}
|
读取frame_num的最大值
|
读取POC计算方法
if (POC计算使用方法0) {
读取最大POC值
} else if (POC计算使用方法1) {
读取一些后面用于计算POC的数据
}
|
读取图像宽高,图像帧场属性
|
读取是否需要裁边以及裁边的宽高