H264基本概念学习笔记
- NALU(Network Abstract Layer Unit)
- GOP (图像组)主要⽤作形容⼀个IDR帧 到下⼀个IDR帧之间的间隔了多少个帧。
- H264将其组织成为 序列(GOP)、图⽚(pictrue)、⽚(Slice)、宏块(Macroblock)、⼦块(subblock)五个层次。
- H264将视频分为连续的帧进⾏传输,在连续的帧之间使⽤I帧、P帧和B帧。同时对于帧内⽽ ⾔,将图像分块为⽚、宏块和字块进⾏分⽚传输;通过这个过程实现对视频⽂件的压缩包装。
- IDR(Instantaneous Decoding Refresh,即时解码刷新) 。
- ⼀个序列的第⼀个图像叫做 IDR 图像(⽴即刷新图像),IDR 图像都是 I 帧图像
- 其核⼼作⽤是,是为了解码的重同步,当解码器解码到 IDR 图像时,⽴即将参考帧队列清 空,将已解码的数据全部输出或抛弃,重新查找参数集,开始⼀个新的序列。
- B帧不能被当做参考帧。
NALU
- SPS:序列参数集,SPS中保存了⼀组编码视频序列(Coded video sequence)的全局参数。
- PPS:图像参数集,对应的是⼀个序列中某⼀幅图像或者某⼏幅图像的参数。
- I帧:帧内编码帧,可独⽴解码⽣成完整的图⽚。
- P帧: 前向预测编码帧,需要参考其前⾯的⼀个I 或者B 来⽣成⼀张完整的图⽚。
- B帧: 双向预测内插编码帧,则要参考其前⼀个I或者P帧及其后⾯的⼀个P帧来⽣成⼀张完整的 图⽚
- 发I帧之前,⾄少要发⼀次SPS和PPS。
NALU结构
- H.264原始码流(裸流)是由⼀个接⼀个NALU组成,它的功能分为两层:
- VCL(视频编码层):包括核⼼压缩引擎和块,宏块和⽚的语法级别定义,设计⽬标是尽可能地独⽴于⽹ 络进⾏⾼效的编码
- NAL(⽹络提取层):负责将VCL产⽣的⽐特字符串适配到各种各样的⽹络和多元环境中,覆盖了所有⽚级 以上的语法级别
- 在VCL进⾏数据传输或存储之前,这些编码的VCL数据,被映射或封装进NAL单元。
- 1个NALU = 1组对应于视频编码的NALU头部信息 + 1个原始字节序列负荷(RBSP,Raw Byte Sequence Payload)
- NALU结构单元的主体结构如下所示:
- ⼀个原始的H.264 NALU单元通常由[StartCode] [NALU Header] [NALU Payload]三部分组成
- 其中 Start Code ⽤于标示这是⼀个NALU 单元的开 始,必须是"00 00 00 01" 或"00 00 01"
- 除此之外基本相当于⼀个NAL header + RBSP;
- 对于FFmpeg解复⽤后,MP4⽂件读取出来的packet是不带startcode,但TS⽂件读取出来 的packet带了startcode。
解析NALU
- 每个NAL单元是⼀个⼀定语法元素的可变⻓字节字符串,包括包含⼀个字节的头信息(⽤来表 示数据类型),以及若⼲整数字节的负荷数据。
- NALU头信息(⼀个字节):
(注:图片参考:https://www.jianshu.com/p/31ed32fd7b6b)
- T为负荷数据类型,占5bit
- nal_unit_type:这个NALU单元的类型,1~12由H.264使⽤,24~31由H.264以外的应⽤ 使⽤
- R为重要性指示位,占2个bit
- nal_ref_idc.:取00~11,似乎指示这个NALU的重要性
- 如00的NALU解码器可以丢弃它⽽不 影响图像的回放,0~3,取值越⼤,表示当前NAL越重要,需要优先受到保护。
- 如果当前 NAL是属于参考帧的⽚,或是序列参数集,或是图像参数集这些重要的单位时,本句法元 素必需⼤于0。
- F为禁⽌位,占1bit
- forbidden_zero_bit: 在 H.264 规范中规定了这⼀位必须为 0
- H.264标准指出,当数据流是储存在介质上时,在每个NALU 前添加起始码:0x000001 或 0x00000001,⽤来指示⼀个NALU 的起始和终⽌位置:
- 在这样的机制下,在码流中检测起始码,作为⼀个NALU得起始标识,当检测到下⼀个起始 码时,当前NALU结束。
- 3字节的0x000001只有⼀种场合下使⽤,就是⼀个完整的帧被编为多个slice(⽚)的时 候,包含这些slice的NALU 使⽤3字节起始码。
- 其余场合都是4字节0x00000001的。
H264 annexb模式
- H264有两种封装:
- annexb模式,传统模式,有startcode,SPS和PPS是在ES中(可参考:《H264 ES PS TS 流的区别》https://blog.csdn.net/coloriy/article/details/80623192)
- mp4模式,⼀般mp4 mkv都是mp4模式,没有startcode,SPS和PPS以及其它信息 被封装在container中,每⼀个frame前⾯4个字节是这个frame的⻓度。
- 很多解码器只⽀持annexb这种模式,因此需要将mp4做转换:在ffmpeg中⽤ h264_mp4toannexb_filter可以做转换
const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb"); AVBSFContext *bsf_ctx = NULL; // 2 初始化过滤器上下⽂ av_bsf_alloc(bsfilter, &bsf_ctx); //AVBSFContext; // 3 添加解码器属性 6avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->cod ecpar); av_bsf_init(bsf_ctx);
GOP group of pictures
- 在视频编码序列中,GOP即Group of picture(图像组),指两个I帧之间的距离。
- Reference(参考周期)指两个P帧之间的距离。
- ⼀个I帧所占⽤的字节数⼤于⼀个P帧,⼀个P 帧所占⽤的字节数⼤于⼀个B帧。
- 所以在码率不变的前提下,GOP值越⼤,P、B帧的数量会越多,平均每个I、P、B帧所占⽤的 字节数就越多,也就更容易获取较好的图像质量;Reference越⼤,B帧的数量越多,同理也 更容易获得较好的图像质量。
- 通过提⾼GOP值来提⾼图像质量是有限度的,在遇到场景切换的情况时, H.264编码器会⾃动强制插⼊⼀个I帧,此时实际的GOP值被缩短了。
- 在⼀个GOP 中,P、B帧是由I帧预测得到的,当I帧的图像质量⽐较差时,会影响到⼀个GOP中后续P、B 帧的图像质量,直到下⼀个GOP开始才有可能得以恢复,所以GOP值也不宜设置过⼤
- 由于P、B帧的复杂度⼤于I帧,所以过多的P、B帧会影响编码效率,使编码效率降低。
- 另外,过⻓的GOP还会影响Seek操作的响应速度,由于P、B帧是由前⾯的I或P帧预测得到 的,所以Seek操作需要直接定位,解码某⼀个P或B帧时,需要先解码得到本GOP内的I帧及之 前的N个预测帧才可以,GOP值越⻓,需要解码的预测帧就越多,seek响应的时间也越⻓。
- 拓展:可参考 https://www.jianshu.com/p/31ed32fd7b6b