本文系微信公众号和知乎专栏《MediaStack》原创文章,欢迎大家关注,随时进行交流。

    最近两天羊了个羊非常火爆,而关注的LiveVideoStack公众号也正好推了一篇文章《云游戏全面解析》,相关链接:
    云游戏之前就听说过,当时还整理过一个笔记:

    看完之后,突然想起上半年在一个音视频学习社群里,有位学友推了一篇PDF文档《 云游戏白皮书 》,由华为技术有限公司和杭州顺网科技股份有限公司在2019年撰写的。虽然过了两年了,现在看完后仍然有几个点感觉挺好的,大家有兴趣的可以一起看看,目前是公开状态,可以自行下载,相关链接如下:
https://www-file.huawei.com/-/media/corporate/pdf/ilab/2019/cloud_game_whitepaper.pdf
    有好多点讲解的还是不错的,自己也算开拓眼界了。其中有一个点比较感兴趣,无B帧编码,文章中的相关介绍:
    该文章给出的一些比较如下:
  •     无 B 帧编码的优势是,除了 I 帧,之后的每一帧,都可以根据前面一帧来完成编码,实现简单,而且 每抓屏一次就可以立刻送往编码,不产生额外的延迟。相应的,P 帧的压缩率较低,需要的带宽更大。 
  •     有 B 帧编码的优势是,B 帧压缩率更高,更节省带宽,但 B 帧需要等到后面的 P 帧才能完成编码, 所以产生了至少一个帧间隔的延迟。 
  •     时延优化是云游戏的重点,因此无 B 帧编码是优选,I 帧后续都是 P 帧,也利于保持帧间隔的稳定。 
  •     音频也有编码标准,常见的有 AAC、MP3、WMA、PCM 等,但由于音频的数据量比较小,有些云 游戏平台并没有做音频的编码压缩过程,而是采样后直接传输。
    要做无B帧编码,首先要搞清楚I帧,P帧,B帧的特点,这样有的放矢才能收放自如,达到我们期待的目标,为此依据该文章结合其他一些资料汇总相关比较如下:
Non-B-Frame
为了深刻理解non-b帧模式,直接review一下FFMPEG代码,这样可以深入学习,同时比较直观地查看相关效果。
相关路径:doc/codec.texi中针对-bf参数有如下描述:
  • 设置非 B 帧之间的最大 B 帧数。
  • 必须是介于 -1 和 16 之间的整数。0 表示禁用 B 帧。如果使用值 -1,它将根据编码器选择自动值。
  • 默认值为 0。
对比实验
   首先通过ffmpeg工具进行转码,本次选取一个yuv文件作为源文件,分别采用bf为0和为2两个值进行转码,源文件一共38帧的yuv数据:
    参数bf为2的转码过程:
ffmpeg -s 640*480 -pix_fmt yuv420p -i file.yuv -vcodec libx264 -bf 2 bf2.mp4
    参数bf为0的转码过程:
ffmpeg -s 640*480 -pix_fmt yuv420p -i file.yuv -vcodec libx264 -bf 0 bf0.mp4
转码后的大小如下:
    通过雷神的VideoEye工具查看,如果bf为0时,确实没有B帧;而bf为2时,则P帧之间间隔两个B帧,这样基本符合我们的预期。
    惊喜的发现,BF0转码后的数据量比BF2的略微偏小一点,而且码率也会小一点点,这倒是没有想到
    或许是源文件数量太小的缘故?因此又做了新的尝试:从YUV的网站上下载一个2000Frames的yuv文件,分别用BF0和BF2进行编码,
http://trace.eas.asu.edu/yuv/
PS:一些视频素材可以查阅之前的公号文章,
音视频测试-测试视频收集
    对比之后结论仍然是BF0的压缩大小略优于BF2的,文件越大,也差距也大,不过该内容涉及很多流程,本文章暂时不做讨论,留作课后作业了。
代码查阅
    既然已经在FFMPEG的可执行文件执行了相关操作,我们简单了解一下FFMPEG代码实现也不为过:
在libavcodec\options_table.h中可以查看到BF相关选项,默认值是0,也就是non-B-frame模式。
    max_b_frames会依据输入参数设定的解码器,完成对应值传输,从而影响编解码效果。
    比如本文实例中采用的x264解码器,相关代码如下:
    通过上下文中max_b_frames的值,设置到x264的参数结构体中;
    之后调用x264的解析函数:x264_param_parse,进行X264编解码器的参数传递:
    之后就是x264的编解码的内容,感兴趣的童鞋可以从官网上下载对应代码(videolan,是不是很熟悉?对,没错,和VLC播放器是同一家的)
https://code.videolan.org/videolan/x264
    通过对应接口可以查看x264_param_parse解析过程,该部分主要完成ffmpeg参数的获取和设置:
    本文关注的参数bframes通过如下代码获取:
    传递参数到这里,之后相关流程就比较复杂了,涉及到宏块,运动估计,lookahead,码率控制等多个流程,相关内容还是非常多的,如下截图:
总结
    对于编码有兴趣的可以继续深入研究,如果用不到,或者不感兴趣的,其实知道这些内容也就差不多可以满足日常开发需求了。
    在此推荐一位大佬的X264的B帧解读文章,
https://www.cnblogs.com/wangnath/p/15194579.html
    这位大佬解读的多篇文章对于x264的流程非常有帮助,相信我,每篇都是干货满满,看过之后收获颇丰。
    不过话又说回来,-bf 为0时文件大小和码率都略小,具体原因还没有找到,接下来仔细跟踪一下代码,探究一下具体原因,学成归来之时再和大家分享。

我是一枚爱跑步的程序猿,很多内容属于自学内容,文中难免会出现一些错误或者不准确的地方,恳请大家批评指正。
继续阅读
阅读原文