关于slice
上文可看到 slice有ABC三种 这个实在太过于细节 真要说 那得说很久 本文不做讨论
当NAL header中带有以上字段时表明这是一个slice 在我们开始讨论RBSP和Start Code之前 先来说说这个东西
一帧图片经过 H.264 编码器之后,就被编码为一个或多个片(slice),而装载着这些片(slice)的载体,就是 NALU 了,我们可以来看看 NALU 跟片的关系(slice)。
图片编码后
片(slice)的概念不同与帧(frame),帧(frame)是用作描述一张图片的,一帧(frame)对应一张图片,而片(slice),是 H.264 中提出的新概念,是通过编码图片后切分通过高效的方式整合出来的概念,一张图片至少有一个或多个片(slice)。
上图中可以看出,片(slice)都是又 NALU 装载并进行网络传输的,但是这并不代表 NALU 内就一定是切片,这是充分不必要条件,因为 NALU 还有可能装载着其他用作描述视频的信息。
片的主要作用是用作宏块(Macroblock)的载体(ps:下面会介绍到宏块的概念)。片之所以被创造出来,主要目的是为限制误码的扩散和传输。
每个片(slice)都应该是互相独立被传输的,某片的预测(片(slice)内预测和片(slice)间预测)不能以其它片中的宏块(Macroblock)为参考图像。
我们可以理解为一 张/帧 图片可以包含一个或多个分片(Slice),而每一个分片(Slice)包含整数个宏块(Macroblock),即每片(slice)至少一个 宏块(Macroblock),最多时每片包 整个图像的宏块。
上图结构中,我们不难看出,每个分片也包含着头和数据两部分:
1.分片头中包含着分片类型、分片中的宏块类型、分片帧的数量、分片属于那个图像以及对应的帧的设置和参数等信息。
2.分片数据中则是宏块,这里就是我们要找的存储像素数据的地方。
宏块是视频信息的主要承载者,因为它包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中的像素阵列。
组成部分:
1.一个宏块由一个16×16亮度像素和附加的一个8×8 Cb和一个 8×8 Cr 彩色像素块组成。
2.每个图象中,若干宏块被排列成片的形式。
从上图中,可以看到,宏块中包含了宏块类型、预测类型、Coded Block Pattern 编码的块模式、Quantization Parameter 量化参数、像素的亮度和色度数据集等等信息。
切片(slice)类型跟宏块类型的关系
I片:只包 I宏块,I 宏块利用从当前片中已解码的像素作为参考进行帧内预测(不能取其它片中的已解码像素作为参考进行帧内预测)。
P片:可包 P和I宏块,P 宏块利用前面已编码图象作为参考图象进行帧内预测,一个帧内编码的宏块可进一步作宏块的分割:即 16×16、16×8、8×16 或 8×8 亮度像素块(以及附带的彩色像素);如果选了 8×8 的子宏块,则可再分成各种子宏块的分割,其尺寸为 8×8、8×4、4×8 或 4×4 亮度像素块(以及附带的彩色像素)。
B片:可包 B和I宏块,B 宏块则利用双向的参考图象(当前和 来的已编码图象帧)进行帧内预测。
SP片(切换P):用于不同编码流之间的切换,包含 P 和/或 I 宏块
SI片:扩展档次中必须具有的切换,它包 了一种特殊类型的编码宏块,叫做 SI 宏块,SI 也是扩展档次中的必备功能。
关于NALU中的RBSP
NALU = NALUHeader+EBSP 组成; EBSP = 防止竞争码+RBSP; RBSP = SODB + RBSP尾部 。
关于我的NALU详细分析2其实是写错了 当时写的就是RBSP 现在想来确实
RBSP其实是中间产品 他既不是最底层也不是最上层的产物 如下图
SODB为原始数据比特流 (String Of Data Bits) ------- 就是最原始的编码/压缩得到的数据。
RBSP为原始字节序列载荷(Raw Byte Sequence Payload)-------- RBSP = SODB + RBSP Trailing Bits(RBSP尾部补齐字节)为了字节对齐
EBSP为扩展字节序列载荷(Encapsulated Byte Sequence Payload) EBSP = RBSP插入防竞争字节(0x03)
tips:防竞争补充说明
用StartCode的字节串来分割NALU,于是问题来了,如果RBSP中也包括了StartCode(0x000001或0x00000001)怎么办呢?所以,就有了防止竞争字节(0x03)也就形成了EBSP
关于是否带Start Code和Start Code是三字节0x00 00 01还是四字节0x00 00 00 01
H.264的两种打包/封装方法:字节流AnnexB格式 和 AVCC格式 (只有这两种)
在H264用于网络发送时,要封装成RTP格式!!!
(一)AnnexB格式---用于实时播放 带Start Code格式
1.AnnexB流结构:使用start code分隔NAL(start code为三字节或四字节,0x000001或0x00000001,一般是四字节);SPS和PPS按流的方式写在头部。
一共有两种起始码start_code:
- 3字节0x000001 单帧多slice(即单帧多个NALU)之间间隔
- 4字节0x00000001 帧之间,或者SPS、PPS等之前
4字节类型的起始码在连续的数据传输中非常有用,因为用字节来对齐、分割流数据,比如:用连续的31个bit 0 后接一个bit 1 来分割流数据,是很容易的。
4字节类型的开始码通常只用于标识流中的随机访问点,如SPS PPS AUD和IDR,然后其他地方都用3字节类型的开始码以减少数据量。
tips:
AnnexB格式每个NALU都包含起始码,且通常会周期性的在关键帧之前重复SPS和PPS (在I帧之前)
所以解码器可以从视频流随机点开始进行解码,实时的流格式
(二)AVCC格式---用于存储
另一个存储H.264流的方式是AVCC格式,在这种格式中,每一个NALU包都加上了一个指定其长度(NALU包大小)的前缀(in big endian format大端格式),这种格式的包非常容易解析,但是这种格式去掉了Annex B格式中的字节对齐特性,而且前缀可以是1、2或4字节,这让AVCC格式变得更复杂了,指定前缀字节数(1、2或4字节)的值保存在一个头部对象中(流开始的部分),这个头通常称为’extradata’或者’sequence header’。(重点)
AVCC格式使用长度来分分割NALU
解码器配置参数在一开始就配置好了(所以我们不能像视频网站中的实时播放一样可以在中间修改参数,比如:帧率,画面),系统可以很容易的识别NALU的边界,不需要额外的起始码,减少了资源的浪费,同时可以在播放时调到视频的中间位置。
这种格式通常被用于可以被随机访问的多媒体数据。如存储在硬盘的文件:MP4、MKV通常用AVCC格式来存储。
所以在解析AVCC格式的时候需要将指定的前缀字节数的值保存在一个头部对象中,这个都通常称为extradata或者sequence header。同时,SPS和PPS数据也需要保存在extradata或者叫’sequence header’中。
同时,SPS和PPS数据也需要保存在extradata或者叫’sequence header’中。
同时,SPS和PPS数据也需要保存在extradata或者叫’sequence header’中。
总结:
1.视频开始有extradata,包含SPS,PPS 指定存储NALU长度的值为几字节
2.每个NALU前有存储NALU的长度
附上图解