H.264 图像参数集(PPS)

基本结构(PPS)

PPS(Picture Parameter Set)是H.264/AVC视频编码标准中的一个参数集,用于描述视频帧的编码参数。它包含了一些与图像处理和编码相关的参数,如图像尺寸、帧率、色彩空间等。PPS通常与SPS(Sequence Parameter Set)一起使用,共同定义视频序列的编码参数。

PPS包含了以下重要信息:

  • pic_parameter_set_id(图片参数集ID):用于唯一标识不同的PPS。
  • seq_parameter_set_id(序列参数集ID):指定与该PPS关联的SPS的ID。
  • entropy_coding_mode_flag(熵编码模式标志):指示使用的熵编码模式,0表示使用CABAC(Context-based Adaptive Binary Arithmetic Coding),1表示使用CAVLC(Context-based Adaptive Variable Length Coding)。
  • pic_order_present_flag(图片顺序标志):指示是否存在图片顺序信息。
  • num_slice_groups_minus1(切片组数减一):切片组的数量减一,用于划分图像帧的切片组。
  • slice_group_map_type(切片组映射类型):指示切片组映射的类型,用于确定图像帧的切片组划分方式。
  • pic_init_qp_minus26(图像初始量化参数减26):用于指定图像的初始量化参数,减去26后的值。

pic_parameter_set_rbsp()

封装结构

// PPS
typedef struct {
    uint32_t pic_parameter_set_id;
    uint32_t seq_parameter_set_id;
    uint32_t entropy_coding_mode_flag; //!< 熵编码模式标识
    uint32_t pic_order_present_flag;
    uint32_t num_slice_groups_minus1;
    //	if (num_slice_groups_minus1 > 0) {
    uint32_t slice_group_map_type;
    //		if (slice_group_map_type == 0) {
    uint32_t run_length_minus1[8];
    //		} else if (slice_group_map_type == 2) {
    //			for(iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) {
    uint32_t top_left[8];
    uint32_t bottom_right[8];
    //			}
    //		} else if (slice_group_map_type == 3 || slice_group_map_type == 4 || slice_group_map_type == 5) {
    uint32_t slice_group_change_direction_flag;
    uint32_t slice_group_change_rate_minus1;
    //		} else if (slice_group_map_type == 6) {
    uint32_t pic_size_in_map_units_minus1;
    //			for (i = 0; i <= pic_size_in_map_units_minus1; i++) {
    uint32_t slice_group_id[8];
    //			}
    //		}
    //	}
    uint32_t num_ref_idx_l0_active_minus1;
    uint32_t num_ref_idx_l1_active_minus1;
    uint32_t weighted_pred_flag;  //!< 标识位,表示在P/SP slice中是否开启加权预测
    uint32_t weighted_bipred_idc; //!< 表示BSlice中加权预测方法: 0:默认加权预测, 1:显式加权预测, 2:隐式加权预测
    int pic_init_qp_minus26;      //!< QP
    int pic_init_qs_minus26;      //!< QS
    int chroma_qp_index_offset;
    uint32_t deblocking_filter_control_present_flag;
    uint32_t constrained_intra_pred_flag;
    uint32_t redundant_pic_cnt_present_flag;
    uint32_t transform_8x8_mode_flag;
    uint32_t pic_scaling_matrix_present_flag;
    //	if (more_rbsp_data()) {
    //		for (i = 0; i < 6 + 2 * transform_8x8_mode_flag; i++) {
    uint32_t pic_scaling_list_present_flag[6];
    //		}
    int second_chroma_qp_index_offset;
    //	}
} NaluPPS;

解析过程

/// 解析PPS信息
bool parse_nalu_pps(uint8_t *pps_data, uint32_t pps_size, const NaluSPS &sps, NaluPPS &pps) {
	if (pps_size < 4)
		return false;

	/// 找到 PPS NAL 单元的起始位置
	int start_code_length = 0;
	if (pps_data[0] == 0 && pps_data[1] == 0 && pps_data[2] == 1) { // TODO: 00 00 01
		start_code_length = 3;
	} else if (pps_data[0] == 0 && pps_data[1] == 0 && pps_data[2] == 0 && pps_data[3] == 1) { // TODO: 00 00 00 01
		start_code_length = 4;
	} else if ((pps_data[0] & 0x1f) == 8) { // TODO: 继StartCode后第一个字节以 0x68 开头
		start_code_length = 0;
	} else {
		return false;
	}
	pps_data += start_code_length;
	pps_size -= start_code_length;

	/// bit stream
	std::vector<uint8_t> rbsp = EBSP2RBSP(pps_data, (int)pps_size);
	bs_t *b = bs_new(rbsp.data(), rbsp.size());

	/// Nalu Header
	uint32_t forbidden_zero_bit = bs_read_u(b, 1);
	uint32_t nal_ref_idc = bs_read_u(b, 2);
	uint32_t nal_unit_type = bs_read_u(b, 5);

	NaluHeader nalu_header;
	nalu_header.nal_ref_idc = nal_ref_idc;
	nalu_header.nal_unit_type = nal_unit_type;

	/// PPS
	if (H264_NAL_PPS == (NAL_TYPE)nal_unit_type) {
		memset(&pps, 0, sizeof(NaluPPS));
		pps.pic_parameter_set_id = bs_read_ue(b);
		pps.seq_parameter_set_id = bs_read_ue(b);
		pps.entropy_coding_mode_flag = bs_read_u1(b); // TODO: 熵编码模式标识
		pps.pic_order_present_flag = bs_read_u1(b);
		pps.num_slice_groups_minus1 = bs_read_ue(b); // TODO: 片组的数量,最多分成8个片组
		if (pps.num_slice_groups_minus1 > 0) {
			pps.slice_group_map_type = bs_read_ue(b);
			if (pps.slice_group_map_type == 0) {
				for (int iGroup = 0; iGroup <= pps.num_slice_groups_minus1; iGroup++) {
					pps.run_length_minus1[iGroup] = bs_read_ue(b);
				}
			} else if (pps.slice_group_map_type == 2) {
				for (int iGroup = 0; iGroup < pps.num_slice_groups_minus1; iGroup++) {
					pps.top_left[iGroup] = bs_read_ue(b);
					pps.bottom_right[iGroup] = bs_read_ue(b);
			} else if (pps.slice_group_map_type == 3 || //
			           pps.slice_group_map_type == 4 || //
			           pps.slice_group_map_type == 5) {
				pps.slice_group_change_direction_flag = bs_read_u1(b);
				pps.slice_group_change_rate_minus1 = bs_read_ue(b);
			} else if (pps.slice_group_map_type == 6) {
				pps.pic_size_in_map_units_minus1 = bs_read_ue(b);
				for (int i = 0; i <= pps.pic_size_in_map_units_minus1; i++) {
					pps.slice_group_id[i] = bs_read_u(b, ceil_log2((int)pps.num_slice_groups_minus1)); //!< u(v)
				}
			}
		}

		pps.num_ref_idx_l0_active_minus1 = bs_read_ue(b);
		pps.num_ref_idx_l1_active_minus1 = bs_read_ue(b);
		pps.weighted_pred_flag = bs_read_u1(b); // TODO: 标识位,表示在P/SP slice中是否开启加权预测
		pps.weighted_bipred_idc = bs_read_u(b, 2); // TODO: 表示BSlice中加权预测方法: 0:默认加权预测, 1:显式加权预测, 2:隐式加权预测

		pps.pic_init_qp_minus26 = bs_read_se(b); // TODO: QP
		pps.pic_init_qs_minus26 = bs_read_se(b); // TODO: QS
		pps.chroma_qp_index_offset = bs_read_se(b);

		pps.deblocking_filter_control_present_flag = bs_read_u1(b);
		pps.constrained_intra_pred_flag = bs_read_u1(b);
		pps.redundant_pic_cnt_present_flag = bs_read_u1(b);
		
		if (more_rbsp_data(b)) {
			pps.transform_8x8_mode_flag = bs_read_u1(b);
			pps.pic_scaling_matrix_present_flag = bs_read_u1(b);

			uint32_t *ScalingList4x4[12];
			uint32_t UseDefaultScalingMatrix4x4Flag[12];
			uint32_t *ScalingList8x8[12];
			uint32_t UseDefaultScalingMatrix8x8Flag[12];
			if (pps.pic_scaling_matrix_present_flag) {
				for (int i = 0; i < 6 + ((sps.chroma_format_idc != 3) ? 2 : 6) * pps.transform_8x8_mode_flag; i++) {
					pps.pic_scaling_list_present_flag[i] = bs_read_u1(b);
					if (pps.pic_scaling_list_present_flag[i]) {
						if (i < 6) {
							scaling_list(b, ScalingList4x4[i], 16, UseDefaultScalingMatrix4x4Flag[i]);
						} else {
							scaling_list(b, ScalingList8x8[i - 6], 64, UseDefaultScalingMatrix8x8Flag[i - 6]);
						}
					}
				}
			}
			pps.second_chroma_qp_index_offset = bs_read_se(b);
		}

		rbsp_trailing_bits(b);
	}

	bs_free(b);
	return true;
}

uint32_t more_rbsp_data(bs_t *b) {
	if (bs_eof(b)) {
		return 0;
	}
	if (bs_peek_u1(b) == 1) {
		return 0;
	}
	return 1;
}

void rbsp_trailing_bits(bs_t *b) {
	uint32_t rbsp_stop_one_bit = bs_read_u1(b); // equal to 1
	while (!bs_byte_aligned(b)) {
		uint32_t rbsp_alignment_zero_bit = bs_read_u1(b); // equal to 0
	}
}

其他附录

scaling_list()

/// 缩放比例列表
void scaling_list(bs_t *b, uint32_t *scalingList, int sizeOfScalingList, uint32_t useDefaultScalingMatrixFlag) {
	int lastScale = 8;
	int nextScale = 8;
	for (int j = 0; j < sizeOfScalingList; j++) {
		if (nextScale != 0) {
			//!< delta_scale
			int32_t delta_scale = bs_read_se(b);
			nextScale = (lastScale + delta_scale + 256) % 256;
			useDefaultScalingMatrixFlag = (j == 0 && nextScale == 0);
		}
		scalingList[j] = (nextScale == 0) ? lastScale : nextScale;
		lastScale = (int)scalingList[j];
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕加索解锁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值