上海打工小伙最近有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)
        }
      )