码控算法

用算法来控制编码器输出码流的大小,码控就是为一帧图像选择一个合适的QP值的过程。

一帧图像的画面确定了之后,画面的复杂度和QP值几乎决定了编码之后的大小。由于编码器无法决定画面的复杂度,因此码控的目标就是选择一个合适的QP值,以此来控制编码后码流的大小。

码控算法的类型

CBR (恒定码率) ,VBR (动态码率) ,CQP (恒定QP),CRF(恒定码率因子)

VBR 码率随着原始视频画面复杂度的变化而不断变化,复杂的时候码率比较高

CQP使用同一个QP值,画面复杂的时候,残差比较大,画面简单的时候,残差很小,一般用来衡量编码算法的性能,在实际工程中不会使用

CRF 是x264默认的码控算法,QP是会变化。在画面运动大时候,提高QP值,画面运动小的时候,降低QP值。

CBR 恒定码率,需要用户设置一个值,不管画面复杂度如何,都尽量使得输出的码率接近设置的目标码率。适合RTC场景,因为RTC场景希望编码的码率跟实际预测的带宽值接近,不能超出码率太大,也希望能够尽量有效地利用带宽,不能太低目标码率,从而能保证编码后图像画面清晰。

CBR算法

一步步的将输出码率逼近目标码率,而不是一步准确确定QP值。

算法控制分为 帧组级,帧级,宏块组GOM

具体操作过程如下

1、先确定帧组级的输出大小尽量接近目标码率。

2、确定组内的每一帧具体应该分配多少的大小才能保证帧组最后输出的大小

3、根据目标帧大小,确定一个帧级的QP值

4、确定帧内的宏块组应该分配多少,来保证当前帧最后的输出大小能接近于目标帧大小

5、确定宏块的QP

输出码率尽量接近目标码率,保证在不同画面复杂度和不同运动程度的情况下,需要先计算得到当前帧的复杂度。

复杂度求解

I帧复杂度求解:帧内预测是用编码块周围已编码的像素来预测当前编码块的像素值,方差能够表示I帧复杂度的值,方差越大,表示帧内变化程度越剧烈,用周围像素去预测当前编码块的像素,可能有较大的残差。

I帧的复杂度,是求每一个宏块的方差,最后将帧的所有宏块的方差之和作为帧的复杂度

P帧复杂度求解: SAD值,使用当前帧的宏块,减去参考帧对应位置的宏块,并将所有宏块的SAD值加起来作为P帧的复杂度。

帧组级

CBR是恒定码率,保证一段时间内输出的码率接近目标码率,而不是每一帧输出都严格接近目标码率。因为,算法是根据一段时间内前面已经编码的结构来调节未编码帧的QP值,从而达到一组帧的输出大小尽量接近目标码率的。

在开始的时候,需要根据目标码率来确定帧组的目标大小,再确定帧组内每一帧的目标大小。

1,在编码刚开始的时候,帧组的剩余大小就是帧组的目标大小

2、编码当前帧组中的第一帧。将帧组的剩余大小除以帧组的帧数,得到第一帧的目标大小

3、第一帧编码后,需要用第一帧实际编码的大小来更新帧组的剩余大小

4、将帧组的剩余大小减去第一帧编码后的实际大小

5、第二帧的目标大小就是等于更新后的帧组的大小,除以剩余帧数

6、帧组中帧不断编码,不断更新帧组的剩余大小,不断调整帧的目标大小

总体意思是,总的减去已经用的,剩下的平均分配,不断迭代

帧级

有了帧组级码控中计算得到的目标帧大小,就能计算当前帧SliceQP

当前帧的复杂度和目标帧大小,加上前面已经编码完成的帧的复杂度和编码使用的Qstep值。以及使用这个QStep编码之后实际的编码大小来计算。

可以根据前面已经编码好了的帧估算一下,大体计算一下,这些帧的复杂度和QStep跟最终的编码大小大概成多少比例,然后再使用这个比例来估算在当前帧的复杂度下,大概使用多少QStep能输出大小接近于目标帧大小。

一帧编码后的大小应该是和帧的复杂度成正比,并且跟帧使用的QStep成反比。

GOM级

在编码一个GOM之前,需要计算帧的实际剩余大小和帧的目标剩余大小,帧的实际剩余大小就是用帧的目标大小减去帧中已编码的GOM的实际大小。

再使用帧的实际剩余大小加上前一个GOM的实际编码大小,减去该GOM的目标大小,就是帧的目标剩余大小。

需要计算当前GOM的目标大小,以供下一个GOM编码的时候做GOM级码控计算的时候使用。