vue 项目进行直播视频 vue-video-player

vue 项目进行直播视频

最近电商直播非常火,于是接到需求搞搞!
看了很多相关的文章,没看出有啥不同,最后直接采用 vue-video-player 来开发。直播流返回的是m3u8格式的,flv格式的播放不了,可能是我配置问题。然后关于这个插件可以用 flash 。我也没去深究,毕竟谷歌都快放弃flash了。

安装插件

npm install vue-video-player videojs-contrib-hls --save

注意这里安装了 2 个插件 vue-video-playervideojs-contrib-hls(这个后面会介绍到)

vue-video-player 使用

github 文档也写的很清楚,这里也做个笔记把:

方式 1:全局引用

// main.js 文件

import Vue from 'vue'
import VueVideoPlayer from 'vue-video-player'

import 'video.js/dist/video-js.css'
// import 'vue-video-player/src/custom-theme.css'

Vue.use(
  VueVideoPlayer /* {
  options: global default options,
  events: global videojs events
} */
)

不太建议使用这种,毕竟不是每个页面都需要用到,没必要加重首页加载的负担

方式二:当作组件引入

import 'video.js/dist/video-js.css'
import { videoPlayer } from 'vue-video-player'
export default {
  components: {
    videoPlayer
  },
  data() {
    return {}
  }
}

引入了之后,就是 vue-video-player 的配置

vue-video-player 的配置

<template>
  <video-player class="video-player-box" ref="videoPlayer" :options="playerOptions" :playsinline="true">
  </video-player>

  <!-- 这里有对应的操作事件,这里就不一一写了 -->
  <!--      
    customEventName="customstatechangedeventname"
    @play="onPlayerPlay($event)"
    @pause="onPlayerPause($event)"
    @ended="onPlayerEnded($event)"
    @waiting="onPlayerWaiting($event)"
    @playing="onPlayerPlaying($event)"
    @loadeddata="onPlayerLoadeddata($event)"
    @timeupdate="onPlayerTimeupdate($event)"
    @canplay="onPlayerCanplay($event)"
    @canplaythrough="onPlayerCanplaythrough($event)"
    @statechanged="playerStateChanged($event)"
    @ready="playerReadied" 
    -->
</template>

<script>
  import 'video.js/dist/video-js.css'
  import { videoPlayer } from 'vue-video-player'
  export default {
    data() {
      return {
        // 很多参数其实没必要的,也还有很多参数没列出来,只是把我看到的所有文章做一个统计
        playerOptions: {
          autoplay: false, //如果true,浏览器准备好时开始回放。(好像微信浏览器不太行)
          techOrder: ['html5'], // 需要加载的插件,如果是要兼容flash的话,必须先加载flash。顺序不能错:['flash','html5']
          flash: {
            hls: { withCredentials: false }
          },
          html5: { hls: { withCredentials: false } },
          muted: true, // 默认情况下将会消除任何音频。
          loop: false, // 导致视频一结束就重新开始。
          language: 'en', // 提示的语言 中文的话是 zh-CN
          fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
          preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
          aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
          playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度 0.7倍...
          sources: [
            // 播放的资源列表,虽然不知为何是个数组,可能是,轮流播放?
            {
              type: 'video/mp4', // 类型。
              src: 'https://cdn.theguardian.tv/webM/2015/07/20/150716YesMen_synd_768k_vp8.webm' // 视频流路径
            },
            {
              withCredentials: false, // 直播是否有播放令牌,反正我是没有
              type: 'application/x-mpegURL', // m3u8/Hls 的视频流类型
              src: 'https://us-2.wl-cdn.com/hls/20200308/a9e9c7b577d4bb05d2a66508e63f5a17/index.m3u8' // 对应播放的m3u8 路径
            }
          ],
          poster: '/static/images/author.jpg', //你的封面地址
          notSupportedMessage: '此视频暂无法播放,请稍后再试', //允许覆盖Video.js无法播放媒体源时显示的默认信息。
          controls: true, // 是否显示操作条
          controlBar: {
            // 播放的操作
            timeDivider: true, // 时间分割线
            durationDisplay: true, // 总时间
            remainingTimeDisplay: false,
            fullscreenToggle: true //全屏按钮
          }
        }
      }
    },
    mounted() {
      console.log('this is current player instance object', this.player)
    },
    computed: {
      player() {
        return this.$refs.videoPlayer.player
      }
    },
    methods: {
      // listen event
      onPlayerPlay(player) {
        // console.log('player play!', player)
      },
      onPlayerPause(player) {
        // console.log('player pause!', player)
      },
      // ...player event

      // or listen state event
      playerStateChanged(playerCurrentState) {
        // console.log('player current update state', playerCurrentState)
      },

      // player is ready
      playerReadied(player) {
        console.log('the player is readied', player)
        // you can use it to do something...
        // player.[methods]
      }
    }
  }
</script>

第一个坑 No compatible source was found for this media.

进过上面的一大段配置,还是不能播放的!

video.cjs.js?3d33:440 VIDEOJS: ERROR: (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) No compatible source was found for this media.

在这里插入图片描述

要解决这个很简单,就是之前提到的 videojs-contrib-hls
如果采用的是方式 1,那就在 main.js 在全局引入这个文件
如果是方式 2,那么就在对应的组件页面引入就可以了

// 如果用的是比较早的版本 比如 5.14.1 版本,则用这句引入
import 'videojs-contrib-hls/dist/videojs-contrib-hls'
// 最新的版本
import 'videojs-contrib-hls'

坑 2:EventTarget’ of undefined

引入了 videojs-contrib-hls 。可是报错 'EventTarget' of undefined

上面有说到,这个关于 videojs-contrib-hls 版本的问题。不同版本引入的方法也不一样。只需要改一下引入的方式就可以了。详情可以看下这条 issuss:
https://github.com/surmon-china/vue-video-player/issues/127

在 vue 中使用 m3u8 的视频流播放到这里就算是可以了。我的项目是可以正常播放了

坑 2:为啥还是跑不了(这个坑我只看到文章提及,没有遇到)

说 HLS 兼容性较好,主要是指可以通过 JS 让用户免配置(不必安装 flash),可以在 caniuse 看下 HLS 的支持程度:http://caniuse.com/#search=HLS

只有 Edge 和 Safari 提供原生支持,其他浏览器都需要 JS 插件支持。那是不是只要引了 videojs-contrib-hls 就 ok 了呢?❌,这里面还有个坑。这个坑在该插件的官方文档有说明:

Unlike a native HLS implementation, the HLS tech has to comply with the browser’s security policies. That means that all the files that make up the stream must be served from the same domain as the page hosting the video player or from a server that has appropriate CORS headers configured. Easy instructions are available for popular webservers and most CDNs should have no trouble turning CORS on for your account.

简单的意思就是:除了原生支持 HLS 的浏览器,其他浏览器要想播 HLS,需要直播流服务端开启 CORS。

一个最简陋可是可以跑的 demo

贴一份最简单的 demo 把。只要把对应组件都引入了这段 demo 是可以跑起来的.很多变量都没来得及调整,随意看看把~

<template>
  <div class="liveView">
    <video-player
      class="vjs-custom-skin"
      ref="videoPlayer"
      :options="playerOptions"
      @ready="onPlayerReadied"
      @timeupdate="onTimeupdate"
    >
    </video-player>

    <div class="inputWrapper">
      <div class="form-group row">
        <label for="" class="col-sm-4 col-form-label">HLS: </label>
        <div class="col-sm-8">
          <input class="form-control" type="text" placeholder="HLS url here" v-model="streams.hls" />
        </div>
      </div>
    </div>
    <div class="buttonWrapper">
      <button class="btn btn-primary" type="button" @click="enterStream">Apply</button>
    </div>
  </div>
</template>

<script>
  import { videoPlayer } from 'vue-video-player'
  import 'video.js/dist/video-js.css'
  import 'vue-video-player/src/custom-theme.css'
  // import 'videojs-contrib-hls/dist/videojs-contrib-hls'
  import 'videojs-contrib-hls'

  export default {
    name: 'live',
    components: {
      videoPlayer
    },
    data() {
      return {
        initialized: false,
        currentTech: '',
        streams: {
          rtmp: '',
          hls: ''
        },
        playerOptions: {
          overNative: true,
          autoplay: false,
          controls: true,
          techOrder: ['html5'],
          sourceOrder: true,
          flash: {
            hls: { withCredentials: false }
          },
          html5: { hls: { withCredentials: false } },
          sources: [
            {
              withCredentials: false,
              type: 'application/x-mpegURL',
              src: 'https://us-2.wl-cdn.com/hls/20200308/a9e9c7b577d4bb05d2a66508e63f5a17/index.m3u8'
            }
          ]
          // controlBar: {
          //   timeDivider: false, // 时间分割线
          //   durationDisplay: false, // 总时间
          //   progressControl: true, // 进度条
          //   customControlSpacer: true, // 未知
          //   fullscreenToggle: true // 全屏
          // },
        }
      }
    },
    computed: {
      player() {
        return this.$refs.videoPlayer.player
      },
      currentStream() {
        return this.currentTech === 'Flash' ? 'RTMP' : 'HLS'
      }
    },
    methods: {
      onPlayerReadied() {
        if (!this.initialized) {
          this.initialized = true
          this.currentTech = this.player.techName_
        }
      },
      // record current time
      onTimeupdate(e) {
        console.log('currentTime', e.cache_.currentTime)
      },
      enterStream() {
        this.playerOptions.sources[0].src = this.streams.hls
        this.playerOptions.autoplay = true
      },
      changeTech() {
        if (this.currentTech === 'Html5') {
          this.playerOptions.techOrder = ['html5']
        } else if (this.currentTech === 'Flash') {
          this.playerOptions.techOrder = ['flash']
        }
        this.playerOptions.autoplay = true
      }
    }
  }
</script>

<style scoped>
  .liveView {
    position: relative;
  }

  .selectWrapper {
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 20px;
    line-height: 30px;
    margin: 20px;
    vertical-align: baseline;
  }

  .inputWrapper {
    width: 500px;
    margin: 0 auto;
  }

  .buttonWrapper {
    text-align: center;
  }
</style>

关于 flash 的组件使用

  • 需要安装 vue-video-player 还有 videojs-flash
  • 如果 flash 和 hls 要一起使用,在配置中的 techOrder 必须配置为 :
{
  "techOrder": ["flash", "html5"] //而且必须flash在前面
}

其他的吭就没去多踩了。下次踩到了在记录把!

一路走来坑不是很多,毕竟前端直播也是老生常谈的问题了。很多坑都有解决的方法,耐心配置,总会播放起来的!

发布了71 篇原创文章 · 获赞 58 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/Jioho_chen/article/details/104806803