八月,依然须要空调续命,这个季节二次元大几率在放烟火,给我映像最深的应该是《声之形》中硝子坠落时的烟火片断,绚丽而安静。javascript
先来看看上面的图片,这是使用 ffmpeg 截取视频片断转成的 gif,用 gif 来实现背景视频也是一种选择,一张图片就能解决的事,为何还要研究背景视频呢?css
先来看一组数据:html
源视频分辨率为 1920×1080,25fps 时长为 6s,体积是 1.4M,转成同分辨率同帧率的 gif 图片,体积竟然要 26M !!java
并且因为 gif 格式只支持 256 色,mp4 转 gif 画面的分辨率虽然不变但画质有很大损失,上图能看到明显的像素块效果。git
因此平常视频转 gif 时都会进行必定的压缩处理,页首 gif 通过 640×360 12fps 的压缩处理过的体积是 2.3M,仍是大于视频的体积。github
# mp4 转 gif
ffmpeg -y -i demo.mp4 -s 640x360 -r 12 demo_mini.gif
复制代码
相较于视频 gif 有两个比较明显的缺点:web
因此说时代变了,gif 这一页能够揭过了,看看视频~chrome
咱们先来看看使用视频来实现背景的关键要素:npm
好像没什么问题,能够开整了:canvas
<section>
<video loop autoplay="autoplay" preload="auto" >
<source src="./demo.mp4" type="video/mp4">
</video>
<div>mask</div>
</section>
复制代码
video 元素上面绝对定位改了一个遮罩层,loop
循环播放,且不配置 controls
是不会展现控制组件的,嗯,看起来正常,不过视频并无自动播放,机智的你又查查资料,发现视频自动播放是有限制的,只有无音轨的视频或者静音 video 元素才能播放,因而乎加上了 muted
你写下了:
<section>
<video loop muted autoplay="autoplay" preload="auto" >
<source src="./demo.mp4" type="video/mp4" >
</video>
<div>mask</div>
</section>
复制代码
视频自动播放了,电脑上看起来没什么问题,要不换手机试试?
打开 charles 挂上代理,用果子的 Safari 打开,看起来没啥问题,换微信试试,而后你惊讶的发现:
好吧找找解决方法
视频元素的层级错乱解决方案
为 video 设置内联播放标识 playsinline
,而后为了兼容须要加上各类前缀:
指定微信端的页面播放器类型:
视频没法自动播放
微信端能够监听页面的 WeixinJSBridgeReady
来触发视频播放
<section>
<video muted loop class="player" autoplay="autoplay" preload="auto" playsinline="true" webkit-playsinline="true" mtt-playsinline="true" x5-video-player-type="h5-page" >
<source src="./demo.mp4" type="video/mp4">
</video>
<div class="mask">
遮罩层
</div>
</section>
<script> window.onload = function () { const player = document.querySelector('.player'); // 自动播放 document.addEventListener('WeixinJSBridgeReady', player.play()); } </script>
复制代码
微信试试,稳得很。保险起见试试安卓端的各类浏览器吧。
果不其然,video
仍是那个 video
,浏览器已经不是那个 chrome 了。
几乎每一个国产品牌的安卓机自带浏览器都有对 video
元素都有些定制化处理,常见且不限于:
controls
)video
元素在安卓端特性并不统一,目前并无找到很好解决方案。
既然 video
不行,换 canvas
不就行了,video draw canvas 不是分分钟的事。
放个图大家感觉下:
同志们,要把 video 绘制到 canvas 得先播放呀!
即便是有些能够自动播放的视频的浏览器,将 video 绘制 canvas 时,video 元素必须是可见的,因此隐藏的 video 元素也是作不到的。
既然这样,咱们能够将视频截取一张张的图片,而后打个压缩文件,经过 canvas 绘制出来?
等等这不就是视频文件吗?还犯得上去截图播放吗?因此咱们须要的是将视频文件解码成可播放的图片帧!
视频解码的方案简单来讲就是将视频文件解码成一一帧帧的图片,在 canvas 上按必定速率绘制出来。
前人栽树,后人乘凉,github 搜罗下找到几个可用的库
WasmVideoPlayer 原型演示,ffmepg + wasm 实现,移动端性能较差
WXInlinePlayer 依赖于 flv, 且体积较大
Broadway 做者实现了一套安卓端的 h264 解码器(c 语言实现 + wasm),支持特定编码的 mp4 格式的视频,且支持不完善有黑屏状况,且没法按照视频帧率进行播放(未对视频进行细颗粒度播放)
jsmpeg 做者手撸了一个 mpeg-ts 的解码器(支持 JavaScript 与 wasm 版本),支持 ts 格式(mpeg1 编码)的视频,支持较为稳定,可支持细颗粒度播放
由于 MP4 格式的视频较为常见,若是能直接播放 MP4 是最理想的,但 WasmVideoPlayer
和 Broadway
的实现都不太理想,一个是移动端性能差,一个解码支持不完善。
上面的工具都未提供 npm 包支持,若是想在生产使用还须要本身作一下二次封装。
最终的选用的是 jsmpeg,jsmpeg 支持 ts 格式的视频有个优点。
ts 是日本高清摄像机拍摄下进行的封装格式,全称为 MPEG2-TS 。ts 即 "Transport Stream" 的缩写。MPEG2-TS 格式的特色就是要求从视频流的任一片断开始都是能够独立解码的。
例如一个背景视频素材 10M
咱们不须要将整个视频请求下来再进行播放,能够经过 Content-Range
拆分红多个片断来加速视频载入播放。jsmpeg 也支持视频的分片请求。
jsmpeg
自己模块拆分的比较清楚,因此二次包装成 npm 也比较方便。
silent-film-player 是我对 jsmpeg
作的简单二次封装,考虑是作背景视频播放的,因此去掉音频解码相关的模块,新增了 Web Workers 的支持:
感兴趣的同窗能够试试~
使用:
<template>
<section>
<canvas ref="canvas"></canvas>
<div class="mask">
遮罩层
</div>
</section>
</template>
<script> import Player from 'silent-film-player'; export default { data() { return { url: 'https://xxx.ts', }; }, mounted() { const { url, $refs: { canvas }, } = this; window.player = new Player(url, { canvas, loop: true, autoplay: true, disableWebAssembly: true, // 分片大小 chunkSize: 1 * 1024 * 1024, videoBufferSize: 512 * 1024, }); }, }; </script>
复制代码
看几个示例:
示例仓库在这:github.com/kinglisky/b…
至此大概是个比较靠谱的背景视频实现方案。
是否是以为背景视频就只能放在视觉的底层,先来看个例子:
是否是很神奇,结构大概以下,canvas 覆盖在一个图片元素之上,但视频的内容却透出了底部图片。
<section class="container">
<img class="view-bg" src="./demo.jpeg" />
<canvas ref="canvas" class="view-canvas" >
</canvas>
<div class="view-mask">MASK</div>
</section>
复制代码
具体实现为在 canvas 上附加上一个 css 属性
mix-blend-mode: screen;
复制代码
对的,只须要设置上这个属性,视频中的黑色部分便可透出下层图片。
关于 mix-blend-mode
属性的详解能够参考张鑫旭的 深刻理解CSS mix-blend-mode滤色screen混合模式。
视频解码比较耗性能,注意控制播放的视频个数,能够对可视区域内视频元素作播放控制,不可见的视频不播放
wasm 解码在移动端支持和性能较差(特别是安卓端),不太建议使用
对支持的标准 video 行为的浏览器,如桌面端浏览器能够直接使用 video 实现背景视频
iOS 虽然大部分浏览器对 video 元素支持不错,但有些特例如:夸克
、UC 极速版
、ALOOK
视频默认是弹层播放的,并且 ALOOK
浏览器的 userAgent
竟然是和 Safari
同样的,因此你根本无法区分它俩
微信页面的 WeixinJSBridgeReady
没法触发异步加载的视频
MP4 转 TS 会形成视频质量降低,建议提升转码的比率
简单讲讲实现的思路,目前这套方案已经在线上跑了,感兴趣的同窗能够看看:
编辑模板:www.gaoding.com/template/18…
下期讲讲:阿里云函数计算 + OSS 触发器实现视频文件批量转码,
over~