明日之后今日头条客户端
1.90 GB · 2025-11-14
一个基于Vue3的实时视频流显示系统,主要用于连接和显示Unreal Engine (UE) 服务器的实时渲染内容。该页面集成了PixelStreaming技术和MQTT通信协议,提供了完整的视频流控制和交互功能。
实时视频流显示:连接UE服务器,显示实时渲染的3D场景
协议支持:支持PixelStreaming连接
MQTT通信:通过MQTT协议进行消息通信和控制
连接状态监控:实时显示UE和MQTT连接状态
错误处理与重连:自动处理连接错误并尝试重连
npm install @epicgames-ps/lib-pixelstreamingfrontend-ue5.3npm install @epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.3npm install mqtt
确保UE服务器运行
确保MQTT服务器运行
前端框架: Vue 3 (Composition API)
视频流技术: Epic Games PixelStreaming
消息协议: MQTT
PixelStreaming链接
MQTT连接(消息通信)
<template>链接链接 <div class="scene-display-container"> <!-- 连接状态 --> <div class="connection-status"> <span>UE: {{ ueStatus }}</span> <span>MQTT: {{ mqttStatus }}</span> </div> <!-- 视频流容器 --> <div class="video-container"> <div id="streamingVideo" class="streaming-video"></div> <!-- 错误状态 --> <div v-if="errorMessage" class="error-overlay"> <p>{{ errorMessage }}</p> <button @click="reconnect">重新连接</button> </div> </div> </div></template>说明:
connection-status:显示UE和MQTT的连接状态
video-container:视频流显示容器
error-overlay:错误状态覆盖层,提供重新连接功能
// 响应式数据const errorMessage = ref('') // 存储错误信息const ueStatus = ref('未连接') // UE连接状态const mqttStatus = ref('未连接') // MQTT连接状态// 实例let pixelStreaming = null // PixelStreaming实例let mqttClient = null // MQTT客户端实例// 初始化UE连接const initPixelStreaming = () => { try { const style = new PixelStreamingApplicationStyle(); style.applyStyleSheet(); Logger.SetLoggerVerbosity(1); const config = new Config({ useUrlParams: false }); config.setFlagEnabled(Flags.AutoPlayVideo, true); config.setFlagEnabled(Flags.AutoConnect, true); config.setTextSetting(TextParameters.SignallingServerUrl, "此处输入UE服务器地址"); config.setFlagEnabled(Flags.HoveringMouseMode, ControlSchemeType.HoveringMouse); config.setFlagEnabled(Flags.MouseInput, true); config.setFlagEnabled(Flags.KeyboardInput, true); config.setFlagEnabled(Flags.TouchInput, true); config.setFlagEnabled(Flags.GamepadInput, false); config.setFlagEnabled(Flags.XRControllerInput, false); pixelStreaming = new PixelStreaming(config); const application = new Application({ stream: pixelStreaming, settingsPanelConfig: { isEnabled: false, visibilityButtonConfig: { creationMode: UIElementCreationMode.Disable } }, statsPanelConfig: { isEnabled: false, visibilityButtonConfig: { creationMode: UIElementCreationMode.Disable } }, fullScreenControlsConfig: { creationMode: UIElementCreationMode.Disable }, xrControlsConfig: { creationMode: UIElementCreationMode.Disable }, videoQpIndicatorConfig: { disableIndicator: true }, }); const container = document.getElementById("streamingVideo"); if (container) { container.innerHTML = ''; container.appendChild(application.rootElement); } setupPixelStreamingEvents(); } catch (error) { errorMessage.value = `UE连接失败: ${error}`; }}配置说明:
AutoPlayVideo: true:自动播放视频
AutoConnect: true:自动连接
SignallingServerUrl:信令服务器地址
HoveringMouseMode:鼠标悬停模式
各种输入控制:鼠标、键盘、触屏等
// 设置PixelStreaming事件监听器const setupPixelStreamingEvents = () => { if (!pixelStreaming) return pixelStreaming.addEventListener('streamReady', () => { ueStatus.value = '已连接' errorMessage.value = '' }) pixelStreaming.addEventListener('connectionEstablished', () => { ueStatus.value = '已连接' errorMessage.value = '' }) pixelStreaming.addEventListener('connectionClose', () => { ueStatus.value = '连接断开' }) pixelStreaming.addEventListener('connectionError', (error) => { ueStatus.value = '连接失败' errorMessage.value = `UE连接错误: ${error}` }) pixelStreaming.addEventListener('webRTCConnected', () => { ueStatus.value = '已连接' }) pixelStreaming.addEventListener('webRTCDisconnected', () => { ueStatus.value = '连接断开' })}事件说明:
streamReady:视频流准备就绪
connectionEstablished:连接建立成功
connectionClose:连接关闭
connectionError:连接错误
webRTCConnected:WebRTC连接成功
webRTCDisconnected:WebRTC连接断开
// 初始化MQTT连接const initMqtt = () => { try { const options = { username: 'admin', password: 'public', clientId: `vue_client_${Math.random().toString(16).substr(2, 8)}`, clean: true, reconnectPeriod: 5000, connectTimeout: 30 * 1000, keepalive: 60, protocolVersion: 4 } mqttClient = mqtt.connect('此处输入MQTT地址', options) // 地址末尾需要加:/mqtt mqttClient.on('connect', () => { mqttStatus.value = '已连接' mqttClient.subscribe('此处输入订阅主题的路径') }) mqttClient.on('error', (error) => { mqttStatus.value = '连接失败' }) mqttClient.on('close', () => { mqttStatus.value = '连接断开' }) mqttClient.on('message', (topic, message) => { // 处理MQTT消息 console.log(`收到MQTT消息 [${topic}]: ${message.toString()}`) }) } catch (error) { mqttStatus.value = '初始化失败' }}MQTT配置说明:
username/password:MQTT认证信息
clientId:客户端唯一标识
reconnectPeriod:重连间隔(5秒)
connectTimeout:连接超时(30秒)
keepalive:心跳间隔(60秒)
const reconnect = () => { errorMessage.value = '' if (pixelStreaming) { try { pixelStreaming.close() } catch (error) { console.warn('PixelStreaming断开连接时出错:', error) } pixelStreaming = null } if (mqttClient) { mqttClient.end() mqttClient = null } ueStatus.value = '未连接' mqttStatus.value = '未连接' setTimeout(() => { initPixelStreaming() initMqtt() }, 1000)}重连流程:
清空错误信息
关闭现有连接
重置状态
延迟1秒后重新初始化
// 生命周期onMounted(() => { initPixelStreaming() initMqtt()})onUnmounted(() => { if (pixelStreaming) { try { pixelStreaming.close() } catch (error) { console.warn('PixelStreaming清理时出错:', error) } } if (mqttClient) { mqttClient.end() }})说明:
onMounted:组件挂载时初始化连接
onUnmounted:组件卸载时清理连接
// 检查网络连接const checkNetworkConnection = () => { const testUrl = 'wss://192.168.110.176' const testSocket = new WebSocket(testUrl) testSocket.onopen = () => { console.log('网络连接正常') testSocket.close() } testSocket.onerror = (error) => { console.log(`网络连接失败: ${error}`) console.log('请检查服务器地址和网络连接') }}// MQTT连接测试const testMqttConnection = () => { const testClient = mqtt.connect('ws://192.168.110.176:8083/mqtt', { username: 'admin', password: 'public', clientId: `test_client_${Date.now()}`, clean: true, connectTimeout: 5000 }) testClient.on('connect', () => { console.log('MQTT连接成功') testClient.end() }) testClient.on('error', (error) => { console.log(`MQTT连接失败: ${error.message}`) console.log('请检查MQTT服务器状态和认证信息') testClient.end() })}nativeWebSocket.onclose = (event) => { console.log(`UE WebSocket连接已关闭 (代码: ${event.code})`) isConnected.value = false connectionStatus.type = 'danger' connectionStatus.text = '连接断开' // 自动重连 if (event.code !== 1000) { // 不是正常关闭 console.log('5秒后尝试重新连接...') setTimeout(() => { if (!isConnected.value) { initNativeWebSocket() } }, 5000) }}const mqttOptions = { reconnectPeriod: 5000, // 5秒重连间隔 connectTimeout: 30 * 1000, // 30秒连接超时 keepalive: 60 // 60秒心跳}