视频播放同时支持h265和h264播放
This commit is contained in:
parent
c3f43f6e71
commit
489ec29184
@ -12,9 +12,10 @@ export function addStreamProxy(params?: any) {
|
||||
params,
|
||||
);
|
||||
}
|
||||
|
||||
export function addFFmpegStreamProxy(params?: any) {
|
||||
return requestClient.post<AddStreamProxyResult>(
|
||||
'sis/stream/realtime/addFfmpeg',
|
||||
'sis/stream/FFmpeg/proxy',
|
||||
params,
|
||||
);
|
||||
}
|
||||
|
21
apps/web-antd/src/utils/video.ts
Normal file
21
apps/web-antd/src/utils/video.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 验证浏览器是否支持播放h265 编码的视频流
|
||||
*/
|
||||
export function checkHEVCSupport() {
|
||||
const video = document.createElement('video');
|
||||
const h265Support = {
|
||||
hevc: false,
|
||||
hvc1: false,
|
||||
};
|
||||
|
||||
// 测试不同的HEVC MIME类型
|
||||
if (video.canPlayType) {
|
||||
h265Support.hevc =
|
||||
video.canPlayType('video/mp4; codecs="hev1.1.6.L93.B0"') !== '';
|
||||
h265Support.hvc1 =
|
||||
video.canPlayType('video/mp4; codecs="hvc1.1.6.L93.B0"') !== '';
|
||||
}
|
||||
const result = h265Support.hevc || h265Support.hvc1;
|
||||
console.log('当前浏览器是否支持h265:' + result);
|
||||
return result;
|
||||
}
|
@ -27,10 +27,12 @@
|
||||
<script setup lang="ts">
|
||||
import DpTree from './dp-tree.vue';
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { onMounted, ref, toRaw } from 'vue';
|
||||
import { onMounted, onUnmounted, ref, toRaw } from 'vue';
|
||||
import mpegts from 'mpegts.js';
|
||||
import { addStreamProxy } from '#/api/sis/stream';
|
||||
import { addFFmpegStreamProxy, addStreamProxy } from '#/api/sis/stream';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { checkHEVCSupport } from '#/utils/video';
|
||||
import type { AddStreamProxyResult } from '#/api/sis/stream/model';
|
||||
|
||||
/**
|
||||
* 屏幕播放器数量
|
||||
@ -74,7 +76,7 @@ function handleParentNoe(node: any, newNode: any[] = []) {
|
||||
if (item.children && item.children.length >= 1) {
|
||||
handleParentNoe(item.children, newNode);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,6 +140,35 @@ function onNodeChecked(
|
||||
// 播放器数据, 每一个位置代表页面上行的一个矩形
|
||||
const playerList: any[] = [];
|
||||
|
||||
function streamProxy(nodeData: any, cb: Function) {
|
||||
let params = {};
|
||||
if (nodeData.nvrIp) {
|
||||
params = {
|
||||
videoIp: nodeData.nvrIp,
|
||||
videoPort: nodeData.nvrPort,
|
||||
factoryNo: nodeData.nvrFactoryNo,
|
||||
account: nodeData.nvrAccount,
|
||||
pwd: nodeData.nvrPwd,
|
||||
channelId: nodeData.nvrChannelNo,
|
||||
};
|
||||
} else {
|
||||
params = {
|
||||
videoIp: nodeData.deviceIp,
|
||||
videoPort: nodeData.devicePort,
|
||||
factoryNo: nodeData.factoryNo,
|
||||
account: nodeData.deviceAccount,
|
||||
pwd: nodeData.devicePwd,
|
||||
channelId: nodeData.channelNo,
|
||||
};
|
||||
|
||||
if (isSupportH265) {
|
||||
addStreamProxy(params).then((res) => cb(res));
|
||||
} else {
|
||||
addFFmpegStreamProxy(params).then((res) => cb(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始播放视频流
|
||||
* @param nodeData 播放的节点数据
|
||||
@ -146,16 +177,7 @@ const playerList: any[] = [];
|
||||
function doPlayer(nodeData: any, index: number = 0) {
|
||||
console.log('index=', index);
|
||||
if (mpegts.isSupported()) {
|
||||
const params = {
|
||||
videoIp: nodeData.deviceIp,
|
||||
videoPort: 554,
|
||||
factoryNo: nodeData.factoryNo,
|
||||
account: nodeData.deviceAccount,
|
||||
pwd: nodeData.devicePwd,
|
||||
channelId: nodeData.channelNo ? nodeData.channelNo : 101,
|
||||
};
|
||||
// }
|
||||
addStreamProxy(params).then((res) => {
|
||||
streamProxy(nodeData, (res: AddStreamProxyResult) => {
|
||||
const url = res.wsFlv;
|
||||
// 将url 绑定到 nodeData
|
||||
nodeData.url = url;
|
||||
@ -195,55 +217,6 @@ function doPlayer(nodeData: any, index: number = 0) {
|
||||
}
|
||||
}
|
||||
|
||||
function changeElPlayer(playerInfo: any, index: number) {
|
||||
const playerData = playerInfo.data;
|
||||
const oldPlayer = playerInfo.player;
|
||||
if (oldPlayer) {
|
||||
closePlayVieo(oldPlayer);
|
||||
}
|
||||
const videoConfig = {
|
||||
type: 'flv',
|
||||
url: playerData.url,
|
||||
isLive: true,
|
||||
hasAudio: false,
|
||||
hasVideo: true,
|
||||
enableWorker: true, // 启用分离的线程进行转码
|
||||
enableStashBuffer: false, // 关闭IO隐藏缓冲区
|
||||
stashInitialSize: 256, // 减少首帧显示等待时长
|
||||
};
|
||||
const playerConfig = {
|
||||
enableErrorRecover: true, // 启用错误恢复
|
||||
autoCleanupMaxBackwardDuration: 30,
|
||||
autoCleanupMinBackwardDuration: 10,
|
||||
};
|
||||
const player = mpegts.createPlayer(videoConfig, playerConfig);
|
||||
const videoElement = itemRefs.value[index];
|
||||
if (videoElement) {
|
||||
player.attachMediaElement(videoElement);
|
||||
player.load();
|
||||
player.play();
|
||||
playerList[index] = {
|
||||
player,
|
||||
data: playerData,
|
||||
el: videoElement,
|
||||
};
|
||||
} else {
|
||||
console.log('视频播放元素获取异常');
|
||||
}
|
||||
}
|
||||
|
||||
function closePlayVieo(plInfo: any) {
|
||||
if (plInfo) {
|
||||
try {
|
||||
plInfo.pause(); // 暂停
|
||||
plInfo.unload(); // 卸载
|
||||
plInfo.destroy(); // 销毁
|
||||
} catch (e) {
|
||||
console.log('播放器关闭失败,e=', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closePlayer(index: number) {
|
||||
// 如果播放器存在,尝试关闭
|
||||
const pData = playerList[index];
|
||||
@ -274,9 +247,18 @@ function catchUp() {
|
||||
});
|
||||
}
|
||||
|
||||
let isSupportH265 = false;
|
||||
onMounted(() => {
|
||||
// 检测浏览器是否支持h265
|
||||
isSupportH265 = checkHEVCSupport();
|
||||
setInterval(catchUp, 10000);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
for (let i = 0; i < playerList.length; i++) {
|
||||
closePlayer(i);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.player {
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Page class="h-full w-full">
|
||||
<!-- 设备分组区域 -->
|
||||
<div class="flex h-full gap-[8px]">
|
||||
<ChannelTree class="h-[83vh] w-[300px]" @check="onNodeChecked" />
|
||||
<ChannelTree class="h-full w-[300px]" @check="onNodeChecked" />
|
||||
|
||||
<!-- 设备分组区域 -->
|
||||
<div class="bg-background flex-1">
|
||||
@ -47,13 +47,15 @@ import { Page } from '@vben/common-ui';
|
||||
import ChannelTree from './channel-tree.vue';
|
||||
import mpegts from 'mpegts.js';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { addStreamProxy } from '#/api/sis/stream';
|
||||
import { addFFmpegStreamProxy, addStreamProxy } from '#/api/sis/stream';
|
||||
import {
|
||||
Svg16FrameIcon,
|
||||
Svg1FrameIcon,
|
||||
Svg4FrameIcon,
|
||||
Svg9FrameIcon,
|
||||
} from '@vben/icons';
|
||||
import { checkHEVCSupport } from '#/utils/video';
|
||||
import type { AddStreamProxyResult } from '#/api/sis/stream/model';
|
||||
|
||||
const selected = 'selected';
|
||||
|
||||
@ -265,25 +267,18 @@ function changeElPlayer(playerInfo: any, index: number) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始播放视频流
|
||||
* @param nodeData 播放的节点数据
|
||||
* @param index 播放器的索引信息
|
||||
*/
|
||||
function doPlayer(nodeData: any, index: number = 0) {
|
||||
console.log('index=', index);
|
||||
if (mpegts.isSupported()) {
|
||||
function streamProxy(nodeData: any, cb: Function) {
|
||||
let params = {};
|
||||
// if (nodeData.nvrIp) {
|
||||
// params = {
|
||||
// videoIp: nodeData.nvrIp,
|
||||
// videoPort: nodeData.nvrPort,
|
||||
// factoryNo: nodeData.nvrFactoryNo,
|
||||
// account: nodeData.nvrAccount,
|
||||
// pwd: nodeData.nvrPwd,
|
||||
// channelId: nodeData.nvrChannelNo,
|
||||
// };
|
||||
// } else {
|
||||
if (nodeData.nvrIp) {
|
||||
params = {
|
||||
videoIp: nodeData.nvrIp,
|
||||
videoPort: nodeData.nvrPort,
|
||||
factoryNo: nodeData.nvrFactoryNo,
|
||||
account: nodeData.nvrAccount,
|
||||
pwd: nodeData.nvrPwd,
|
||||
channelId: nodeData.nvrChannelNo,
|
||||
};
|
||||
} else {
|
||||
params = {
|
||||
videoIp: nodeData.deviceIp,
|
||||
videoPort: nodeData.devicePort,
|
||||
@ -292,8 +287,24 @@ function doPlayer(nodeData: any, index: number = 0) {
|
||||
pwd: nodeData.devicePwd,
|
||||
channelId: nodeData.channelNo,
|
||||
};
|
||||
// }
|
||||
addStreamProxy(params).then((res) => {
|
||||
|
||||
if (isSupportH265) {
|
||||
addStreamProxy(params).then((res) => cb(res));
|
||||
} else {
|
||||
addFFmpegStreamProxy(params).then((res) => cb(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始播放视频流
|
||||
* @param nodeData 播放的节点数据
|
||||
* @param index 播放器的索引信息
|
||||
*/
|
||||
function doPlayer(nodeData: any, index: number = 0) {
|
||||
console.log('index=', index);
|
||||
if (mpegts.isSupported()) {
|
||||
streamProxy(nodeData, (res: AddStreamProxyResult) => {
|
||||
const url = res.wsFlv;
|
||||
// 将url 绑定到 nodeData
|
||||
nodeData.url = url;
|
||||
@ -360,8 +371,10 @@ function closePlayer(index: number) {
|
||||
}
|
||||
}
|
||||
|
||||
let isSupportH265 = false;
|
||||
onMounted(() => {
|
||||
// 初始化不加载任何视频
|
||||
// 检测浏览器是否支持h265
|
||||
isSupportH265 = checkHEVCSupport();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
|
@ -27,11 +27,7 @@ export default defineConfig(async () => {
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
// mock代理目标地址
|
||||
// target: 'http://192.168.43.169:8080',
|
||||
// target: 'https://by.missmoc.top/api/',
|
||||
target: 'http://127.0.0.1:8080',
|
||||
// target: 'http://192.168.0.106:8080',
|
||||
// target: 'http://47.109.37.87:3010',
|
||||
ws: true,
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user