x264 杂谈和引子
x264 杂谈和引子
个人学习的时候,碰到的棘手概念,看似简单,却在各种网站上被人带到坑里去的一个东西……
1. 关于frame,slice,mb,nal之间的关系
错误的理解:
在x264的设计中,会把frame拆分成若干个slice,然后每个slice拆分成若干个MB,最后再对每一个MB逐个编码。编码完毕之后,会打包成一个个的NAL数据包。
正确的理解:
其实上面的理解并没有错,但从某一种意义上来说,它又错了,它错就错在没有说清楚因果关系。
从正常人的角度,视频被分成一组组的帧Frame,然后为了编码方便,再把Frame细分成一个个的MB,就应该是这么个流程。可奇怪的是,x264偏偏引入了一个叫做slice的概念,那不由得叫人发问:
- 为什么引入slice?
slice仅仅是一个分组的概念。在x264的设计中,因为要兼顾现代流媒体需要网络传输的概念(而网络在传输数据的时候,需要把数据分割成一个个的数据包),所以为了兼容网络传输,才不得不提出slice。因为一个网络数据包的大小是有限的,可能装不下一个完整的Frame,只能把Frame分割成数个slice,这样一来,就成了“一个网络数据包装一个slice的数据”,所以一个slice中的数据会刚好塞满一个NAL的buffer,二者是1:1的关系。
-
一个slice中包含多少个MB?
我们知道了slice的目的,就该明白一个slice中包含的MB数量是未知的,这完全取决于MB编码之后的大小。有些MB编码之后size比较大,这时候slice就装得数目就少一点;而有些MB编码之后很小,那么slice就装得多一些。这完全是一个动态的数目。
所以我们不能说“把frame拆分成若干个slice,然后每个slice拆分成若干个MB”,这完全弄乱了因果关系,应该说:“把Frame 拆分成MB,编码之后,再按照NAL设定的大小,把数据分组成一个一个的slice再打包进NAL里面”。
所以slice仅仅是一个分组的概念,它的目的是适配NAL的大小,和编码的效率一点关系也没有!
2. 关于i_lambda 和 i_lambda2 两个系数
这两个参数,是为了在评估图像的时候用到。
-
i_lambda = 某个系数 * QStep,是专门在SATD评估模式下使用的,是为了把bits转化成SATD相同的“单位/量级”。
-
i_lambda2 = 某个系数 * QStep * QStep,是专门在RD模式下使用的,是为了把bits转化成ssd相同的“单位/量级”。
一个例子:
在运动预测中,x264会使用SATD值来评估一个MB的最优运动结果,此时就涉及到MB的拆分策略,在拆成16x16的情况需要1 bits来标记拆分类型,而拆成4个8x8的时候,则需要4个bits来标记每一个子块的类型。这时候,根据不同的拆分类型,最后的评分score= SATD + 额外的标记bits * i_lambda,而这个i_lambda就是为了把bits转化成SATD相同的“量级/单位”,让两边处在同一个“单位”下才能进行加权,否则“单位/量级”不一样的东西又怎么能加权呢?