上海打工小伙最近有H5视频自动播放的需求,
可是都到24年了,还是被H5视频自动播放困扰啊!
项目中一直都有H5播放视频的需求,从PC强制来的需求,设计师只会提供视频,需要H5上也能像PC上一样背景静音播放,
目前处理方案是:视频转png序列帧,6s视频转换成图片后能达到30M左右,对于H5的加载开销太大了,体验非常差。
首先方案一,将视频转成webp动图
借助工具将视频文件转成webp格式,项目中直接引入图片即可
优点:webp动图对比了apng,gif,透明背景支持,体积最小,相比视频,体积增加最小
缺点:有兼容问题,需要兼容处理
<picture>
<source
srcset="***.webp"
type="image/webp">
<img src="***.png">
</picture>
方案二,腾讯VAP.js
webp图片体积还是过大,可以考虑vap动效解决方案
通过vap转化序列帧图成mp4,引入插件vap.js播放mp4视频即可
优点:vap.js转化mp4体积非常小,可以达到几十k,但是web端兼容性一般,本人实测小米自带浏览器不支持,微信内嵌浏览也不支持
缺点:兼容性一般
方案三,jsmpeg
将原视频转成TS格式视频,可以自动播放,暂未发现兼容问题,jsmpeg传送门
优点:视频体积未增加,基本全部兼容H5视频自动化播放,TS视频能分段边播边下,体验比较好
缺点:视频格式必须是MPEG1,也就后缀.ts,以前古老DVD存储格式,视频清晰度一般,必须ffmpeg转化,项目有转化代码命令行,本人实测,目前最佳
// ffmpeg转换命令
ffmpeg -i in.mp4 -f mpegts \
-codec:v mpeg1video -s 960x540 -b:v 1500k -r 30 -bf 0 \
-codec:a mp2 -ar 44100 -ac 1 -b:a 128k \
out.ts
// -s 尺寸
// 3500-5000k清晰度比较好
方案四,Broadway.js
考虑Broadway.js播放更多视频源格式,也引入Broadway.js,但是有个明显短板,未在项目中使用
优点:对比jsmpeg支持H.264视频格式,清晰度比较好
缺点:视频资源需要加载完才能播放,会出现黑屏现象,体验就下降了
目前实测,方案一和方案三比较可行,可以解决H5视频自动播放问题,如果纠结于视频清晰度,那就降级序列帧动画,将序列帧图片抽帧,压缩,动画和图片大小平衡即可;
序列帧绝佳处理工具,gka.js;
最后来个预加载降级序列动画代码:
const imgData = {
width: 750,
offX: 0,
offY: 0,
sourceW: 750,
sourceH: 1624,
w: 15000,
h: 1624,
y: 0,
file: '123.png',
frames: [
{
height: 1623,
x: 0,
},
{
height: 1623,
x: 750,
},
{
height: 1624,
x: 1500,
},
{
height: 1623,
x: 2250,
},
{
height: 1623,
x: 3000,
},
{
height: 1623,
x: 3750,
},
{
height: 1623,
x: 4500,
},
{
height: 1623,
x: 5250,
},
{
height: 1623,
x: 6000,
},
{
height: 1624,
x: 6750,
},
{
height: 1624,
x: 7500,
},
{
height: 1623,
x: 8250,
},
{
height: 1623,
x: 9000,
},
{
height: 1624,
x: 9750,
},
{
height: 1623,
x: 10500,
},
{
height: 1624,
x: 11250,
},
{
height: 1624,
x: 12000,
},
{
height: 1624,
x: 12750,
},
{
height: 1623,
x: 13500,
},
{
height: 1623,
x: 14250,
},
],
animations: {
'gka-animate': [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19,
],
},
}
function preloadImage(names, cb) {
window.gkaCache = window.gkaCache || []
var n = 0,
img,
imgs = {}
names.forEach(function (name) {
img = new Image()
window.gkaCache.push(img)
img.onload = (function (name, img) {
// console.log('name', name, img)
return function () {
imgs[name] = img
++n === names.length && cb && cb(imgs)
}
})(name, img)
img.src = name
})
}
preloadImage(
[
'123.png',
],
function (imgs) {
var canvas = document.getElementById('webCanvas2Video'),
ctx = canvas.getContext('2d'),
frames = imgData.frames,
i = 0,
o = {},
key = Object.keys(imgData.animations)[0],
list = imgData.animations[key],
len = list.length,
width = imgData.sourceW,
height = imgData.sourceH,
ratio = Math.max(document.body.clientWidth / 375, 1)
canvas.style.width =
(width / (375 * undefined)) * document.body.clientWidth + 'px'
canvas.style.height =
(height / (375 * undefined)) * document.body.clientWidth + 'px'
canvas.width = width * ratio
canvas.height = height * ratio
ctx.scale(ratio, ratio)
var cacheCanvas = document.createElement('canvas'),
ctxCache = cacheCanvas.getContext('2d')
cacheCanvas.width = canvas.width
cacheCanvas.height = canvas.height
setInterval(function () {
o = list[i]
ctxCache.clearRect(0, 0, canvas.width, canvas.height)
o = Object.prototype.toString.call(o) == '[object Array]' ? o : [o]
for (var j = 0, t; j < o.length; j++) {
t = frames[o[j]]
ctxCache.drawImage(
imgs[t.file] || imgs[imgData.file],
t.x || imgData.x || 0,
t.y || imgData.y || 0,
t.width || imgData.width,
t.height || imgData.height,
t.offX || imgData.offX || 0,
t.offY || imgData.offY || 0,
t.width || imgData.width,
t.height || imgData.height
)
}
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(cacheCanvas, 0, 0, canvas.width, canvas.height)
i = ++i === len ? 0 : i
}, 200)
}
)