H5直播 寻找最优解(1)

1,740 阅读4分钟

直播架构

直播组成:一个直播项目通常由三部分(两端一服)组成:两端-推流端、拉流端,一服-流媒体服务。

直播流程:主播通过推流端(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();
      }
    },
}
  • 无用方案
  1. 设置autoplay属性,由于移动端浏览器默认不润许媒体文件自动播放,为了避免浪费用户的流量。个别情况加入muted(静音)属性可自动播放,但效果并不理想,鸡肋。
  2. 直接调用play() 方法
  3. 通过js主动触发click事件
  4. 监听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);
          }
      })
    },
  }    
}

遇到问题继续更新,有更好的方案或问题请指教,谢谢!