乐趣区

关于前端:网页视频autoplay兼容及解决方案

网页视频自动播放的局限

自动播放是指无需通过用户的批准就能够开始播放视频。这包含在 video 元素应用 autoplay 属性或者通过 JavaScript 代码间接调用 video 元素的 play 办法。
<video src="/video.mp4" autoplay>

videoElement.play();

十分遗憾的是,各个浏览器都为多媒体的自动播放设置了不尽相同的限度策略,也就意味着目前想要实现有良好兼容性的自动播放,是很难办到的。

各个浏览器对视频自动播放的限度

IOS

IOS9 以下版本:

(在过后挪动互联网的条件下,播放一个视频的流量和电量老本都是十分高的,因而视频的播放必须要先通过用户批准)

无奈自动播放

IOS10 以上版本:

(浏览器厂商不给主动播视频,开发者只好曲线救国,应用 GIF 动图代替视频实现自动播放,然而 GIF 动图须要耗费的流量是视频的 12 倍,性能耗费是视频的 2 倍,并且挪动互联网倒退飞速,用户对视频播放占用的流量和电量也不再这么敏感,于是决定给挪动设施的视频自动播放放宽限度)

<video autoplay>满足下列条件能够自动播放:

1. 视频的源是没有音轨的或 video 元素应用了 muted 属性手动静音
2.video 元素须要在屏幕上可见
3.video 元素设置了 playinline 属性

videoElement.play()满足下列条件能够自动播放:

1. 视频的源是没有音轨的或 video 标签应用了 muted 属性手动静音
2.video 元素设置了 playinline 属性

以下行为将导致自动播放生效:

<video>元素在没有用户手势的状况下有了音轨或勾销了静音,播放将被暂停


Chrome in Android

Android 4.3 及以下版本:

4.3 及以下版本的安卓,应用的是基于 Webkit 实现的内核,和 ios 有着雷同的体现

无奈自动播放


Android 4.4 及以上版本:

4.4 及以上版本的安卓,用上了 Bink/Chromium 内核,有了本人的一套限度规定

Chrome 53 版本以前:

​ 无奈自动播放

Chrome 53 版本当前,Chrome 58 版本以前:

<video autoplay>videoElement.play() 满足下列条件能够自动播放:

1. 视频的源是没有音轨的或 video 元素应用了 muted 属性手动静音
2. 用户未开启流量节俭模式

Chrome 58 版本当前,Chrome66 版本以前:

<video autoplay>满足下列条件能够自动播放:

1. 视频的源是没有音轨的或 video 元素应用了 muted 属性手动静音
2. 用户未开启流量节俭模式
3.video 元素须要在屏幕上可见


​ 1. 站点被 ” 增加到主屏幕 ”,且视频的源在manifest 文件标识的范畴内

videoElement.play()满足下列条件能够自动播放:

1. 视频的源是没有音轨的或 video 元素应用了 muted 属性手动静音
2. 用户未开启流量节俭模式

Chrome 66 版本当前:

​ 在 Chrome 58 版本的根底上移除了“未开启流量节俭模式”的限度


Chrome in PC

Chrome 66 版本以前:

​ 齐全反对自动播放

Chrome 66 版本及当前:

​ 视频的源是没有音轨的或 video 元素应用了 muted 属性手动静音

​ 站点是一个 PWA 利用,并且用户把它装置到了桌面

Safari in PC

Safari 11 版本以前:

​ 齐全反对自动播放!


Safari 11 版本当前:

​ 视频的源是没有音轨的或 video 元素应用了 muted 属性手动静音

能够发现,无论是什么浏览器内核,它们对于视频自动播放限度的改变趋势都是相近的,挪动端在一直地放松限度,而桌面端则在一直地收紧限度,直到达成了一个近乎对立的规范:只有静音视频能力自动播放。

参考:
Muted Autoplay on Mobile: Say Goodbye to Canvas Hacks and Animated GIFs!
Media updates in Chrome 58
Chrome’s autoplay feature
updated video policies for iOS
Auto-Play Policy Changes for macOS

解决办法

1. 静音自动播放

只在桌面端应用的网页,采取静音的形式自动播放视频,挪动端则无奈在低版本手机中失常运行。

2. 通过用户交互行为解除自动播放限度

在桌面端浏览器上,能够通过在调用 video.play() 办法之前疏导用户与页面产生交互行为,即可使自动播放限度解除。

在挪动端,只容许通过用户交互来触发有声媒体的播放,而不是在用户与页面产生交互后解除自动播放限度,因而须要把 video.play() 办法放到 HTMLElement 容器的交互事件回调中(点击 / 触摸)。

document.body.addEventListener('click', () => {console.log('触发播放')
    this.videoRef.play();})

联合静音自动播放与交互播放

  • 视频自动播放时设置 muted: true。
  • video.play()办法绑定到 HTMLElement 容器的交互事件回调中(点击 / 触摸)。
  • 在播放界面上通过图标显示以后视频被静音,疏导用户点击。
  • 当用户点击绑定的容器时,在事件的回调中将视频再次播放,此时无需设置静音,同时更改静音图标

!用户手势令牌过期

如果须要在取得用户手势令牌后,提早数秒进行 video.play() 办法的调用,比如说想要在交互事件回调函数中先异步申请视频链接再进行播放,则须要留神在挪动端,用户的手势令牌可能会在 N 秒后过期,在不同的机型中 N 的大小也不同,即提早调用 video.play() 办法可能会生效。

尝试在点击事件回调中提早几秒调用 play() 办法并捕捉报错:Play() can only be initiated by a user gesture.

<img width=”378″ alt=”Snipaste_2022-01-13_16-15-11″ src=”https://user-images.githubusercontent.com/44472735/149320483-ea7709b8-2355-4a5f-90c5-433e0eaa378d.png”>

在线尝试

解决办法:先调用video.load(),再去提早调用video.play()

<video id="video"></video>
<button id="button"></button>

<script>
  button.addEventListener('click', onButtonClick);

  function onButtonClick() {
    // This will allow us to play video later...
    video.load();
    fetchVideoAndPlay();}

  function fetchVideoAndPlay() {fetch('https://example.com/srcApi')
    .then(src => {
      video.src = src;
      return video.play();})
    .then(_ => {// Video playback started ;)
    })
    .catch(e => {// Video playback failed ;(})
  }
</script>

参考:

DOMException: The play() request was interrupted

3. 检测自动播放,播放失败时回退到用户交互触发播放
  • 通过 play API 返回的 Promise 检测自动播放胜利还是失败

不应用 autoplay 属性,而是调用 play API 来尝试进行自动播放,高版本浏览器会返回一个 Promise,如果自动播放失败,则 Promise 会回绝(低版本浏览器不会返回 Promise,此时能够通过事件或参数来检测自动播放)

var promise = document.querySelector('video').play();

if (promise !== undefined) {
    promise.catch(error => {
        // Auto-play was prevented
        // Show a UI element to let the user manually start playback
    }).then(() => {// Auto-play started});
}
  • 通过 video 事件或参数检测自动播放胜利,通过超时判断自动播放失败

应用 autoplay 属性,或调用 play API 来尝试进行自动播放,通过监听由自动播放触发的 play 事件,监听 timeupdate 事件,查看 currentTime 是否产生了变动等等方法来检测自动播放胜利,并通过设置定时器超时来作为判断自动播放失败的根据。

this.videoRef.addEventListener('timeupdate', (e) => {// console.log('视频自动播放胜利');
})
this.videoRef.addEventListener('canplay', (e) => {// console.log('视频已就绪');
    setTimeout(() => {// console.log('视频自动播放失败');
    }, this.maxWaitTime)
})

不要假如 video 标签肯定会依照预期触发某个事件或扭转某个属性。

4. 减少网站视频的受众,解除自动播放的限度

浏览器的限度策略不是相对的,如果在本地尝试将你的网页代理到出名的视频网站(比方 youtube.com),会发现自动播放限度被解除了。

间接尝试自动播放失败,并报错显示“调用 play()办法失败,因为用户尚未与文档产生交互”

<img width=”1115″ alt=”Snipaste_2022-01-13_14-57-46″ src=”https://user-images.githubusercontent.com/44472735/149320517-83f9fc7e-3b83-485c-a995-fb1a854c08c2.png”>

将页面代理到出名视频网站的域名后,自动播放胜利

<img width=”846″ alt=”Snipaste_2022-01-13_14-58-20″ src=”https://user-images.githubusercontent.com/44472735/149320537-5bfb9615-66f2-421a-a332-9644a8d03fd0.png”>

桌面端 Chorme 会针对用户给每个网站统计一个 MEI 指数,用来掂量用户在网站上生产多媒体的偏向强烈水平,并在浏览器内保护一个 MEI 列表(无奈通过 JS 探测)。当用户在网站上观看视频并满足以下条件时

  • 观看时长大于 7 秒。
  • 视频音轨存在并且没有静音。
  • 带有视频的选项卡处于沉闷状态。
  • 视频的像素大小大于 200×140。

浏览器就会进步该网站的 MEI 指数,当网站的 MEI 指数足够高时,自动播放的限度就会被解除。

新用户会加载一个初始 MEI 列表,这个初始列表会事后植入一些被很多用户打了 MEI 高分的网站,也就是说如果一个网站有足够多的用户容许自动播放,那么这个网站就会默认失去新用户的 MEI 高分,并放开自动播放限度(这个初始列表是齐全由算法生成的)。并且这个初始列表会被用户集体的 MEI 行为所笼罩。

通过拜访 chrome://media-engagement 来查看你的 MEI 列表(不蕴含初始 MEI 列表)

桌面端 Safari 也有相似的策略,它声称“应用主动推理引擎来阻止大多数网站自动播放带有声音的视频”,但没有公开具体的策略内容。

参考:

媒体参加指数(Media Engagement Index,MEI)

Web Audio, Autoplay Policy and Games

5. 应用 gif 图片,程序展现序列图片等伎俩模仿视频成果

应用 gif 图片模仿视频播放成果。

应用动静绘制图片到 canvas 的形式模仿视频播放成果:

  1. 图片对象预加载,放在内存中;
  2. 播放开始,canvas 擦除上一帧图片,同时绘制以后帧图片。

应用动静更新图片 dom 的形式模仿视频播放成果:

  1. 图片对象预加载,放在内存中;
  2. 播放开始,页面增加以后图片元素,同时移除上一帧图片元素,保障页面中仅有一个图片元素。

因为动静更新图片 dom 的形式实质是播放 html 元素,因而还能够实现弱网状态下“抽帧播放”,在“视频播放”中手动增加额定信息等。

查看在线演示

参考:

https://www.didiglobal.com

https://juejin.cn/post/686958…

退出移动版