一、H264概念
H.264 是一次概念的革新,它打破常规,完全没有 I 帧、P帧、B 帧的概念,也没有 IDR帧的概念。
H264和H265的每一个NALU前缀码也是一样的,即“0x00 00 00 01”或者 “0x00 00 01”。
分析一下H264码流,nal单元如何分割,类型:
二、 H.264 NAL 类型分析type
类型枚举定义:
typedef enum {
NALU_TYPE_SLICE = 1,
NALU_TYPE_DPA = 2,
NALU_TYPE_DPB = 3,
NALU_TYPE_DPC = 4,
NALU_TYPE_IDR = 5,
NALU_TYPE_SEI = 6,
NALU_TYPE_SPS = 7,
NALU_TYPE_PPS = 8,
NALU_TYPE_AUD = 9,
NALU_TYPE_EOSEQ = 10,
NALU_TYPE_EOSTREAM = 11,
NALU_TYPE_FILL = 12,
#if (MVC_EXTENSION_ENABLE)
NALU_TYPE_PREFIX = 14,
NALU_TYPE_SUB_SPS = 15,
NALU_TYPE_SLC_EXT = 20,
NALU_TYPE_VDRD = 24 // View and Dependency Representation Delimiter NAL Unit
#endif
} NaluType;
三、帧类型判断
unsigned char * pBS = (unsigned char *)pBSBuf;
int nType = pBS[4] & 0x1F; // NAL类型在固定的位置上
if ( nType <= H264NT_PPS )
return nType;// nTYPE 为5 表示关键帧
四、其它细节
对于 H.264中出现的一些概念从大到小排序依次是:序列、图像、片组、片、NALU、宏块、亚宏块、块、像素。这里有几点值得说明:
(1).在 H.264协议中图像是个集合概念,顶场、底场、帧都可以称为图像(本文图像概念时都是集合概念)。因此我们可以知道,对于H.264 协议来说,我们平常所熟悉的那些称呼,例如:I 帧、P 帧、B帧等等,实际上都是我们把图像这个概念具体化和细小化了。我们在 H.264里提到的“帧”通常就是指不分场的图像;
(2).如果不采用FMO(灵活宏块排序) 机制,则一幅图像只有一个片组;
(3).如果不使用多个片,则一个片组只有一个片;
(4).如果不采用DP(数据分割)机制,则一个片就是一个NALU,一个 NALU 也就是一个片。
否则,一个片由 三个 NALU 组成(即标准“表7-1”中 nal_unit_type 值为2、3、4 的三个 NALU 属于 一个片);
2 编码条带数据分割块A slice_data_partition_a_layer_rbsp()
3 编码条带数据分割块Bslice_data_partition_b_layer_rbsp( )
4 编码条带数据分割块Cslice_data_partition_c_layer_rbsp( )
(5).以上所述的片和 NALU的大小关系并不是抽象概念上的从属关系。从概念的从属关系上来看,NALU其实又是片的一个集合概念,例如:标准“表7-1”中nal_unit_type 值为 5 的 NALU 包括 I 片或者 SI片。
一幅图像根据组成它的片类型来分,可以分为标准“表7-5”中的 8种类型。我们平常应用中所最常见到的其实是这些类型的特例。例如:我们平常所谓的“I帧”和“IDR 帧”,其实是 primary_pic_type 值为 0的图像,我们平常所谓的“P帧”其实是 primary_pic_type 值为 1的图像的特例,我们平常所谓的“B帧”其实是 primary_pic_type 值为 2的图像的特例。
在收到h264码流的每个NAL数据(Buffer指针)时,对于如下代码的理解:
if((*(Buffer) == 0) && (*(Buffer+1) == 0) && (*(Buffer+2) == 0) && (*(Buffer+3) == 1)) //NAL头的0x00 00 00 01起始码
{
if(*(Buffer+4) == SPS_FRAME)
{ //ox67为 0110 0111(nal_unit_type为低5位,u(5)= 0 0111 = 7)
frame_type = SPS_FRAME;
}
else if(*(Buffer+4) == PPS_FRAME)
{ //ox68为 0110 1000 (nal_unit_type为低5位,u(5)= 0 1000 = 8)
frame_type = PPS_FRAME;
}
else if(*(Buffer+4) == I_FRAME)
{ //ox65为 0110 0101 (nal_unit_type为低5位,u(5)= 0 0101 = 5)
frame_type = I_FRAME;
}
else
{ //0x41为0100 00001 (nal_ref_idc是参考级别,代表被其它帧参考情况,u(2)= 10 = 2; nal_unit_type为低5位,u(5)= 0 0001 = 1)
frame_type = P_FRAME;
}
if((*(Buffer+5) & 0x80) == 0x80)
{
start_frame = 1;
}
}