首帧视频体验的优化实践 零耗时 (首帧视频体验在线观看)

首帧视频体验的优化实践 零耗时 (首帧视频体验在线观看)

点播端到端音视频解决方案

上图是火山引擎点播端到端的音视频解决方案架构图。点播端到端一般指视频从上传到播放所经历的全链路技术解决方案,涉及的主要技术模块包括 上传 SDK 视频处理与管理 CDN 分发 以及最终播放端的点播 SDK。在每一个环节里火山引擎点播中台都做了很多相关的技术优化和重点功能的迭代。随着我们服务的用户和业务越来越多,我们也经常收到实现极致体验的需求。于是,在近几年的主要工作中,我们面向用户体验做了一些相关的点播端到端解决方案。

但是体验与成本存在一定的矛盾关系,如何在有限的资源条件下将用户体验最大化,取得两者间的最佳平衡,是我们点播解决方案所面临的挑战。

播放质量指标

在介绍我们的技术优化实现之前,先来看一下如何衡量用户体验。

我们将用户体验拆解为播放源质量、交互体验和观看体验三个方向,而用户体验的质量指标一般会分成三个层次:

▪播放失败率:基于起播和未起播两个环节,涉及大盘级的播放失败率和起播率。

▪起播时间:和用户播控时间点相关,涉及首帧时间和 seek 后的起播时间。

▪卡顿指标:卡顿是影响用户观看体验的一个重要因素,卡顿指标包括卡顿渗透率、百秒卡顿时长、卡顿次数等。

以上三个层次的数据指标可以让我们实现真正对业务增长有收益的播放体验优化。

认识首帧时间

在介绍首帧这个概念之前,我们先来了解下播放事件的生命周期。一次播放,也就是 VV ( VideoView ),是指这次播放任务从建立到结束的整个过程。

我们把一个完整的播放任务分为起播前、播放过程中和播放完成三个状态。

在起播过程中,由于用户等不及而退出,或者因为播放器原因导致用户被迫退出,这些都属于未起播率。

在播放过程中,我们需要关注所有网络相关的问题如卡顿等,以及 seek 、 pause 等播控行为。

播放完成这个状态也包含三个类型:

以上播放事件生命周期几个环节的拆解也是我们播放埋点建设的依据。我们通过一次播放的 sessionID 或 traceID ,将整个播放过程中所有事件进行关联,然后进行细致的播放体验分析。

播放器首帧拆解

首先我们定义一下什么是首帧。一般来讲,首帧时间的定义是从用户操作播放相关动作(点击播放、滑动卡片等)到首帧渲染出来的耗时,即用户从 App 上感知到的耗时。首帧时间除了业务侧关于用户点击、页面创建和渲染的耗时之外,还包括播放器层面的视频 prepare 、视频 play 、数据下载以及数据下载完之后的解码和渲染这些环节的耗时。

而再往下进行拆分,首帧的时间会区分为两个层面:

下图是我们线上一次真实的播放首帧埋点耗时示例。

示例的首帧耗时分为 4 个阶段:

上图所示的从设置 URL 一直到收到首帧消息整个过程的时间,就是最后呈现在大盘上的首帧时间。

“零耗时”首帧优化实践

什么是“零耗时”首帧?耗时本身想描述的是用户侧是否感受到了耗时这件事。 所谓 “零耗时” ,并不是真的 0 毫秒起播,而是指用户在起播时平滑播放,没有首屏的顿感

从我们现在的大盘来看,核心业务方 50% 的播放首帧都已经 小于 100ms 了。从交互设计体验角度来看,小于 200ms 的时间人体感知就已经不明显了。所以我们认为, 100ms 对于用户来说就是零耗时的首帧

我们做了哪些优化来达到小于 100ms 的零首帧呢?前面提到对于每一个首帧,我们都细拆了很多环节,不同的环节都进行了有针对性的技术优化。我们梳理了一下,将首帧时长的构成拆解为了 4 个模块:

下面会详细介绍我们正在进行或是已经上线的一些优化案例。

业务耗时优化:预渲染

预加载是当前通用的优化网络耗时的解决方案,指的是在播放当前视频时,如果网络能力允许,会提前触发后续视频的下载。预加载相当于减少了用户可感知的网络加载和网络连接的耗时。

但是 通用的预加载解决方案没有把播放器和网络 IO 进行强紧密的结合 ,在预加载时只是基于数据模块触发下载任务,而此时播放器的实例还没有创建起来。

对于这种情况,我们在思考能否把播放器创建以及初始化的工作整体前置。

此外,我们还发现当播放的封面图和首帧差异很大的时候,用户会感受到明显的跳变。这个跳变有可能会让用户感受到卡顿,或者是其他不舒适的感觉。所以这一部分也是我们整体的优化目标。

基于以上这些考虑,就产生了我们的 预渲染的解决方案:当前任务在播放时,提前起播下一个播放任务,渲染首帧替代封面,从而降低首帧耗时

这是一种播放器多实例解决方案,除了当前播放的视频之外,还需要初始化一个额外的播放器实例以支撑下一个视频的渲染。

上图是我们相关业务实践的真实过程。在上一个视频的播放过程中,会先判断下一个视频播放的触发时间。我们会考虑几种触发时机:

以上就是预渲染在业务侧的基本逻辑。在极致情况下,用户侧对于网络、解码、渲染耗时均是无感知的。

网络耗时优化——节点优选

前文提到,在首帧出现之前还有一个很重要的数据准备环节。数据准备主要是数据模块的下载,可以分为请求开始、 DNS 域名解析、 DNS cache 等阶段。如何从 DNS cache 或者 IP 池中选出高质量 IP 进行后续建联,从而完成相关首帧播放以及后续播放,这就节点优选要做的事情。

网络 IP 选择影响到首帧、未起播率、播放失败甚至后续卡顿等一系列数据,重要性非常高。节点优选就是要在 IP 池里选择最优 IP ,保证播控和数据加载都符合预期。但是,节点优选对于点播体系来说,也存在很多潜在风险性问题。端侧本身存在较大的限制:设备之间无法实时感知彼此的择优路径。在极端情况下,如果大量用户都优选到了同一个节点,而请求量级超过了节点的负荷能力,就会影响服务端 CDN 的稳定性。因此,目前我们会把节点优选作为长尾用户的质量优化。

上图是节点优选的整体逻辑。在 DNS 解析之后,相关 IP 会经历节点优选的过程,得到最优的推荐 IP 。我们再基于这个 IP 进行后续的 TCP 建联、数据上传下载,并在数据传输过程中反向把建联、下载过程中的网络状态传递给节点优选组件,进行二次训练和数据迭代。

我们在节点优选过程中面临两个大的挑战:

节点优选策略包括:

以上介绍的节点优选是我们近期正在做的事情,也是我们想持续优化和尝试的,目的是最大化端侧播放的可用性。

网络耗时优化——解码耗时

解码耗时的优化是我们相比其他开源播放器在首帧上保持优势的根本原因。

解码本身需要耗时。当一个视频的数据完成准备,在解码过程中至少会经历以下几个环节:

如果我们不进行任何优化,把以上所有所流程都托管, ffmpeg 进行解复用, MediaCodec 进行解码,整个过程基于不同机型的耗时至少在 100ms 以上。

我们在解码耗时上主要做了如下三个方面的事情:

解码初始化耗时

一般情况下,硬解初始化的平均耗时大于 100ms 。就硬解本身的原理来看,在初始化的过程中只需将相关的 Codec ID 或者 Codec name 给 OpenMAX 层, OpenMAX层再进行解码器实例的创建。也就是说,正常的解码或初始化流程,需要先下载数据,将 header 前部分的视频流 header 信息进行解析,解析完以后获取视频的 Codec 进行初始化。

对这个过程,我们当前的策略是把硬解的初始化和 header 解析以及解复用完全并行。在下发视频流时,我们会告知该视频的 codec ,这样在数据下载及解复用的并行过程中已经完成了当前的硬解初始化,从而优化了整体的数据消耗。

此项优化平均减少了 80ms-120ms 的首帧耗时。

解码器复用

在完成了异步初始化后,下一步我们就在思考能否省略初始化的步骤。以当前短视频比较常见的 feed 流的实现方式为例:当上一个视频完成了解码初始化,下一个视频是否可以直接复用上一个视频的解码器?这里我们使用了 codec_pool 进行相关解码器的复用。在上一个视频完成播放时,我们把相关的 codec 复用到下一个视频,这样就省略了两个视频初始化过程中 stop release 到 start 的耗时。这一部分优化的耗时平均在。

机型能力大数据择优

播放器可以最大化播放成功率,但不是所有设备都能 100% 保证硬解成功。我们在播放端有硬解的 fallback 策略,也就是当硬解失败之后,会 fallback 到软解来支撑播放顺利进行。但是这个过程经历了硬解初始化、硬解初始化失败、 fallback 到软解、软解初始化、后续解码这样一连串的过程。

对于这一部分,我们想利用大数据的能力来快速理解当前设备的性能,在分发的时候进行相关策略优化,也就是我们现在在尝试的机型能力大数据择优。我们会埋点追踪每次 VV 是否在客户端侧进行了相关 fallback 的二次兜底,并且把每一个设备支撑到 codec 的能力进行落地,从而能够基于用户的机型能力分发最优的决策判断,包括对应的 codec 、是否硬解等,这样我们就尽量减少了视频在初始化过程中出现的被动 fallback 的情况。

从线上当前的优化来看,整体 VV 的千分之三才会涉及 fallback 能力的触发。

首帧优化目标——拐点分析

前面技术性的优化都是通过做减法来保证首帧能够快速出现。但是我们在做首帧的时候也不能忘记初衷,就是让用户感知不到首帧的加载。所以我们也在探索什么叫做无感知。我们近期在尝试的拐点分析就是去探索起播时长为多少对于业务才算极致最优。于是我们把起播时长和用户离开当前视频的速率对应了起来。基于数据拟合,我们就能够看到当前业务在起播阶段用户整体的容忍程度情况。

我们从某一个业务的数据观测到:

从整体的大盘数据来看,首帧时间要保证优化到 200ms 以内对业务才是尽量无损的。在 200ms 的数据指标下,我们有时候就可以进行相关指标置换。

前面提到,在起播的时候,可以选择立即起播,也可以选择缓冲到一定水位再起播。因为缓冲到一定水位之后能保证用户后续播放的流畅度。有了以上的数据支撑,我们也就知道了在不同的业务侧用户的容忍度的边界值,在这个边界值之内,我们可以平衡各种指标进行优化。

总结与展望

我们现在做的事情是通过优化打造极致体验的点播解决方案。我们理解的极致体验优化并不是技术上的自嗨,而是尝试站在用户的角度衡量这些优化能否解决他们在真实播放场景下的痛点。

我们作为点播中台,需要支撑不同的业务,在不同业务场景里要能具备满足用户需求的能力。对于点播中台的技术架构来说,我们有“三高”的愿景:

声明:本文来自用户分享和网络收集,仅供学习与参考,测试请备份。