TGideas

分享

剑侠情缘忘忧镇H5 视频无缝顺滑切换大揭密

经验·团队博客

2019-06-18

开灯
剑侠情缘忘忧镇H5,这是一个以视频为主题的移动端H5专题,不同的是,视频体量巨大,用户分支选择多; 本次总结主要介绍video在移动端页面上的一些新思路,以及何如实现video之间的无缝顺滑切换;

前言:

如果是还没看过的同学,可以拿起手机扫下二维码观看(可能有一点点长):

剑侠情缘忘忧镇H5二维码

这是一个以视频为主题的移动端H5专题,不同的是,视频体量巨大,用户分支选择多;
稍加梳理,流程图如下:

分支流程图

总共有17个视频片段,7个用户选项,9种结局(其中台下看看再说选项有出现彩蛋视频的概率,所以有第九种结局),总时长23分钟,总大小约266MB;
按照以往的做法,类似视频多分支的H5,一般有两种处理方式:
方式1:将所有视频整合在在一起,然后通过video标签的currentTime属性来切换画面;
方式2:不整合视频,通过video标签的src属性,来切换对应的视频;

弊端:
  方式1 对于这个具体的需求来说不太合适,视频的时长太长,通过currentTime来跳转的时候,目标区域的缓冲区基本是空的,切直接跳转currentTime画面会出现明显的抖动,同时也不利于视频更新,假如更新了其中一个画面,整条视频都必须重新合成;
  方式2 用video标签来切换src属性的方式,会有一个问题,就是在画面衔接上,当我们在切换src的瞬间,video会出现黑屏,且需要等待下个视频播放,前一个问题可以通过静态图片来做过度,但后面加载新视频的等待过程,则会给用户带来不流畅的感觉;
       那么现在的思路就从方式2为基础入手,主要解决两个问题,1,视频画面衔接,2.视频瞬间播放;

新思路:

       先从用户交互画面开始思考,在用户做二选一的选择页面时,当用户做出选择的瞬间,我们能否直接开始播放对应的视频?这里指的直接开始播放视频,是去除了视频请求的等待时间,没有卡顿的衔接;
       前言提到的方式2里面是用一个video标签来播放视频,假如我们用3个video标签呢?大体思路是这样的,我们先用A,B,C来代表3个video标签,首先A用来播放当前的视频内容,然后B,C用来缓冲即将出现的两个视频,那么当用户在二选一的时候,其实两个视频都已经有缓冲,用户做出选择的时候,B或C视频就能立马播放,给用户一种瞬间播放的体验;

技术实现:

基于上述的思路,前端需要考虑的技术难点(沿用上述表达,A,B,C):

1.预先激活ABC三个video标签;

2.video标签的缓冲进度;

3.video标签预加载;

4.video标签停止加载;

5.video标签无缝切换;

接下来我们较为详细的讲一下具体的实现;

1.预先激活ABC三个video标签:

  为什么要预先激活ABC?跟移动端video打过交道的人儿一般都懂,除了IOS微信和手Q,其他场景上基本上都需要用户主动操作,才能激活播放视频,然而当video标签激活成功之后,后续怎么设置src,都是能够正常播放的,因此我们需要在一开始引导用户来点击页面,并且同时激活ABC三个video标签,为我们后续为所欲为的操作做准备;
      用最简短的视频源,赋予video标签的src属性,在用户操作之后,video标签开始播放, 接着在video标签的canplay事件里面做暂停处理,不让播放;达到预先激活的功能;

示例如下:

2.video标签的缓冲进度:

       这个功能的为了保证A的正常浏览,当A正在播放的时候,假如随意启动了BC的预加载,那势必会对A的缓冲造成影响,必须在保证A全部缓冲完成的情况下,方能启动BC的预载,这才是合理的预载方式;
       利用video标签的bufferd属性返回的TimeRanges对象,TimeRanges对象表示用户的视频缓冲范围,假如video标签有currentTime的操作,会得到多个缓冲范围,所以我们在获取缓冲时长的时候,必须以最后一个为主;
(ps:在测试过程中发现video的缓冲进度比较随性,它主要保证播放头的正常播放,而不是一开始缓冲就一直加载,可能在缓冲区满足播放的情况下,它就暂停,然后等到需要的时候,再重新缓冲,这是它的特点;
还有一点需要注意,缓冲进度功能是我们模拟出来的,理论上当video缓冲完成的时候,缓冲总时长应该等于video的总时长,但在测试过程中发现有误差的情况,会出现个别不触发video缓冲完成的情况,这里应该做一个容错判断,当video已经播放完成回调,而缓冲完成的回调却没有完成时,需要做下处理,代码逻辑不能100%依赖video缓冲完成的回调来实现)

示例如下:

3.video标签预加载:

       在A完成缓冲之后,开启BC的预加载,由于前面已经激活了BC,所以可以为所欲为的对BC进行操作,包括预加载;
       video标签的预加载其实跟1,video标签激活有点类似,不同点是激活用的是预设的base64视频源,而预加载是用真实的视频源,同样也需要在canplay事件里面暂停视频;

示例如下:

4.video标签停止加载:

       当用户确认了选择之后,BC里面有一个视频已经是作废的,需要停止缓冲,避免带宽开销。
       在video标签的src属性,赋值空字符串就能达到效果;

示例如下:

5.video标签无缝切换:

       假定用户选择B,由于前面已经预加载了B的视频源,所以B的播放会非常快速,那么AB如何切换呢?我们会将A的最后一帧和B的第一帧处理成连续画面,接下来就是考虑如何切换的问题,刚开始我们用了样式里面的display属性,通过设置none/block来隐藏/显示video,也就是当B准备好画面可以开始播放的时候,B显示,A隐藏,以此来达到无缝切换的效果,但是在手机上测试的时候,会偶先闪屏情况,一开始怀疑是性能问题,后来在iPhone7上面测试,也是闪屏不断,经过一系列的排查定位,发现是display属性设置的问题,当给B设置display为none时,B是属于未激活状态,当重新设置为block时,浏览器重新激活了B,这似乎是浏览器的一种优化机制,当设置为block的时候,重新初始video标签,从背景->视频内容的一个初始过程,因此会偶先闪屏;
       为了规避上述的问题,尝试使用宽高来实现隐藏/显示的功能,把video标签的宽高设置为1*1为隐藏,设置原始尺寸为显示,这样就避免了浏览器重新激活video标签的机制;

示例如下:

上述五个功能点的实现原理都大致描述完成,那么组合起来使用如下:

       首先在用户点击交互的时候播放A,同时激活BC,接着开始监控A的缓冲进度,当A缓冲进度达到100%时候,前端逻辑会筛选出二选一的两个视频源,分别赋值给BC,并启动预加载,后续A播放完成,出现二选一UI画面,当用户做出选择之后,例如用户选择B,则停止C的缓冲,然后AB做无缝衔接并且播放,这就是一个小环节的流程,以此类推。

小结:

       一些思考,我们曾经以为video的交互操作无非两种,要么合成一整条视频操作currentTime,要么分段设置src,在操作currentTime或设置的src的卡顿情况算是一种必然想象,或者就这样固化下来.其实还是有其他解决的可能性,多尝试从不同角度来思考问题,即使不能兼顾到所有用户,起码我们为一部分用户带来新的体验,也是一件很酷的事情;

-
求经验 -

COPYRIGHT © 2019. ALL RIGHTS RESERVED.

点击“ . . . ”进行分享