效果对比
先简单介绍一下蘑菇街的短视频业务。蘑菇街目前的短视频主要围绕发表,短视频图墙和短视频全屏页。这里我们主要涉及的是用户浏览短视频图墙,从短视频图墙跳转到全屏页的用户体验和用户在全屏页上下滑动切换视频的用户体验。
数据驱动
在我们开始优化前,我们需要先统一和明确能够体现短视频基础体验的数据指标,这些指标可以准确反馈线上用户真实的体验,并作为我们持续优化的参考。目前我们主要从下面几个方面去衡量一个短视频页面的用户体验:
在数据指标确认之后,我们首先需要线上的数据,来建立数据模型,从模型中分析哪些流程&指标是需要我们去优化的。
基础用户体验
在上面有提到我们的优化需要数据驱动,此外基础优化本身也是要结合业务的,在蘑菇街主要的短视频业务都是集中在短视频全屏页,我们先看一下短视频全屏页的主要流程和内容。
结合上面优化之前的效果和我们这一张图可以发现,复杂的业务逻辑,从网络获取短视频的低效率,导致了黑屏,等待时间长等不好的用户体验。下面看一下我们是怎么样解决这些问题的。
我们对视频全屏页的架构做了一些调整,抽取了一些基础部分,优化和解耦了内部的流程,使部分逻辑并发。
数据带入
我们对外暴露了带数据的接口,业务方在从图墙进入全屏页的时候可以通过这个接口带入短视频和业务相关的数据。
基础体验和交互
用户体验除了功能本身,也包含了一些交互和动画上的效果,在这里我们主要是封装了蘑菇街自己的转场动画,我们将上一个页面的画面作为视频全屏页的基底,然后逐步放大被点击的视频Item,让用户可以更加顺滑的进入到视频全屏页里面。
页面基础模块
在这里我们处理了一些页面和短视频播放器初始化的逻辑,并且通过业务代理将业务逻辑剥离开。
短视频控制层,这里封装了短视频播放逻辑和短视频播放状态的回调。
解析外部带入的数据元素,如果带入了短视频的播放地址,则直接将数据交给短视频控制层。
业务插槽,这里是给后续业务实现用的,不同的业务逻辑会通过插槽渲染在页面的各个位置。
业务实现
我们通过实现基础模块提供的代理来触发业务逻辑,这里面的业务数据处理和网络请求等逻辑都是独立的,当我们在内部处理完之后,会生成一个个的业务模块,然后将业务模块重新丢给基础模块,基础模块内部会将业务模块进行渲染。其中各个业务模块之间也是独立的,我们可以只渲染必要业务,部分非必要业务采用懒加载渲染,提高渲染的效率。
我们也可以通过基础模块暴露的接口来控制视频的播放和接收视频播放状态的回调。
上面在页面层我们对播放器和业务做了剥离,那么在短视频链接给到播放器之后,播放器内部是怎么样一个流程,哪些地方是耗时的,又有哪些是我们可以避免或优化的。
从上面的流程图我们可以看到,IO操作一定是一个耗时操作,这里会是一个可以优化的地方,我们先看一下IO操作内部是做了一些什么。
短视频预加载
鉴于上面的分析,我们需要做的就是将服务端返回的视频地址转换成本地资源:短视频预加载。
关于短视频预加载,我们先了解一下MP4视频文件的格式:
这里不详细介绍MP4的格式信息。但是可以知道moov box对播放很关键,它提供的信息如:宽高、码率、编码格式、帧列表、关键帧列表等等。播放器没有获取到moov box是没办法进行播放的。所以我们预加载的数据应该要包含moov box再加上开始几帧的数据。
我们在实际的预加载中该怎么计算需要下载多少文件,其实大部分视频ftyp+moov在加上前10帧大约在100K左右,我们这边选择的做法是用控制单个视频的预加载时长来控制大小。(避免网络等异常情况导致一直卡在某个视频的预加载而影响了后续的预加载)
对于蘑菇街来说预加载主要分为两个场景:
短视频图墙的预加载
我们需要将用户可能点击的视频提前预加载,这样就可以保证在用户点击的时候他可以立马看到视频(从缓存中读取),而不需要等待网络的返回。那么我们该怎么样去提高这个预加载的命中率,主要有两个方向。
我们要去猜用户会点屏幕中的哪个视频,从而调整预加载的顺序。
从前往后,先进先加载(命中率:60%)
从后往前,后进先加载(命中率:61%)
从中间开始加载(命中率:68%)
2.我们要在相同的时间内尽可能多的预加载屏幕中的视频个数。
针对用户快速滑动,队列数量暴增,我们该怎么处理。
视频全屏页的预加载
这个的话就相对比较简单,也就是在短视频全屏页,当用户在观看当前视频的时候,我们去为他预加载下面的视频,当然我们这里也有一些单独的而配置,比如单个视频的预加载时长,单次往下多预加载多少个视频。这些配置会配合业务的需要动态调整。
HTTPDNS预解析
从数据可以看到预加载的命中率不会是100%,那么对于那些没有命中预加载的我们该怎么优化。
首先DNS请求包会先发到本地DNS服务器,如果查不到,会递归到根域名服务器,这个过程是比较耗时的,针对这个问题我们可以做:HTTPDNS的预解析,提前把域名解析出来,用的时候直接使用IP地址,这种方式应该是可以优化几十到100毫秒的时间。(这个方式对于短视频播放地址比较多样的不是很适用,操作起来也比较复杂)
短视频基础框架
通过上面的一些工作,我们基本完成了对短视频基础体验的优化,然而在蘑菇街有相对较多的短视频业务,比如内容短视频,直播相关的短视频和商品相关的短视频业务,他们分散在不同的业务线,虽然业务形态本身很相似,但业务实现却千差万别。我们做短视频基础体验的提升不仅仅是针对一个业务,还要统一全站的短视频基础体验。
为了处理上面的问题,我们需要一个短视频应用层的UI基础架构,对于业务来说,他们只要继承这个基础框架,通过框架暴露的接口,代理来实现自己的业务逻辑,就可以快速的搭建出一个短视频页面,这一层架构需要解决以下问题:
基础框架内部要实现短视频的播放逻辑,封装基础的交互。
抽离和独立播放逻辑,使之与页面复杂度,网络请求等业务逻辑高度解耦。
支持各业务方快速接入框架,可以低成本的实现业务与短视频的融合。
在短视频UI基础框架中,我们对前面做的基础体验的相关工作做了进一步的封装,将预加载,HTTPDNS等基础的逻辑进行下沉,对于短视频和业务共建的部分我们在之前的基础上我们又封装了一些蘑菇街通用的基础业务和UI逻辑,然后对外暴露服务和代理。
对于业务来说它只需要关注自己的逻辑,在内部处理完业务逻辑之后通过代理和服务,将业务传递到UI基础框架内部,也可以通过自定义参数来调整短视频的基础配置,实现自己特有的一些功能。
其他优化
针对这个问题其实有两种解决方法:
1、服务端对视频进行转码,发现moov位置不对的时候,服务端通过转码来更正位置。(我们选择了这一种方式,我们的服务端本身就有对视频的压缩和转码)
2、在播放端进行处理:发起 HTTP MP4 请求,读取响应 body 的开头,如果发现 moov 在开头,就接着往下读mdat。如果发现开头没有,先读到 mdat,马上 RESET 这个连接,然后通过 Range 头读取文件末尾数据,因为前面一个 HTTP 请求已经获取到了 Content-Length ,知道了 MP4 文件的整个大小,通过 Range 头读取部分文件尾部数据也是可以的。
我们的视频来源很多,从而视频的分辨率,码率等参数也很乱,我们利用后端对短视频进行了统一的窄带高清转码(会根据视频的类型和清晰度,预期选择码率和分辨率,同时根据视频内容做合理的码率分配)。在保证视频质量的情况下,尽可能的缩小视频大小。
总结展望
当前短视频应用层基础框架的探索,核心是通过对短视频相关交互,基础功能,基础体验的封装和升级,利用框架剥离了短视频功能与业务之间的耦合,同时也打通了两者的边界,实现了业务与短视频之间的闭环。通过框架来下沉短视频,让短视频相关的功能和交互统一化,让业务可以更加专注本身。
对于未来,首先是短视频衡量指标上我们会不断的更新,更加深入的挖掘基础体验的细节。除了应用层之外,后面在短视频本身的基础层我们也要做更多的事情,比如字幕能力扩展等,这些也是巨大的挑战。
总体来说对于应用层的优化这件事情:
数据要先行:只有拿到了数据,我们才能真正了解用户的现状,才能找到瓶颈和优化点。
适当总结,下沉逻辑:对于优化的中后期,我们要及时的复盘,对基础功能进行下沉和分层,这样才能更好地服务于其他业务。
用户体验永远是第一位:数据是一个衡量的指标,优化方案也有很多,我们要选择真正服务于用户的方案,不能只服务于数据,这样就本末倒置了。
坚持不懈,追求极致:这也是为什么上面我说衡量指标是会变的,一开始的优化往往很简单,越到后面效果越小,但是我们要坚持,这样才能给到用户最好的体验。