随着直播和短视频的兴起,视频由于承担了更大的信息量,因此现在已经是非常主流的运营/产品信息输出方式。但由于国内各个浏览器厂商自身的利益关系所在,他们对HTML5的Video能力做了非常多的限制,不限于:
其具体问题可以参考腾讯IMWeb团队编写的《复杂帧动画之移动端Video采坑实现》。
为了解决这些问题,我们通过软解FLV的方式实现了WXInlinePlayer,其用的第三方技术和平台API如下:
同时我们也编写了WebAssembly版本的FLV Demuxer,你可以在lib/codec找到相关代码。
兼容测试使用BrowserStack服务提供的相关机型,仅供参考:
https://eroszy.github.io/WXInlinePlayer/example/index.html
请确保你安装过parcel / emscripten 1.38.45 / cmake 以及 make,然后执行以下命令即可:
npm install # 初始化工程
npm update # 更新工程有关的插件。如果网络错误,改用 cnpm update
bash build.sh
最终产物会在example文件夹中。
请注意:
- 请在*nix环境下进行build,并不保证Windows下的OpenH264的编译
- 请确保emscripten在1.38.45版本,否则会出现wasm32错误
- cmake 版本需要是 3.16+
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>WXInlinePlayer</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="container" width="800" height="450"></canvas>
<script src="./index.js"></script>
<script>
if (WXInlinePlayer.isSupport()) {
WXInlinePlayer.init({
asmUrl: './prod.baseline.asm.combine.js',
wasmUrl: './prod.baseline.wasm.combine.js'
});
WXInlinePlayer.ready().then(() => {
const player = new WXInlinePlayer({
url: 'https://static.petera.cn/mm.flv',
$container: document.getElementById('container'),
hasVideo: true,
hasAudio: true,
volume: 1.0,
muted: false,
autoplay: true,
loop: true,
isLive: false,
chunkSize: 128 * 1024,
preloadTime: 5e2,
bufferingTime: 1e3,
cacheSegmentCount: 64,
customLoader: null
});
const { userAgent } = navigator;
const isWeChat = /MicroMessenger/i.test(userAgent);
if (!isWeChat) {
alert('click to play!');
document.body.addEventListener('click', () => {
player.play();
});
}
});
}
</script>
</body>
</html>
在工程根目录,输入命令启动server:
npm run serve
然后输入网址访问demo:
http://localhost:8888/example/index.html
当前执行环境是否支持WXInlinePlayer。
if(WXInlinePlayer.isSupport()){
console.log('WXInlinePlayer support');
}
初始化WXInlinePlayer,需要传入加载的H264解码库的具体地址,关于解码库的选择,请参考:如何选择解码依赖。
if(WXInlinePlayer.isSupport()){
WXInlinePlayer.init({
asmUrl: './prod.baseline.asm.combine.js',
wasmUrl: './prod.baseline.wasm.combine.js'
}).catch(e=>{
console.log(`WXInlinePlayer init error: ${e}`);
});
}
WXInlinePlayer已经准备就绪,可以安全的进行初始化操作。
if(WXInlinePlayer.isSupport()){
WXInlinePlayer.init({/*.....*/});
WXInlinePlayer.ready().then(()=>{
console.log('WXInlinePlayer ready');
});
}
WXInlinePlayer构造函数,相关初始化参数请参考:初始化参数。
WXInlinePlayer.ready().then(()=>{
const player = new WXInlinePlayer({/*...*/});
});
进行视频播放。需要注意的是由于浏览器限制(不包含微信及Chrome 66版本以下),高版本已经禁用了音频自动播放,因此直接调用此方法可能并不会有作用,请在click/touchstart/touchend/touchmove等事件中让用户主动触发。
document.body.addEventListener('click', ()=>{
player.play();
});
停止整个播放器,不可被恢复(resume)。
player.stop();
暂停当前播放。
player.pause();
恢复由pause引起的暂停操作。
player.resume();
获取/设置当前音量。
const volume = player.volume(); // get volume
player.volume(volume); // set volume
获取/设置静音状态。
const muted = player.mute(); // get mute
player.mute(muted); // set mute
销毁播放器,释放所有内存等待回收。
player.destroy();
获取当前播放时间,请注意,可能出现负值的情况请注意处理。
player.on('timeUpdate', ()=>{
let currentTime = player.getCurrentTime();
currentTime = currentTime <= 0 ? 0 : currentTime;
});
可播放时长,可理解为缓冲的时长。
player.on('timeUpdate', ()=>{
const duration = player.getAvaiableDuration();
});
目前有3套解码库,分别是:
其区别在于:
我们推荐当你播放广告视频/营销视频/小动画视频等对依赖库大小敏感的时候使用baseline.asm/baseline.wasm,而在播放点播视频/直播视频时等对依赖库大小不敏感的时候使用all.asm/all.wasm。
在开发本机上,针对同一视频,WXInlinePlayer与手淘、花椒等FFMpeg实现在内存占用和CPU占用上相差不大,WXInlinePlayer性能整体较FFMpeg方案好5-10%左右,而H265由于减少的deblock,其性能相比于FFMpeg方案好30%左右,以下为H265的播放性能对比:
WXInlinePlayer的卡顿和延迟主要来自于3个地方:
一般来说,如果在用户网络环境较好的情况下,渲染由于使用了WebGL,很难造成瓶颈(操作很单一),其中一般会因为软解码性能不足造成不停卡顿及延迟。
优化因为软解码性能不足造成的延迟,我们一般从几个地方着手:
目前WXInlinePlayer在中高端机上解1280x720,码率1024,帧率24fps的视频比较流畅。
关于以上提到的视频参数你可以通过FFmpeg查看:
ffmpeg -i "your.flv"
在这里我们给出主流平台的profile/帧率/码率/分辨率供参考:
平台 | 类型 | 清晰度 | profile | 帧率 | 码率 | 分辨率 |
---|---|---|---|---|---|---|
虎牙 | 横屏 | 标清 | High | 24 | 500k | 800x450 |
虎牙 | 横屏 | 高清 | High | 24 | 1200k | 1280x720 |
虎牙 | 竖屏 | 高清 | Main | 16 | 1280k | 540x960 |
奇秀 | 竖屏 | 标清 | High | 15 | 307k | 204x360 |
奇秀 | 竖屏 | 高清 | High | 15 | 512k | 304x540 |
奇秀 | 竖屏 | 超清 | Baseline | 15 | 1440k | 720x1280 |
抖音 | 竖屏 | 默认 | High | 30 | 1600k(变化较多,仅供参考) | 720x1280 |
快手 | 竖屏 | 默认 | High | 25 | 2880k(变化较多,仅供参考) | 720x1280 |
我们建议你:
WXInlinePlayer的我们常用的低延迟配置参数如下,仅供参考,实际请根据你的直播流/点播文件配置调整:
{
chunkSize: 128 * 1024,
preloadTime: 5e2,
bufferingTime: 1e3,
cacheSegmentCount: 64,
}
同时,你可以使用performance事件来判断当前的解码性能,然后提示用户并降级到你的后备方案(例如直接video播放/静态图/序列帧等):
player.on('performance', ({averageDecodeCost, averageUnitDuration})=>{
const prop = averageUnitDuration / averageDecodeCost;
if(prop >= 2.0){
console.log('good performance');
}else if(prop < 2.0 && prop >= 1.0){
console.log('ok, thats fine');
}else{
console.log('bad performance');
}
});
FFmpeg方案目前有几个比较大的问题,第一个是解码库的大小,精简后2M左右,gzip大约600k,这对于在意依赖库大小的产品是不可接受的。其次FFmpeg的方案难以被自己优化,比如WXInlinePlayer在2.0时会做多Worker的解码,这对于此类方案的修改成本是非常大的。
卡顿和延迟的原因比较复杂,对于WXInlinePlayer来说一般情况是解码速度跟不上播放速度,请参考如何降低卡顿和延迟进行优化。
UC不管是iOS还是Android都对WebAssembly/ASM.js进行了阉割,因此索性不支持了。
请使用FFmpeg或是其他类似的工具,这里给出一个简单的命令示例:
ffmpeg -i "your.mp4" -vcodec libx264 -acodec aac out.flv
WXInlinePlayer的FLV规范遵循金山的FLV拓展规范,如果需要进行相关的编码,可以参考其相关的FFmpeg patch或者金山编写的编码器。