固阳音箱协会

【GITC精华演讲】搜狐金昊:视频直播APP开发与性能痛点

麒麟会2018-11-07 15:56:18

导读

11月24日移动互联网专场上,搜狐技术总监金昊分享了《如何解决视频直播APP开发与性能痛点》演讲,介绍了视频直播的多方流程。


演讲嘉宾介绍


金昊

搜狐

技术总监


演讲主题:

如何解决视频直播APP开发与性能痛点


30秒get演讲干货

搜狐技术总监金昊分享了视频直播APP开发与性能痛点,首先简单介绍了千帆直播APP,然后介绍了直播的基本交互流程,制定技术指标与开播基本流程。随后借助千帆直播APP,具体介绍了推流优化与拉流优化以及直播间和连麦等功能。


千帆直播

直播主要的核心技术架构包括这些方面,左边的是音视频采集、处理、分包、推流、分发、直播间、音视频的解码播放。右边是比较核心一些的上层建筑,比如说我们的连麦、PK,数据接口的交互、图片、礼物、实时聊天互动。一些更上层的建筑,娱乐、游戏等等。

 


直播APP一般的交互流程,这里有一个比较简单的时序图。一般我们主播发起直播,服务端分配一个推流地址,这里的流标识一般是不变的,为了方便统计和后面处理。主播端开始处理推流到我们转码中心,转码之后进行自动分发、同时上报状态到我们服务端。观众端通过我们的拉流地址进行拉流,然后解码播放,这样一个基本的流程,基本上所有的直播 APP 都是这样的流程。


 

开播基本流程

开播主要包括五个步骤,一般是采集、音视频的处理、编码、封包、推流五个步骤。这里面比较重要的是处理部分,因为画质好不好、主播漂亮不漂亮、你的直播效果做的好不好,主要还是看我们的处理这方面。


然后是采集,我们看到 iOS、安卓的音视频格式基本是固定的。iOS 上面有一个比较成熟的 AVFoundtion 框架,安卓封装的摄像头也是比较成熟。采集完实际数据之后我们要进行处理,刚刚采集下来的数据是相当大的,不进行处理是推不上去的。现在视频处理方面比较成熟的,都是往 GPU 上面去堆,iOS 有一个比较成熟的框架 GPUImage,安卓也是有一个类似的实现 Android-GPUImage,这使得这部分的开发简易的很多。GPUImage 是一个热插拔的设计,在里面可以通过它做很多事情。比如说美颜滤镜、瘦脸、大眼、AR/VR、道具等等。



经过这样一步一步的过滤、处理之后,最终我们的视频数据有两个出路,一个是我们主播端的回显,另外一部分是我们实际上的编码队列。但是美颜滤镜会占用我们的CPU资源,会影响我们的编码效率,还会增大主播回显延迟,因为每加一个滤镜就有一个缓冲队列在那里处理。我们在开发过程中是通过不断的实践和调整,达到最佳的组合。


视频处理好之后,就是编码分包。视频编码方面是比较成熟的,现在用的基本是 H.264,音频方面用的 AAC,封装格式方面基本还是 FLV,这个组合是实践得出压缩比最高,清晰度最高,性价比最高的一个方案。这里介绍一下 H.264,这一块主要包括三个元素,关键帧 I 帧,还有一个向前的预测帧 B帧,前后预测帧 P帧。这些帧,即 GOP 组成了连续的画面。我们从原站拉流下来,拉画面就是一个个 GOP。在设置 GOP 间隔的时候,实际上更多是根据各家的情况来设,基本都是不一样的。根据你的 CDN 配置,服务器转码性能,包括编码、解码的效率,综合的去不断测试实践得出的。    

 

这里再简单介绍一下 H.265,去年到今年都比较火的一个话题。在实际测试的时候,我们推流 RTMP 的时候,H.265 反而会快一些,压缩比也是比较高的。如果单纯的不涉及编码转码的话,H.265是快的。我们遇到的问题主要在于,“高”转“低”比较快,“低”转“高”就比较快。H.264 转 H.265 就会非常慢,效率慢至 1/6 的速度。最关键的是得同时输出全部的拓展编码方案,因为你要兼容各个终端的推流和解码,意味着你的编码、你的线路、你的链路和你的拉流、你的下行线路、解码播放都得这样支持,这个成本是比较大的。

 

推流

推流最重要的是稳定性,一个主播开播的时候要是连直播流都推不上去,或者频繁的受干扰,那观众们就抓狂了。这个是我们开发的时候必须注意的,必须精简我们的动画、特效,必须时刻注意和留心我们 CPU 和 GPU 的使用率。然后是内存的优化都得定期去做,最后一个重要的是我们的线路,时刻关注我们的线路,好的推流线路下次我们得优先用。

 

CDN多路互通

择优选路,即上次的推流往这里走,这里比较通畅,下次也优先选择这条路,但实际上我们有很多条路子。在稳定性方面我们做的是多路互通。比如说我们有 CDN 节点A、CDN节点B、或者还有C、D等等,还有私有线路供主播去选择。我们有一个流媒体中心去负责这个直播流的互通工作,现在我们已经做到了两秒以内的延迟,这个也是可以继续优化的。


多路还有一个好处是主播推流可以降级,一个用不了,另外的也是可以用的,简单做一个降级的操作。以下图的情况为例,A主播推到A的线路,只有A的线路的观众能够看到它。但是我们做了互推之后,我们可以在A线路看到B的主播,这就是我们保证多路、推流稳定性的最重要的工作。


 

推流动态配置

在主播端我们可以做什么呢?我们可以做一个动态的配置,网络不好的时候给一个低的帧率,好的时候给一个高的帧率。24帧的时候基本肉眼就分不清了,但这个不是我们的默认标准,我们有一个默认值码率,还有个特殊的卡顿码率,这个指的是主播的弱网情况相当严重,濒临推不上去了,可以给他一个特殊的卡顿,音频码率也是类似。还有这里的视频动态码率,指的是咱们推流过程中为了适应不同网络情况而做的自动适应。


分辨率现在也基本是四种,我们默认是504P。推流端的配置是逐步的降级的,比如说我们有一个全局的配置是涉及到所有手机的,还有一个用户级的配置,因为同个用户下可能有很多设备,还有各个系统的个别配置,比如安卓4、安卓5、安卓6,这些都不一样儿。只有做到配置细致,你才能够有效的帮助所有主播正常顺利地开播。比如说我们的老板,张朝阳先生天天开直播,有时候换了一个手机突然推不上去了,我们立刻的调整、修改配置,他就可以开播了,这是我们保证可用性的一个重要工作。


  

推流外部监听防护

对于推流,咱们在APP上面可以做什么工作呢?- 监听和防护。“监听来电”,用户打电话的时候推流不能断。“监听压后台”,应用压后台之后,咱们得给它自动静音,而且推流不能中断。“监听断网”,比如说主播他突然断网了,这个是很常见的,那么在网络恢复的时候,咱们得把推流自动给接上。“监听网络切换”,比如主播从室内到室外,4G 和 WiFi 的切换也是会引起断网,这个时候就不能简单的重推,因为你的网络环境不一样了,IP出口也不一样了,可能要重新获取推流地址,甚至重新走一遍开播流程。这些咱们都得顾及到。


 

中心转码

我们千辛万苦把这个流推上去之后,有一个中心节点转码的过程,这个是最耗时的,可以说是性能“怪兽”。主播推一路流,从边缘节点一直到达我们的中心节点,最后到转码、分发。这个时间实际上都是可以大概算出来的,图所示的为最佳情况。比如说我们的主播端,进行了采集、处理、分包、推流等等这么多操作,需要六百毫秒左右。通过光纤把数据推上来,最佳情况是20毫秒左右,到达转码中心,我们通常花费几秒钟的时间把流转好,这个时间跟你需要拉去多少个GOP是有关的,比如满足播放条件是3个 GOP,那么你通常就得花两到三秒去转码。

 


最不可控的是我们最后的分发,最后一公里是最难解决的。从边缘节点下发,到达最终用户,从几十毫秒到几十秒都有可能,实际中我们用了多路 CDN+私有云 的策略,尽量帮助用户找到他最好的节点。除了中心转码之外,还有一个方案是边缘转码,即在边缘节点直接转码。它的时间也是可以算出来的,它有一个好处是可以近点下发,咱们自有的 CDN 和合作伙伴都有这样一个设计。这个可以解决一些突发性的热点问题,可以近点进行转码,这是非常实时的,至少保证了部分用户的实时性。但是这个成本比较高,CPU 和内存都是非常珍贵的,成本比较大,暂时还不能大范围部署。

 

 

弱网窄带推流

主播进行弱网推流,这里指的是较弱,假如网络实在太差,那么谁都没办法。这方面咱们现在一般有两个优化措施,一个是动态丢帧,在网络不稳定的时候 TCP 就会产生重连,网络切换的时候大码率的帧就发不出去了,导致的结果是你累积的包越来越多。我们说动态码率,就是当你的包累积到一定的阈值的时候,赶紧就把码率降下来,直到包的累积逐渐减少,它会逐步的发出去。直到它降低到阈值以下,我们才重新调高这个码率。

 

 

第二个是我们的动态丢帧方案,把我们的参考帧给丢弃掉。对于 H.264 来说,就是保留咱们的关键帧,把参考帧给丢掉。这里有几个好处,帧少了,编码就快,降低功耗,减少数据传输量。因为对于关键帧来讲,参考帧没有什么价值,但是能使得画面比较连贯,但是你丢弃了,对肉眼来讲,实际上权重不是非常大。

 

拉流

拉流主要包括三个步骤:拉流、解码和渲染播放。


拉流中比较核心的一点就是秒开,直播APP的秒开,即播放页的秒开,主要是 GOP 的缓存,通过主动去推,把 GOP 主动推送到边缘节点。我们的主播通过 DNS 的预解析,通过GSLB 找到近点,然后预拼接流地址进行拉流。比如在一个主播关注页,我预计你对这个主播是感兴趣的,你会点进去,那么你在浏览这个页面的时候,咱们就开始预先把关键帧拉下来开始播,点进去的时候就实现了秒开。

 

 

我们把音视频拉下来之后,接下来就是解码,解码是相当技术的活儿。当音视频流拉下来之后,我们目前的播放器是设置成一个无缓冲的设计,当我拿到关键帧的时候立刻解码。最后视频解出来的画面,是基于音频的时序同步控制的,就是说视频的时序是根据音频为准的。


 

播放器的缓冲队列,它有几个作用,一个是弱网播放的时候,起到一个临时缓冲的作用。一个是主播端产生累积延迟,这时候我们可以通过技术手段去优化它,比如说追帧或丢弃音频帧,这样观众看起来至少是实时的。


最后播放端我们在APP启动的时候还可以做一些优化,重要的是播放器。播放器是内存占用非常大的控件,可以进行预热,比如在我们的启动界面加载的时候,就把播放器预热好。

 

 

直播间

直播是一个相当垂直的领域,它有些点也是比较特殊的,比如它的直播间是相当重要,但是又是最容易“混乱”的,它这个一个界面的复杂度就等于APP其他所有界面的总和,它会有以下这些问题,比如不停疯狂的广播,疯狂礼物连击,各种控件展现、消除,动画疯狂的播放,这些都是每时每刻都在发生的事情。


我们做的工作就是把各个主要控件的线程给管理好,它们的CPU和内存占用资源的分配,时序的控制,中间执行的时间间隔等等。这里再简单介绍一下卡顿监控。这里是我们的一个比较简单的方案,简单的讲就是计算方法调用之间的时间差,这个是在异步线程做的,但这是相当简单的示意图,怎么量化,怎么计算,怎么衡量,或者你的卡顿只是一个由于机器性能导致的,这些都是细致的活儿。


 

连麦

大家看过直播的,都应该看过主播和主播之间连麦。实现一个连麦中心的过程这里简单讲讲,业务服务器同步状态列表,我们的主播去注册申请连麦,然后查询近点,执行推流。这里用的也是RTMP的两路流。MCU主要控制主播的状态同步,还负责推流等等,最后合成画面推送到达观众端。


 

连麦痛点有这些:1、连⻨麦稳定性;2、播放器内存消耗,CPU消耗;3、两路流带宽压力,码率不高导致画质问题;4、多路连⻨的扩展,音频连麦;5、网络抖动导致延迟。

 

数据接口

接下来介绍一下我们在数据和接口方面做的一些优化工作。首先是数据接口请求流程,这里所列的方案,其实适用于所有APP。对于移动端来说,一个TCP就相当于一次的性能消耗,因此我们需要把接口合并,还有一个版本控制。APP每个数据接口对应的版本可能是不一样的,版本控制能给开发更强的灵活性。然后是一个加密层,比如用非对称的加密,还有一个在这之上还可以再做一层对称加密。最后压缩输出,压缩可以有几种,最普遍的方案,可以转化成二进制流,只要APP支持就可以了,这里已经有比较成熟的方案,如Protobuf。这里面还有很多的优化手段,可以去把接口的交互压缩到最小。

 

 

最近这一年,我们也上线了全站的 Http/2.0,在我们实践的过程中,确实从总体大小到耗时都是有一个比较大的提升。这里总体大小的节省主要在于它的头部压缩还有头部复用。时间耗时主要得益于它的多路复用。安卓我们还是用的 OkHttp3,iOS用的 AFNetworking 3.x,都支持的比较好。


直播类APP有个特点,功能迭代相当快,很多活动都要一个个的上,我们的产品运营需要很多的数据,数据上报这块儿一直是个难点,所以今年就做了一个“动态埋点”的项目。原理就是控件上绑定一个标识,事件ID,后端设计一个统计ID,把这两个加上版本号做一个映射。后端在把所有的日志进行清洗的时候,按照这个映射关系来进行清洗,最后入库。最终的效果还是比较好的,只有10%左右仍然需要手动,因为有些控件实在支持不了。

 

 

图片&动画

直播APP是重度的图片和动画的使用者,这方面的优化占了很大一部分的工作量。图片在下载过程中是有一个子线程队列控制的,大量的并发图片下载必须控制好。这里有一个比较特殊的针对直播APP的优化点,那就是去重,小图片小头像特别多重复图片。另外,监控图片大小,自动剪裁、修正,监控缓存等等工作,也是很重要的。


 

动画优化,我们从一开始的序列帧,到现在基本全部使用WebP,对带宽的节省了很多。再到近期的BPG格式,这个号称压缩率还能在WebP的上提升10倍,但是性能损耗也是10倍,这个我们还在调研中。大礼物分段播放,热门的图片咱们提前打包,另外降低分辨率,减少实时计算量,缓存中间结果等等,这些都适用于所有的动画优化。另外,代码里面尽量使用整形替代浮点计算,减少临时变量,减少大内存的使用,使用硬件加速充分发挥GPU性能。咱们在动画优化方面做了很多。

 

直播+

直播+物联网是今年出现一个热潮,比如最近比较火的抓娃娃,就是直播和物联网经典的结合。基本的架构是这样的,硬件设备、WIFI、云端服务、APP四者的结合。我们自己也有这方面的实践 - 喷气功能,这个功能是这样的,主播开直播到后端,开启喷气模式,后端把通知和进度组播到客户端,我们的观众就可以通过送礼,进行“开喷” :)  ,这还是挺有趣的一个功能。

 

 

敏捷开发

我们之所以能够在过去2年中,快速地进行APP迭代,靠的也是我们的敏捷开发的一些准则,这里相信大家都在日常工作中都会遇到,比如说测试打包,这里面包括了周期性,小版、大版、自动打包,包括之前提到的自动化测试,卡顿的监控等等。另外,每次发包我们都会执行一个质检,有一些是人工的,有一些是自动的。

 


最后总结一下,其实即归结为如何快速创新。我们说直播APP,首先得制定一个技术指标,要优化我们的开播流程,优化我们的采集和音视频的处理,编码分包要做好,推流、转码的高可用要做好,拉流实现秒开,用户不能等。我们的解码、缓冲、播放各个环节也要做细致。还要做好质量统计,我们的直播间得优化好,搭建一些有趣的上层功能。数据接口、数据交互优化好,图片和动画也得花大力气优化,还有一些直播+创新。这就是我所定义的直播的创新和敏捷开发。谢谢大家。



GITC2017北京站各演讲嘉宾的PPT已经开放下载,请点击底部“阅读原文”下载获取!

Copyright © 固阳音箱协会@2017