- 分析下h265码流(字节流模式),nal单元如何分割,类型。
- 先上一段h265的码流片段
- nal单元分割
寻找0x000001或者0x00000001, 规则如下:- 每个NALU前面都有起始码0x000001, 3bits
- 如果NALU类型为vps, sps, pps, 或者解码顺序为第一个AU的第一个NALU, 起始码前面再加一个0x00
- 视频流的首个NALU的起始码前加入0x00
实际分析中,不必要整的这么复杂,只要找到0x000001或者0x00000001即可
- 上图中的码流nal拆分为:
第一帧:
0000 0001 4001 0c01 ffff 0160 0000 0300 0003 0000 0300 0003 00ba 9702 40
第二帧:
00 0000 0142 0101 0160 0000 0300 0003 0000 0300 0003 00ba a00f 0804 47f9 65e4 91b6 1c5e 4924 fe79 fcf2 ffff ffcf e7f3 f3f9 d9
第三帧:
00 0000 0144 01c1 9095 8112
第四帧:
0000 0126 01af 1380 790b dc5c 557c 74...
- NAL类型分析
类型枚举定义
enum NALUnitType {
NAL_TRAIL_N = 0,
NAL_TRAIL_R = 1,
NAL_TSA_N = 2,
NAL_TSA_R = 3,
NAL_STSA_N = 4,
NAL_STSA_R = 5,
NAL_RADL_N = 6,
NAL_RADL_R = 7,
NAL_RASL_N = 8,
NAL_RASL_R = 9,
NAL_BLA_W_LP = 16,
NAL_BLA_W_RADL = 17,
NAL_BLA_N_LP = 18,
NAL_IDR_W_RADL = 19,
NAL_IDR_N_LP = 20,
NAL_CRA_NUT = 21,
NAL_VPS = 32,
NAL_SPS = 33,
NAL_PPS = 34,
NAL_AUD = 35,
NAL_EOS_NUT = 36,
NAL_EOB_NUT = 37,
NAL_FD_NUT = 38,
NAL_SEI_PREFIX = 39,
NAL_SEI_SUFFIX = 40,
};
类型判断方式为分隔符之后的第一个字节右移一位的值
第一帧:0x40 >> 1 , 得到0x20,十进制32,为NAL_VPS
第二帧:0x42 >> 1 , 得到0x21, 十进制33, 为NAL_SPS
第三帧:0x44 >> 1 , 得到0x22, 十进制34, 为NAL_PPS
第四帧:0x26 >> 1 , 得到0x13, 十进制19, 为NAL_IDR_W_RADL
- 代码如下
static int hevc_probe(char* pbuf, int buf_size)
{
unsigned int code = -1;
int vps = 0, sps = 0, pps = 0, irap = 0;
int i;
for (i = 0; i < buf_size - 1; i++) {
code = (code << 8) + pbuf[i];
if ((code & 0xffffff00) == 0x100) {
char nal2 = pbuf[i + 1];
int type = (code & 0x7E) >> 1;
if (code & 0x81) // forbidden and reserved zero bits
return 0;
if (nal2 & 0xf8) // reserved zero
return 0;
switch (type) {
case NAL_VPS: vps++; break;
case NAL_SPS: sps++; break;
case NAL_PPS: pps++; break;
case NAL_BLA_N_LP:
case NAL_BLA_W_LP:
case NAL_BLA_W_RADL:
case NAL_CRA_NUT:
case NAL_IDR_N_LP:
case NAL_IDR_W_RADL: irap++; break;
}
}
}
return 0;
}