H.264 片段头(SliceHead)

基本结构(SliceHead)

H.264(也称为 AVC)是一种视频编码标准,它将视频帧分割成多个片段进行压缩。每个片段称为 Slice,SliceHeader 是 H.264 中用于描述每个片段的结构。

SliceHeader 结构包含了以下一些重要信息:

  1. first_mb_in_slice:表示当前 Slice 中的第一个宏块(Macroblock)在整个图像中的索引。
  2. slice_type:表示 Slice 的类型,如 I 帧(Intra Frame)、P 帧(Predictive Frame)或 B 帧(Bi-Directional Predictive Frame)。
  3. pic_parameter_set_id:指示当前 Slice 使用的图像参数集(Picture Parameter Set)的索引。
  4. frame_num:表示当前 Slice 所属的帧的帧号。
  5. idr_pic_id:在 IDR 图像(Instantaneous Decoder Refresh)中,表示当前 Slice 所属的 IDR 图像的图像标识符。
  6. pic_order_cnt_lsb:表示当前 Slice 的图像顺序计数器的最低有效位。
  7. slice_qp_delta:表示当前 Slice 的量化参数偏移量,用于控制编码的质量和压缩率。
  8. 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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
========================================================== \根目录 ├── _blank.html 空白页(每次我们都拿空白页去创建,这样比较干净!) ├── _footer.html 页脚公共代码片段 ├── _header.html 部公共代码片段 ├── _meta.html meta公共代码片段 ├── robots.txt 搜索引擎爬虫配置文件 ├── login.html 管理员登陆 ├── index.html 首页(主框架) ├── welcome.html 我的桌面(默认永远打开的页面) ├── member-开的 用户相关 ├── artice-开的 资讯相关 ├── picture-开的 图片相关 ├── product-开的 产品相关 ├── page-开的 页面相关 ├── system-开的 系统相关 ├── admin-开的 管理员相关 ├── charts-开的 统计相关 …… static/ 资源 ├── h-ui/ H-ui特有资源 │ ├── css/ 样式 │ │ ├── H-ui.css H-ui基础样式 │ │ ├── H-ui.min.css H-ui.css 压缩版 │ │ ├── H-ui.ie.css H-ui.css IE低版本兼容补丁 │ ├── images/ 图片资源 │ ├── js/ │ │ ├── H-ui.js H-ui核心脚本 ├── h-ui.admin/ H-ui.admin核心资源 │ ├── css/ 样式 │ │ ├── H-ui.login.css 后台管理员登录页样式 │ │ ├── H-ui.admin.css 后台界面主要样式 │ ├── images/ 图片资源 │ ├── js/ │ │ ├── H-ui.admin.js 后台管理核心脚本 │ ├── skin/ 皮肤资源 │ │ ├── blue 蓝色 │ │ ├── default 黑色(默认) │ │ ├── green 绿色 │ │ ├── orange 橙色 │ │ ├── red 红色 │ │ ├── yellow 黄色 Lib/ 第三方插件 ├── jquery jQuery类库(v1.9.1) ├── Hui-iconfont 阿里图标字体库(H-ui定制) ├── jquery.SuperSlide 幻灯片组件 ├── Validform 表单验证插件 ├── jquery.validation 表单验证插件 ├── My97DatePicker 日期插件 ├── datatables 表格插件 ├── nprogress 进度条插件 ├── layer layer弹出层插件 ├── laypage laypage 翻页插件 ├── jquery.contextmenu 右键菜单插件 ├── ueditor 百度编辑器 ├── Highcharts 图表插件 ├── echarts 百度图标插件 ├── datatables 表格排序,检索插件 ├── WebUploader 百度文件上传组件 ├── lightbox2 图片预览组件 ├── html5shiv.js html5插件,让低版本IE支持html5元素 ├── DD_belatedPNG_0.0.8a-min.js 解决IE6png透明 ├── swfobject.js Flash插件 ├── expressInstall.swf 检查flash插件 ├── respond.min.js 让IE兼容media ├── colpick.js 颜色插件 └─temp 测试数据、图片

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

毕加索解锁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值