index.vue 5.56 KB
<template>
  <div ref="jPlayer" class="j-player">
    <watermark-layer v-if="watermark.text"
      ref="watermarkLayer"
      :width="watermark.width"
      :height="watermark.height"
      :text="watermark.text"
    />
  </div>
</template>

<script>
import WatermarkLayer from './watermark.vue'

export default {
  name: 'JPlayer',
  components: {
    WatermarkLayer,
  },
  props: {
    type: {
      type: String,
      default: 'live', // live playback
    },
    // 渠道ID
    channelId: {
      type: String,
      required: true,
    },
    datetimeRange: {
      type: Array,
      default: null,
    },
    watermarkText: {
      type: String,
      default: '',
    },
    // url 前缀
    prefixUrl: {
      type: String,
      default: 'static',
    },
    // TODO: 改变属性名称和ip地址由上层传入。若替换组件,应通知应用层人员
    playerAddress: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      watermark: {
        width: 0,
        height: 0,
        text: '',
      },
      // eslint-disable-next-line
      _iframeEl: null,
    }
  },
  computed: {
    prefixSegment() {
      if (this.prefixUrl) {
        return `/${this.prefixUrl}`;
      } else {
        return '';
      }
    },
    playerUrl() {
      if (this.channelId) {
        if (this.type === 'live') {
          // 直播
          return `${this.prefixSegment}/jplayer/index.html?ip=${this.playerAddress}&id=${this.channelId}`;
        } else if (this.type === 'playback') {
          // 回放
          if (this.datetimeRange && this.datetimeRange.length > 0) {
            const startTs = this.formatDatetime(this.datetimeRange[0]);
            const endTs = this.formatDatetime(this.datetimeRange[1] || (new Date().getTime()));
            // TODO: 时间戳
            return `${this.prefixSegment}/jplayer/playback.html?ip=${this.playerAddress}&id=${this.channelId}-${startTs}-${endTs}-1-0`;
            // return `/jplayer/playback.html?ip=${this.playerAddress}&id=${this.channelId}-1693877405-1693923756-1-0`;
          }
        }
      }

      return '';
    },
  },
  watch: {
    playerUrl(val) {
      console.log('playerUrl', val);
      console.log('playerUrl-iframe', this._iframeEl);
      if (val && this._iframeEl) {
        this._iframeEl.src = val;
      }
    },
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      // 获取playerURL,若地址存在则动态创建iframe
      if (this.playerUrl) {
        this.createPlayer(this.playerUrl);
      }
    },
    createPlayer(url) {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('frameborder', 0);
      iframe.setAttribute('name', this.type);
      iframe.setAttribute('src', url);
      iframe.setAttribute('width', '100%');
      iframe.setAttribute('height', '100%');

      if (iframe.attachEvent) {
        iframe.attachEvent('onload', (event) => this.iframeReady(event));
      } else {
        iframe.onload = (event) => this.iframeReady(event);
      }

      // 插入iframe
      const commonIframeEl = this.$refs.jPlayer;
      if (commonIframeEl) {
        commonIframeEl.appendChild(iframe);
        this._iframeEl = iframe;
      }
    },
    iframeReady(event) {
      console.log('iframeReady', event.target);
      if (this.watermarkText && event.target) {
        const width = event.target.offsetWidth;
        const height = event.target.offsetHeight;
        this.createWatermark(width, height);
      }
    },
    createWatermark(width, height) {
      console.log('createWatermark', width, height);
      this.watermark.width = width;
      this.watermark.height = height;
      this.watermark.text = this.watermarkText;
    },
    formatDatetime(timestamp) {
      return parseInt(timestamp / 1000);
    },

    // 暴露外部
    screenshot() {
      const imgData = this._iframeEl.contentWindow.screenshotBase64();
      // console.log('handleScreenshot', imgData);

      return imgData;
    },
    screenshotWatermark() {
      // eslint-disable-next-line
      return new Promise((resolve, reject) => {
        // 创建一个新的图片对象
        const image = new Image();

        // 当图像加载完成后执行
        image.onload = () => {
          // 创建一个 Canvas 元素
          const canvas = this.$refs.watermarkLayer.createCanvas(image);

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

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

        // 设置图像的 src 属性,加载图像
        image.src = this.screenshot();
      });
    },
    stopPlay() {
      return this._iframeEl.contentWindow.stopPlayer();
    },
    ptzController(arrow) {
      /**
       * arrow传参说明:
       * 方向控制:up, down, left, right, leftUp, rightUp, rightDown, leftDown
       * 缩放控制:zoomExpand, zoomNarrow
       * 调用完成,需要调用停止 ptzController('stop')
       *
       * 光圈控制:apertureFar, apertureNear
       * 聚焦控制:focusFar, focusNear
       * 调用完成,需要调用停止 ptzController('fiStop')
       */
      this._iframeEl.contentWindow.handlePtzController(arrow);
    },
  },
}
</script>

<style scoped lang="less">
.j-player {
  height: 100%;
  width: 100%;
  position: relative;
  ::v-deep(.watermark-layer) {
    position: absolute;
    top: 0px;
    left: 0px;
    // z-index: 10;
  }
}
</style>