index.vue 6.88 KB
<template>
  <div ref="container" :class="containerClassName" ></div>
</template>

<script>
// checkSupportMSEHevc checkSupportSIMD, checkSupportWCSHevc
import { getWatermarkCanvasImg } from './utils';

export default {
  name: 'VionPlayer',
  props: {
    playUrl: {
      type: String,
      default: '', // 若配置,则播放器加载后,自动播放
    },
    watermarkText: {
      type: String,
      default: '',
    },
    hideControls: {
      type: Boolean,
      default: false,
    },
    showPtz: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      // eslint-disable-next-line
      _jessibuca: null,
      playOriginUrl: '',

      player: {
        height: 0,
        width: 0,
      },
    }
  },
  computed: {
    containerClassName() {
      return this.hideControls ? ['vion-player', 'hide-controls'] : 'vion-player';
    },
  },
  mounted() {
    this.init(this.playUrl);
    // console.log('mounted', window.JessibucaPro.EVENTS);
  },
  beforeDestroy() {
    this.destroy();
  },
  methods:{
    init(url, params = {}) {
      const options = Object.assign({
        container: this.$refs.container,
        decoder: 'jessibuca-pro/decoder-pro.js',
        text: '', // TODO: 功能暂不清楚
        keepScreenOn: true, // 屏幕常亮
        isResize: false,
        isNotMute: false,
        debug: false, // 是否开启控制台调试打印

        // 播放相关
        videoBuffer: 0.1, // 缓存时长
        videoBufferDelay: 0.2, // 缓存延迟(延迟超过会触发丢帧)
        // TODO: 是否通过浏览器API判断是否支持后,再赋值true或false
        // useMSE: false,
        // useWCS: checkSupportWCSHevc(),
        // useWCS: false,
        // useSIMD: checkSupportSIMD(),
        // wcsUseVideoRender: checkSupportWCSHevc(),
        // useWebFullScreen: true, // ios可能不支持系统级别全屏,可能要使用此配置
        timeout: 10, // 在连接成功之前(loading)和播放中途(heart),如果超过设定时长无数据返回,则回调timeout事件

        // 按钮和界面
        loadingText: '加载中...',
        controlAutoHide: true,
        supportDblclickFullscreen: false,
        showBandwidth: true, // 显示网速
        fullscreenWatermarkConfig: {
          text: this.watermarkText || '',
        },
        operateBtns: {
          fullscreen: true,
          screenshot: false,
          play: true,
          audio: true,
          ptz: this.showPtz, // 云台
          zoom: true,
          performance: true,
          record: true, // 录制
          scale: true, // 显示模式:拉伸、缩放、正常
          quality: false, // 视频清晰度
        },
        extendOperateBtns: [],
        showPerformance: false, // 显示性能
        qualityConfig: ['标清', '高清'],


        // 云台控制
        ptzClickType: 'click', // click mouseDownAndUp
        ptzZoomShow: true,
        ptzMoreArrowShow: true,
        // ptzApertureShow: true, // 光圈
        ptzFocusShow: true,
      });

      console.log('init-options', options);
      this._jessibuca = new window.JessibucaPro(options);

      this.registerEvent(this._jessibuca);

      if (url) {
        // 示例上有延迟写法
        this.delayPlay(url);
      }
    },
    registerEvent(playerIns) {
      playerIns.on(JessibucaPro.EVENTS.videoInfo, (data) => {
        console.log('width:', data.width, 'height:', data.height);
        this.player.width = data.width;
        this.player.height = data.height;
      });

      /* playerIns.on('play', (flag) => {
        console.log('on-play', flag);
        this.playing = true;
      });
      playerIns.on('pause', (flag) => {
        console.log('on-pause', flag);
        this.playing = false;
      }); */

      // 断线重连
      playerIns.on(JessibucaPro.EVENTS.playFailedAndPaused, (e) => {
        console.log('playFailedAndPaused', e);
        this.replay();
      });

      playerIns.on(JessibucaPro.EVENTS.ptz, (arrow) => {
        // console.log('ptz', arrow);
        this.$emit('ptz-control', arrow);
      });
    },
    getWatermarkBase64() {
      const data = getWatermarkCanvasImg(150, 48, '文安智能');
      console.log('getWatermarkBase64', data);
    },
    delayPlay(url) {
      setTimeout(() => {
        this._jessibuca.play(url);
        this.playOriginUrl = url;
      }, 150);
    },

    // 暴露方法
    play(url) {
      if (url) {
        // 播放地址不同,则先停止再播放。地址相同,相当于暂停后,继续播放
        if (this.playOriginUrl && this.playOriginUrl !== url) {
          // 切换视频流地址,先销毁当前实例,再创建新实例,避免内存溢出
          this.replay(url);
        } else {
          this.delayPlay(url);
        }
      } else {
        console.error('The url is not valid');
      }
    },
    replay(url) {
      this.destroy().then(() => {
        this.init(url);
      });
    },
    pause() {
      this._jessibuca.pause();
    },
    stop() {
      this._jessibuca.close();
    },
    destroy() {
      if (this._jessibuca) {
        return this._jessibuca.destroy().then(() => {
          // this._jessibuca = null;
        }).catch(() => {
          return Promise.reject(new Error('destruction failed'));
        });
      } else {
        return Promise.resolve(true);
      }
    },
    screenshot(filename = '', format = 'png', quality = 0.92, type = 'base64') {
      return new Promise((resolve, reject) => {
        // 如果是播放状态
        const isPlaying = this._jessibuca.isPlaying();
        console.log('screenshot', isPlaying);
        if (!this.player.height || !this.player.width || !isPlaying) {
          reject(new Error('invaild data'));
        }

        // 创建一个新的图片对象
        const image = new Image();

        // 当图像加载完成后执行
        image.onload = () => {
          // 创建一个 Canvas 元素
          const canvas = getWatermarkCanvasImg(this.player.width, this.player.height, this.watermarkText, image);;

          // 将带有水印的 Canvas 转换回 base64
          const watermarkedBase64 = canvas.toDataURL('image/png');

          // 现在,watermarkedBase64 包含了带有水印的 base64 图像数据
          // console.log(watermarkedBase64);
          resolve(watermarkedBase64);
        };
        image.error = function() {
          reject(new Error('image loade fail'));
        }

        // 设置图像的 src 属性,加载图像
        image.src = this._jessibuca.screenshot(filename, format, quality, type);
      });
    },
    screenshotOrigin(filename = '', format = 'png', quality = 0.92, type = 'base64') {
      return this._jessibuca.screenshot(filename, format, quality, type);
    }
  },
}
</script>

<style lang="scss" scoped>
.vion-player {
  height: 100%;
  widows: 100%;
  background-color: rgba(13, 14, 27, 0.7);
}
.hide-controls {
  ::v-deep(.jessibuca-controls) {
    display: none !important;
  }
}
</style>