Commit 0f31669da86600ef142d2bbe0afea668671de793

Authored by ww
1 parent 5d526eda

feat: 视频配置实现支持flv视频播放

... ... @@ -7,15 +7,18 @@
7 7 "cSpell.words": [
8 8 "COAP",
9 9 "edrx",
10   - "EFENTO",
  10 + "EFENTO",
  11 + "flvjs",
11 12 "inited",
  13 + "liveui",
12 14 "MQTT",
13 15 "notif",
14   - "PROTOBUF",
  16 + "PROTOBUF",
15 17 "SCADA",
16 18 "SNMP",
17 19 "unref",
18 20 "vben",
  21 + "videojs",
19 22 "VITE",
20 23 "windicss"
21 24 ]
... ...
... ... @@ -49,6 +49,7 @@
49 49 "cropperjs": "^1.5.12",
50 50 "crypto-js": "^4.1.1",
51 51 "echarts": "^5.1.2",
  52 + "flv.js": "^1.6.2",
52 53 "hls.js": "^1.0.10",
53 54 "intro.js": "^4.1.0",
54 55 "jsoneditor": "^9.7.2",
... ... @@ -65,6 +66,7 @@
65 66 "tinymce": "^5.8.2",
66 67 "vditor": "^3.8.6",
67 68 "video.js": "^7.20.3",
  69 + "videojs-flvjs-es6": "^1.0.1",
68 70 "vue": "3.2.31",
69 71 "vue-i18n": "9.1.7",
70 72 "vue-json-pretty": "^2.0.4",
... ...
... ... @@ -4,7 +4,7 @@
4 4 import 'video.js/dist/video-js.css';
5 5 import { computed, CSSProperties, onMounted, onUnmounted, ref, unref } from 'vue';
6 6 import { useDesign } from '/@/hooks/web/useDesign';
7   -
  7 + import 'videojs-flvjs-es6';
8 8 const { prefixCls } = useDesign('basic-video-play');
9 9
10 10 const props = defineProps<{
... ... @@ -21,11 +21,20 @@
21 21
22 22 const getOptions = computed(() => {
23 23 const { options } = props;
24   - const defaultOptions: VideoJsPlayerOptions = {
  24 + const defaultOptions: VideoJsPlayerOptions & Recordable = {
25 25 language: 'zh',
26 26 muted: true,
27 27 liveui: true,
28 28 controls: true,
  29 + techOrder: ['html5', 'flvjs'],
  30 + flvjs: {
  31 + mediaDataSource: {
  32 + isLive: true,
  33 + cors: true,
  34 + hasAudio: false,
  35 + withCredentials: false,
  36 + },
  37 + },
29 38 };
30 39 return { ...defaultOptions, ...options };
31 40 });
... ... @@ -58,7 +67,9 @@
58 67 <video
59 68 ref="videoPlayEl"
60 69 class="video-js vjs-big-play-centered vjs-show-big-play-button-on-pause !w-full !h-full"
61   - ></video>
  70 + muted
  71 + >
  72 + </video>
62 73 </div>
63 74 </template>
64 75
... ...
1   -export enum VideoPlayerType {
2   - m3u8 = 'application/x-mpegURL',
3   - mp4 = 'video/mp4',
4   - webm = 'video/webm',
5   -}
6   -
7   -export const getVideoTypeByUrl = (url: string) => {
8   - const splitExtReg = /(?:.*)(?<=\.)/;
9   - const type = url.replace(splitExtReg, '');
10   - /**
11   - * https://vcsplay.scjtonline.cn:8200/live/HD_1569b634-4789-11eb-ab67-3cd2e55e0b20.m3u8?auth_key=1681179278-0-0-5c54a376f2ca32d05c4a152ee96336e9
12   - * 如果是这种格式的m3u8,则截取的是这一部分.m3u8?auth_key=1681179278-0-0-5c54a376f2ca32d05c4a152ee96336e9
13   - */
14   - if (type.startsWith('m3u8')) return VideoPlayerType.m3u8;
15   - if (type.startsWith('mp4')) return VideoPlayerType.mp4;
16   - if (type.startsWith('webm')) return VideoPlayerType.webm;
17   - return;
18   -};
  1 +export enum VideoPlayerType {
  2 + m3u8 = 'application/x-mpegURL',
  3 + mp4 = 'video/mp4',
  4 + webm = 'video/webm',
  5 + flv = 'video/x-flv',
  6 +}
  7 +
  8 +export const getVideoTypeByUrl = (url: string) => {
  9 + try {
  10 + const { pathname } = new URL(url);
  11 +
  12 + const reg = /[^.]\w*$/;
  13 + const mathValue = pathname.match(reg) || [];
  14 + const ext = (mathValue[0] as keyof typeof VideoPlayerType) || 'webm';
  15 + const type = VideoPlayerType[ext];
  16 + return type ? type : VideoPlayerType.webm;
  17 + } catch (error) {
  18 + console.error(error);
  19 + return VideoPlayerType.webm;
  20 + }
  21 +};
... ...
... ... @@ -11,9 +11,9 @@
11 11 @cancel="handleCancel"
12 12 >
13 13 <div
14   - class="flex items-center justify-center bg-dark-900 w-full h-full min-h-52 video-container"
  14 + class="flex items-center justify-center bg-dark-900 w-full h-full min-h-96 video-container"
15 15 >
16   - <BasicVideoPlay v-if="showVideo" :options="options" />
  16 + <BasicVideoPlay v-if="showVideo" :options="(options as any)" />
17 17 </div>
18 18 </BasicModal>
19 19 </div>
... ... @@ -31,7 +31,7 @@
31 31 const showVideo = ref(false);
32 32 const options = reactive<VideoJsPlayerOptions>({
33 33 width: '100%' as unknown as number,
34   - height: '100%' as unknown as number,
  34 + height: 384 as unknown as number,
35 35 autoplay: true,
36 36 });
37 37
... ...
1 1 <script setup lang="ts">
2 2 import { PageWrapper } from '/@/components/Page';
3 3 import OrganizationIdTree from '../../common/organizationIdTree/src/OrganizationIdTree.vue';
4   - import { onMounted, reactive, ref, unref, watch } from 'vue';
  4 + import { onMounted, reactive, Ref, ref, unref, watch } from 'vue';
5 5 import { Spin, Button, Pagination, Space, List } from 'ant-design-vue';
6 6 import { cameraPage } from '/@/api/camera/cameraManager';
7 7 import { CameraRecord } from '/@/api/camera/model/cameraModel';
... ... @@ -84,12 +84,14 @@
84 84 const beforeVideoPlay = async (record: CameraRecordItem) => {
85 85 if (record.accessMode === AccessMode.ManuallyEnter) {
86 86 if (record.videoUrl) {
  87 + const type = getVideoTypeByUrl(record.videoUrl);
  88 +
87 89 (record as CameraRecordItem).videoPlayerOptions = {
88 90 ...basicVideoPlayOptions,
89 91 sources: [
90 92 {
91 93 src: record.videoUrl,
92   - type: getVideoTypeByUrl(record.videoUrl),
  94 + type,
93 95 },
94 96 ],
95 97 };
... ... @@ -112,7 +114,7 @@
112 114 type: getVideoTypeByUrl(url),
113 115 },
114 116 ],
115   - },
  117 + } as any,
116 118 isTransform: true,
117 119 };
118 120 }
... ... @@ -134,7 +136,7 @@
134 136 getCameraList();
135 137 };
136 138
137   - const { enter, isFullscreen } = useFullscreen(videoContainer);
  139 + const { enter, isFullscreen } = useFullscreen(videoContainer as Ref<HTMLDivElement>);
138 140
139 141 const handleFullScreen = () => {
140 142 enter();
... ... @@ -244,7 +246,7 @@
244 246 :loading="loading"
245 247 :data-source="cameraList"
246 248 class="bg-light-50 w-full h-full dark:bg-dark-900 split-mode-list"
247   - :grid="gridLayout"
  249 + :grid="(gridLayout as any)"
248 250 :style="{ '--height': `${100 / pagination.colNumber}%` }"
249 251 >
250 252 <template #renderItem="{ item }">
... ... @@ -316,6 +318,10 @@
316 318 .split-mode-list:deep(.ant-row) {
317 319 width: 100%;
318 320 height: 100%;
  321 +
  322 + > div {
  323 + height: var(--height);
  324 + }
319 325 }
320 326
321 327 .split-mode-list:deep(.ant-list-item) {
... ...