parent
ab54e66297
commit
c028f200aa
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<div
|
||||
id="app"
|
||||
class="parent"
|
||||
>
|
||||
<video
|
||||
style="width: 100%; height: 100%; object-fit: fill;"
|
||||
ref="video"
|
||||
muted
|
||||
autoplay
|
||||
>
|
||||
</video>
|
||||
<!-- <ptz v-if="ptzShow" :cameraId="cameraId" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ZLMRTCClient } from "../camera/ZLMediaKit-Webrtc-Vue/ZLMRTCClient";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
cameraId: {
|
||||
default: 2,
|
||||
},
|
||||
ptzShow: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
video: null,
|
||||
selfVideo: null,
|
||||
url: null,
|
||||
simulcast: null,
|
||||
useCamera: null,
|
||||
audioEnable: null,
|
||||
videoEnable: null,
|
||||
datachannel: null,
|
||||
msgsend: null,
|
||||
msgrecv: "",
|
||||
streamUrl: "",
|
||||
player: null,
|
||||
recvOnly: true,
|
||||
resolutions: [],
|
||||
resolution: "",
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
cameraId(newCameraId, oldCameraId) {
|
||||
console.log(newCameraId);
|
||||
if (newCameraId !== oldCameraId) {
|
||||
this.getHttp()
|
||||
this.startVideo();
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.video = this.$refs.video;
|
||||
|
||||
this.getHttp()
|
||||
ZLMRTCClient.GetAllScanResolution().forEach((r, i) => {
|
||||
let text = r.label + "(" + r.width + "x" + r.height + ")";
|
||||
this.resolutions.push({
|
||||
text: text,
|
||||
value: r,
|
||||
});
|
||||
});
|
||||
|
||||
this.resolution = this.resolutions[0].text;
|
||||
this.startVideo();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.stopVideo();
|
||||
},
|
||||
methods: {
|
||||
getHttp(){
|
||||
this.streamUrl =
|
||||
|
||||
"http://127.0.0.1:8096/index/api/webrtc?app=live&stream=camera" +
|
||||
this.cameraId +
|
||||
"&type=play";
|
||||
},
|
||||
radioChange(value) {
|
||||
let urlObj = new URL(this.streamUrl);
|
||||
urlObj.searchParams.set("type", value);
|
||||
this.streamUrl = urlObj.href;
|
||||
|
||||
if (value == "play") {
|
||||
this.recvOnly = true;
|
||||
} else if (value == "echo") {
|
||||
this.recvOnly = false;
|
||||
} else {
|
||||
this.recvOnly = false;
|
||||
}
|
||||
},
|
||||
changeResolution(e) {
|
||||
this.resolution = e.target.options[e.target.selectedIndex].text;
|
||||
},
|
||||
start_play() {
|
||||
console.log(this.cameraId);
|
||||
let res = this.resolution.match(/\d+/g);
|
||||
let h = parseInt(res.pop());
|
||||
let w = parseInt(res.pop());
|
||||
|
||||
this.player = new ZLMRTCClient.Endpoint({
|
||||
element: this.video,
|
||||
debug: false,
|
||||
zlmsdpUrl: this.streamUrl,
|
||||
simulecast: false,
|
||||
useCamera: false,
|
||||
audioEnable: false,
|
||||
videoEnable: true,
|
||||
recvOnly: this.recvOnly,
|
||||
usedatachannel: false,
|
||||
resolution: {
|
||||
w: "100px",
|
||||
h: "100px",
|
||||
},
|
||||
});
|
||||
|
||||
this.player.on(
|
||||
ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,
|
||||
(e) => {
|
||||
console.log("ICE 协商出错");
|
||||
}
|
||||
);
|
||||
|
||||
this.player.on(
|
||||
ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,
|
||||
(e) => {
|
||||
console.log("播放成功", e.streams);
|
||||
}
|
||||
);
|
||||
|
||||
this.player.on(
|
||||
ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,
|
||||
(e) => {
|
||||
console.log("offer anwser 交换失败", e);
|
||||
this.stopVideo();
|
||||
}
|
||||
);
|
||||
|
||||
this.player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, (s) => {
|
||||
this.selfVideo.srcObject = s;
|
||||
this.selfVideo.muted = true;
|
||||
});
|
||||
|
||||
this.player.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, (s) => {
|
||||
console.log("获取本地流失败");
|
||||
});
|
||||
|
||||
this.player.on(
|
||||
ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE,
|
||||
(state) => {
|
||||
console.log("当前状态==>", state);
|
||||
}
|
||||
);
|
||||
|
||||
this.player.on(
|
||||
ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_OPEN,
|
||||
(event) => {
|
||||
console.log("rtc datachannel 打开 :", event);
|
||||
}
|
||||
);
|
||||
|
||||
this.player.on(
|
||||
ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_MSG,
|
||||
(event) => {
|
||||
console.log("rtc datachannel 消息 :", event.data);
|
||||
this.msgrecv = event.data;
|
||||
}
|
||||
);
|
||||
|
||||
this.player.on(
|
||||
ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_ERR,
|
||||
(event) => {
|
||||
console.log("rtc datachannel 错误 :", event);
|
||||
}
|
||||
);
|
||||
|
||||
this.player.on(
|
||||
ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_CLOSE,
|
||||
(event) => {
|
||||
console.log("rtc datachannel 关闭 :", event);
|
||||
}
|
||||
);
|
||||
},
|
||||
startVideo() {
|
||||
this.stopVideo();
|
||||
let res = this.resolution.match(/\d+/g);
|
||||
let h = "50%";
|
||||
let w = "50%";
|
||||
this.start_play();
|
||||
},
|
||||
stopVideo() {
|
||||
if (this.player) {
|
||||
this.player.close();
|
||||
this.player = null;
|
||||
}
|
||||
},
|
||||
send() {
|
||||
if (this.player) {
|
||||
this.player.sendMsg(this.msgsend);
|
||||
}
|
||||
},
|
||||
close() {
|
||||
if (this.player) {
|
||||
this.player.closeDataChannel();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.parent {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.operation-item img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
|
||||
.direction-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.direction-item img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,283 @@
|
||||
<template>
|
||||
<div class="ptz-control">
|
||||
<div class="direction-list">
|
||||
<div class="operation-item">
|
||||
<Icon
|
||||
:icon="zoomSubIcon"
|
||||
alt="Zoom In"
|
||||
@mousedown="handleControl('zoomSub', 'start')"
|
||||
@mouseup="handleControl('zoomSub', 'stop')"
|
||||
@mouseleave="handleControl('zoomSub', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<span>变倍</span>
|
||||
<div class="operation-item">
|
||||
<Icon
|
||||
:icon="zoomAddIcon"
|
||||
alt="Zoom Out"
|
||||
@mousedown="handleControl('zoomAdd', 'start')"
|
||||
@mouseup="handleControl('zoomAdd', 'stop')"
|
||||
@mouseleave="handleControl('zoomAdd', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="operation-item">
|
||||
<Icon
|
||||
:icon="focusSubIcon"
|
||||
alt="Focus In"
|
||||
@mousedown="handleControl('focusSub', 'start')"
|
||||
@mouseup="handleControl('focusSub', 'stop')"
|
||||
@mouseleave="handleControl('focusSub', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<span>变焦</span>
|
||||
<div class="operation-item">
|
||||
<Icon
|
||||
:icon="focusAddIcon"
|
||||
alt="Focus Out"
|
||||
@mousedown="handleControl('focusAdd', 'start')"
|
||||
@mouseup="handleControl('focusAdd', 'stop')"
|
||||
@mouseleave="handleControl('focusAdd', 'stop')"
|
||||
/>
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="operation-item">
|
||||
<Icon
|
||||
:icon="irisSubIcon"
|
||||
alt="Iris Open"
|
||||
@mousedown="handleControl('irisSub', 'start')"
|
||||
@mouseup="handleControl('irisSub', 'stop')"
|
||||
@mouseleave="handleControl('irisSub', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<span>光圈</span>
|
||||
<div class="operation-item">
|
||||
<Icon
|
||||
:icon="irisAddIcon"
|
||||
alt="Iris Close"
|
||||
@mousedown="handleControl('irisAdd', 'start')"
|
||||
@mouseup="handleControl('irisAdd', 'stop')"
|
||||
@mouseleave="handleControl('irisAdd', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="leftUpIcon"
|
||||
alt="Left Up"
|
||||
@mousedown="handleControl('leftUp', 'start')"
|
||||
@mouseup="handleControl('leftUp', 'stop')"
|
||||
@mouseleave="handleControl('leftUp', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="upIcon"
|
||||
alt="Up"
|
||||
@mousedown="handleControl('up', 'start')"
|
||||
@mouseup="handleControl('up', 'stop')"
|
||||
@mouseleave="handleControl('up', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="rightUpIcon"
|
||||
alt="Right Up"
|
||||
@mousedown="handleControl('rightUp', 'start')"
|
||||
@mouseup="handleControl('rightUp', 'stop')"
|
||||
@mouseleave="handleControl('rightUp', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="leftIcon"
|
||||
alt="Left"
|
||||
@mousedown="handleControl('left', 'start')"
|
||||
@mouseup="handleControl('left', 'stop')"
|
||||
@mouseleave="handleControl('left', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="centerIcon"
|
||||
alt="Center"
|
||||
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="rightIcon"
|
||||
alt="Right"
|
||||
@mousedown="handleControl('right', 'start')"
|
||||
@mouseup="handleControl('right', 'stop')"
|
||||
@mouseleave="handleControl('right', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="leftDownIcon"
|
||||
alt="Left Down"
|
||||
@mousedown="handleControl('leftDown', 'start')"
|
||||
@mouseup="handleControl('leftDown', 'stop')"
|
||||
@mouseleave="handleControl('leftDown', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="downIcon"
|
||||
alt="Down"
|
||||
@mousedown="handleControl('down', 'start')"
|
||||
@mouseup="handleControl('down', 'stop')"
|
||||
@mouseleave="handleControl('down', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<Icon
|
||||
:icon="rightDownIcon"
|
||||
alt="Right Down"
|
||||
@mousedown="handleControl('rightDown', 'start')"
|
||||
@mouseup="handleControl('rightDown', 'stop')"
|
||||
@mouseleave="handleControl('rightDown', 'stop')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios' // 确保 axios 已经安装并引入
|
||||
import { config } from '@/config/axios/config'
|
||||
import {CameraControlApi} from '@/api/cameraControl/camera'
|
||||
|
||||
const { result_code, base_url, request_timeout } = config
|
||||
export default {
|
||||
props: {
|
||||
cameraId: {
|
||||
default: 2
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
console.log(props.cameraId)
|
||||
// 定义响应式数据
|
||||
const zoomSubIcon = ref('ep:zoom-out') // 替换为实际的图标名称
|
||||
const zoomAddIcon = ref('ep:zoom-in') // 替换为实际的图标名称
|
||||
const focusSubIcon = ref('ep:minus') // 替换为实际的图标名称
|
||||
const focusAddIcon = ref('ep:plus') // 替换为实际的图标名称
|
||||
const irisSubIcon = ref('ep:minus') // 替换为实际的图标名称
|
||||
const irisAddIcon = ref('ep:plus') // 替换为实际的图标名称
|
||||
const leftUpIcon = ref('ep:top-left') // 替换为实际的图标名称
|
||||
const upIcon = ref('ep:arrow-up') // 替换为实际的图标名称
|
||||
const rightUpIcon = ref('ep:top-right') // 替换为实际的图标名称
|
||||
const leftIcon = ref('ep:arrow-left') // 替换为实际的图标名称
|
||||
const centerIcon = ref('ep:aim') // 替换为实际的图标名称
|
||||
const rightIcon = ref('ep:arrow-right') // 替换为实际的图标名称
|
||||
const leftDownIcon = ref('ep:bottom-left') // 替换为实际的图标名称
|
||||
const downIcon = ref('ep:arrow-down') // 替换为实际的图标名称
|
||||
const rightDownIcon = ref('ep:bottom-right') // 替换为实际的图标名称
|
||||
|
||||
const activeIcons = {
|
||||
zoomSub: 'ep:zoom-out-active',
|
||||
zoomAdd: 'ep:zoom-in-active',
|
||||
focusSub: 'ep:minus-active',
|
||||
focusAdd: 'ep:plus-active',
|
||||
irisSub: 'ep:minus-active',
|
||||
irisAdd: 'ep:plus-active',
|
||||
leftUp: 'ep:top-left-active',
|
||||
up: 'ep:arrow-up-active',
|
||||
rightUp: 'ep:top-right-active',
|
||||
left: 'ep:arrow-left-active',
|
||||
center: 'ep:aim-active',
|
||||
right: 'ep:arrow-right-active',
|
||||
leftDown: 'ep:bottom-left-active',
|
||||
down: 'ep:arrow-down-active',
|
||||
rightDown: 'ep:bottom-right-active'
|
||||
}
|
||||
|
||||
// 定义控制方法
|
||||
const handleControl = (action, state) => {
|
||||
console.log(`${action}-${state}`)
|
||||
const iconRef = `${action}Icon`
|
||||
if (state === 'start') {
|
||||
if (activeIcons[action]) {
|
||||
eval(`${iconRef}.value = activeIcons[action]`)
|
||||
}
|
||||
} else if (state === 'stop') {
|
||||
eval(`${iconRef}.value = '${eval(iconRef).value.replace('-active', '')}'`)
|
||||
}
|
||||
const data ={"id":props.cameraId}
|
||||
CameraControlApi.cameraControl(`/camera/control/${action}/${state}`,data)
|
||||
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
// 关闭控制面板的逻辑
|
||||
console.log('关闭控制面板')
|
||||
}
|
||||
|
||||
return {
|
||||
zoomSubIcon,
|
||||
zoomAddIcon,
|
||||
focusSubIcon,
|
||||
focusAddIcon,
|
||||
irisSubIcon,
|
||||
irisAddIcon,
|
||||
leftUpIcon,
|
||||
upIcon,
|
||||
rightUpIcon,
|
||||
leftIcon,
|
||||
centerIcon,
|
||||
rightIcon,
|
||||
leftDownIcon,
|
||||
downIcon,
|
||||
rightDownIcon,
|
||||
handleControl,
|
||||
close
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ptz-control-panel {
|
||||
position: relative; /* 改为绝对定位 */
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
border: 1px solid #ccc;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
z-index: 1000; /* 确保浮在最上层 */
|
||||
}
|
||||
|
||||
.operation-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.operation-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.operation-item img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.direction-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 40px);
|
||||
grid-gap: 5px;
|
||||
}
|
||||
|
||||
.direction-item img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue