基本结构(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];
}
}