在手机游戏直播中,悟空TV采用以下方案达到多源录制、多端播放的效果。主要分为三大过程:录制源的采集,以RTMP传输协议动态上传到CDN,各播放端实时拉流。
图1 手机游戏直播方案
接下来将一一讨论悟空 TV 移动推流端和播放端遇到的难点及对应的优化方案。
移动端抓屏方案
Android
Android 5.0 之后系统版本,开放了屏幕采集接口,这里不再赘述。5.0系统之前,则需要使用其他方式抓屏,悟空TV采取了先获取root权限,再使用Runtime执行命令的方式来实现屏幕抓取,流程如图2所示。
图2 Android抓屏流程
iOS
如何在苹果设备上抓屏一直是个难题,悟空TV利用苹果AirPlay镜像(AirPlay Mirroring)功能,将应用本身变成支持Airplay投屏的虚拟服务器,从而将手机屏幕通过AirPlay投到应用内,实现抓屏的功能,流程如图3所示。
图3 iOS抓屏流程
直播卡顿优化
直播讲究播放的流畅性,如果频繁卡顿会严重影响用户的观看体验。在直播中,卡顿的大多是由网络环境不佳引起的。而悟空TV移动端的推流/播放处于移动网络环境,相较于PC平台更加复杂,主要难点包括以下方面:
移动网络上传、下载带宽不足
移动3G网络在信号不佳时,最高只能达到100Kb/s的上传、下载速度,在直播时,游戏本身也会占据非常高的带宽;然而,游戏直播对画面质量和连贯性的要求,要比其他类型的直播更高。综合以上因素,移动网络带宽不足的问题尤为突出。主要解决思路是压缩传输的数据量。通过优化推流端的编码参数,包括分辨率、码率、帧率、i帧间隔等,可以非常有效地缩小传输消耗的带宽。另外,合理选择编码协议(常见有H.261/H.263/H.264/H.265),也能极大提高数据压缩能力。悟空TV设定了超清、高清、普清、标清四个档位的直播质量,以适应不同情况的移动网络。
除此之外,悟空TV还采用了两种方案来实时监控直播效果:一种为推流端网络实时监测系统,在推流的过程中,实时监测推流效果,当监测到推流效果不佳时,直接在推流端给出降低编码档位的提示,引导用户提高当前推流效果,减少视频卡顿;另外一种为后台人工干预手段,当工作人员在巡查中发现直播严重卡顿时,会通过后台发送调整推流档位指令,推流端自动降低该直播的编码档位。
带宽足够的情况下,经常会遇到网络波动极大的情况
移动端直播过程中,WIFI信号的强弱变化非常容易使网速时快时慢。3G/4G环境更加容易发生此问题。那么如何在网络经常波动的情况下,保持直播流畅呢?
悟空TV主要采取了两种手段降低网络波动的影响。第一,在可接受延迟的范围内,合理设定推流端和播放端的缓冲区大小;第二,推流端会在网络波动大的时候,数据上传时间过长,导致缓冲区剩余空间不足。此时如果一味增加缓冲区大小,会导致播放端与推流端延迟过大,这就需要推流端丢弃部分数据帧,加快直播进度。但是,在某些丢帧情况下,会导致播放端花屏,需要在设定丢帧策略时注意。
CDN链路优化
移动网络经常会遇见用户的DNS与其实际所处区域偏差较大的情况,严重影响了CDN调度效率。
悟空TV主要采用三个手段解决此问题,一是优化调度方式,将DNS调度改为IP调度,结合各CDN厂商自有调度系统(如网速的NGB调度系统),规避虚假IP地址,实时判断节点机器的性能、负载情况、网络情况等,更合理、更精确地分配了推流端和播放端的节点资源,提高流畅性;第二个方法是后台切换CDN,工作人员在巡查中,如果发现当前推流质量不佳是链路质量过低导致的,会通过后台发送切换CDN节点指令,推流端自动切换CDN节点。
播放端首屏时长的优化
首屏时间,指的是从进入直播间开始到第一次看到直播画面的时间。首屏时间过长极易导致用户失去对直播的耐心,降低用户的留存。但游戏直播对画面质量和连贯性的要求高,对应推流端编码后的数据量和其他类型直播相比大的多,如何降低首屏时间是一个不小的难题。
在播放端的首屏过程中,主要有以下三个操作需要进行:加载直播间UI(包括播放器本身)、下载直播数据流(未解码)和解码数据播放。其中数据解码播放又可细分为以下几个步骤:
检测传输协议类型(RTMP、RTSP、HTTP等)并与服务器建立连接接收数据;
解析数据类型获取视频流信息;
视频流解复用得到音视频编码数据(H.264/H.265、AAC等);
音视频数据解码,音频数据同步至外设,视频数据渲染到屏幕,至此,视频开始播放,首屏时间结束。
由此,我们总结出以下提高首屏时间的方案:首先,加载UI可以以单例的方式进行,能够一定程度地提升首屏展示速度;其次,可以预设解码类型,减少数据类型检测时间;再次,设定合理的下载缓冲区大小,尽可能减少下载的数据量,当检测到I帧数据,立即开始解码单帧画面进行播放,提高首屏展示时间。
音视频同步
观看直播时,最令人头痛的就是音视频不同步,解决不同步问题的方法有很多种,从技术上来说,其中时间戳是最成熟最完美也是最复杂的解决办法,可以解决任何多媒体领域的音视频同步问题。主要原理是选择一个参考时间,在生成数据流时依据参考时间给每个数据块都打上时间戳;播放时,读取数据块上的时间戳,同时参考本地时间来安排播放。但如果源数据帧上打的时间戳本身就有问题,那么播放时再怎么调整也于事无补,所以解决音视频不同步问题,必须先从源上来解决。一般来说,解决同步问题我们有三种选择:同步音频到视频,同步视频到音频,或者都同步到外部时钟(例如系统时钟)。悟空TV使用同步视频到音频方案来保障音视频的同步,实现流程如图4所示。
图4 音视频同步实现流程
推流端启用独立的音频和视频线程,进行音视频采集以及编码,音频采集编码后只管往外发送数据即可。而视频线程采集编码完之后,需要同步时间戳到音频的时间戳,并做时间戳的有效性判定,只有有效的视频数据才会发送到服务器。
软硬编解码的选择
软编解码:使用CPU进行编解码,大多使用FFmpeg来编码和解压音视频数据;
硬编解码:主要使用非CPU进行编解码,如GPU等。在使用中,大多直接调用系统API进行音视频编解码处理。
综合以上情况,经过悟空TV和大量用户的测试及总结,在推流方面,iOS系统和硬件设备统一性高,使用全硬编方案效果更好;Android因机型繁杂,支持程度不一,推荐4.3以上使用硬编。在播放解码方面,iOS硬解和软解支持性都较高,软解功耗更高,但是在部分细节方面表现较优,可控性强,具体视项目情况选择;Android推荐4.1版本以上使用硬解,以下版本使用软解。
繁杂的机型适配
做Android应用的开发人员都知道,市面上冗杂的机型再加上各式各样的屏幕尺寸,已经让适配非常繁琐,而做直播软件,适配问题远远不止这些,下面列举几个悟空TV遇到的适配问题:
部分Android 5.0以上机型由于ROM被修改无法实现抓屏。
部分机型录制的视频出现花屏问题。
部分机型录制摄像头出现旋转、拉升等问题。
部分厂商机型因权限问题无法打开浮窗。
不断出产新的机型,不断出现新的适配问题。
针对各种繁杂的适配问题,如果在客户端代码中写死了配置或判断逻辑将非常不利于版本的维护和迭代。悟空TV使用了“云控”的手段来处理适配问题,在与服务器进行交互时,把客户端机型、系统版本号、分辨率、应用版本号等信息上传给服务器,然后在云端(即服务器端)来做整体配置,从而控制此设备是否允许直播、是否需要弹出浮窗设置以及直播应该使用的码率、FPS等。
总结
做直播,尤其是要在移动端提供稳定、流畅的直播服务,是在日常工作中不断改进不断调优、不断调整算法和动态运营的结果,并不是实现几个技术点或攻克几个Bug就能坐享一套稳定流畅的直播服务的。直播之路还很长,仍需继续努力。悟空TV将秉承为大家提供一个稳定流畅好玩的手游直播平台而继续努力。
作者简介
本文为《程序员》原创文章,未经允许不得转载,更多精彩文章请订阅2016年《程序员》
刘燕青,Android高级开发工程师,多年Android研发经验,主要负责悟空TV App的架构以及研发工作,包括Android端屏幕录制、摄像头录制、音频采集、编码推流等工作。目前专注于音视频相关的研究和应用。
李越,iOS开发工程师,主要负责悟空TV iOS客户端和录制端的研发工作,包括iOS端屏幕录制、摄像头录制、音频采集、编码推流、拉流播放等工作。目前专注于音视频相关的研究和应用。