android上视频播放存在的问题
在PC上播放html5视频,设置video.currentTime=5,视频将跳到5s的位置,并且显示出第5s的画面。在安卓下,却存在下面两个问题:
- 在安卓上,为了省电,在暂停的时候,改变视频属性不会刷新画面,直到你再次播放的时候,这些改变才会表现出来。所以暂停的时候改变currentTime不会更新画面,手动改变进度条也不行。
- 在安卓上,视频并不是准确的按currentTime播放,可能你设置 currentTime = 5,但是播放出来的内容却是第8s的。这个问题,用手改变进度条也会出现,可以将视频拖到60s,在拖回10s,看看播放的内容是否是第10s的。
所以,对于一些需要精确控制视频进度的情景,比如视频演示,这两个问题会造成很大的困扰,因为android下,没有办法很精确的控制视频进度。
可能并不是所有移动端都存在这两个问题,没验证哪些存在
解决办法
对于第二个问题,是没有办法改变的,这是html5 video的实现问题。但是第一个问题,却可以通过模拟“暂停下设置视频进度”解决。
模拟的方式是,先播放视频,然后将视频设置到目标时间,当视频加载出第一帧的时候,暂停视频,如下:
播放视频,监听playing事件
触发playing事件,说明视频已经开始播放,此时设置currentTime等于目标时间,监听seeked事件
触发seeked事件,在移动端下,seeked事件触发后,表示已经寻址到了指定时间,但是画面还没更新,监听timeupdate事件
触发timeupdate事件,在移动端下,第一次触发这个事件表示即将更新画面,此时设置50ms的延迟,因为一般视频为24fps,也就是40ms刷新一帧,50ms的延迟为了确保第一帧加载出来
延迟结束,暂停视频。此时视频暂停再目标时间,画面也已经加载出来。
之所以要搞得这么复杂,是因为在android下,事件触发并不是很准确,经触发了playing
和timeupdate
事件,但视频可能都还没开始播放,但是有这么几个规律:
- 第一,触发
seeked
之后的timeupdate
的时候,视频已经很接近播放了 - 第二,触发
playing
后,第2次触发timeupdate
的时候一定已经播放着了,但是触发两次timeupdate
的间隔比较大,往往视频已经很明显的播放一小段。
并非放之四海皆准的规律
下面的代码就是用这种方式实现的,能够在android上暂停时设置currentTime,主要看setTime
方法:
/*** Created by Administrator on 2017/1/9.*/
export default class Video{constructor(src){let uid = new Date().getTime();this.id = 'video'+uid;this.video = $(`<video id="${this.id}"></video>`).get(0);this.status = null; //播放状态}play(){this.status = "playing";this.video.play();return this;}pause(){this.status = "paused";this.video.pause();return this;}/*** 设置视频当前的事件* @param time 时间* @returns {Number}*/setTime(time){if(this.status == "playing"){this.video.currentTime = time;console.log("当前视频时间:"+this.video.currentTime);return time;}/*目的:在移动端下加载指定时长的视频画面移动端下存在的问题:在移动端下,如果不播放视频,则视频控件显示黑屏,此时不可指定视频当前时间解决办法:在移动端下,设置到指定时长后,播放极小的一段时间,让视频控件显示出当前的画面,然后暂停,看起来就像直接指定时间一样实现说明:1、监听playing事件,并在其中监听seeked和timeupdate事件,两个事件都触发后,视频一般接近或已经开始播放了,然后再设置50ms的延迟,一般可保证视频播放2、在setTime执行的过程中,有可能外部已经更改了视频播放的状态(通过调用this.play()或this.pause()),因此设置一个status字段,保存外部的操作*/let that = this;that.video.play();$(that.video).one("playing",function(){that.video.currentTime = time;$(that.video).one("seeked",function(){$(that.video).one("timeupdate",function(){clearTimeout(that.timeout);that.timeout = setTimeout(()=>{console.log("当前视频时间:"+that.video.currentTime);if(that.status == "playing"){that.video.play();}else{that.video.pause();}},that.delay);});})})return time;}}
一些链接
video标签在不同平台上的事件表现差异分析
Jumping to time offsets in HTML5 video
移动端HTML5视频播放优化实践
html5 video seekable属性
【W3C】 HTML DOM Video 对象
【MDN】video标签
视频播放的那些事
html5–移动端视频video的android兼容,去除播放控件、全屏等