视频编码的底层?
帧间编码,帧内编码。差异化内容以宏块编码为主,之前有宏块编码的以矢量为主。
帧分为三种:
i帧:第一帧叫i帧,也叫关键帧,以宏块编码为主,不依赖于其他帧。i帧是比较大的。大概100k(大小依据编码方式而定,目前主要是参考h264)左右,帧类型(65),帧类型(0x65)。
P帧:运动矢量+宏块,需要参考其他帧。单向依赖,大小40-80k。与i帧相似率大概70%以上编码为p帧,帧类型(0x41)。
b帧:双向依赖,是计算出来的帧。只保存百分比,0-5k。与i帧相似率大概95%以上编码为b帧,帧类型(0x21 或 0x01)。(在传输缓冲器缓存)
GOP:一个场景,场景内的物体都是相似的。两个关键帧(i帧)之间的图像序列。
直播帧i帧越多越好,强调秒开率。
h264在设计上,分vcl跟nal两层。
vcl:video coding layer,即视频编码层,负责编码视频,独立于网络环境。
nal:network abstraction layer,即网络抽象层,把vcl提供的数据进行封装,应用于网络传输。
nal层的基本单位叫nalu。
NALU:两个分隔符之间的数据
编码的帧顺序和播放的帧顺序不一定一样,因为有传输缓冲器的存在,比如b帧需要前后的帧才能编码输出。
一个可播放的视频文件顺序第一帧是i帧,第二帧是p帧,因为中间的b帧需要等第一二帧编码输出后才能输出。而且中间的b帧输出没有先后顺序,因为两个b帧没有关联。
当输出一个p帧时,会将传输器缓冲器中的b帧全部输出。这样b帧位置也不会错乱。
编解码要根据pts(时间戳)
编码i帧最简单,编码b帧编解码比较复杂,时间也长。
h264包含很多分隔符(一般是00 00 00 01),用来给视频播放器判断视频帧是否完整,而判断cpu是否去解码。可以通过分隔符判断有多少帧。
为了区别帧内包含该分隔符编码,会在编码时遇到两个连续的00 00 就插入一个0x03,用来做区别分隔符,解码时读取后将0x03删掉,显示出正常像素。如果还有和分割符相同的就把该像素删除?
分隔符后面会跟着帧类型i(0x65)、p(0x41)、b(0x01)。
码流顺序:帧在代码里的顺序
pts:时间戳,帧的输出顺序
编码i帧容易些,编码b帧时间比较长,个人理解b帧是计算帧。
编码流程
视频信源编码器:(提纯数据)
1.划分宏块并预测宏块的方向
2.判断当前宏块之前有没有编码需不需要重新编码。
3.输出运动矢量。
4.当前图像与之前图像有差异化的地方进行宏块编码
视频复合编码器(加工整理数据)
用来整理残差数据(宏块只保存左、上边以及方向),输出运动矢量。
传输缓冲器(检查数据)
缓存B帧,B帧输出需要得到i帧之后的p/i帧才可以计算输出。
传输编码器(包装数据)
序列化数据,好比将bean序列化为json数据一般。
为什么音视频会不同步?
音频是线性的,视频不线性,因为帧的码流顺序不一定和时间戳一样,还有解析b帧得等前后两帧的数据才行。
解决办法:音频找到对应的时间戳才开始播放。
h64怎么判断帧是否完整?
通过分隔符去判断,有00 00 00 01和00 00 01两种。如果在帧里有这样连续两个00 00 00 01的数据,在编码时00 00后边插入03,在解码时去掉03,以防止被误判分隔符。如果正常数据00 00 03 00 01,也会显示00 00 00 01,去掉一个像素不影响(这里存疑)。
分隔符后边是帧类型
也可以通过这个计算一个流里有多少帧。
注:本文章内容图片来源于网络