cameraItem.vue 3.41 KB
<template>
  <div class="go-content-box" :style="{ width: w + 'px', height: h + 'px' }">
    <video crossOrigin="anonymous" :id="`my-player${index}`" ref="videoRef"
      class="video-js my-video vjs-theme-city vjs-big-play-centered">
    </video>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ref, onUnmounted, watch } from 'vue'
import videojs from 'video.js'
import 'videojs-flvjs-es6'
import type { VideoJsPlayerOptions } from 'video.js'
import 'video.js/dist/video-js.min.css'

const props = defineProps({
  sourceSrc: {
    type: String
  },
  name: {
    type: String
  },
  avatar: {
    type: String
  },
  w: {
    type: Number,
    default: 300
  },
  h: {
    type: Number,
    default: 300
  },
  index: {
    type: Number
  }
})

enum VideoPlayerType {
  m3u8 = 'application/x-mpegURL',
  mp4 = 'video/mp4',
  webm = 'video/webm',
  flv = 'video/x-flv',
}

const isRtspProtocol = (url: string) => {
  const reg = /^rtsp:\/\//g;
  return reg.test(url);
};

const getVideoTypeByUrl = (url = '') => {

  try {
    const { protocol, pathname } = new URL(url)

    if (isRtspProtocol(protocol)) return VideoPlayerType.flv

    const reg = /[^.]\w*$/
    const mathValue = pathname.match(reg) || []
    const ext = mathValue[0] as keyof typeof VideoPlayerType || 'webm'
    const type = VideoPlayerType[ext]
    return type ? type : VideoPlayerType.webm
  } catch (error) {
    console.error(error)
    return VideoPlayerType.webm
  }
};


// video标签
const videoRef = ref<HTMLElement | null>(null)

// video实例对象
let videoPlayer: videojs.Player | null = null

//options配置
const options: VideoJsPlayerOptions & Recordable = {
  language: 'zh-CN', // 设置语言
  controls: true, // 是否显示控制条
  preload: 'auto', // 预加载
  autoplay: true, // 是否自动播放
  fluid: false, // 自适应宽高
  poster: props?.avatar || '',
  // src: getSource() || '', // 要嵌入的视频源的源 URL
  sources: [],
  muted: true,
  userActions: {
    hotkeys: true
  },
  techOrder: ['html5', 'flvjs'],
  flvjs: {
    mediaDataSource: {
      isLive: true,
      cors: true,
      withCredentials: false,
    }
  },
}


async function getSource() {
  return [
    {
      type: getVideoTypeByUrl(props.sourceSrc),
      src: props.sourceSrc || ''
    }
  ]
}

// 初始化videojs
const initVideo = async () => {
  if (videoRef.value) {
    // 创建 video 实例   
    options.sources = await getSource()
    if (options.sources && options.sources.length) {
      videoPlayer = videojs(videoRef.value, options)
    }
  }
}

watch(
  () => props.sourceSrc,
  async (newData: any) => {
    const result = await getSource()
    // props.sourceSrc = newData
    videoPlayer?.src(result) as any
    videoPlayer?.play()
  },
  {
    immediate: true
  }
)

onMounted(() => {
  initVideo()
})

onUnmounted(() => {
  handleVideoDispose()
})

//播放
const handleVideoPlay = () => videoPlayer?.play()

const handleVideoDispose = () => videoPlayer?.dispose() && videoPlayer?.pause()
//暂停
defineExpose({
  handleVideoPlay,
  handleVideoDispose
})
</script>

<style lang="scss" scoped>
.go-content-box {
  display: flex;
  align-items: center;
  justify-content: center;
  .my-video {
    width: 100% !important;
    height: 100% !important;
    position: relative;
  }
}
</style>