小程序直播拉流笔记
背景
需要实现扫码开台后自动开启球桌绑定的摄像头,同步进行球桌直播,直播结束后还支持选择录播回放。其实就是将各个镜头的内容同时在一个页面内进行播放。不过直播和录播的生成都是在后端实现,前端只负责视频资源的播放。
思考
对于简单的直播场景,前端需要关注的主要是「编解码格式」
和「直播协议」
,因为这两点直接决定直播能否播放。
「编解码格式:」
视频的编码方式决定了视频的压缩方式,同样的需要对应的解码格式才能正常播放视频。但视频编码这个过程是在推流端做的,通常会采用H.264,目前基本上所有的播放器和浏览器都支持该解码方式,其兼容性基本不用考虑;所以虽然视频的编解码格式很重要,但只要没有特殊的场景如4k,一般无需过多考虑。
「拉流端直播协议:」
不同的直播协议,其兼容性和直播效果有一些差异,而前端对兼容性的差异是敏感的,所以对于Web端,尽量选择兼容性最佳的HLS。
调研了下支付宝 和微信小程序的视频播放支持格式,取二者均兼容的格式,只有mp4、3gp和m3u8这三种格式能够两个平台安卓和iOS全兼容
为什么使用xgPlayer
在确定了我所需要使用的直播协议后,我调研了一些社区推荐的播放器:tcplayer.js、xgplayer、DPlayer、plyr、ArtPlayer.js、Video.js。
其实以上的播放器在功能上都可以满足我的需求,并且也都支持H.264编码格式;在直播能力的支持上也都会在底层依赖hls.js,flv.js,不过像tcplayer和xgplayer还单独包了一层,使得直播的实现更加的符合播放器的体系;
在我所调研的播放器里xgPlayer的文档是最清晰和完善的,并且xgPlayer使用插件机制,所有功能均可插拔,而且支持自定义扩展能力,十分方便,所以在开发体验上我认为更胜一筹。
基本使用
- 初始化
1 | import Player from 'xgplayer' |
- 多实例
初始化时可以使用选择器id或容器el。但对于同时实例化多个播放器的场景,使用Id很容易导致最终只实例化成功一个,虽然可以通过ID+索引的方式避免,但使用容器el还是更为简洁的。
1 | <div ref="playerRef"></div> |
常用属性
1
2
3
4
5
6
7
8
9
10
11new Player({
poster // 封面
autoplay // 自动播放,基本上不支持有声自动播放;
autoplayMuted // 自动静音播放,需要自动播放可使用改属性
playsinline // 对于移动 Safari 浏览器来说是必需的,它允许视频播放时不强制全屏模式
loop // 循环播放
fitVideoSize // 根据视频内容调整容器宽高
videoFillMode // 视频画面填充模式
controls // 是否展示进度条
videoAttributes // 透传给video标签的属性
})自定义插件
1 | // demoPlugin.js |
1 | // demoPlugin.vue |
1 | // 使用 |
坑
- 跨域
问题的起因是当时的直播流内容总是会间隔性的黑屏,而且后端无法监控到并调整视频源。于是需要前端通过截取画面并分析截图的像素点来判断是否黑屏,以实现黑屏自动切换视频源的能力。
但是当通过canvas获取图片数据时getImageData报了一个SecurityError异常。
经查阅发现这是浏览器的安全策略,不通过CORS使用其他来源的资源,会污染画布。
在”被污染”的 canvas 中调用以下方法将会抛出安全错误:
- 在 canvas 的上下文上调用getImageData()
- 在canvas元素本身调用toBlob()、toDataURL()、captureStream()
所以如果要对视频内容进行截图或者对视频画面做一些操作处理,需要给video标签设置crossOrigin属性,在xgplayer中可以通过videoAttributes属性传入。
1 | const player = new Player({ |
- 内存溢出
当不需要播放器时,记得及时销毁,否则可能会导致内存溢出。(尤其是多实例、切换播放的场景)
1 | player.destroy() // 销毁播放器 |