Sfoglia il codice sorgente

贵州大学演示用1080p 监控相关修改

dedsudiyu 7 ore fa
parent
commit
ede3971ecb

+ 2 - 2
.env.development

@@ -2,10 +2,10 @@
 NODE_ENV=development
 
 # 项目名称
-VUE_APP_TITLE=中国安全生产科学研究院实验室安全智慧化管控中心
+VUE_APP_TITLE=贵州大学实验室安全智慧化管控中心
 
 # 接口基础地址
-VUE_APP_BASE_API=http://192.168.1.8/api
+VUE_APP_BASE_API=http://192.168.1.88/labSystem
 
 # 接口超时时间(毫秒)
 VUE_APP_TIMEOUT=20000

+ 1 - 1
.env.production

@@ -5,7 +5,7 @@ NODE_ENV=production
 VUE_APP_TITLE=中国安全生产科学研究院实验室安全智慧化管控中心
 
 # 接口基础地址
-VUE_APP_BASE_API=https://192.168.166.11/api
+VUE_APP_BASE_API=http://192.168.1.88/labSystem
 
 # 接口超时时间(毫秒)
 VUE_APP_TIMEOUT=20000

File diff suppressed because it is too large
+ 2380 - 5175
package-lock.json


+ 1 - 0
package.json

@@ -13,6 +13,7 @@
     "echarts": "^5.4.3",
     "element-ui": "^2.15.14",
     "js-md5": "^0.8.3",
+    "mpegts.js": "^1.8.0",
     "mqtt": "^4.3.7",
     "vue": "^2.7.14",
     "vue-router": "^3.6.5",

+ 46 - 7
src/components/LabStats/videoStats.vue

@@ -4,9 +4,10 @@
     <div class="corner-deco bl"></div><div class="corner-deco br"></div>
     <div class="panel-title">实验室视频监控</div>
     <div class="video-content">
-      <webRTC v-if="webRtcType"></webRTC>
-      <videoForMod v-for="(item,index) in modList" :key="index"
-                   :deviceNo="item.deviceNo"></videoForMod>
+      <!--<webRTC v-if="webRtcType"></webRTC>-->
+      <!--<videoForMod v-for="(item,index) in modList" :key="index"-->
+                   <!--:deviceNo="item.deviceNo"></videoForMod>-->
+      <mpegts-video style="display: inline-block" :videoProps="item" v-for="(item,index) in demoList" :key="index"></mpegts-video>
     </div>
   </div>
 </template>
@@ -14,9 +15,14 @@
   import { getVideoList,laboratoryLabScreenScreenConfigGet,iotDeviceList } from '@/api/index'
   import videoForMod from '@/components/videoForMod/videoForMod.vue'
   import webRTC from './webRTC.vue'
+  import mpegtsVideo from '@/components/mpegtsVideo/mpegtsVideo.vue'
   export default {
     name: 'videoStats',
-    components: { videoForMod,webRTC },
+    components: {
+      videoForMod,
+      webRTC,
+      mpegtsVideo,
+    },
     data () {
       return {
         width:470,
@@ -25,15 +31,48 @@
         pollTimer:null,
         page:1,
         webRtcType:false,
+        demoList:[
+          {
+            id:1,        //(ID:非必传-默认随机生成)
+            width:470,    //(宽度:非必传-默认600)
+            height:280,   //(高度:非必传-默认338)
+            type:'flv',   //(视频类型:非必传-默认'flv')
+            isLive:true,  //(是否直播流:非必传-默认true)
+            url:"http://192.168.1.88:8230/rtp/440102004920000000010064_34020000001320000064.flv"        //(视频地址:必传)
+          },
+          {
+            id:2,        //(ID:非必传-默认随机生成)
+            width:470,    //(宽度:非必传-默认600)
+            height:280,   //(高度:非必传-默认338)
+            type:'flv',   //(视频类型:非必传-默认'flv')
+            isLive:true,  //(是否直播流:非必传-默认true)
+            url:"http://192.168.1.88:8230/rtp/440102004920000000010064_34020000001320000064.flv"        //(视频地址:必传)
+          },
+          {
+            id:3,        //(ID:非必传-默认随机生成)
+            width:470,    //(宽度:非必传-默认600)
+            height:280,   //(高度:非必传-默认338)
+            type:'flv',   //(视频类型:非必传-默认'flv')
+            isLive:true,  //(是否直播流:非必传-默认true)
+            url:"http://192.168.1.88:8230/rtp/440102004920000000010064_34020000001320000064.flv"        //(视频地址:必传)
+          },
+          {
+            id:4,        //(ID:非必传-默认随机生成)
+            width:470,    //(宽度:非必传-默认600)
+            height:280,   //(高度:非必传-默认338)
+            type:'flv',   //(视频类型:非必传-默认'flv')
+            isLive:true,  //(是否直播流:非必传-默认true)
+            url:"http://192.168.1.88:8230/rtp/440102004920000000010064_34020000001320000064.flv"        //(视频地址:必传)
+          },
+        ],
       }
     },
     created(){
 
     },
     mounted(){
-      this.laboratoryLabScreenScreenConfigGet();
-      this.pollTimer = setInterval(this.laboratoryLabScreenScreenConfigGet, 5 * 60 * 1000)
-      // this.getVideoData();
+      // this.laboratoryLabScreenScreenConfigGet();
+      // this.pollTimer = setInterval(this.laboratoryLabScreenScreenConfigGet, 5 * 60 * 1000)
     },
     methods:{
       //指定视频

+ 265 - 0
src/components/mpegtsVideo/mpegtsVideo.vue

@@ -0,0 +1,265 @@
+<!--
+@name: mpegtsVideo
+@description: 通用视频组件
+@author: zc
+@time: 2023/11/30
+@引入:
+
+  <mpegts-video style="display: inline-block" :videoProps="item" v-for="(item,index) in videoList" :key="index"></mpegts-video>
+
+    或
+
+  <mpegts-video style="display: inline-block" :videoProps="videoProps"></mpegts-video>
+
+  import mpegtsVideo from '@/components/mpegtsVideo/mpegtsVideo.vue'
+
+  components: {
+    mpegtsVideo,
+  },
+
+  videoProps:{
+    id:50,        //(ID:非必传-默认随机生成)
+    width:600,    //(宽度:非必传-默认600)
+    height:338,   //(高度:非必传-默认338)
+    type:'flv',   //(视频类型:非必传-默认'flv')
+    isLive:true,  //(是否直播流:非必传-默认true)
+    url:""        //(视频地址:必传)
+  }
+
+-->
+
+<template>
+  <div class="mpegtsVideo">
+    <p class="reconnectText"
+       :style="'height:'+videoData.height+'px;width:'+videoData.width+'px;line-height:'+videoData.height+'px;'"
+       v-if="reconnectType">连接已断开,请联系管理员或等待重连</p>
+    <video
+      :id="videoData.id" :ref="videoData.id"
+      :width="videoData.width" :height="videoData.height"
+      autoplay controls  muted >
+    </video>
+    <!--<img :src="videoImg" style="width:600px;height:300px;">-->
+    <p class="el-icon-full-screen full-screen-button" @click="fullScreen"></p>
+  </div>
+</template>
+<script>
+  import mpegts from 'mpegts.js'
+  export default {
+    name: 'mpegtsVideo',
+    props: {
+      videoProps:{},
+    },
+    data () {
+      return {
+        videoData:{},
+        flvPlayer:null,//连接数据
+        decodedFrames:null,//断流帧
+        decodedFramesNum:null,//断流计数器
+        reconnectType:false,//重连状态
+        videoImg:null,
+        errorNum:0//异常次数
+      }
+    },
+    created(){
+      this.$set(this,'videoData',{
+        id:this.videoProps.id?this.videoProps.id:this.generateRandomString(),
+        width:this.videoProps.width?this.videoProps.width:600,
+        height:this.videoProps.height?this.videoProps.height:338,
+        type:this.videoProps.type?this.videoProps.type:'flv',
+        isLive:this.videoProps.isLive?this.videoProps.isLive:true,
+        url:this.videoProps.url,
+      });
+    },
+    mounted(){
+      this.initMpegts();
+    },
+    methods:{
+      //窗口全屏
+      fullScreen(){
+        this.$refs[this.videoData.id].webkitRequestFullScreen();
+      },
+      //截取封面
+      videoCover(){
+        let video = document.getElementById(this.videoData.id);
+        let canvas = document.createElement("canvas");
+        let width = video.width; //canvas的尺寸和图片一样
+        let height = video.height;
+        canvas.width = width;
+        canvas.height = height;
+        canvas.getContext("2d").drawImage(video, 0, 0, width, height); //绘制canvas
+        let videoImg = canvas.toDataURL('image/jpeg'); //转换为base64
+      },
+      //连接视频
+      initMpegts() {
+        //连接
+        if (mpegts.getFeatureList().mseLivePlayback) {
+          //视频DOM
+          let videoElement = document.getElementById(this.videoData.id);
+          //设置
+          let config = {
+            liveBufferLatencyChasing: true,//自动追针
+            autoCleanupMaxBackwardDuration:3*60,//清除缓存  默认保留3*60
+          };
+          this.flvPlayer = mpegts.createPlayer({
+            type: this.videoData.type,
+            isLive: this.videoData.isLive,
+            url: this.videoData.url,
+          },config);
+          this.flvPlayer.attachMediaElement(videoElement);
+          this.flvPlayer.load();
+          this.flvPlayer.play();
+          let playPromise = this.flvPlayer.play();
+          if (playPromise !== undefined) {
+            playPromise.then((_) => {
+              this.$set(this,'reconnectType',false);
+              //播放
+            }).
+            catch ((error) => {
+              //暂停
+              this.$set(this,'reconnectType',true);
+              this.reconnectVideo();
+            });
+          }
+          //断流检测
+          this.flvPlayer.on(mpegts.Events.STATISTICS_INFO, (e) => {
+            // 已经解码的帧数
+            if(this.decodedFrames !== e.decodedFrames){
+              // 连接正常
+              this.$set(this,'decodedFrames',e.decodedFrames);
+              this.$set(this,'decodedFramesNum',0);
+            }else{
+              //连接异常
+              this.decodedFramesNum++
+              if(this.decodedFramesNum>30){
+                this.$set(this,'reconnectType',true);
+                this.reconnectVideo();
+              }
+            }
+          });
+          this.flvPlayer.on(mpegts.Events.ERROR, e=> {
+            // 发生异常
+            if(this.errorNum > 5){
+              this.videoOff();
+            }else{
+              this.errorNum++
+              this.$set(this,'reconnectType',true);
+              this.reconnectVideo();
+            }
+          });
+          this.flvPlayer.on(mpegts.Events.LOADING_COMPLETE, (e) => {
+            // 视频流已结束
+            this.$set(this,'reconnectType',true);
+            this.reconnectVideo();
+          });
+        }
+      },
+      //重新连接
+      reconnectVideo(){
+        let self = this;
+        this.flvPlayer.pause();
+        this.flvPlayer.unload();
+        this.flvPlayer.detachMediaElement();
+        this.flvPlayer.destroy();
+        this.flvPlayer = null;
+        setTimeout(function(){
+          self.initMpegts();
+        },2000);
+      },
+      //断开视频流
+      videoOff(){
+        // 断开连接
+        this.flvPlayer.pause();
+        this.flvPlayer.unload();
+        this.flvPlayer.detachMediaElement();
+        this.flvPlayer.destroy();
+        this.flvPlayer = null;
+      },
+      //生成随机ID
+      generateRandomString() {
+        let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+        let randomString = "";
+        for (let i = 0; i < 8; i++) {
+          let randomIndex = Math.floor(Math.random() * chars.length);
+          randomString += chars.charAt(randomIndex);
+        }
+        return randomString;
+      }
+    },
+    beforeDestroy() {
+      let self = this;
+      self.videoOff();
+    },
+  }
+</script>
+<style scoped lang="scss">
+  .mpegtsVideo{
+    *{
+      margin:0;
+      padding:0;
+    }
+    position: relative;
+    .reconnectText{
+      position: absolute;
+      color:#fff;
+      z-index:2;
+      text-align: center;
+      top:0;
+      left:0;
+    }
+    .full-screen-button{
+      color:#fff;
+      position:absolute;
+      font-size:20px;
+      height:30px;
+      width:30px;
+      line-height:30px;
+      text-align: center;
+      top:0;
+      right:0;
+      z-index: 1;
+      cursor: pointer;
+    }
+    .full-screen-button:hover{
+      color:#00b7ee;
+    }
+    video::-webkit-media-controls-enclosure {
+      display: none;
+    }
+    // 音频开关
+    video::-webkit-media-controls-mute-button {
+      display: none;
+    }
+    // 音频大小
+    video::-webkit-media-controls-volume-slider {
+      display: none;
+    }
+    //全屏按钮
+    video::-webkit-media-controls-fullscreen-button {
+      display: none;
+    }
+    //开始暂停按钮
+    video::-webkit-media-controls-play-button {
+      display: none;
+    }
+    // 时间显示
+    video::-webkit-media-controls-current-time-display {
+      display: none;
+    }
+    // 未知时间
+    video::-webkit-media-controls-toggle-closed-captions-button {
+      display: none;
+    }
+    //进度条
+    video::-webkit-media-controls-timeline {
+      display: none;
+    }
+    //未知进度条
+    video::-webkit-media-controls-time-remaining-display {
+      display: none;
+    }
+    video {
+      object-fit: fill; //视频全铺
+      pointer-events: none; //点击禁用
+    }
+  }
+</style>