视频播放同时支持h265和h264播放

This commit is contained in:
15683799673 2025-08-10 19:35:45 +08:00
parent c3f43f6e71
commit 489ec29184
5 changed files with 104 additions and 91 deletions

View File

@ -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,
);
}

View 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;
}

View File

@ -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 {

View File

@ -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,6 +267,35 @@ function changeElPlayer(playerInfo: any, index: number) {
}
}
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 播放的节点数据
@ -273,27 +304,7 @@ function changeElPlayer(playerInfo: any, index: number) {
function doPlayer(nodeData: any, index: number = 0) {
console.log('index=', index);
if (mpegts.isSupported()) {
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,
};
// }
addStreamProxy(params).then((res) => {
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(() => {

View File

@ -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,
},
},