如何理解H.265头部?H.264与H.265头部差异及解析疑问
H.264与H.265头部差异及H.265 SPS解析问题解答
一、H.264与H.265头部核心差异
- NALU头部结构:H.264的NALU头部仅1字节,包含1位禁止位、2位参考等级、5位NAL类型;H.265的NALU头部是2字节,包含1位禁止位、6位NAL类型、6位分层ID、3位时间ID+1,结构更复杂,适配更高阶的编码特性。
- 参数集体系:H.264只有SPS(序列参数集)和PPS(图像参数集);H.265新增了VPS(视频参数集),把全局共享的参数从SPS中拆分出来,层级划分更清晰。
- 分辨率与宽高比表示:H.264的分辨率需要通过宏块数或直接字段计算,宽高比依赖
aspect_ratio_idc及扩展参数;H.265直接在SPS中用pic_width_in_luma_samples和pic_height_in_luma_samples定义亮度分辨率,宽高比逻辑类似但参数位置和前置依赖字段不同。
二、你当前的解析代码存在的问题
先贴你的代码:
while (buf->Size > 0) { //forbidden bit flushbits(buf, 1); int nNALType = showbits(buf, 6); if (nNALType == NAL_TYPE_SPS) { // flushbits until I retrieve desired parameter flushbits(buf, 4); // sps_video_parameter_set_id } else { // align bits buf->Size -= buf->BitsLeft & 0x7; } }
几个明显错误:
- NALU头部处理完全错误:H.265的NALU头部是16位(2字节),你只跳过1位禁止位就读6位NAL类型,后面还有6位分层ID和3位时间ID没处理,直接导致后续比特偏移全部错位。
- SPS内部解析太潦草:就算找到SPS NALU,你只跳过了
sps_video_parameter_set_id,但要拿到目标参数,必须先解析一堆前置字段(比如sps_max_sub_layers_minus1、profile_tier_level结构等),这些不处理根本找不到目标参数的位置。 - 非SPS NALU的跳过逻辑无效:
buf->Size -= buf->BitsLeft & 0x7这种方式根本跳不过整个NALU,NALU是字节对齐的,你得根据封装格式(Annex-B或AVCC)来确定NALU的长度,再跳过对应字节数,不是简单对齐比特。
三、快速定位H.265 SPS NALU的方法
分两种常见封装格式:
1. Annex-B格式(裸流、TS流等)
- 先扫缓冲区里的起始码:要么是
0x000001(3字节),要么是0x00000001(4字节),每个起始码后面跟着一个完整的NALU。 - 找到起始码后,读后面2字节的NALU头部,解析出
nal_unit_type(禁止位之后的6位),如果是33(SPS的类型值),就开始解析这个NALU内部;否则直接跳过从当前起始码到下一个起始码之间的所有字节。
2. AVCC格式(MP4、FLV等)
- 每个NALU开头有4字节的长度字段,先读这4字节得到整个NALU的字节数。
- 接着读后面2字节的NALU头部,解析
nal_unit_type,如果是SPS就解析内部;否则直接跳过刚才读到的长度对应的所有字节。
四、提取目标参数的关键解析步骤
要拿到pic_width_in_luma_samples、pic_height_in_luma_samples、aspectRatioH、aspectRatioV,必须按顺序解析前置字段(只列关键的):
- 先跳过整个NALU头部的16位(1位禁止位+6位NAL类型+6位分层ID+3位时间ID+1)。
- 解析
sps_video_parameter_set_id(4位)。 - 解析
sps_max_sub_layers_minus1(3位)。 - 解析
sps_temporal_id_nesting_flag(1位)。 - 解析
profile_tier_level结构(这部分比较繁琐,要按子层数解析对应参数)。 - 解析
sps_seq_parameter_set_id(4位)。 - 解析
chroma_format_idc(2位),如果值是3,还要解析separate_colour_plane_flag(1位)。 - 这时候才能解析
pic_width_in_luma_samples和pic_height_in_luma_samples(都是无符号指数哥伦布编码,要按这个编码规则解码)。 - 解析
conformance_window_flag(1位),如果是1,还要跳过窗口相关的4个参数。 - 解析
aspect_ratio_info_present_flag(1位),如果是1:- 先解析
aspect_ratio_idc(8位),如果这个值是255,才会读取aspectRatioH和aspectRatioV(同样是无符号指数哥伦布编码);否则直接用aspect_ratio_idc对应的预定义宽高比即可。
- 先解析
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

