一、【rtmp视频流】

要点:主要是使用vue-video-player进行播放。要注意,这种播放方式需要flash播放器,遗憾的是很多浏览器已经不再支持flash播放器,如果是这样建议直接看下边第二种【flv视频流】。

1、安装vue-video-player

npm i -S vue-video-player

2、编写my-video.vue 组件

<template>
  <div class="video-js">
   
   <div 
   v-if="!videoSrc" 
   class="no-video">
    暂未播放视频
   </div>

   <video-player 
    v-else 
    class="video-player vjs-custom-skin"
    ref="videoPlayer"
    :playsinline="true"
    :options="playerOptions"
    >
   </video-player>
  </div>
</template>

script - 引入依赖文件

//  引入以下文件


import videojs from 'video.js'
import 'video.js/dist/video-js.css'
import 'vue-video-player/src/custom-theme.css'
import {videoPlayer} from 'vue-video-player'
import 'videojs-flash'
import SWF_URL from 'videojs-swf/dist/video-js.swf'
 
videojs.options.flash.swf = SWF_URL // 设置flash路径,Video.js会在不支持html5的浏览中使用flash播放视频文件

配置video相关属性

export default {
 name: 'videojs',
 components: {
  videoPlayer
 },
 data () {
  return {
   videoSrc: '',
   playerOptions: {
    live: true,
    autoplay: true, // 如果true,浏览器准备好时开始播放
    muted: false, // 默认情况下将会消除任何音频
    loop: false, // 是否视频一结束就重新开始
    preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
    aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
    fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
    controlBar: {
     timeDivider: false,
     durationDisplay: false,
     remainingTimeDisplay: false,
     currentTimeDisplay: false, // 当前时间
     volumeControl: false, // 声音控制键
     playToggle: false, // 暂停和播放键
     progressControl: false, // 进度条
     fullscreenToggle: true // 全屏按钮
    },
    techOrder: ['flash', 'html5'], // 兼容顺序
    flash: {
     hls: {
      withCredentials: false
     },
     swf: SWF_URL
    },
    sources: [{
     type: 'rtmp/flv',
     src: '' // 视频地址-改变它的值播放的视频会改变
    }],
    notSupportedMessage: '此视频暂无法播放,请稍后再试' // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
   }
  }
 }
}

注意样式:

<style scoped lang="scss">
 .video-js{
  width:100%;
  height:100%;
  .no-video{
   display:flex;
   height:100%;
   font-size:14px;
   text-align:center;
   justify-content: center;
   align-items:center;
  }
 }
</style>

3、封装 video.vue,引入上边封装好的my-video.vue

<template>
 <div class="about">
  <MyVideo 
  ref="playerObj">
  </MyVideo>
  <!-- <a @click="playVideo">播放视频</a> -->
 </div>
</template>
<script>
 import MyVideo from './my-video';
 import {
   getVideoStream,
   getCameraInfo,
   putCameraHeart
 } from '@/apis/equipmentApis'
 export default {
   name: 'about',
   props: {
     row: {
       type: Object,
       default () {
         return {

         }
       }
     }
   },
   components: {
     MyVideo
   },
   data() {
     return {}
 
   },
   methods: {
     // 播放视频
     playVideo (url) {
       // 可以测试一下 下边是湖南卫视直播视频流 看看能不能播放 
      //  this.$refs['playerObj'].videoSrc = 'rtmp://192.168.6.101:1935/live/7d7f8e6632dc0cb60292e5c519ef6981'
      //  this.$refs['playerObj'].playerOptions.sources[0].src = 'rtmp://192.168.6.101:1935/live/7d7f8e6632dc0cb60292e5c519ef6981'
      this.$refs['playerObj'].videoSrc = url;
       this.$refs['playerObj'].playerOptions.sources[0].src = url;
     },
     // 动态获取视频流
     async getVideoSrc (params) {
       try {
         let res = await getVideoStream(params);
         console.log('动态获取视频流 - res', res);
         if (res.data.code == 0 && res.data.data) {
           let {
             url,
             token
           } = res.data.data;
           window.sessionStorage.setItem('videoToken', String(token));
           url!= '' && (this.playVideo(url));
           token && (await putCameraHeart(token));
         }
       } catch (error) {
         console.log('动态获取视频流 - 失败', error);
       }
     },
     // 获取摄像头的信息 比如 ip password等等
     async getVideoInfo () {
       try {
         let res = await getCameraInfo(this.row.devId);
         console.log('相机的信息---', res);
         if (res.data.code == 0 && res.data.data) {
           let {
            ip,
            username,
            password,
           } = res.data.data;
          // 获取视频流的参数  
          let params = {
            channel: '1',
            factory: 'hikvision',
            ip,
            username,
            password,
            stream: 'main',
          };
          this.getVideoSrc(params);
         }
       } catch (error) {
         console.log('获取摄像头的信息 - 失败', error);
       }
     }
   },
   created () {
     this.getVideoInfo();
   },
   mounted () {
    //  setTimeout(() => {
    //    this.playVideo();
    //  }, 1500);
   }
 }
</script>
<style lang="scss">

.about {
  width: 500px;
  height: 300px;
}

</style>

4、在需要直播室视频的地方引入video.vue

......


<my-video :row="rowinfo">
          
</my-video>

......


<script>

export default {
    name: 'camera',
    
}



</script>

注意:

页面关闭之后,实际上引入的视频控件(创建的video的dom)并没有销毁。这就会导致一直报错,this.xxxx is not a function 这样的错误。所以要在你关闭这个有视频的页面或者是弹窗的时候,手动清除这个控件。

因为我的视频控件在一个对话框内,所有我在关闭对话框的时候,停止了这个视频流。

// dialog关闭弹窗的回调
    closeDialog () {
      this.stopVideoStream();
    },
    // 停止视频流
    async stopVideoStream () {
      try {
        let token = window.sessionStorage.getItem('videoToken');
        let res = await stopCameraHeart(token);
        console.log('停止视频流', res);
      } catch (error) {
        console.log('停止视频流', error);
      }
    },

也有人在beforeDestory中直接通过ref操作dom清除的。

 

二、【flv视频流】

要点:这种视频流只要是利用flv.js和html5的video进行播放,解决了很多浏览器不支持flash问题。

1、安装

npm i -S flv.js

2、直接在对应的vue组件中直接引入使用

<template>
  <div id="flv-app">
    <video 
    controls
    muted
    id="videoElement"></video>
  </div>
</template>

<script>


// 引入flvjs
import flvjs from 'flv.js'

export default {
    name: 'flv-app',
     data() {
        return {
          flvPlayer: null,
          urlHttpFlv: null
        }
     },
methods: {
    /**
     * @description 新建flv实例
     */
    createFlvPlayer(url) {
      if (flvjs.isSupported()) {
        const videoElement = document.getElementById('videoElement')
        this.flvPlayer = flvjs.createPlayer({
          type: 'flv',
          isLive: true,
          url
        })
        
        this.flvPlayer.attachMediaElement(videoElement)
        this.flvPlayer.load()
        this.flvPlayer.play()
      }
    },

    // 切换历史视频源头
    switchHistoryVideo (url) {
      this.pausemix();
      this.createFlvPlayer(url);
    },

    // 转换到实时视频
    switchLiveVideo () {
      this.pausemix();
      this.getVideoInfo();
    },

    /**
     * @description 停止混流播放并移除直播流抓取
     * (注:离开并重新进入当前路由,观察Network,可知该操作的必要性)
     */
    pausemix() {
      this.flvPlayer.pause()
      this.flvPlayer.unload()
      this.flvPlayer.detachMediaElement()
      this.flvPlayer.destroy()
      this.flvPlayer = null
    },

    // 动态获取视频流
     // 参数
    // {
    // "channel": "1",  暂时写死
    // "factory": "hikvision", 暂时写死
    // "ip": "192.168.10.59",
    // "password": "tsl123456",
    // "stream": "main", -> main/sub 用于切换全屏和小屏播放
    // "username": "admin"
    // }
     async getVideoSrc (params) {
       try {
         let res = await getVideoStream(params);
         console.log('动态获取视频流 - res', res);
         if (res.data.code == 0 && res.data.data) {
           let {
             urlHttpFlv,
             token
           } = res.data.data;
           window.sessionStorage.setItem('videoToken', String(token));
           urlHttpFlv!= '' && (this.createFlvPlayer(urlHttpFlv));
           token && (await putCameraHeart(token));
         }
       } catch (error) {
         console.log('动态获取视频流 - 失败', error);
       }
     },

     // 获取摄像头的信息 比如 ip password等等
     async getVideoInfo () {
       try {
         let res = await getCameraInfo(this.row.devId);
         console.log('相机的信息---', res);
         if (res.data.code == 0 && res.data.data) {
           let {
            ip,
            username,
            password,
            nvrId
           } = res.data.data;

           // 传递相机的基本信息
           this.$emit('getcamerainfo', res.data.data);

          let params = {
            channel: '1',
            factory: 'hikvision',
            ip,
            username,
            password,
            stream: 'main',
          };


          // let params = {
          //   "channel": "1",
          //   "factory": "hikvision",
          //   "ip": "192.168.10.44",
          //   "password": "tsl123456",
          //   "stream": "main",
          //   "username": "admin"
          // }

          this.getVideoSrc(params);
          this.getNvrVideoInfo(nvrId);
         }
       } catch (error) {
         console.log('获取摄像头的信息 - 失败', error);
       }
     },

     // 获取nvr相关信息 用于获取历史视频参数 getNvrCaremaInfo
    async getNvrVideoInfo (nvrId) {
      try {
        let res = await getNvrCaremaInfo(nvrId);
        console.log('获取nvr相关信息---', res);
        if (res.data.code == 0 && res.data.data) {
          // description: "超脑"
          // installLocationId: null
          // ip: "192.168.10.80"
          // mcn: null
          // name: "NVR-10.80"
          // nvrId: "1605578253-192.168.10.80"
          // password: "tsl123456"
          // productKey: "a4f3f1dc1744823b8369eba387ebf6a9"
          // projectId: 1605578224
          // status: "online"
          // statusInfo: "telnet ok"
          // statusTime: 1614068464
          // username: "admin"  
          this.$emit('getcamerainfonvrid', res.data.data)
        } else {
          this.$message({
            type: 'error',
            message: `${res.data.msg}`
          })
        }
      } catch (error) {
        console.log('获取nvr相关信息 - 失败', error);
      }
    },  
  },
  mounted() {
    this.getVideoInfo();
  },
  beforeDestroy() {
    this.pausemix()
  },
        
}


</script>

这种方案更加快捷。

Logo

前往低代码交流专区

更多推荐