PixelStreaming数据通信
- 简介
- H5到UE4通信
- H5发送
- UE4接收
- UE4到H5通信
- UE4发送
- H5接收
- iframe + postMessage
- 父页面
- 子页面(改造UE4提供的像素流送H5)
- UE4项目bat启动器
- 问题
- * UE4.26像素流送,使用Chrome94版崩溃问题
- * UE4像素流送多个鼠标问题(Web启用了HoverMouse模式,UE4勾选了ShowMouseCursor)
- * UE4.27 setup.ps1无法运行此脚本
- * exe窗口与像素流送分别设置不同的分辨率
- * UE4.27之后的版本默认无法动态更改VideoResolution (控制台命令SetRes导致VideoFrame拉伸)
简介
- 使用UE4.26像素流送方案,启动像素流送插件
- UE4编辑器设置中添加运行参数与打包后exe快捷方式添加命令行参数 -AudioMixer -RenderOffScreen -PixelStreamingIP=localhost -PixelStreamingPort=8888 -PixelStreamingHideCursor -Log
r.setres超过屏幕分辨率无效:需加快捷方式最后处添加参数 NvEncH264ConfigLevel=NV_ENC_LEVEL_H264_52。
参数 | 描述 |
AllowPixelStreamingCommands | 决定播放器网页是否能使用 emitCommand() 函数在虚幻引擎中远程执行控制台命令。注意这可能涉及安全问题,请谨慎处理。 |
-AudioMixer | 强制虚幻引擎使用软件混合音频,以便像素流送插件采集音频。从应用程序采集音频并流送到浏览器需要用到此参数。 |
-PixelStreamingIP=< value > | 必需 |
-PixelStreamingPort=< value > | 必需 |
-PixelStreamingKeyFilter=“< value >” | 像素流送插件应从播放器网页中继至虚幻引擎的输入中过滤掉的键盘键的列表,以逗号分隔。如果在浏览器中按下其中一个键,此事件将不会被中继至虚幻引擎的输入控制器。举例而言,-PixelStreamingKeyFilter=“F1…F12,W,A,S,D” 将过滤掉所有12个功能键和移动键。 |
-PixelStreamingReceiveStringMaxLength | 设置虚幻引擎应用从信令和网页服务器接收的信息的最大长度,以字节为单位。默认值为 1024。 |
-RenderOffScreen | 以headless模式运行虚幻引擎应用程序,本地机上不带任何可见的渲染。应用程序不会显示任何窗口,也不会以全屏渲染。可使用此参数结合 -ForceRes 使虚幻引擎停止基于主显示分辨率自动调整分辨率。如遗漏此参数,虚幻引擎应用程序窗口将正常渲染。如果此应用程序窗口被最小化,像素流送视频和输入采集将停止工作。因此我们推荐固定包含此参数,除非需要在运行时在同一台电脑上本地查看虚幻引擎应用程序的渲染输出。 |
-NvEncFrameRateNum=< value > | 指定后,覆盖默认的编码器帧率。默认值设为匹配 t.MaxFPS。 |
-NvEncMaxEncodeWidth=< value > | 编码器可编码的帧的最大宽度。默认值为 3840。 |
-NvEncMaxEncodeHeight=< value > | 编码器可编码的帧的最大高度。默认值为 2160。 |
-NvEncAverageBitRate=< value > | 指定后,覆盖编码器的默认平均比特率。 |
-NvEncH264ConfigLevel=< value > | 决定H.264的压缩级别:5.2或5.1。如果不设置此参数,解码器将使用5.2级别,可以解码高清分辨率,如3840x2160(4K)。 如果要解码较低的分辨率,可以将此参数设置为 NV_ENC_LEVEL_H264_51 以切换到5.1级别,以节省带宽。 如需了解H.264等级的更多内容,请参阅此页面。如果虚幻引擎应用程序报告其 未能初始化NvEncoder,且正在处理高分辨率输出,则可能需要移除此选项,将压缩级别恢复到5.2。 |
- 复制出引擎目录下的WebServers文件夹
E:\Program Files\Epic Games\UE_4.26\Engine\Source\Programs\PixelStreaming\WebServers - 修改WebServers\player.htm内容
- 运行WebServers\SignallingWebServer\run.bat
- UE4编辑器独立运行游戏
- 测试像素流送
H5到UE4通信
H5发送
- emitCommand 可向游戏发送命令的预设列表、更改分辨率、执行控制台命令,或是降低编码器的码率。
//显示fps
let descriptor = {ConsoleCommand: 'stat fps'}
//重置虚幻引擎程序的渲染分辨率
let descriptor = {
Resolution: {
Width: 1024,
Height: 768
}}
//控制媒体流的质量,此值默认为50%.如部署中出现延迟和视频瑕疵,可进一步降低该值
let descriptor = {
Encoder: {
BitrateReduction: 20
}}
- emitUIInteraction 可向游戏发送任意字符串或JavaScript对象。使用此功能将自定义命令从播放器UI处发射,用户可在gameplay逻辑中响应此类命令以在程序中产生所需效果。
//传递单个字符串
emitUIInteraction("MyCustomCommand");
//传递JavaScript对象,emitUIInteraction 函数会在内部将其转换为JSON字符串
let descriptor = {
LoadLevel: "/Game/Maps/Level_2",
PlayerCharacter: {
Name: "Shinbi",
Skin: "Dynasty"
}}
emitUIInteraction(descriptor);
UE4接收
在程序的gameplay逻辑中,使用 Bind Event to OnPixelStreamingInputEvent 节点绑定自定义事件来处理此类输入。
UE4到H5通信
UE4发送
要将事件发射到播放器页面时可使用 Pixel Streaming > Send Pixel Streaming Response 节点。将自定义字符串参数指定到节点,向播放器页面说明发生的事件内容。
H5接收
- JavaScript中编写自定义事件处理器函数,每当页面从虚幻引擎程序接收到响应事件时将调用该函数。
//显示fps
function myHandleResponseFunction(data) {
console.warn("Response received!");switch (data) {
case "MyCustomEvent":
... // handle one type of event
case "AnotherEvent":
... // handle another event}
}
- 调用 app.js 提供的 addResponseEventListener 函数来注册监听器函数。为事件监听器和函数向此函数传递一个独特命名。
addResponseEventListener("handle_responses", myHandleResponseFunction);
- 如需移除事件监听器,可调用 removeResponseEventListener 并传递相同命名。
removeResponseEventListener("handle_responses");
iframe + postMessage
- 修改app.js(UE4提供的像素流送Web项目文件)
var isStart = false;
webRtcPlayerObj.onDataChannelConnected = function () {
if (ws && ws.readyState === WS_OPEN_STATE) {
showTextOverlay('WebRTC connected, waiting for video');
setTimeout(()=>
{
isStart = true;
<!-- 其他代码省略 -->
}, 500);
}
};
父页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<style type="text/css">
iframe {
width: 960px;
height: 540px;
}
</style>
</head>
<body>
<button id="button">给子页面发消息</button>
<iframe id="iframe" src="http://127.0.0.1:81"></iframe>
<script>
window.addEventListener('message', e=> {
console.log(e.data)
});
var button = document.getElementById('button');
let iframe = document.getElementById('iframe');
button.onclick = function(){
<!-- iframe.contentWindow.postMessage('hello from parent', 'http://127.0.0.1:80') -->
iframe.contentWindow.postMessage('hello from parent', '*')
}
</script>
</body>
</html>
子页面(改造UE4提供的像素流送H5)
<!DOCTYPE HTML>
<html>
<head>
<link rel="shortcut icon" href="/images/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="96x96" href="/images/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png">
<link type="text/css" rel="stylesheet" href="player.css">
<script type="text/javascript" src="scripts/adapter-latest.js"></script>
<script type="text/javascript" src="scripts/webRtcPlayer.js"></script>
<script type="text/javascript" src="scripts/app.js"></script>
</head>
<body onload="load()">
<div id="playerUI">
<div id="player"></div>
<div id="overlay" class="overlay">
<div>
<div id="qualityStatus" class="greyStatus">●</div>
<div id="overlayButton">+</div>
</div>
<div id="overlaySettings">
<div id="KickOthers">
<div class="settings-text">Kick all other players</div>
<label class="btn-overlay">
<input type="button" id="kick-other-players-button" class="overlay-button btn-flat" value="Kick">
</label>
</div>
<div id="FillWindow">
<div class="settings-text">Enlarge Display to Fill Window</div>
<label class="tgl-switch">
<input type="checkbox" id="enlarge-display-to-fill-window-tgl" class="tgl tgl-flat" checked>
<div class="tgl-slider"></div>
</label>
</div>
<div id="QualityControlOwnership">
<div class="settings-text">Quality control ownership</div>
<label class="tgl-switch">
<input type="checkbox" id="quality-control-ownership-tgl" class="tgl tgl-flat">
<div class="tgl-slider"></div>
</label>
</div>
<div id="statsSetting">
<div class="settings-text">Show Stats</div>
<label class="tgl-switch">
<input type="checkbox" id="show-stats-tgl" class="tgl tgl-flat" checked>
<div class="tgl-slider"></div>
</label>
<div id="statsContainer">
<div id="stats"></div>
</div>
</div>
</div>
</div>
</div>
<script>
inputOptions.controlScheme = ControlSchemeType.HoveringMouse;
<!-- inputOptions.fakeMouseWithTouches = true; -->
styleAdditional = 'cursor: default; cursor: -moz-default; cursor: -webkit-default';
function SendMessage(data){
emitUIInteraction(data);
};
function SendJsonMessage(data){
if(!isStart)
return;
let jsonStr = JSON.stringify(data); //.replace(/[\\]/g,'')
console.log(jsonStr);
emitUIInteraction(jsonStr);
};
function HandleResponse(data) {
if(!isStart)
return;
console.log("-------------UE4_To_H5Parent-----------------");
top.postMessage(data, '*');
console.log(data);
};
addResponseEventListener("handle_responses", HandleResponse);
window.addEventListener('message',function(event){
if(!isStart)
return;
console.log("-------------H5Parent_To_UE4-----------------");
console.log(event.data);
emitUIInteraction(event.data);
}, false);
</script>
</body>
</html>
UE4项目bat启动器
UE4项目打包目录下创建Run.bat代替创建exe快捷方式(以便其他电脑上运行也有效)
注:Demo.exe根据实际名修改
@echo off
cd %~dp0
start Demo.exe -AudioMixer -RenderOffScreen -PixelStreamingIP=localhost -PixelStreamingPort=8888 -Log
exit
问题
* UE4.26像素流送,使用Chrome94版崩溃问题
解决办法:添加一行代码
offer.sdp = offer.sdp.replace(/(a=extmap-allow-mixed)\r\n/gm, "");
* UE4像素流送多个鼠标问题(Web启用了HoverMouse模式,UE4勾选了ShowMouseCursor)
解决办法1:
快捷方式添加 -PixelStreamingHideCursor
解决办法2:
1.隐藏UE4像素流送模式下的光标:UE4的ProjectSettings -> PixelStreaming -> DefaultCursorClass使用HiddenCursor
2.SignallingWebServer鼠标模式设置
// player.htm内容设置鼠标模式 inputOptions.controlScheme = ControlSchemeType.HoveringMouse; styleAdditional = 'cursor: default; cursor: -moz-default; cursor: -webkit-default';
* UE4.27 setup.ps1无法运行此脚本
解决办法:
管理员运行Windows PowerShell执行命令,Y确认 set-ExecutionPolicy RemoteSigned //Y确认 ./setup.ps1 //回车安装
* exe窗口与像素流送分别设置不同的分辨率
解决办法:PlayerController的BeginPlayer中执行控制台命令
PixelStreaming.Capturer.UseBackBufferSize false
PixelStreaming.Capturer.CaptureSize 960x540
* UE4.27之后的版本默认无法动态更改VideoResolution (控制台命令SetRes导致VideoFrame拉伸)
解决办法:DRC 0