Commit ab77ae575f24c61c745c94e59bdfedfe23fde80f

Authored by ww
1 parent 46ab5b88

feat: 实现监控视频rtsp协议播放

@@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
19 "dependencies": { 19 "dependencies": {
20 "@amap/amap-jsapi-loader": "^1.0.1", 20 "@amap/amap-jsapi-loader": "^1.0.1",
21 "@amap/amap-jsapi-types": "^0.0.8", 21 "@amap/amap-jsapi-types": "^0.0.8",
  22 + "@fingerprintjs/fingerprintjs": "^3.4.1",
22 "@types/color": "^3.0.3", 23 "@types/color": "^3.0.3",
23 "@types/crypto-js": "^4.1.1", 24 "@types/crypto-js": "^4.1.1",
24 "@types/keymaster": "^1.6.30", 25 "@types/keymaster": "^1.6.30",
  1 +import { defHttp } from "@/utils/external/http/axios";
  2 +import { useGlobSetting } from '@/hooks/external/setting';
  3 +enum Api {
  4 + OPEN_FLV = '/rtsp/openFlv',
  5 + CLOSE_FLV = '/rtsp/closeFlv'
  6 +}
  7 +
  8 +export const getOpenFlvPlayUrl = (url: string, browserId: string) => {
  9 + const { urlPrefix, apiUrl } = useGlobSetting()
  10 + return `${apiUrl || ''}${urlPrefix || ''}${Api.OPEN_FLV}?url=${encodeURIComponent(url)}&browserId=${browserId}`;
  11 +};
  12 +
  13 +export const closeFlvPlay = (url: string, browserId: string) => {
  14 + return defHttp.get({
  15 + url: Api.CLOSE_FLV,
  16 + params: {
  17 + url: encodeURIComponent(url),
  18 + browserId
  19 + }
  20 + });
  21 +};
@@ -6,11 +6,16 @@ @@ -6,11 +6,16 @@
6 </div> 6 </div>
7 </template> 7 </template>
8 <script setup lang="ts"> 8 <script setup lang="ts">
9 -import { onMounted, ref, onUnmounted, watch } from 'vue' 9 +import { onMounted, ref, onUnmounted, watch, unref } from 'vue'
10 import videojs from 'video.js' 10 import videojs from 'video.js'
11 import 'videojs-flvjs-es6' 11 import 'videojs-flvjs-es6'
12 import type { VideoJsPlayerOptions } from 'video.js' 12 import type { VideoJsPlayerOptions } from 'video.js'
13 import 'video.js/dist/video-js.min.css' 13 import 'video.js/dist/video-js.min.css'
  14 +import { getJwtToken, getShareJwtToken } from '@/utils/external/auth'
  15 +import { isShareMode } from '@/views/share/hook'
  16 +import { getOpenFlvPlayUrl, closeFlvPlay } from '@/api/external/flvPlay'
  17 +import { useFingerprint } from '@/utils/external/useFingerprint'
  18 +import { GetResult } from '@fingerprintjs/fingerprintjs'
14 19
15 const props = defineProps({ 20 const props = defineProps({
16 sourceSrc: { 21 sourceSrc: {
@@ -48,11 +53,10 @@ const isRtspProtocol = (url: string) => { @@ -48,11 +53,10 @@ const isRtspProtocol = (url: string) => {
48 }; 53 };
49 54
50 const getVideoTypeByUrl = (url = '') => { 55 const getVideoTypeByUrl = (url = '') => {
51 -  
52 try { 56 try {
53 const { protocol, pathname } = new URL(url) 57 const { protocol, pathname } = new URL(url)
54 58
55 - if (isRtspProtocol(protocol)) return VideoPlayerType.flv 59 + if (protocol.startsWith('rtsp:')) return VideoPlayerType.flv
56 60
57 const reg = /[^.]\w*$/ 61 const reg = /[^.]\w*$/
58 const mathValue = pathname.match(reg) || [] 62 const mathValue = pathname.match(reg) || []
@@ -72,6 +76,8 @@ const videoRef = ref<HTMLElement | null>(null) @@ -72,6 +76,8 @@ const videoRef = ref<HTMLElement | null>(null)
72 // video实例对象 76 // video实例对象
73 let videoPlayer: videojs.Player | null = null 77 let videoPlayer: videojs.Player | null = null
74 78
  79 +const fingerprintResult = ref<Nullable<GetResult>>(null)
  80 +
75 //options配置 81 //options配置
76 const options: VideoJsPlayerOptions & Recordable = { 82 const options: VideoJsPlayerOptions & Recordable = {
77 language: 'zh-CN', // 设置语言 83 language: 'zh-CN', // 设置语言
@@ -92,16 +98,24 @@ const options: VideoJsPlayerOptions & Recordable = { @@ -92,16 +98,24 @@ const options: VideoJsPlayerOptions & Recordable = {
92 isLive: true, 98 isLive: true,
93 cors: true, 99 cors: true,
94 withCredentials: false, 100 withCredentials: false,
95 - } 101 + },
96 }, 102 },
97 } 103 }
98 104
99 105
  106 +const { getResult } = useFingerprint()
100 async function getSource() { 107 async function getSource() {
  108 + fingerprintResult.value = await getResult()
  109 + let src = props.sourceSrc || ''
  110 +
  111 + if (isRtspProtocol(props.sourceSrc!)) {
  112 + src = getOpenFlvPlayUrl(src, unref(fingerprintResult)?.visitorId || '')
  113 + }
  114 +
101 return [ 115 return [
102 { 116 {
103 type: getVideoTypeByUrl(props.sourceSrc), 117 type: getVideoTypeByUrl(props.sourceSrc),
104 - src: props.sourceSrc || '' 118 + src
105 } 119 }
106 ] 120 ]
107 } 121 }
@@ -112,6 +126,17 @@ const initVideo = async () => { @@ -112,6 +126,17 @@ const initVideo = async () => {
112 // 创建 video 实例 126 // 创建 video 实例
113 options.sources = await getSource() 127 options.sources = await getSource()
114 if (options.sources && options.sources.length) { 128 if (options.sources && options.sources.length) {
  129 +
  130 + if (isRtspProtocol(props.sourceSrc || '')) {
  131 + options.flvjs = {
  132 + ...(options.flvjs || {}),
  133 + config: {
  134 + headers: {
  135 + 'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`,
  136 + }
  137 + }
  138 + }
  139 + }
115 videoPlayer = videojs(videoRef.value, options) 140 videoPlayer = videojs(videoRef.value, options)
116 } 141 }
117 } 142 }
@@ -135,6 +160,9 @@ onMounted(() => { @@ -135,6 +160,9 @@ onMounted(() => {
135 }) 160 })
136 161
137 onUnmounted(() => { 162 onUnmounted(() => {
  163 + if (props.sourceSrc) {
  164 + closeFlvPlay(props.sourceSrc, unref(fingerprintResult)!.visitorId!)
  165 + }
138 handleVideoDispose() 166 handleVideoDispose()
139 }) 167 })
140 168
@@ -154,6 +182,7 @@ defineExpose({ @@ -154,6 +182,7 @@ defineExpose({
154 display: flex; 182 display: flex;
155 align-items: center; 183 align-items: center;
156 justify-content: center; 184 justify-content: center;
  185 +
157 .my-video { 186 .my-video {
158 width: 100% !important; 187 width: 100% !important;
159 height: 100% !important; 188 height: 100% !important;
  1 +import { load } from '@fingerprintjs/fingerprintjs';
  2 +export const useFingerprint = () => {
  3 + const getResult = async () => {
  4 + const fp = await load();
  5 + const result = await fp.get();
  6 + return result;
  7 + };
  8 +
  9 + return { getResult };
  10 +};