直播架构
直播组成:一个直播项目通常由三部分(两端一服)组成:两端-推流端、拉流端,一服-流媒体服务。
直播流程:主播通过推流端(OBS等设备)将视频流推送到流媒体服务,流媒体服务进行视频切片、转换等过程,推送视频流到拉流端。
实时通信:实时通信功能,例如评论等实时展示的数据,交互可以用WebSocket实现,长连接通信需要有一个保持机制,也叫心跳机制,也可以使用其他方式实现同等效果的机制。目的是保持通信不断。
直播协议
1. 直播协议背景
-
HLS协议
HTTP Live Streaming(HLS),顾名思义,这是一个基于HTTP协议的直播流协议,苹果公司开发,移动端支持度很好,可以查一下caniuse,pc端仅支持safari。
HLS协议提供的视频在服务端被切割成ts切片,然后通过m3u8索引文件按序加载,从而达到视频的效果,它的格式有如下特点:
视频格式:MPEG-Ts。
编码: 视频编码为H.264。
一个m3u8文件是这样的: 文件里有版本号,时长,例如此文件 #EXTINF 代表加载一个ts切片需要10s,也就是延时10s。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:14
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.000000,
http://video.xxx.cc/fudaoqewq_record/23143269/fb5376dqwew7a064309ec3ec3ff.ts
#EXTINF:10.000000,
http://video.xxx.cc/fudao_rdsadecord/2343669/4de471c2gqeq3ecad13a592a63ec.ts
#EXTINF:11.150000,
http://video.aaa.cc/fudaasdecsadord/54569/e5397fdgwe343870abe02a3cb18f.ts
#EXTINF:10.000000,
http://video.ccc.cc/fudaoadcord/231369/4b69216b8be571rwqb8da8171e5f2.ts
#EXTINF:10.000000,
http://video.bbbb.cc/fudaocsacaecord/231e19/a5789671231212b4d7c8497b0321.ts
#EXT-X-ENDLIST
-
RTMP协议
Real Time Messaging Protocol(RTMP)是 Macromedia 开发的一套视频直播协议,现在属于 Adobe。RTMP协议只能使用 Flash 实现播放器。它的实时性好,延迟低,但不支持移动端。
-
HTTP - FLV协议
http-flv是将流媒体数据封装成flv格式,然后通过http协议传输到客户端,移动端不支持flash,需要使用flv.js进行转码播放。
2. 协议选择
| 协议 | 传输方式 | 视频格式 | 延时 | 数据分段形式 | Html5是否支持 |
|---|---|---|---|---|---|
| http-flv | http流 | flv | 2s | 连续流 | 支持 |
| rtmp | tcp | flv tag | 2s | 连续流 | 依赖flash,移动端不支持 |
| hls | http | ts | 20s | 切片 | 支持 |
video标签上的兼容
- 看代码:
<video
webkit-playsinline // 针对ios9不全屏播放
playsinline // 针对ios10、11不全屏播放
x5-playsinline // 阻止x5内核浏览器全屏播放
x-webkit-airplay="allow" // 默认不全屏播放
x5-video-player-type="h5" // 限制启用微信默认播放器,改用H5播放
x5-video-player-fullscreen="true" // true为支持全屏播放
x5-video-orientation="portraint" // 播放器方向,landscape横屏,portraint竖屏
src="xxxx.m3u8"
/>
H5 video 自动播放问题
- 问题:H5 video 实现自动播放,hybrid模式,端内可直接调用play()方法,端外仅ios微信内可实现自动播放。
- 可用方案:iOS 微信内通过监听WeixinJSBridgeReady事件,调用play()事件,vue中代码如下:
document.addEventListener('WeixinJSBridgeReady', ()=> {
if (this.$refs.liveVideo) {
this.$refs.liveVideo.play();
}
}, false);
- 如果视频地址是通过接口返回的,会出现自动播放失败的问题,因为WeixinJSBridgeReady只触发一次。采用定时器连续调用的方式解决,优化完的代码:
created(){
document.addEventListener('WeixinJSBridgeReady', this.repeat, false);
},
method:{
repeat() {
if (this.loadStatus) { // loadStatus 为接口返回后状态
this.videoPlay();
} else if (this.repeatNum < 10) {
// 根据数据统计的接口返回时间, 自动播放时间设置为2s
this.repeatNum++;
setTimeout(() => {
this.repeat();
}, 200);
}
},
videoPlay() {
if (this.$refs.liveVideo) {
this.$refs.liveVideo.play();
}
},
}
- 无用方案
- 设置autoplay属性,由于移动端浏览器默认不润许媒体文件自动播放,为了避免浪费用户的流量。个别情况加入muted(静音)属性可自动播放,但效果并不理想,鸡肋。
- 直接调用play() 方法
- 通过js主动触发click事件
- 监听touchstart事件,调用play()方法,可以实现,但需要用户触发一次touchstart,可作为降级方案,并不建议采用。
video标签播放回放视频加载优化
- 背景:回放视频格式原本采用的是mp4格式,大的视频(比如500MB)加载第一桢时间较长,用户体验不够好,更改为m3u8格式。 经测试,端内外,ios都可以使用video的功能
- 问题:video标签播放m3u8格式视频,x5内核内,不能在第一时间获取到视频总时长。
- 解决方案:在安卓端微信内,监听video的loadedmetadata事件,触发后每隔200ms获取video的duration值,即可解决。
<template>
<video @loadedmetadata="load" id="player" />
</template>
export default() {
methods: {
load(e) {
this.duration=e.target.duration; // 正常情况下直接赋值即可
// 安卓微信下获取到的duration值为无限大Infinity
this.getDuration();
let timer = setInterval(() => {
if(this.duration === Infinity) {
this.duration = document.querySelector('#player');
} else {
clearInterval(timer);
}
})
},
}
}
遇到问题继续更新,有更好的方案或问题请指教,谢谢!