音视频笔记(二)

218 阅读4分钟

视频编码的底层?

帧间编码,帧内编码。差异化内容以宏块编码为主,之前有宏块编码的以矢量为主。


帧分为三种:

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,去掉一个像素不影响(这里存疑)。

分隔符后边是帧类型

也可以通过这个计算一个流里有多少帧。


注:本文章内容图片来源于网络