【编解码】从零开始写H264解码器(6) PPS解析-参数含义,伪代码解析

1. 引言

前一篇搞完了最重要SPS,接下来就是PPS了。
PPS(picture parameter set)也是一份很重要的数据,会被很多slice参考到,里面的参数我们也需要熟悉和理解。
PPS的解析方式和SPS类似,没有什么很复杂的地方,分支也不多。基本上按照指数哥伦布的解析方式,按照白皮书依次挨个解析下去即可,所以我们主要要注意的就是里面每个参数的含义,以及他们的使用场合。

2. PPS

翻到白皮书《Rec. ITU-T H.264 (03/2010) 46面。 章节 “7.3.2.2 Picture parameter set RBSP syntax”,可以看出来这个表不是非常长,参数有限,依然先上一个原版全家福。
在这里插入图片描述
在这里插入图片描述

下面我们来挨个理解每个参数的作用。

3. 参数解析

  • pic_parameter_set_id: 当前PPS的id号,范围0~255,用于slice 参考时指定使用。

  • seq_parameter_set_id:指定当前PPS所参考的SPS。

  • entropy_coding_mode_flag:熵编码类型,0 是 CAVLC,1是CABAC。CAVLC编解码简单,但是效率没有CABAC高。

  • bottom_field_pic_order_in_frame_present_flag:标识位,用于表示片头中的两个语法元素delta_pic_order_cnt_bottom和delta_pic_order_cn是否存在,用于计算POC。
    具体POC的计算流程图详见《新一代视频压缩编码标准》P185。

  • num_slice_groups_minus1:片组的数量,为0时表示没有使用片组模式。H264规定每张影像最多分成8个片组。
    注意,这里并不是说slice片的数量,而是片组。一帧中可能会有多个片,但是他们属于同一个片组。

  • slice_group_map_type:片组的类型。片组这又是一个单独的概念了,主要用于恢复重建的作用。

  • run_length_minus1:

  • top_left

  • bottom_right

  • slice_group_change_direction_flag

  • slice_group_change_rate_minus1

  • pic_size_in_map_units_minus1

  • slice_group_id
    以上这些都是针对不同的片组类型,用于计算MB与slice group的归属关系。
    slice group还有一个名字就是 FMO(Flexibility Macroblock Order)。
    这一块比较多,就不在这展开写了,以后单独开一章单独介绍。
    在这里插入图片描述

  • num_ref_idx_l0_default_active_minus1:minus1是计算方式的后缀,num_ref_idx_l0_default_active是指明当前参考队列list0中有多少有效的参考帧。

  • num_ref_idx_l1_default_active_minus1:指明当前参考队列list1中有多少有效的参考帧。

  • weighted_pred_flag:是否允许P和SP的加权预测,0:不允许,1允许。

  • weighted_bipred_idc:指明B的加权预测模式,0:默认加权,1:显式加权,2:隐式加权

  • pic_init_qp_minus26:范围[-26,25],用于计算宏块的qp。
    宏块的qp在PPS(pic_init_qp_minus26),slice header (slice_qp_delta)和 宏块层(qp_mb_delta)中都有涉及。
    片中第一个MB的qp计算为

    QP y = 26 + pic_init_qp_minus26 + slice_qp_delta
    

    后续的MB的qp都是基于上一个MB的qp计算得到

    QP y = (QP y,prev + qp_mb_delta + 52 ) % 52
    
  • pic_init_qs_minus26:和pic_init_qp_minus26基本一致,主要用于SP和SI。

  • chroma_qp_index_offset:范围[-12,12],用于基于亮度分量的qp来计算色度分量的qp。详见《新一代视频压缩编码标准》P219,主要用于Cb
    在这里插入图片描述

  • deblocking_filter_control_present_flag : 表明去块效应滤波器的语法元素是否在slice header中出现。1:出现,使用设定值;0:不出现,使用预测值。

  • constrained_intra_pred_flag:用于标志在intra的宏块预测中,是否可以使用相邻的inter块的数据。1的话表示不行,0的话表示可以,这个在后面intra宏块的时候会细说,会细分出来很多种可能。

  • redundant_pic_cnt_present_flag:指明slice header中是否会出现redundant_pic_cnt 元素。

  • transform_8x8_mode_flag:是否使用8x8的size。在baseline中,intra只有16x16和4x4的size,后面加入了8x8,这个增加了灵活度,但是在MB解算的时候多了一堆可能性。这个在后面intra宏块的时候会细说。

  • pic_scaling_matrix_present_flag:指明pic_scaling_matrix是否存在

  • pic_scaling_list_present_flag:指明 pic_scaling_list是否存在
    关于 pic_scaling_matrix 和 pic_scaling_list的使用方法,我暂时没找到说明。后续会补充这里。

  • second_chroma_qp_index_offset:功能和chroma_qp_index_offset类似,主要用于Cr。
    在这里插入图片描述

4. 伪代码解析


解析 pic_parameter_set_id 
解析 seq_parameter_set_id 
解析 entropy_coding_mode_flag 
解析 bottom_field_pic_order_in_frame_present_flag 
解析 num_slice_groups_minus1 
|
if (num_slice_groups_minus1 > 0)  					如果存在片组
	解析 slice_group_map_type 						获取片组的类型
	if (slice_group_map_type  == 0 )				如果片组是类型0,根据run_length_minus1来分片组
		for (iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++)
			run_length_minus1[iGroup]				读取每个片组的run_length,取出run_length个map unit之后就切换成下一个片组
	else if( slice_group_map_type == 2 )			如果片组是类型2for( iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++ ) {
			top_left[iGroup] 						读取top_left和bottom_right确定每个片组的矩形的位置。
			bottom_right[iGroup]					片组重叠位置的map unit归于片组id小的那个
		}
	else if( slice_group_map_type = = 3 ||			如果是类型3,45,都是只分2个group。
		slice_group_map_type = = 4 ||
		slice_group_map_type = = 5 )	{
			slice_group_change_direction_flag		指明是顺时针还是逆时针
			slice_group_change_rate_minus1
		} else if( slice_group_map_type = = 6 ) {	如果是类型6, 这个规律性比较低,所以要传很多参数,完全是encoder自行决定 MapUnit和 slice group的对应关系
			pic_size_in_map_units_minus1			指明图像中有多少个map unit,虽然从SPS中也能算出来,但是有时候,PPS比SPS先到。所以再传一次。
			for( i = 0; i <= pic_size_in_map_units_minus1; i++ )
				slice_group_id[i]					每一个map unit都要指明是属于哪个片组的
			}
	}
|
解析 num_ref_idx_l0_default_active_minus1
解析 num_ref_idx_l1_default_active_minus1
解析 weighted_pred_flag
解析 weighted_bipred_idc
解析 pic_init_qp_minus26
解析 pic_init_qs_minus26
解析 chroma_qp_index_offset
解析 deblocking_filter_control_present_flag
解析 constrained_intra_pred_flag
解析 redundant_pic_cnt_present_flag
|
if(more_rbsp_data()) {							如果这个NALU的数据还没读取完
	解析 transform_8x8_mode_flag
	解析 pic_scaling_matrix_present_flag
	if( pic_scaling_matrix_present_flag )		如果 pic_scaling_matrix 存在
	for( i = 0; i < 6+((chroma_format_idc!= 3) ? 2 : 6 ) * transform_8x8_mode_flag; i++ ) {
		解析 pic_scaling_list_present_flag[i]
		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])
	}
	解析second_chroma_qp_index_offset
}	

5. 小总结

SPS里的参数都也是比较重要的,但是解析起来都比较好懂。
个人感觉片组和scalelist会相对冷僻一些,要再花点心思。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值