JessVideoPlayer.vue 7.44 KB
<template>
  <div class="root">
    <div id="container" ref="container" class="player-container">
      <!-- 重试按钮 -->
      <div v-if="showRetryButton" class="retry-overlay" @click="handleRetry">
        <el-icon class="retry-icon"><refresh /></el-icon>
      </div>
    </div>
  </div>
</template>

<script>

import userService from '../service/UserService';

export default {
  name: "VideoPlayer",
  props: {
    initialBufferTime: {
      type: Number,
      default: 0.2
    },
    initialPlayUrl: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      jessibuca: null,
      version: '',
      wasm: false,
      vc: "ff",
      playing: false,
      quieting: true,
      loaded: false, // mute
      showOperateBtns: true,
      showBandwidth: true,
      err: "",
      speed: 0,
      performance: "未知",
      volume: 1,
      rotate: 0,
      useWCS: false,
      useMSE: true,
      useOffscreen: false,
      recording: false,
      recordType: 'mp4',
      scale: 0.2,
      bufferTime: this.initialBufferTime,
      playUrl: this.initialPlayUrl,
      showRetryButton: false, // 重试按钮
      timeoutTimer: null, // 重试定时器
      config: {
        userName: userService.getUser().username,
        nowTime: "2024-03-01 12:00:00"
      } // 水印
    };
  },
  watch: {
    /**
     * 监听initialPlayUrl变化
     * @param val 播放地址
     */
    initialPlayUrl(val) {
      this.destroy()
      console.log('initialPlayUrl changed:', val);
      this.playUrl = val;
      if (this.jessibuca && this.playUrl){
        this.play();
      }
    }
  },
  beforeDestroy() {
  }, //生命周期 - 销毁之前",
  destroyed() {
    this.destroy()
  }, //生命周期 - 销毁完成",
  // 在播放成功时清除定时器
  mounted() {
    this.create();
    this.$errorHandler = this.handleError;

    this.jessibuca.on('play', () => {
      clearTimeout(this.timeoutTimer);
    });

    if (this.playUrl) {
      this.play();
    }
  },
  unmounted() {
    if (this.jessibuca) {
      this.jessibuca.destroy();
    }
  },
  methods: {
    updatePlayerDomSize() {
      let dom = this.$refs.container;
      let width = dom.parentNode.clientWidth
      let height = (9 / 16) * width
      console.log(height)

      console.log(dom.clientHeight)
      if (height > dom.clientHeight) {
        height = dom.clientHeight
        width = (16 / 9) * height
      }
      if (width > 0 && height > 0) {
        dom.style.width = width + 'px';
        dom.style.height = height + "px";
        console.log(width)
        console.log(height)
      }
    },
    create(options) {
      // 初始化Jessibuca播放器
      options = options || {};
      this.jessibuca = new window.Jessibuca(
        Object.assign(
          {
            container: this.$refs.container,
            background: "#000", //背景图片
            controlAutoHide: true, //底部控制台自动隐藏
            videoBuffer: Number(this.bufferTime), // 缓存时长
            isResize: false,
            autoWasm: true,
            useWCS: this.useWCS,
            useMSE: this.useMSE,
            decoder: "static/js/jessibuca/decoder.js",
            text: "",
            loadingText: "疯狂加载中...",
            debug: false,
            supportDblclickFullscreen: true,
            showBandwidth: this.showBandwidth, // 显示网速
            operateBtns: {
              fullscreen: this.showOperateBtns,
              screenshot: this.showOperateBtns,
              audio: this.showOperateBtns,
              record: this.showOperateBtns,
              refresh: this.showOperateBtns,
            },
            vod: this.vod,
            forceNoOffscreen: !this.useOffscreen,
            isNotMute: true,
            timeout: 10
          },
          options
        )
      );
      // 处理播放器事件
      const handleEvent = (event, callback) => {
        this.jessibuca.on(event, (...args) => {
          console.log(`on ${event}`, ...args);
          callback && callback(...args);
        });
      };

      handleEvent("load", () => {
      });
      handleEvent("log", msg => {
        console.log(`on log`, msg)
      });
      handleEvent("record", msg => {
        console.log(`on record`, msg)
      });
      handleEvent("pause", () => this.playing = false);
      handleEvent("play", () => {
        this.playing = true;
        this.loaded = true;
        this.quieting = this.jessibuca.isMute();
      });
      handleEvent("fullscreen", msg => {
        console.log(`on fullscreen`, msg)
      });
      handleEvent("mute", msg => this.quieting = msg);
      handleEvent("audioInfo", msg => {
        console.log(`on audioInfo`, msg)
      });
      handleEvent("videoInfo", info => {
        console.log(`on videoInfo`, info)
      });
      handleEvent("error", error => this.handleError(error));
      handleEvent("timeout", () => {
      });
      handleEvent("start", () => {
      });
      handleEvent("performance", performance => {
        this.performance = ["卡顿", "流畅", "非常流畅"][performance] || "未知";
      });
      handleEvent("buffer", buffer => {
        console.log(`on buffer`, buffer)
      });
      handleEvent("stats", stats => {
        console.log(`on stats`, stats)
      });
      handleEvent("kBps", kBps => {
        console.log(`on kBps`, kBps)
      });
      handleEvent("recordingTimestamp", ts => {
        console.log(`on recordingTimestamp`, ts)
      });
    },
    handleError(msg) {
      // 处理错误信息
      this.err = msg;
      // 触发自定义事件,通知父组件播放失败
      this.$emit('play-error', this.playUrl);
    },
    play() {
      // 重置状态
      this.showRetryButton = false;
      clearTimeout(this.timeoutTimer);

      if (!this.playUrl) {
        console.log("playUrl 无效 ===>", this.playUrl);
        return;
      }
      // 设置超时检测
      this.timeoutTimer = setTimeout(() => {
        if (!this.playing) {
          this.showRetryButton = true;
        }
      }, 10000); // 10秒超时

      this.jessibuca.play(this.playUrl);
    },
    handleRetry() {
      this.showRetryButton = false;
      this.destroy();
      this.$nextTick(() => {
        this.create();
        this.play();
      });
    },
    pause() {
      // 暂停视频
      this.jessibuca.pause();
      this.playing = false;
      this.performance = "未知";
    },
    destroy() {
      // 销毁并重新创建播放器
      if (this.jessibuca) {
        this.jessibuca.destroy();
      }
      this.create();
      this.playing = false;
      this.loaded = false;
      this.performance = "未知";
    },
    startRecord() {
      // 开始录制视频
      const time = new Date().getTime();
      this.jessibuca.startRecord(time, this.recordType);
    },
    stopAndSaveRecord() {
      // 停止并保存录制的视频
      this.jessibuca.stopRecordAndSave();
    },
    changeBuffer() {
      // 改变缓冲时间
      this.jessibuca.setBufferTime(Number(this.bufferTime));
    },
  },
};
</script>

<style scoped>
.player-container {
  position: relative;
  width: 100%;
  height: 100%;
}

.retry-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  cursor: pointer;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 50%;
  padding: 20px;
  transition: all 0.3s;
}

.retry-overlay:hover {
  background: rgba(0, 0, 0, 0.7);
}

.retry-icon {
  font-size: 40px;
  color: rgba(255, 255, 255, 0.8);
  display: block;
}

.retry-icon:hover {
  color: rgba(255, 255, 255, 1);
}
</style>