标题
- 1.H264介绍
- 2.H264编解码解析
- 2.1. H264编码原理
- 2.2 H264的I帧,P帧,B帧
- 2.3 H264编码结构解析
- 2.4 NALU
- 2.4.1 NALU结构
- 2.4.2 解析NALU
- 2.4.3 annexb模式
1.H264介绍
H.264从1999年开始,到2003年形成草案,最后在2007年定稿有待核实。在ITU的标准⾥称为H.264,在MPEG的标准⾥是MPEG-4的⼀个组成部分–MPEG-4 Part 10,⼜叫Advanced Video Codec,因此常常称为MPEG-4 AVC或直接叫AVC。
2.H264编解码解析
2.1. H264编码原理
在音视频传输过程中, 视频文件的传输是一个很大的问题,比如一个1920*1080分辨率的视频, 每个像素为RGB占用3字节,帧率为25的视频,那么对于传输带宽要求为:1920 * 1080 * 3 * 25 / 1024/1024=148.315MB/s,这种网络速率对于我们现在的网络技术是不可取的,因此视频压缩和编码技术应运而生, 对于视频文件来说,视频由单张图片帧组成,而视频一般都是连续的,因此每一帧都有相似性, 视频压缩技术就是用了这一点进行图片压缩.
H264采用了16 * 16的分块大小对,视频帧图像进行像素对比进行压缩编码.
2.2 H264的I帧,P帧,B帧
H264采取帧内压缩和帧外压缩的方式提高编码速率
H264采用了独特I帧,P帧,B帧策略进行实现连续帧之间的压缩
如上图所示:
帧的分类 | 中文 | 意义 |
---|---|---|
I帧 | 帧内编码帧 | I帧通常是每个GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度的压缩,作为随机访问的参考点,可以当成图像. I帧可以看出一个图像经过压缩的产物,因此I帧可以通过自身通过解压算法进行还原成一张完成的图片 |
P帧 | 前向预测编码帧 | 通过充分将低于图像序列中前⾯已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧。需要参考前面的I帧或者P帧来生成一张完整的图片 |
B帧 | 双向预测帧 | 既要考虑前面的帧,又要考虑后面的帧,已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧。参考前一个I帧或者P帧及后一个P帧或者I帧来生成一张完整的图片 |
压缩率: B>P>I
2.3 H264编码结构解析
H264除了实现了视频压缩之外,为了网络传输还提供了对应的视频编码及分片策略;类似网络数据封装成IP帧一样,在H264中将其称为组(GOP,group of pictures),片(slice),宏块(Macroblock)这些⼀起组成了H264的码流分层结构.
H264将其组织成为序列(GOP)、图⽚(pictrue)、⽚(Slice)、宏块(Macroblock)、⼦块(subblock)五个层次。
GOP (图像组)主要⽤作形容⼀个IDR帧 到下⼀个IDR帧之间的间隔了多少个帧。
H264将视频分为连续的帧进⾏传输,在连续的帧之间使⽤I帧、P帧和B帧。同时对于帧内⽽⾔,将图像分块为⽚、宏块和字块进⾏分⽚传输;通过这个过程实现对视频⽂件的压缩包装。
IDR(Instantaneous Decoding Refresh,即时解码刷新)
一个序列的第一个图像叫做IDR帧,IDR帧一定是I帧,但是I帧不一定是IDR帧,由于P帧和B帧还原时需要其他帧,因此在解压出图像时,之前还原的图像还要存放在一个队列中,但是并不是所有图像解压后一直都放在队列中的,当遇到IDR帧后之前的队列就要清空一下,这样如果前一个序列遇到重大错误,后面的帧都不会受到影响.
2.4 NALU
- SPS:序列参数集,SPS中保存了⼀组编码视频序列(Coded video sequence)的全局参数。
- PPS:图像参数集,对应的是⼀个序列中某⼀幅图像或者某⼏幅图像的参数。
- I帧:帧内编码帧,可独⽴解码⽣成完整的图⽚。
- P帧: 前向预测编码帧,需要参考其前⾯的⼀个I 或者B 来⽣成⼀张完整的图⽚。
- B帧: 双向预测内插编码帧,则要参考其前⼀个I或者P帧及其后⾯的⼀个P帧来⽣成⼀张完整的图⽚。
- 发I帧之前,⾄少要发⼀次SPS和PPS。
2.4.1 NALU结构
H.264裸流是由一个个NALU组成的,他的功能分为两层,VCL(视频编码层)和NAL(网络提取层):
- VCL:包括核心压缩引擎和块,宏块和片的语法级别定义,设计目标是尽可能独立于网络进行高效编码.
- NAL:负责将VCL产生的比特字符串适配各种网络环境和多元环境中,覆盖了所有片级以上语法.
在VCL在进行数据传输或者存储之前,这些编码的VCL数据需要映射到或者封装到NAL单元中(NALU)
一个NALU=一组NALU头部信息+一个原始字节序列负荷(RBSP,Raw Byte Sequence Payload).
NALU结构单元的主体结构如下:一个原始的H264原始单元通常由[StartCode][NALUHeader][NALU Payload]三部分组成,其中StartCode 用于标识一个NALU单元的开始,必须是"00 00 00 01"或者"00 00 01",除此之外基本上相当于NALU Header+ RBSP
对于FFmpeg来说,MP4文件解复用后的packet是不带startcode的,但是TS文件读取出来的packet是带startcode的
2.4.2 解析NALU
每个NALU单元一个一定语法元素的可变字节长字符串,包括一个字节的头信息(用来表示数据类型),以及若干负荷数据.
其中:
- T为负荷数据类型,占用5bit
-
nal_unit_type:这个NALU单元的类型,1~12 由H.264使⽤,24~31由H.264以外的应⽤使⽤
- R为重要指标,占用2bit
-
nal_ref_idc.:取00~11,似乎指示这个NALU的重要性,如00的NALU解码器可以丢弃它⽽不影响图像的回放,0~3,取值越⼤,表示当前NAL越重要,需要优先受到保护。如果当前NAL是属于参考帧的⽚,或是序列参数集,或是图像参数集这些重要的单位时,本句法元素必需⼤于0。
- F作为禁止位,占1bit
-
forbidden_zero_bit: 在 H.264 规范中规定了这⼀位必须为 0
nal_unit_type | NAL 单元和 RBSP 语法结构的内容 |
---|---|
0 | 未指定 |
1 | ⼀个⾮IDR图像的编码条带slice_layer_without_partitioning_rbsp( ) |
2 | 编码条带数据分割块A slice_data_partition_a_layer_rbsp() |
3 | 编码条带数据分割块B slice_data_partition_b_layer_rbsp( ) |
4 | 编码条带数据分割块C slice_data_partition_c_layer_rbsp( ) |
5 | IDR图像的编码条带(片) slice_layer_without_partitioning_rbsp( ) |
6 | 辅助增强信息 (SEI)sei_rbsp( ) |
7 | 序列参数集 seq_parameter_set_rbsp( ) |
8 | 图像参数集 pic_parameter_set_rbsp( ) |
9 | 访问单元分隔符 access_unit_delimiter_rbsp( ) |
10 | 序列结尾 end_of_seq_rbsp( ) |
11 | 流结尾 |
12 | 填充数据 |
13 | 序列参数集扩展 |
2.4.3 annexb模式
h264一共有2中封装格式:
- 一种是annexb模式,传统模式,有startcode,SPS和PPS,在ES中
- 一种是mp4模式,一般mp4,mkv都是mp4模式,没有startcode,SPS和PPS以及其他信息,是被封装在container中,每一个frame前面4字节是这个frame的长度
一般解码器只支持annexb模式,因此需要将mp4做转换,在ffmpeg中使用h264_mp4toannexb_filter