阿里云「飞天发布时刻」2024来啦!新产品、新特性、新能力、新方案,等你来探~ 了解详情
写点什么

喜马拉雅直播秒开优化实践

  • 2023-07-12
    北京
  • 本文字数:4486 字

    阅读完需:约 15 分钟

喜马拉雅直播秒开优化实践

作者:喜马拉雅直播技术客户端 杜若尘

 

随着互联网的发展,越来越多人喜欢直播,喜马拉雅直播也在快速发展中,现如今已有秀场直播、课程直播、语音聊天室等类型。为了提升用户的使用体验,本文针对喜马拉雅直播的复杂流程进行了整体梳理,并详细说明了开展的一系列直播启播优化工作。 

背景


在直播场景中,QoE(Quality of Experience) 很重要,也就是用户体验,而 QoE 和 QoS 又是紧密相关的,作为技术开发,需要从技术的角度去思考如何提升用户体验。直播场景中,用户的体验指标有很多种:首帧、卡顿、延迟、清晰度等等。站在用户的角度出发,在进入直播间后,肯定希望能够马上看到画面,也就是启播速度要快。所以首帧优化成为首要任务。

统计口径



在做直播启播优化前,首先要思考如何去衡量启播体验,也就是说要将启播体验转化为可量化的指标,并制定体验标准以便衡量体验的好坏。启播体验问题可以转化为首帧耗时问题,首帧耗时越短,启播体验也就越好,比如以下标准:

体验等级

衡量标准

优秀

启播耗时<=500ms

良好

500ms<启播耗时<=1s

一般

1s<启播耗时<=1.5s

较差

1.5s<启播耗时<=2s

很差

启播耗时>2s


制定标准后,体验优化问题也就转化成了指标优化问题。要做指标优化,需要获取准确可靠的统计数据作为开展工作的支持,明确统计口径是什么,只有这样客户端上报的埋点数据才是有参考价值的。对于时长的统计,需要明确开始和结束时间的定义,其差值就是需要上报的首帧时间了。


对于开始时间,选择不同的入口,统计方式也不相同。直播启动入口可以分为两个类:


1. 一类是从其他页面跳转进入直播间页面的,这类方式可以将页面的创建时间作为开始时间,在 Android 中对应 Fragment 的 onCreate 回调。

2. 另一类是在直播间页面内上下滑进入其他直播间,这类方式可以将下个页面被选中时作为开始时间,在 Android 中对应 ViewPager 的 onPageSelected 回调。


对于结束时间,可以将播放器的首帧回调作为结束时间,首帧耗时即为结束时间减去开始时间。

直播全链路分析

直播整体流程环节较多,主播推流到流媒体服务器,然后流媒体服务器分发到各地的 CDN ,用户通过播放器再从 CDN 进行拉流播放,即主播端推流 -> 流媒体服务器 -> CDN 边缘节点 -> 终端设备。其中终端拉流又可以细化成许多环节,像网络请求、读取数据、解封装、解码、渲染。


可以根据不同的端大致分为三个部分:推流部分、流服务部分和拉流部分。客户端所做的主要优化工作集中在拉流部分,但推流部分、流服务部分同样也会间接对启播速度产生影响,这里也一并提一下。

现状

直播协议选择



RTMP 协议为流媒体而设计,在推流中用得比较多,同时大多 CDN 厂商支持 RTMP 协议。


HTTP-FLV 使用类似 RTMP 流式的 HTTP 长连接,由特定流媒体服务器分发,兼顾两者的优点,还可以复用现有 HTTP 分发资源的流式协议。它的实时性和 RTMP 相当,与 RTMP 相比又省去了部分协议交互时间,首帧时间更短、可拓展的功能也更多。


HLS 由苹果公司提出基于 HTTP 的流媒体网络传输协议,可用于直播场景,Android 端也同时提供相应的支持。


喜马直播移动端使用的 RTMP 推流、HTTP-FLV 拉流。

推流端—动态码率


流量控制功能可以让主播根据自己当前网络环境状态来动态调整视频推流的码率、帧率、分辨率,以及音频码率,自动适应当前网络环境及网络波动,从而保证视频能流畅发布。


流量控制的原理是基于当前网络情况,对用户的网络环境建模并估算它的上行带宽。如果当前上行带宽小于设置的推流码率,则会通过配置的选项分别从视频码率、分辨率、帧率、音频码率几处循序渐进地降低,以减少最终推流的上行码率,保证直播的流畅性。在网络环境恢复正常以后,上行码率也会重新恢复到初始设置值。

流媒体服务器优化—缓存 GOP



视频是由一帧帧的图像组成的,GOP(Group of Pictures)是一组可以被独立解码的图像序列,它由一组不同类型的帧组成,包括关键帧(I 帧)、预测帧(P 帧)和双向预测帧(B 帧)。关键帧是视频序列中的完整帧,没有依赖其他帧进行解码。预测帧和双向预测帧则根据前面的关键帧或其他预测帧进行编码和解码。如果拉流时返回的第一个视频帧是 B 帧或 P 帧,那是无法被成功解码的,直到收到下一个 I 帧才能被解码展示画面,从而导致首帧时间变长。因此,一般 CDN 都会缓存一到两组最近的 GOP,在收到客户端的资源访问请求时返回最近的 GOP,这样能确保客户端收到的第一个视频帧就是 I 帧,可以立马进行解码和渲染。

启播优化方案

拉流各阶段耗时拆分


对于拉流过程,可以细化成许多环节,如获取拉流地址、网络请求、读取数据、解封装、解码、渲染。因此,需要把直播启播耗时进行阶段拆解、细化各个流程,并进行数据上报。在实际数据统计中,我们会对各个环节(如网络请求部分、解封装部分)进行更精细的统计。



 下方表格列出了喜马直播业务的启播耗时各阶段的数据统计:


阶段

名称

详细说明

1

businessCost

业务耗时:主要包含获取拉流地址的耗时,以及跨进程通信给播放器设置播放地址这一阶段的耗时

2

prepareMediaSourceCost

播放器资源准备耗时

3

cdnRequestCost

请求cdn 资源耗时

3.1

dnsCost

dns 解析耗时

3.2

connectCost

网络连接耗时

3.3

firstPackageCost

建链到收到首包耗时

4

flvHeaderCost

读取flv header 耗时

5

flvScrpitTagCost

读取ScrpitTag 耗时

6

audioHeaderTagCost

读取音频头耗时(主要包含音频编码方式等信息)

7

videoHeaderTagCost

读取视频头耗时(主要包含视频分辨率、编码方式等信息)

8

firstVideoTagCost

读取第一个视频帧耗时

9

audioDecoderCreateCost

音频解码器初始化耗时

10

videoDecoderCreateCost

视频解码器初始化耗时

11

firstFrameDecodeCost

首帧解码耗时


上表中步骤 4-7 需要读取解析 flv 头部信息,其具体结构组成如下所示:



从用户点击跳转到直播间或者在直播间内上下滑动切换直播间,到最终的直播播放成功,预计会有十多个的点位进行一系列的追踪分析。详细的数据表格呈现启播过程中每一步骤的耗时,然后针对于耗时多的地方进行优化。

预获取拉流地址


一般而言,用户进入直播间的业务场景,是从一个直播列表页面点击某一个直播卡片进入直播间。这个过程中,数据流是怎么走的呢?


在启播优化改造之前,观众从直播列表页点击某个直播卡片到直播间后,需要先向服务端请求一个直播间详情接口,详情接口发现直播间当前是处于开播中状态的话,再去请求该直播间拉流地址接口,交给播放器播放。


在这个过程中,播放器必须等到进入直播间,串行请求完两个接口拿到直播流地址后才能开始播放,这个时间点是可以提前的:在直播列表页及其他直播入口拿到直播间对应的流地址,在进入直播间时直接传过去,这样一进入直播间播放器就可以拿着直播流地址开始播放了,省去了从服务器请求直播流地址的时间。对于在直播间内上下滑切换房间的情况,就需要改造上下滑接口、增加拉流地址信息。


组件渐进式加载


直播间功能组件数量多达 34 个(如视频播放组件、红包功能组件、礼物动画功能组件等),页面层级复杂,在一些中低端机型上加载较慢,可以采用渐进式的加载方案,让优先级高的组件先进行展示。组件加载方式遵循以下三条原则:


1. 组件按需加载,用到的时候再进行加载;

2. 组件视图如果复杂,耗时问题不好解决,可以使用异步加载;

3. 组件可以按优先级串行加载,先展示主要视图,而后加载次要视图,最后加载特定条件才触发动态添加的视图。


这样设计的好处是可以减缓同一时刻加载 View 带来的压力,实现先加载核心部分的 View,再逐步去加载其他 View。比如在喜马直播间就可以先加载视频播放组件,然后再依次加载其他的功能组件。 

预渲染


1. 从外部页面进入直播间场景


直播间页面是在一个上下滑容器中进行加载的,从其他页面进入直播间遵循这样的时间线:直播间容器页面创建-> 直播间容器页面渲染 -> 直播间页面创建 -> 直播间页面渲染。当点击入口跳转的时候调用播放器进行播放,如果在直播间页面渲染出来之前第一帧画面已经解码好了,这时由于直播间页面的 TextureView 的 Surface 仍然是不可用的状态,会导致解码的视频帧无法去送显。


因此,可以在直播间容器页面创建一个 SurfaceView ,将解码的视频帧先渲染至容器页面的 SurfaceView 上(之所以用 SurfaceView ,因为它 Surface 的渲染可以放到单独线程去做,避免主线程卡顿造成画面无法渲染的问题),等到直播间 TextureView 的 Surface 可用后,再将视频帧渲染到 TextureView 上,实现无缝切换。



2. 直播间上下滑场景


针对直播间上下滑场景,因历史原因,播放器是单例,所以在直播间上下滑场景中无法进行下一个直播间的预加载,只能等到下个直播间被选中时才能进行播放,也就是上下滑过程中手指抬起后开始播放下一个视频。同时,由于直播间 view 是复用的,要等到屏幕停止滑动后,才可以去复用上个直播间的 view 。

因此,如果屏幕在滚动过程中,首帧已解码成功后,可先渲染至容器页面的 SurfaceView 上,待屏幕停止滚动直播间 TextureView 的 Surface 可用后,再将视频帧渲染到 TextureView 上。


使用 HttpDNS



网络请求中,DNS 解析是一个相对耗时的过程。在传统的 localDNS 方案中,APP 向所在网络运营商的 DNS Server 发起域名解析的请求,而运营商 DNS Server 会向 CDN 的 GSLB (Global Server Load Balancing)全局负载均衡系统发起递归查询,GSLB 通过运营 DNS Server 所属 IP 地址判断查询来自于哪个运营商和地理位置,然后返回若干合适的 CDN 边缘节点 IP 给它。


HttpDNS 使用 HTTP 协议进行域名解析,把域名解析请求直接发送到 HttpDNS 服务器,从而绕过运营商的 Local DNS ,能够避免 Local DNS 造成的域名劫持问题和调度不精准问题。由于中间少了一条链路,所以这部分的耗时大致可以省却几十毫秒。同时将节点 ip 进行缓存,下次有相同域名的请求时直接返回该 ip,省去 DNS 解析耗时。

优化播放器缓存水位管理


播放器缓冲区主要有两个水位管理概念,一个是启播水位,另一个是卡顿后启播水位。顾名思义,启播水位表示首次拉流播放时,缓冲区达到多长时间的数据可以开始播放。卡顿后启播水位表示如果缓冲区没有数据发生卡顿了,需要再下载达到多长时间的数据才可以继续播放。对于启播优化来讲,为了让用户能够更快地启播,可以将启播水位调的尽可能小。因此在直播场景下,我们将播放器的启播水位设置为了 100ms,以达到更快的启播速度。


成果与思考


经过一个季度的优化,目前喜马音频直播的秒开率达到了 90% 以上:



视频直播的秒开率达到了 85% 以上:


体验导向的应用理念


通过优化直播启播速度,不同渠道直播入口的播放转化率都得到了不同程度的提升,因此可以得出一个体验导向的应用理念:在引入任何优化时,首先需要评估方案的整体收益;之后需要设计整体优化方案进行开发调优;通过 AB 实验评估每项技术的业务指标影响,刻画性能指标与业务指标的关联;反复以上迭代过程。

未来展望

H.265


H.265 旨在在有限带宽下传输更高质量的网络视频,仅需 H.264 的一半带宽即可播放相同质量的视频。因此,对于相同质量的视频,H.265 只需下载 H.264 约一半的数据量即可进行解码渲染,有利于提高启播速度。

 

上下滑多播放器实例


上下滑是喜马切换直播间的一个重要的方式,后续可以使用多个播放器实例,在手指按下开始滑动的时候就去静音播放下一个直播间的资源,待手指抬起确定滑入下个直播间后再取消静音播放,同时停止上个直播间的播放。相比于单播放器实例,这样可以省去拖动屏幕这段时间的耗时。


解码器复用



通常情况下,视频正常播放时解码器都需要进行 create()、configure()、start() 等初始化操作,而播放其他视频时,每次播放都必须重新进行这一初始化流程。根据上面的解码器状态流转图,如果播放完一个视频后不去 release 、stop 解码器资源,而是直接用于解码下一个视频,实现解码器的复用,就可以省去创建及初始化解码器的耗时。


解码器复用的核心条件是支持自适应播放属性,此属性是指 Android 提供的一种无缝切换不同分辨率视频的能力,可以由系统接口(android.media.MediaCodecInfo.CodecCapabilities.isFeatureSupported(String)) 查询是否支持。同时还要求当前视频编码格式要保持相同,分辨率不能超过上个视频的分辨率。

 

2023-07-12 17:202807

评论

发布
暂无评论
发现更多内容

PHP8的匿名函数-PHP8知识详解

百度搜索:蓝易云

php 云计算 Linux 运维 云服务器

构建大模型争分夺秒?快用天翼云并行文件服务HPFS“加速包”!

编程猫

9. 跨境电商入门思考

Joy

如何快速上手Vue,一篇文章教会你

霍格沃兹测试开发学社

淘系接口推荐:淘宝宝贝评论内容数据接口

tbapi

淘宝宝贝评论接口 淘宝宝贝评论内容接口 淘宝评论API

淘系接口推荐:淘宝图片搜索商品数据接口

tbapi

以图搜图 淘宝API接口 淘宝图片搜索API 淘宝图搜接口

免费的ai一键生成ppt工具有哪些?这10款AI软件超好用!

彭宏豪95

人工智能 效率工具 PPT AIGC AI生成PPT

无人直播是如何做到不被封号的?

青否数字人

数字人

华为各应用发布妇女节专题,一起感受女性创作者的力量

最新动态

Vue router路由设计

霍格沃兹测试开发学社

API可视化编排,提高API可复用率

RestCloud

API 可视化编排 ipaas

ToothFairy for Mac:一键链接蓝牙功能

Rose

蓝牙 蓝牙智能设备 ToothFairy

硅基,奇妙元,元分身,青否数字人的四大头部厂商!

青否数字人

OpenSearch 与 Elasticsearch:哪个开源搜索引擎适合您?

极限实验室

搜索引擎 elasticsearch opensearch service

一文搞懂如何自己写一个Python库

快乐非自愿限量之名

Python 运维 开发语言

Vue3:使用 Composition API 不需要 Pinia?

高端章鱼哥

【论文速读】 | DeGPT:通过大语言模型优化反编译器输出

云起无垠

ELK安装、部署、调试zookeeper安装,配置

百度搜索:蓝易云

云计算 zookeeper Linux 运维 ELK

鞋服品牌怎样合理把控订货深度和宽度

第七在线

解决 npm install 报错的常见问题

霍格沃兹测试开发学社

一文告诉你Vue的事件处理

霍格沃兹测试开发学社

超算互联网统一存储平台技术研究

Alluxio

Alluxio GPU算力 模型训练优化 超算中心 超算互联网

低代码与AI大时代:推动企业数智转型的双重动力

不在线第一只蜗牛

人工智能 AI 低代码 AI技术

使用 Amazon Bedrock 上的 Claude 3 将架构图转换为 CDK/Terraform 代码

亚马逊云科技 (Amazon Web Services)

生成式人工智能

Java ArrayList 与 LinkedList 的灵活选择

小万哥

Java 程序人生 编程语言 软件工程 后端开发

淘系接口推荐:淘宝宝贝详情数据接口

tbapi

淘宝商品详情数据接口 淘宝API接口 淘宝宝贝详情数据接口

【教程】修改应用程序开发者名称的步骤

雪奈椰子

你认为未来十年内科技发展的最大趋势是什么?

算法的秘密

低代码与微服务:重塑软件开发的未来

快乐非自愿限量之名

微服务 运维 低代码

专访天谋科技谭新宇:我与 IoTDB 的这些年

Apache IoTDB

Simplemind pro mac破解版 思维导图

Rose

思维导图 SimpleMind Pro下载 SimpleMind Pro破解版

喜马拉雅直播秒开优化实践_音视频(前端)_喜马拉雅技术团队_InfoQ精选文章