<!--
@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>
