八月,依然須要空調續命,這個季節二次元大機率在放煙火,給我映像最深的應該是《聲之形》中硝子墜落時的煙火片斷,絢麗而安靜。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~