H264中的NALU概念解析

转载 2018年04月17日 14:56:30
1.什么是NAL
NAL全称Network Abstract Layer,即网络抽象层。
在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传播。VCL(Video Coding Layer)是H.264/AVC的规格,意思是压缩后、去冗余(Visual Redundancy)的影像资料,其技术核心包括动作估计、转换编码、预测编码、去区块效应滤波、及熵编码等。
视讯编码层往往与网络抽象层(NAL)相互配合,标准的NAL-unit总共规范(profile)有12种,这12种型式可粗分成VCL NAL-unit及non-VCL NAL-unit,其中 VCL NAL-unit是指NAL-unit中存放的完全是VCL的影像资料。
现实中的传输系统是多样化的,其可靠性,服务质量,封装方式等特征各不相同,NAL这一概念的提出提供了一个视频编码器和传输系统的友好接口,使得编码后的视频数据能够有效的在各种不同的网络环境中传输。
2.NALU/Sample/帧(frame)/分片(slice)/宏块(MB)的关系
(1)可以认为一个NALU就是一个sample,即NALU=sample。错错错!!!大错特错!!!我自己阅读了ISO-14496-15,里面明确说明,一个sample有多个NALU!!!而且我亲自解析了一个mp4文件,确实是一个sample有多个NALU。否则,NALU的长度就没有意义了,因为MP4文件的头中包含了每个sample的size信息。
(2)Slice是片的意思,H264中把图像分成一帧(frame)或两场(field),而帧又可以分成一个或几个片(Slilce);片由宏块(MB)组成。宏块是编码处理的基本单元。
(3)一个frame是可以分割成多个Slice来编码的,而一个Slice编码之后被打包进一个NAL单元,不过NAL单元除了容纳Slice编码的码流外,还可以容纳其他数据,比如序列参数集SPS。
3.RBSP、SODB、EBSP三者的区别和联系
(1)SODB:最原始的编码数据,没有任何附加数据
(2)RBSP:在 SODB 的基础上加了rbsp_stop_ont_bit(bit 值为 1)并用 0 按字节补位对齐
(3)EBSP:在 RBSP 的基础上增加了防止伪起始码字节(0X03)
(4)NALU是对RBSP的封装。而RTP之类的是对NALU的封装。
4.NALU/NAL Units/NAL 单元
NALU是一种封装的模组,并拥有NAL-unit 标头(Header),此Header内又有许多资讯,包括 Type。一个完整的NALU是标头(Header)加上位元流(bitstream)。多个NAL-units组成一个存储单元(access unit)。
5.NALU的类型
标识NAL单元中数据类型,其中,nal_unit_type为1, 2, 3, 4, 5及12的NAL单元称为VCL的NAL单元,其他类型的NAL单元为非VCL的NAL单元。
0:未规定
1:非IDR图像中不采用数据划分的片段
2:非IDR图像中A类数据划分片段
3:非IDR图像中B类数据划分片段
4:非IDR图像中C类数据划分片段
5:IDR图像的片段
6:补充增强信息 (SEI)
7:序列参数集/SPS
8:图像参数集/PPS
9:分割符
10:序列结束符
11:流结束符
12:填充数据
13 – 23:保留
24 – 31:未规定
即认为SPS和PPS都是特殊的NALU。一个MP4文件只有一个SPS,但是有很多PPS,SPS必须在所有NALU的最开头。
补充:
(1)I frame 是自己独立编码,不依赖于其他frame 数据。
P frame 依赖 I frame 数据。
B frame 依赖 I frame, P frame 或其他 B frame 数据。
(2)IDR帧属于I帧。解码器收到IDR帧时,将所有的参考帧队列丢弃(用x264_reference_reset函 数实现——在encoder.c文件中)。这点是所有I帧共有的特性,但是收到IDR帧时,解码器另外需要做的工作就是:把所有的PPS和SPS参数进行更新。由此可见,在编码器端,每发一个IDR,就相应地发一个 PPS&SPS_nal_unit。
(3)分ABC片主要目的是为了对重要程度不同的数据进行不同程度的保护。
6.NALU的顺序要求
H.264/AVC标准对送到解码器的NAL单元顺序是有严格要求的,如果NAL单元的顺序是混乱的,必须将其重新依照规范组织后送入解码器,否则解码器不能够正确解码。
(1)序列参数集NAL单元(nal_unit_type为7)必须在传送所有以此参数集为参考的其他NAL单元之前传送,不过允许这些NAL单元中间出现重复的序列参数集NAL单元。所谓重复的详细解释为:序列参数集NAL单元都有其专门的标识,如果两个序列参数集NAL单元的标识相同,就可以认为后一个只不过是前一个的拷贝,而非新的序列参数集。
(2)图像参数集NAL单元(nal_unit_type为8)必须在所有以此参数集为参考的其他NAL单元之先,不过允许这些NAL单元中间出现重复的图像参数集NAL单元,这一点与上述的序列参数集NAL单元是相同的。
(3)不同基本编码图像中的片段(slice)单元和数据划分片段(data partition)单元在顺序上不可以相互交叉,即不允许属于某一基本编码图像的一系列片段(slice)单元和数据划分片段(data partition)单元中忽然出现另一个基本编码图像的片段(slice)单元片段和数据划分片段(data partition)单元。
(4)参考图像的影响:如果一幅图像以另一幅图像为参考,则属于前者的所有片段(slice)单元和数据划分片段(data partition)单元必须在属于后者的片段和数据划分片段之后,无论是基本编码图像还是冗余编码图像都必须遵守这个规则
(5)基本编码图像的所有片段(slice)单元和数据划分片段(data partition)单元必须在属于相应冗余编码图像的片段(slice)单元和数据划分片段(data partition)单元之前。
(6)如果数据流中出现了连续的无参考基本编码图像,则图像序号小的在前面。
(7)如果arbitrary_slice_order_allowed_flag置为1,一个基本编码图像中的片段(slice)单元和数据划分片段(data partition)单元的顺序是任意的,如果arbitrary_slice_order_allowed_flag置为零,则要按照片段中第一个宏块的位置来确定片段的顺序,若使用数据划分,则A类数据划分片段在B类数据划分片段之前,B类数据划分片段在C类数据划分片段之前,而且对应不同片段的数据划分片段不能相互交叉,也不能与没有数据划分的片段相互交叉。
(8)如果存在SEI(补充增强信息) 单元的话,它必须在它所对应的基本编码图像的片段(slice)单元和数据划分片段(data partition)单元之前,并同时必须紧接在上一个基本编码图像的所有片段(slice)单元和数据划分片段(data partition)单元后边。假如SEI属于多个基本编码图像,其顺序仅以第一个基本编码图像为参照。
(9)如果存在图像分割符的话,它必须在所有SEI 单元、基本编码图像的所有片段slice)单元和数据划分片段(data partition)单元之前,并且紧接着上一个基本编码图像那些NAL单元。
(10)如果存在序列结束符,且序列结束符后还有图像,则该图像必须是IDR(即时解码器刷新)图像。序列结束符的位置应当在属于这个IDR图像的分割符、SEI 单元等数据之前,且紧接着前面那些图像的NAL单元。如果序列结束符后没有图像了,那么它的就在比特流中所有图像数据之后。
(11)流结束符在比特流中的最后。
①NALU(Network Abstract Layer Unit):H264标准中的比特流是以NAL为单位,每个NAL单元包含一个RBSP(raw byte sequence payload,原始字节序列载荷),NALU的头信息定义了RBSP所属类型。类型一般包括序列参数集(SPS)、图像参数集(PPS)、增强信息(SEI)、条带(Slice)等,其中,SPS和PPS属于参数集,两标准采用参数集机制是为了将一些主要的序列、图像参数(解码图像尺寸、片组数、参考帧数、量化和滤波参数标记等)与其他参数分离,通过解码器先解码出来。此外,为了增强图像的清晰度,AVS-M添加了图像头(Picture head)信息。读取NALU流程中,每个NALU前有一个起始码0x000001,为防止 内部0x000001序列竞争,H.264编码器在最后一字节前插入一个新的字节——0x03,所以解码器检测到该序列时,需将0x03删掉,而AVS-M只需识别出起始码0x000001。
②读取宏块类型(mb type)和宏块编码模板(cbp):编解码图像以宏块划分,一个宏块由一个16*16亮度块和相应的一个8*8cb和一个8*8cr色度块组成。
7.NALU的语法/结构
(1)NALU的结构及含义
nal_unit( NumBytesInNALunit ) {
forbidden_zero_bit // forbidden_zero_bit 等于 0表示网络传输没有出错
nal_ref_idc // 指示当前 NAL 的优先级。取值范围为 0-3, 值越高,表示当前 NAL 越重要,需要优先受到保护。H.264 规定如果当前 NAL 是属于参考帧的片,或是序列参数集,或是图像参数集这些重要的数据单位时,本句法元素必须大于 0。
nal_unit_type // NAL类型 指明当前 NAL unit 的类型
NumBytesInRBSP = 0
for( i = 1; i <</span> NumBytesInNALunit; i++ ) {
if( i + 2 <</span> NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {
rbsp_byte[ NumBytesInRBSP++ ]
rbsp_byte[ NumBytesInRBSP++ ]
i += 2
//emulation_prevention_three_byte NAL 内部为防止与起始码竞争而引入的填充字节,值为 0x03。
emulation_prevention_three_byte
} else
rbsp_byte[ NumBytesInRBSP++ ]
}
}
(2)第1位禁止位,值为1表示语法出错;第2~3位为参考级别;第4~8为是nal单元类型
举例:如果某个NAL的第一个字节值为0x67,0x68,0x65
其中0x67的二进制码为:
0110 0111
4-8为00111,转为十进制7,7对应序列参数集SPS
其中0x68的二进制码为:
0110 1000
4-8为01000,转为十进制8,8对应图像参数集PPS
其中0x65的二进制码为:
0110 0101
4-8为00101,转为十进制5,5对应IDR图像中的片(I帧)
(3)NAL头的进一步说明
NAL的头占用了一个字节,按照比特自高至低排列可以表示如下:
0AABBBBB
其中,AA用于表示该NAL是否可以丢弃(有无被其后的NAL参考),00b表示没有参考作用,可丢弃,如B slice、SEI等,非零——包括01b、10b、11b——表示该NAL不可丢弃,如SPS、PPS、I Slice、P Slice等。常用的NAL头的取值如:
0x67: SPS
0x68: PPS
0x65: IDR
0x61: non-IDR Slice
0x01: B Slice
0x06: SEI
0x09: AU Delimiter
由于NAL的语法中没有给出长度信息,实际的传输、存储系统需要增加额外的头实现各个NAL单元的定界。
其中,AVI文件和MPEG TS广播流采取的是字节流的语法格式,即在NAL单元之前增加0x00000001的同步码(即看到0x00000001,便知道到了NALU的开头),则从AVI文件或MPEG TS PES包中读出的一个H.264视频帧以下面的形式存在:
00 00 00 01 06 ... 00 00 00 01 67 ... 00 00 00 01 68 ... 00 00 00 01 65 ...
SEI信息 SPS PPS IDR Slice
而对于MP4文件,NAL单元之前没有同步码,却有若干字节的长度码,来表示NAL单元的长度,这个长度码所占用的字节数由MP4文件头给出;此外,从MP4读出来的视频帧不包含PPS和SPS,这些信息位于MP4的文件头中,解析器必须在打开文件的时候就获取它们。从MP4文件读出的一个H.264帧往往是下面的形式(假设长度码为2字节):
00 19 06 [... 25 字节...] 24 aa 65 [... 9386 字节...]
SEI信息 IDR Slice
备注:上面这个例子是我在网上看到的,我认为不对,因为经过我亲自测试,发现,length应该是包括NALU的头部的长度的。
8.MP4文件中的NAL
MP4文件中的一个sample由多个NALU组成。大体结构如下:Length1+NALU1+Length2+NALU2+。。。。其中Length表示下一个NALU的长度(不包括Length本身的长度),而NALU的第一个字节是表示该NALU的头部。通过NALU头部的信息可以得到该NALU的类型。每个sample的总长度可以由mp4中的stsz中的条目得到。至于PPS和SPS,存储在mp4的头部moov-trak-mdia-minf-stbl-stsd-avc1-avcC中。
关于Length的长度:Length的长度是1/2/4字节中的一种,且在一个mp4文件中是固定的,存储在mp4的头部moov-trak-mdia-minf-stbl-stsd-avc1-avcC中。

h264 NALU的获取与分析

0x00000001或0x000001是一个nalu的起始标志,遇到下一个此标志时为该nalu的结尾。起始标志的后面第一个字节(type)里包含有nalu的类型,type & 0x1F即为该nalu的...
  • xiaoluer
  • xiaoluer
  • 2016-12-05 10:36:33
  • 3236

H264文件解析出nalu数据,送给ffmpeg解码,opencv显示

本博客主要是H264的视频码流有ffmpeg 解码后,有opencv先,这里贴出全部代码,你只需自己建个工程,配置一下ffmpeg库和opencv3.0库就好了。 头文件 H264.h#includ...
  • baidu_31872269
  • baidu_31872269
  • 2017-08-15 22:20:36
  • 584

H264--NALU/SPS/PPS

帧格式 H264帧由NALU头和NALU主体组成。 NALU头由一个字节组成,它的语法如下:       +---------------+       |0|1|2|3|4|5|6|7|      ...
  • evsqiezi
  • evsqiezi
  • 2013-01-11 10:39:28
  • 10876

h.264码流解析_一个SPS的nalu及获取视频的分辨率

00 00 00 01 67 42 00 28 E9 00  A0 0B 77 FE 00 02 00 03 C4 80  00 00 03 00 80 00 00 1A 4D 88  1...
  • a2657222
  • a2657222
  • 2012-08-31 23:51:08
  • 7271

H264 NALU结构

当前流行的应该还算是h264,接下来中国广播电视会使用avs,而国际上应该会使用h265(要收专利费)和Google的VP9(开源,无专利费)   一个h264视频由N组GOP(group of ...
  • u011757360
  • u011757360
  • 2014-05-22 18:59:21
  • 1605

H264码流解析及NALU

ffmpeg 从mp4上提取H264的nalu http://blog.csdn.net/gavinr/article/details/7183499 639     /* bitstre...
  • wh8_2011
  • wh8_2011
  • 2016-07-12 11:59:10
  • 4009

H264 NALU slice 模式

slice模式下一个完整的NALU需要判断每一个slice包得第5个字节与上0x80是否等于80.还是举个例子来说明好了....比如:第一个包 00 00 00 01 65 9A …第二个包 00 0...
  • niino
  • niino
  • 2011-07-28 09:24:04
  • 3987

H264 NALU RTP

对h.264压缩视频码流中i帧的提取(firstime) 2010-06-30 09:15 转载自 fandy586  http://hi.baidu.com/sdlyfdy   这 个问题要...
  • ljzcom
  • ljzcom
  • 2013-08-08 12:42:55
  • 3312

H.264 NALU语法结构

补充笔记: 关于VCL:VCL层是指视频编码层,VCL NAL 单元是指那些nal_unit_type 值等于 1 到 5(包括 1 和 5)的 NAL 单元,这些单元都包含了视频数据。所有其他的 ...
  • NewThinker_wei
  • NewThinker_wei
  • 2013-04-01 20:53:01
  • 27966

H.264 NAL层解析(0x00000001,编码,打包,NALU)

H.264 NAL层解析(0x00000001,编码,打包,NALU)   1.引言 H.264的主要目标: 1.高的视频压缩比 2.良好的网络亲和性 解决方案: VCL  video ...
  • wudebao5220150
  • wudebao5220150
  • 2013-10-31 19:59:54
  • 10588
收藏助手
不良信息举报
您举报文章:H264中的NALU概念解析
举报原因:
原因补充:

(最多只允许输入30个字)