视频总结(h5直播)

本文记录一下最近在直播组关于在移动端视频播放器的笔记。
分别使用了原生video标签,video.js,flv.js, TC player几个来实现在移动端各设备间和PC端 视频、直播播放的兼容适配。

原生video标签

原生的video标签中,事件等各个方面属性在不同设备、不同浏览器下会出现不兼容情况。

使用原生video标签,在安卓和I0S11以下机型中,autoplay不支持;解决办法:

  1. 使用静音【muted】播放
  2. 引导用户点击后播放<–>推荐

在微信内核和一些移动端浏览器中,播放视频会默认全屏;需添加以下属性阻止全屏:

x5-video-orientation="portraint"
webkit-playsinline='true'
playsinline='true'
x-webkit-airplay='true'
x5-video-player-type='h5'
x5-video-player-fullscreen='true'
x5-video-ignore-metadata='true'

以上属性,经测试后在微信内是如期的;但在小米浏览器上视频还是全屏播放。

关于更多各个设备下video标签属性的差异,非常推荐这位前辈的文章: 移动端HTML video视频播放优化实践

以下为原生video标签示例,支持暂停播放,是否缓冲到可播放状态

step1: 在组件中声明video

<template>
    <div>
        <div class="video">
            <video :src="infoData.imagesUrls[0].url" :poster="infoData.imagesUrls[0].thumbUrl" ref="video"
             x5-video-orientation="portraint" @timeupdate="handleTimeupdate"
             webkit-playsinline='true' playsinline='true' x-webkit-airplay='true'
             x5-video-player-type='h5' x5-video-player-fullscreen='true' x5-video-ignore-metadata='true'
             id="video" loop preload="auto" :playOrPause="playOrPause">
        您的设备不支持!
              </video>
        </div>
        <div class="playOrPause">
          <img class="video_play" @click="pauseVideo()" v-show="!playOrPause" src="http://lztimg.oss-cn-qingdao.aliyuncs.com/images/20210203/share03.png"/>
        </div>
    </div>
</template>

step2:设置播放器和一些事件处理

<script>
mounted() {
  this.$video = this.$refs.video;
    /**
     * 定时获取当前视频长度,获取到后获取当前视频已经下载多少了
     * 当当前视频下载量大于等于当前视频长度时去除加载动画;待用户点击播放
     * 以下定时器中,在非IOS中使用
     * */
    this.$video.setAttribute('autoplay', true)
    let getVideoLengthTimer = setInterval(()=>{
      let duration = this.$video.duration;
      if(!isNaN(duration)){
        let end = this.getVideoEnd();
        if(end <= duration) {
          return
        }
        // 去除加载动画和遮罩
        clearInterval(getVideoLengthTimer)
      }else{
        // 去除加载动画和遮罩
        clearInterval(getVideoLengthTimer)
      }
    },1000)
  }
  methods: {
  // 暂停/开始视频
    pauseVideo(){
      try {
        let video = document.getElementById('video');
        if (this.playOrPause) {
          video.pause();
        } else {
          video.play();
          video.pause();
          setTimeout(() => {
            video.play();
          }, 100);
        }
        this.playOrPause = !this.playOrPause;
        // this.getVideoDuration();
      } catch (e) {
        alert(e);
      }
    },
    // 获取当前视频已经加载多少了
    getVideoEnd(){   // video:video标签对象
      let end = 0
      try {
        if(this.$video.buffered.length>0){
          end = this.$video.buffered.end(0) || 0
          end = parseInt(end * 1000 + 1) / 1000
        }
      } catch(e) {
        console.log(e)
      }
      return end
    },
    // IOS下会自动播放,在自动播放后清除遮罩
    handleTimeupdate(){
      if(!this.$video.paused){
        this.playOrPause = true
      }
      let mask = document.getElementById('mask');
      mask.style.opacity = 0;
      mask.style.zIndex = -99;
    },
  }
</script>

TCplayer Lite 在vue中使用笔记

腾讯出品:TCPlayerLite 文档

首先先说明 此播放器不支持在移动端播放.FLV格式视频。

listener可以监听到video各个时间段的事件;并针对特别事件做处理

step1:引入

// 在index.html头文件引入
<script src="https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js" charset="utf-8"></script>

step2: 在组件中创建容器

<template>
    <div class="video" >
        <div id="id_test_video" style="width:100%; height:100vh;"></div>
    </div>
</template>

step3: 设置播放器

<script>
    export default {
     mounted() {
        var self = this;
        var player = new TcPlayer('id_test_video', {
          "mp4": "//vjs.zencdn.net/v/oceans.mp4", //请替换成实际可用的播放地址
          "autoplay" : true,      //iOS 下 safari 浏览器,以及大部分移动端浏览器是不开放视频自动播放这个能力的
          "poster" : "http://www.test.com/myimage.jpg",
          "width" :  '100vw',//视频的显示宽度,请尽量使用视频分辨率宽度
          "height" : '100vh', //视频的显示高度,请尽量使用视频分辨率高度
          "live": false,    // 是否直播
          // "controls": "none"    // 是否显示控制条
          listener: (msg) => {    // 监听播放器事件
            console.log(msg.type)
            // progress timeupdate
            if(msg.type === 'progress'){
              self.loading = true
            }
            if(msg.type === 'timeupdate'){
              self.loading = false;
            }
          }
    });

    // 给video标签添加,在各个设备下不自动全屏显示
    let video = document.getElementsByTagName('video')[0];
    video.setAttribute("x5-video-orientation", "portraint")
    video.setAttribute("webkit-playsinline", "true")
    video.setAttribute("playsinline", "true")
    video.setAttribute("x-webkit-airplay", "true")
    video.setAttribute("x5-video-ignore-metadata", "true")
    video.setAttribute("x5-video-player-fullscreen", "true")
    video.setAttribute("x5-video-player-type", "h5")
  }
}
</script>

此时,播放器可以使用了

step4: 修改默认样式

// 视频播放区域
.vcp-player video{
  width: 100vw;
  height: auto;
  min-height: 100vh;
}

#id_test_video{
  display: flex;
  align-items: center;
}

// 视频封面
.vcp-poster img{
  width: 100%;
  //height: 100%;
}

.vcp-bigplay{
  height: 100%;
}

// 加载动画
.vcp-loading{
  border: none;
  background: url("https://lztimg.oss-cn-qingdao.aliyuncs.com/ips/images/20210201/loading.gif") center no-repeat;
  width: 1.6rem;
  height: 1rem;
  background-size: 60%;
  margin-left: -0.8rem;
}
.vcp-loading:before{
  content: "";
  display: inline;
}

// 全屏
.vcp-fullscreen-toggle{
  display: none;
}

// 播放/暂停 按钮
.vcp-playtoggle{
  position: absolute;
  top: -50vh;
  left: 50%;
  background: url("http://lztimg.oss-cn-qingdao.aliyuncs.com/images/20210203/share03.png") center no-repeat;
  width: 1.6rem;
  height: 1.6rem;
  margin-left: -0.8rem;
}

// 进度条
.vcp-slider{
  background-color: rgba(89,83,84,1);
}
.vcp-slider .vcp-slider-track{
  background-color: #fff;
}

// 控制条背景
.vcp-panel-bg{
  background: none;
}

// 时间显示
.vcp-timelabel{
  // display: none;
  text-align: center;
  width: 100%;
  font-size: 0.28rem;
  line-height: 1.8;
  padding: 0;
}

video.js + flv.js 播放.flv直播数据

因为IOS不支持MSE,所以,FLV视频不能在IOS下播放

参考:

如何在iOS WebView中播放FLV视频?

Can I use… Support tables for HTML5, CSS3, etc

给video绑定ended事件,当直播流结束时会触发(不要循环播放:loop:false);

step1:引入

// 在index.html头文件引入
    <link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
    <script src="https://unpkg.com/video.js/dist/video.min.js"></script>
    <script src="https://unpkg.com/flv.js/dist/flv.min.js"></script>
    <script src="https://unpkg.com/videojs-flvjs/dist/videojs-flvjs.min.js"></script>

step2: 在组件中创建容器

<template>
    <div class="video">
      <video id="videojs-flvjs-player" class="video-js liveVideo vjs-default-skin vjs-big-play-centered" width="100vw" height="100vh"
             x5-video-orientation="portraint" ref="videojs"
             webkit-playsinline='true' playsinline='true' x-webkit-airplay='true'
             x5-video-player-type='h5' x5-video-player-fullscreen='true' x5-video-ignore-metadata='true'>

      </video>
    </div>
</template>

step3: 设置播放器

<script>
  export default {
    mounted() {
    var flvUrl = this.infoData.room.mixedPlayURL;

    var player = videojs('videojs-flvjs-player', {
      techOrder: ['html5', 'flvjs'],
      flvjs: {
        mediaDataSource: {
          isLive: true,
          cors: true,
          withCredentials: false,
        },
      },
      sources: [{
        src: flvUrl,
        type: 'video/mp4'
      }],
      autoplay: true,
      loop: false,    // 需要捕获直播结束事件,一定要禁止循环播放
      controls: true,
      preload: "auto",
      poster: this.infoData.room.liveCover
    }, function onPlayerReady() {
      console.log('player ready')

      player.on('error', (err) => {
        console.log('first source load fail')

        player.src({
          src: flvUrl,
          type: 'video/x-flv'
        });

        player.ready(function () {
          console.log('player ready')
          player.load();
          player.play();
        });
      })

      // 绑定直播结束事件
      player.on('ended', () => {
        console.log("直播结束")
      })

      // 绑定加载到可以播放的事件
      player.on("canplaythrough", function () {
        console.log("视频源数据加载完成")
      })

    });
  },
  }
</script>

此时,播放器可以使用了

step4: 修改默认样式

<style>
/*播放按钮*/
.liveVideo .vjs-big-play-button {
  background: url("http://lztimg.oss-cn-qingdao.aliyuncs.com/images/20210203/share03.png") center no-repeat;
  height: 2.2em;
  border: none;
}

/*去掉自带的播放按钮样式*/
.liveVideo .vjs-big-play-button .vjs-icon-placeholder:before {
  content: "";
}

/*隐藏控制条*/
.liveVideo .vjs-control-bar {
  display: none !important;
}

/*更改加载动画*/
.liveVideo .vjs-loading-spinner {
  border: none;
  background: url("https://lztimg.oss-cn-qingdao.aliyuncs.com/ips/images/20210201/loading.gif") center no-repeat;
  width: 1.6rem;
  height: 1rem;
  background-size: 60%;
  margin-left: -0.8rem;
}

/*去除原生加载动画*/
.liveVideo .vjs-loading-spinner:before,
.liveVideo .vjs-loading-spinner:after {
  border: none;
  animation: none !important;
}
</style>

vue中使用flv.js播放直播数据(pc)

在移动端直播等视频播放需求完成后,产品又让在后台管理系统中播放当前所有的直播画面,故记录下:不涉及兼容性,只用flv.js来实现

  1. 下载依赖

    npm i flv.js S
    
  2. 引入依赖

    在需要的组件内引入即可,无需全局引入

    import flvjs from 'flv.js'
    
  3. 定义video标签位置

    <template>中定义video标签

    <video id="videoElement" ref="videoElement" width="100%" height="100%"></video>
    
  4. 创建加载播放直播

    在script事件中创建并播放直播

    let url="http://xxx.com/live/room_123.flv";
    if (flvjs.isSupported()) {
        let videoElement = document.getElementById("videoElement");
        this.flvPlayer = flvjs.createPlayer({
            type: "flv", isLive: true, hasAudio: true, url
        })
        this.flvPlayer.attachMediaElement(videoElement)
        this.flvPlayer.load()
    }
    
  5. 销毁直播组件

    关闭页面时,或切换画面的话建议先销毁播放组件

    if (this.flvPlayer) {
        this.flvPlayer.pause();
        this.flvPlayer.unload();
        this.flvPlayer.detachMediaElement();
        this.flvPlayer.destroy();
        this.flvPlayer = null;
    }
    

附:自定义弹窗

自定义弹窗组件代码:

<template>
  <div id='customDialog'>
    <div class="warrp"></div>
    <div class="main">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'customDialog',
  created() {
    let body = document.getElementsByTagName('body')[0]
    body.style.height = '100vh'
    body.style.overflow = 'hidden'
  },
  destroyed() {
    let body = document.getElementsByTagName('body')[0]
    body.style.height = 'auto'
    body.style.overflow = 'auto'
  }
}
</script>

<style scoped lang="scss">
#customDialog{
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100vw;
  height: 100vh;
  z-index: 3000;
  .warrp{
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100vw;
    height: 100vh;
    background-color: rgba(0,0,0,.6);
    z-index: 3001;
  }
  .main{
    z-index: 3002;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100vw;
    height: 100vh;
    transition: all 1s ease-out;
  }
}
</style>

使用:

<custonDialog v-if="showLive">
  <div class="view">
      <button @click="showLive = false" class="closeBtn">点我关闭弹窗</button>
  </div>
</custonDialog>

前端苦设备适配久矣!


参考文章:

video.js的一些监听事件汇总

video.js 结合 flv.js播放flv视频

移动端HTML5 video 视频播放优化实践

播放器 SDK TCPlayerLite 腾讯云

Video.js Documentation

在vue中使用flv.js播放flv直播


很多未尽之处,在日后想起便会更新~
撒花,散会~