基本结构(SliceHead)
H.264(也称为 AVC)是一种视频编码标准,它将视频帧分割成多个片段进行压缩。每个片段称为 Slice,SliceHeader 是 H.264 中用于描述每个片段的结构。
SliceHeader 结构包含了以下一些重要信息:
- first_mb_in_slice:表示当前 Slice 中的第一个宏块(Macroblock)在整个图像中的索引。
- slice_type:表示 Slice 的类型,如 I 帧(Intra Frame)、P 帧(Predictive Frame)或 B 帧(Bi-Directional Predictive Frame)。
- pic_parameter_set_id:指示当前 Slice 使用的图像参数集(Picture Parameter Set)的索引。
- frame_num:表示当前 Slice 所属的帧的帧号。
- idr_pic_id:在 IDR 图像(Instantaneous Decoder Refresh)中,表示当前 Slice 所属的 IDR 图像的图像标识符。
- pic_order_cnt_lsb:表示当前 Slice 的图像顺序计数器的最低有效位。
- slice_qp_delta:表示当前 Slice 的量化参数偏移量,用于控制编码的质量和压缩率。
- disable_deblocking_filter_idc:表示是否禁用去块滤波器,用于平滑边缘和减少压缩伪影。
slice_header()
封装结构
// SliceHeader
typedef struct {
uint32_t first_mb_in_slice;
uint32_t slice_type;
uint32_t pic_parameter_set_id;
uint32_t frame_num;
// if (!frame_mbs_only_flag) {
uint32_t field_pic_flag;
// if (field_pic_flag) {
uint32_t bottom_field_flag;
// }
// }
// if (nal_unit_type == 5) {
uint32_t idr_pic_id;
// }
// if (pic_order_cnt_type == 0) {
uint32_t pic_order_cnt_lsb;
// if (pic_order_present_flag && !field_pic_flag)
int delta_pic_order_cnt_bottom;
// }
// }
// if (pic_order_cnt_type == 1 && !delta_pic_order_always_zero_flag) {
int delta_pic_order_cnt[2];
// }
// if (redundant_pic_cnt_present_flag) {
uint32_t redundant_pic_cnt;
// }
// if (slice_type == B) {
uint32_t direct_spatial_mv_pred_flag;
// }
// if (slice_type == P || slice_type == SP || slice_type == B ) {
uint32_t num_ref_idx_active_override_flag;
// if (num_ref_idx_active_override_flag) {
uint32_t num_ref_idx_l0_active_minus1;
uint32_t num_ref_idx_l1_active_minus1;
// }
// }
NaluSliceRefPicListReordering ref_pic_list_reordering;
// if ((weighted_pred_flag && (slice_type == P || slice_type == SP) || (weighted_bipred_idc == 1 && slice_type == B)) {
NaluSlicePredWeightTable pred_weight_table;
// }
// if ( nal_ref_idc != 0) {
NaluSliceDecrefPicMarking dec_ref_pic_marking;
// }
// if (entropy_coding_mode_flag && slice_type != I && slice_type != SI) {
uint32_t cabac_init_idc;
// }
int slice_qp_delta;
// if (slice_type == SP || slice_type == SI) {
// if (slice_type == SP)
uint32_t sp_for_switch_flag;
int slice_qs_delta;
// }
// if (deblocking_filter_control_present_flag) {
uint32_t disable_deblocking_filter_idc;
int slice_alpha_c0_offset_div2;
int slice_beta_offset_div2;
// }
// }
// if (num_slice_groups_minus1 > 0 && slice_group_map_type >= 3 && slice_group_map_type <= 5) {
uint32_t slice_group_change_cycle;
// }
} NaluSliceHeader;
typedef struct {
// if (nal_unit_type == 5) {
uint32_t no_output_of_prior_pics_flag;
uint32_t long_term_reference_flag;
// } else {
uint32_t adaptive_ref_pic_marking_mode_flag;
// if (adaptive_ref_pic_marking_mode_flag) {
// do {
uint32_t memory_management_control_operation;
// if (memory_management_control_operation == 1 ||
// memory_management_control_operation == 3) {
uint32_t difference_of_pic_nums_minus1;
// }
// if (memory_management_control_operation == 2) {
uint32_t long_term_pic_num;
// }
// if (memory_management_control_operation == 3 ||
// memory_management_control_operation == 6) {
uint32_t long_term_frame_idx;
// }
// if (memory_management_control_operation == 4) {
uint32_t max_long_term_frame_idx_plus1;
// }
// } while (memory_management_control_operation != 0)
// }
} NaluSliceDecrefPicMarking;
typedef struct {
uint32_t luma_log2_weight_denom;
// if (chroma_format_idc != 0) {
uint32_t chroma_log2_weight_denom;
// }
// for (i = 0; i <= num_ref_idx_l0_active_minus1; i++) {
uint32_t luma_weight_l0_flag;
// if (luma_weight_l0_flag) {
int luma_weight_l0[32];
int luma_offset_l0[32];
// }
// if (chroma_format_idc != 0) {
uint32_t chroma_weight_l0_flag;
// if (chroma_weight_l0_flag) {
int chroma_weight_l0[32][2];
int chroma_offset_l0[32][2];
// }
// }
// }
// if (slice_type == B) {
// for (i = 0; i <= num_ref_idx_l1_active_minus1; i++) {
uint32_t luma_weight_l1_flag;
// if (luma_weight_l1_flag) {
int luma_weight_l1[32];
int luma_offset_l1[32];
// }
// if (chroma_format_idc != 0) {
uint32_t chroma_weight_l1_flag;
// if (chroma_weight_l1_flag)
int chroma_weight_l1[32][2];
int chroma_offset_l1[32][2];
// }
// }
// }
// }
} NaluSlicePredWeightTable;
typedef struct {
uint32_t reordering_of_pic_nums_idc;
uint32_t ref_pic_list_reordering_flag_l0;
uint32_t ref_pic_list_reordering_flag_l1;
uint32_t abs_diff_pic_num_minus1;
uint32_t long_term_pic_num;
} NaluSliceRefPicListReordering;
解析过程
/// 解析切片头
bool parse_slice_header(uint8_t *slice_data, uint32_t slice_size, const NaluSPS &sps, const NaluPPS &pps, NaluSliceHeader &slice_header) {
if (slice_size < 4) {
return false;
}
/// 找到 SLICE NAL 单元的起始位置
int start_code_length = 0;
if (slice_data[0] == 0 && slice_data[1] == 0 && slice_data[2] == 1) { // TODO: 00 00 01
start_code_length = 3;
} else if (slice_data[0] == 0 && slice_data[1] == 0 && slice_data[2] == 0 && slice_data[3] == 1) { // TODO: 00 00 00 01
start_code_length = 4;
} else if ((slice_data[0] & 0x1f) == 8) { // TODO: 继StartCode后第一个字节以 0x68 开头
start_code_length = 0;
} else {
return false;
}
slice_data += start_code_length;
slice_size -= start_code_length;
/// bit stream
std::vector<uint8_t> rbsp = EBSP2RBSP(slice_data, (int)slice_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;
/// SLICE
if (H264_NAL_SLICE == (NAL_TYPE)nal_unit_type || //
H264_NAL_IDR_SLICE == (NAL_TYPE)nal_unit_type) {
memset(&slice_header, 0, sizeof(NaluSliceHeader));
slice_header.first_mb_in_slice = bs_read_ue(b);
slice_header.slice_type = bs_read_ue(b);
slice_header.pic_parameter_set_id = bs_read_ue(b);
slice_header.frame_num = bs_read_u(b, (int)sps.log2_max_frame_num_minus4 + 4);
if (!sps.frame_mbs_only_flag) {
slice_header.field_pic_flag = bs_read_u1(b);
if (slice_header.field_pic_flag) {
slice_header.bottom_field_flag = bs_read_u1(b);
}
}
if (nal_unit_type == 5) {
slice_header.idr_pic_id = bs_read_ue(b);
}
if (sps.pic_order_cnt_type == 0) {
slice_header.pic_order_cnt_lsb = bs_read_u(b, (int)sps.log2_max_pic_order_cnt_lsb_minus4 + 4);
if (pps.pic_order_present_flag && !slice_header.field_pic_flag) {
slice_header.delta_pic_order_cnt_bottom = bs_read_se(b);
}
}
if (sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero_flag) {
slice_header.delta_pic_order_cnt[0] = bs_read_se(b);
if (pps.pic_order_present_flag && !slice_header.field_pic_flag) {
slice_header.delta_pic_order_cnt[1] = bs_read_se(b);
}
}
if (pps.redundant_pic_cnt_present_flag) {
slice_header.redundant_pic_cnt = bs_read_ue(b);
}
std::string sSliceType = get_slice_type_str(slice_header.slice_type);
if (sSliceType == "B") {
slice_header.direct_spatial_mv_pred_flag = bs_read_u1(b);
}
if (sSliceType == "P" || sSliceType == "SP" || sSliceType == "B") {
slice_header.num_ref_idx_active_override_flag = bs_read_u1(b);
if (slice_header.num_ref_idx_active_override_flag) {
slice_header.num_ref_idx_l0_active_minus1 = bs_read_ue(b);
if (sSliceType == "B") {
slice_header.num_ref_idx_l1_active_minus1 = bs_read_ue(b);
}
}
}
/// 参考图像列表重排序语法
ref_pic_list_reordering(b, slice_header);
/// 预测加权表格语法
if ((pps.weighted_pred_flag && (sSliceType == "P" || sSliceType == "SP")) || (pps.weighted_bipred_idc == 1 && sSliceType == "B")) {
pred_weight_table(b, sps, pps, slice_header);
}
/// 解码的参考图像标识语法
if (nal_ref_idc != 0) {
dec_ref_pic_marking(b, slice_header, nal_unit_type);
}
if (pps.entropy_coding_mode_flag && sSliceType != "I" && sSliceType != "SI") {
slice_header.cabac_init_idc = bs_read_ue(b);
}
slice_header.slice_qp_delta = bs_read_se(b);
if (sSliceType == "SP" || sSliceType == "SI") {
if (sSliceType == "SP") {
slice_header.sp_for_switch_flag = bs_read_u1(b);
slice_header.slice_qs_delta = bs_read_se(b);
}
if (pps.deblocking_filter_control_present_flag) {
slice_header.disable_deblocking_filter_idc = bs_read_ue(b);
if (slice_header.disable_deblocking_filter_idc != 1) {
slice_header.slice_alpha_c0_offset_div2 = bs_read_se(b);
slice_header.slice_beta_offset_div2 = bs_read_se(b);
}
}
}
if (pps.num_slice_groups_minus1 > 0 && pps.slice_group_map_type >= 3 && pps.slice_group_map_type <= 5) {
slice_header.slice_group_change_cycle =
bs_read_u(b, ceil_log2((int)(pps.pic_size_in_map_units_minus1 / pps.slice_group_change_rate_minus1) + 1));
}
}
bs_free(b);
return true;
}
int ceil_log2(int value) {
double logValue = log2(value);
int ceilValue = ceil(logValue);
return ceilValue;
}