Commit 5e6df27d254f5e9402ba7649f2f4e51fb621dc4c

Authored by fengwotao
1 parent b6587d76

feat(src/packages): 修改信息下的单个摄像头,如果是rtsp,则调用接口进行播放

1 <template> 1 <template>
2 - <div class="videoPlay"> 2 + <div class="go-content-box" :style="{ width: w + 'px', height: h + 'px' }">
3 <video 3 <video
4 - style="object-fit: cover"  
5 - :poster="poster"  
6 crossOrigin="anonymous" 4 crossOrigin="anonymous"
  5 + :id="`my-player`"
7 ref="videoRef" 6 ref="videoRef"
8 - class="video-js vjs-default-skin vjs-big-play-centered"  
9 - controls  
10 - >  
11 - <source :src="path" />  
12 - </video> 7 + class="video-js my-video vjs-theme-city vjs-big-play-centered"
  8 + ></video>
13 </div> 9 </div>
14 </template> 10 </template>
15 -<script lang="ts" setup>  
16 -import { nextTick, onBeforeUnmount, onMounted, ref, watch, toRefs } from 'vue'  
17 -import videojs, { VideoJsPlayer } from 'video.js' 11 +<script setup lang="ts">
  12 +import { onMounted, ref, onUnmounted, watch, unref } from 'vue'
  13 +import videojs from 'video.js'
  14 +import 'videojs-flvjs-es6'
18 import type { VideoJsPlayerOptions } from 'video.js' 15 import type { VideoJsPlayerOptions } from 'video.js'
19 -import 'video.js/dist/video-js.css'  
20 -import zh from 'video.js/dist/lang/zh-CN.json'  
21 -  
22 -const props = withDefaults(  
23 - defineProps<{  
24 - path: string  
25 - autoPlay?: boolean  
26 - h?: number  
27 - poster?: string  
28 - }>(),  
29 - { autoPlay: false }  
30 -) 16 +import 'video.js/dist/video-js.min.css'
  17 +import { getJwtToken, getShareJwtToken } from '@/utils/external/auth'
  18 +import { isShareMode } from '@/views/share/hook'
  19 +import { getOpenFlvPlayUrl, closeFlvPlay } from '@/api/external/flvPlay'
  20 +import { useFingerprint } from '@/utils/external/useFingerprint'
  21 +import { GetResult } from '@fingerprintjs/fingerprintjs'
31 22
32 -const videoRef = ref()  
33 -  
34 -let player: VideoJsPlayer  
35 -  
36 -const initPlay = async () => {  
37 - videojs.addLanguage('zh-CN', zh)  
38 - await nextTick()  
39 - const options: VideoJsPlayerOptions = {  
40 - muted: true,  
41 - controls: true,  
42 - autoplay: props.autoPlay,  
43 - src: props?.path,  
44 - poster: props?.poster,  
45 - language: 'zh-CN',  
46 - techOrder: ['html5'],  
47 - preload: 'none' 23 +const props = defineProps({
  24 + sourceSrc: {
  25 + type: String
  26 + },
  27 + autoplay: {
  28 + type: Boolean
  29 + },
  30 + name: {
  31 + type: String
  32 + },
  33 + avatar: {
  34 + type: String
  35 + },
  36 + w: {
  37 + type: Number,
  38 + default: 300
  39 + },
  40 + h: {
  41 + type: Number,
  42 + default: 300
48 } 43 }
49 - player = videojs(videoRef.value, options, () => {  
50 - videojs.log('Video is reading')  
51 - if (props.autoPlay) {  
52 - player.play() 44 +})
  45 +
  46 +enum VideoPlayerType {
  47 + m3u8 = 'application/x-mpegURL',
  48 + mp4 = 'video/mp4',
  49 + webm = 'video/webm',
  50 + flv = 'video/x-flv'
  51 +}
  52 +
  53 +const isRtspProtocol = (url: string) => {
  54 + const reg = /^rtsp:\/\//g
  55 + return reg.test(url)
  56 +}
  57 +
  58 +const getVideoTypeByUrl = (url = '') => {
  59 + try {
  60 + const { protocol, pathname } = new URL(url)
  61 +
  62 + if (protocol.startsWith('rtsp:')) return VideoPlayerType.flv
  63 +
  64 + const reg = /[^.]\w*$/
  65 + const mathValue = pathname.match(reg) || []
  66 + const ext = (mathValue[0] as keyof typeof VideoPlayerType) || 'webm'
  67 + const type = VideoPlayerType[ext]
  68 + return type ? type : VideoPlayerType.webm
  69 + } catch (error) {
  70 + console.error(error)
  71 + return VideoPlayerType.webm
  72 + }
  73 +}
  74 +
  75 +// video标签
  76 +const videoRef = ref<HTMLElement | null>(null)
  77 +
  78 +// video实例对象
  79 +let videoPlayer: videojs.Player | null = null
  80 +
  81 +const fingerprintResult = ref<Nullable<GetResult>>(null)
  82 +
  83 +//options配置
  84 +const options: VideoJsPlayerOptions & Recordable = {
  85 + language: 'zh-CN', // 设置语言
  86 + controls: true, // 是否显示控制条
  87 + preload: 'auto', // 预加载
  88 + autoplay: true, // 是否自动播放
  89 + fluid: false, // 自适应宽高
  90 + poster: props?.avatar || '',
  91 + // src: getSource() || '', // 要嵌入的视频源的源 URL
  92 + sources: [],
  93 + muted: true,
  94 + userActions: {
  95 + hotkeys: true
  96 + },
  97 + techOrder: ['html5', 'flvjs'],
  98 + flvjs: {
  99 + mediaDataSource: {
  100 + isLive: true,
  101 + cors: true,
  102 + withCredentials: false,
  103 + hasAudio: false
  104 + },
  105 + config: {
  106 + autoCleanupSourceBuffer: true
53 } 107 }
54 - player.on('ended', () => {  
55 - videojs.log('Play end')  
56 - })  
57 - player.on('error', () => {  
58 - player.errorDisplay.close()  
59 - videojs.log('Play parse error')  
60 - })  
61 - }) 108 + }
62 } 109 }
63 110
64 -onMounted(() => {  
65 - initPlay()  
66 -}) 111 +const { getResult } = useFingerprint()
  112 +async function getSource() {
  113 + fingerprintResult.value = await getResult()
  114 + let src = props.sourceSrc || ''
67 115
68 -//直接改变路径测试  
69 -watch(  
70 - () => props.path,  
71 - () => {  
72 - if (props.path && props.autoPlay) {  
73 - try {  
74 - player?.pause()  
75 - player?.load()  
76 - player?.src(props.path)  
77 - player?.play()  
78 - } catch (e) {  
79 - console.log(e) 116 + if (isRtspProtocol(props.sourceSrc!)) {
  117 + src = getOpenFlvPlayUrl(src, unref(fingerprintResult)?.visitorId || '')
  118 + }
  119 +
  120 + return [
  121 + {
  122 + type: getVideoTypeByUrl(props.sourceSrc),
  123 + src
  124 + }
  125 + ]
  126 +}
  127 +
  128 +// 初始化videojs
  129 +const initVideo = async () => {
  130 + if (videoRef.value) {
  131 + // 创建 video 实例
  132 + options.sources = await getSource()
  133 + if (options.sources && options.sources.length) {
  134 + if (isRtspProtocol(props.sourceSrc || '')) {
  135 + options.flvjs = {
  136 + ...(options.flvjs || {}),
  137 + config: {
  138 + headers: {
  139 + 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`
  140 + }
  141 + }
  142 + }
80 } 143 }
  144 + videoPlayer = videojs(videoRef.value, options)
81 } 145 }
  146 + }
  147 +}
  148 +
  149 +watch(
  150 + () => props.sourceSrc,
  151 + async (newData: any) => {
  152 + const result = await getSource()
  153 + // props.sourceSrc = newData
  154 + videoPlayer?.src(result) as any
  155 + videoPlayer?.play()
82 }, 156 },
83 { 157 {
84 immediate: true 158 immediate: true
85 } 159 }
86 ) 160 )
87 161
88 -onBeforeUnmount(() => {  
89 - player?.dispose() 162 +onMounted(() => {
  163 + initVideo()
  164 +})
  165 +
  166 +onUnmounted(() => {
  167 + if (props.sourceSrc) {
  168 + closeFlvPlay(props.sourceSrc, unref(fingerprintResult)!.visitorId!)
  169 + }
  170 + handleVideoDispose()
  171 +})
  172 +
  173 +//播放
  174 +const handleVideoPlay = () => videoPlayer?.play()
  175 +
  176 +const handleVideoDispose = () => videoPlayer?.dispose() && videoPlayer?.pause()
  177 +//暂停
  178 +defineExpose({
  179 + handleVideoPlay,
  180 + handleVideoDispose
90 }) 181 })
91 </script> 182 </script>
92 -<style>  
93 -.vjs-poster {  
94 - background-size: cover !important;  
95 -}  
96 -</style> 183 +
97 <style lang="scss" scoped> 184 <style lang="scss" scoped>
98 -.videoPlay {  
99 - flex: 1;  
100 - height: v-bind('`${h}px`');  
101 - .video-js {  
102 - height: 100%;  
103 - width: 100%; 185 +.go-content-box {
  186 + display: flex;
  187 + align-items: center;
  188 + justify-content: center;
  189 +
  190 + .my-video {
  191 + width: 100% !important;
  192 + height: 100% !important;
  193 + position: relative;
104 } 194 }
105 } 195 }
106 </style> 196 </style>
1 <template> 1 <template>
2 <div> 2 <div>
3 - <VideoPlay :h="h" :path="option.dataset" :autoPlay="autoplay" :poster="option.poster" /> 3 + <VideoPlay :w="w" :h="h" :sourceSrc="option.dataset" :autoPlay="autoplay" :avatar="option.poster" />
4 </div> 4 </div>
5 </template> 5 </template>
6 <script setup lang="ts"> 6 <script setup lang="ts">
@@ -16,7 +16,7 @@ const props = defineProps({ @@ -16,7 +16,7 @@ const props = defineProps({
16 } 16 }
17 }) 17 })
18 18
19 -const { h } = toRefs(props.chartConfig.attr) 19 +const { w, h } = toRefs(props.chartConfig.attr)
20 20
21 const { autoplay, dataset, poster, url } = toRefs(props.chartConfig.option) 21 const { autoplay, dataset, poster, url } = toRefs(props.chartConfig.option)
22 22