H264头简单说明
1,h264帧数据在开头的位置可能是00 00 01也可能是00 00 00 01
为什么要这样做呢?通过查看多篇文章发现它应该是这样的:
在一个完整的帧分成多个Slice时,在除了第一个Slice,其他的Slice中会被添加上0x 00 00 01
2, sps描述
00 00 00 01 67 (SPS)
前面00 00 00 01 就不再做解释了,下面是67的二进制
+---------------+
|0|1|2|3|4|5|6|7|
+---------------+
|F|NRI| Type |
+---------------+
|0|1|1|0|0|1|1|1|
+---------------+
下面是NALU header的说明 对应上面的表
F: 占一位 禁止为,0表示正常,1表示错误,一般都是0
NRI: 重要级别,11表示非常重要。
Type:
{
0:未使用
1:不区分,非I帧
2:片分区A
3:片分区B
4:片分区C
5:I帧
6:补充增强信息单元(DEI)
7:SPS标识(序列参数集)
8:PPS标识(图像参数集)
9:分节符
10:序列结束
11:码流结束
12:填充
13-23:保留
24-31:未使用
}
通过上面 00 00 00 01 67 头部的二进制 01100111分析 我们可以等出
在上面的片段中:
禁止位:0 正常
重要级别:11 非常重要
Type:00111 SPS标识(序列参数集)
所以可以判断出 00 00 00 01 67 是一个正常的非常重要的SPS标识头
那么我们就可以通过H264的头部判断该帧类型,如下:
0x67,0x47,0x27 SPS, 序列参数集,重要级别分别为11、10、01
0x68,0x48,0x28 PPS,图像参数集,重要级别分别为11、10、01
0x65,0x45,0x25 IDR帧,重要级别分别为11、10、01
0x61,0x41,0x21 非IDR帧,重要级别分别为11、10、01
下面是两个struct举例
typedef struct H264_3_Head
{
uint8_t start_code1; // 0x00
uint8_t start_code2; // 0x00
uint8_t start_code3; // 0x01
//小端存储,需要反着放
uint8_t type : 5; //类型: 5:I帧 7:SPS标识(序列参数集) 8:PPS标识(图像参数集)
uint8_t nri : 2; //重要级别,11表示非常重要。
uint8_t f : 1; //F: 占一位 禁止为,0表示正常,1表示错误,一般都是0
H264_3_Head(uint8_t t) :start_code1(0x00), start_code2(0x00), start_code3(0x01),
f(0x00), nri(0x03), type(t)
{}
}H264_3_Head;
typedef struct H264_4_Head
{
uint8_t start_code1; // 0x00
uint8_t start_code2; // 0x00
uint8_t start_code3; // 0x00
uint8_t start_code4; // 0x01
//小端存储,需要反着放
uint8_t type : 5; //类型: 5:I帧 7:SPS标识(序列参数集) 8:PPS标识(图像参数集)
uint8_t nri : 2; //重要级别,11表示非常重要。
uint8_t f : 1; //F: 占一位 禁止为,0表示正常,1表示错误,一般都是0
H264_4_Head(uint8_t t) :start_code1(0x00), start_code2(0x00), start_code3(0x00), start_code4(0x01),
f(0x00), nri(3), type(t)
{}
}H264_4_Head;
如果有什么不对的,欢迎指出,多多学习