前言
假期在家把虚幻引擎像素流的源码有研究了一下,进行了一下总结,本文适合有一定使用虚幻引擎像素流经验的人阅读。
源码地址
这里研究的是UE5.1的版本,源码位置如下
C:\Program Files\Epic Games\UE_5.1\Engine\Plugins\Media\PixelStreaming
websocket处理
像素流和signal服务之间通过websocket进行通信,处理业务的逻辑在FPixelStreamingSignallingConnection这个类中,处理消息的函数如下
void FPixelStreamingSignallingConnection::OnMessage(const FString& Msg)
{
FJsonObjectPtr JsonMsg;
const auto JsonReader = TJsonReaderFactory<TCHAR>::Create(Msg);
if (!FJsonSerializer::Deserialize(JsonReader, JsonMsg))
{
UE_LOG(LogPixelStreamingSS, Error, TEXT("Failed to parse SS message:\n%s"), *Msg);
return;
}
FString MsgType;
if (!JsonMsg->TryGetStringField(TEXT("type"), MsgType))
{
UE_LOG(LogPixelStreamingSS, Error, TEXT("Cannot find `type` field in SS message:\n%s"), *Msg);
return;
}
TFunction<void(FJsonObjectPtr)>* Handler = MessageHandlers.Find(MsgType);
if (Handler != nullptr)
{
(*Handler)(JsonMsg);
}
else
{
UE_LOG(LogPixelStreamingSS, Error, TEXT("Unsupported message `%s` received from SS"), *MsgType);
}
}
一共定义了12种类型的消息处理,如下图
意外发现,居然还有一个PixelStreamServers工程,可以创建signal服务,这样的话,就可以一个虚幻程序,搞定所有,不再需要再启动一个nodejs的signal服务了。websocket服务监听,代码如下:,调用的是WebSocketNetworking这个模块创建的服务端。
相关业务处理逻辑见FSignallingServer这个类,可以管理连接上来的websocket连接。
web与UE通信事件
web和UE的通信事件,在FPixelStreamingModule::PopulateProtocol函数中进行定义,每个事件有一个id。
我们的peerstream里面定义的事件id也是和这里一一对应的。
大家可以看到两边的值是一样的,整个通信,实际上就是通过这个id来进行区分。
UE接受web的消息处理函数为FPixelStreamingDataChannel::OnMessage,
这里所有接受到的数据,都会丢进游戏线程进行处理。这里第一个字节,表示消息类型,所以最大可以定义255种消息。
接下来,业务逻辑处理的函数在FStreamer::OnDataChannelMessage中进行处理。
通过InputHandler对象进行统一处理,其定义如下
InputHandler = MakeShared<FPixelStreamingInputHandler>(PixelStreamerApplicationWrapper, BaseHandler);
整个业务处理封装在FPixelStreamingInputHandler类中,在其定义中,我们发现了根据不同类型的处理函数。
其定义了一个void FPixelStreamingInputHandler::OnMessage(const webrtc::DataBuffer& Buffer)函数,作为统一的消息处理入口。
所有的消息处理,都统一丢到了一个消息处理队列中。最后在tick中进行处理,所以UE接受的数据,都是在游戏线程进行业务逻辑的。
视频处理
视频处理是单独开启了一个线程来抓取图像,在FVideoSourceGroup类中,
根据帧率,定期的调用tick处理函数
图像的抓取,在FVideoSource这个类中进行,并通过OnFrame推送给webrtc库
整个图像的获取封装在FPixelStreamingVideoInput对象中,但是真正的抓取在FPixelCaptureCapturerMultiFormat类中,这个处理都封装在另外一个插件PixelCapture中,位置如下
视频的读取这一块,还没看明白,还需要再研究研究,如何从虚幻引擎读取画面,并推送到webrtc。
蓝图交互
蓝图的交互封装在UPixelStreamingInput这个对象里面,其继承至UActorComponent。其主要是想了两个函数,一个是回调数据给蓝图,一个是发送数据给web。
然后顺便还实现了json的一些简单操作,这里不做介绍。
相关的事件消息封装在UPixelStreamingDelegates对象中,其继承UObject。用户的连接事件、断线事件都是在这里进行处理。
总结
本文大概得研究了一下信令的交互流程,由于内容比较多,还有比较多的细节,需要深入研究。
我的知识星球
请关注公众号g0415shenw 加入知识星球。
星球地址 https://t.zsxq.com/15EvfoA7n
星球有本人经验心得全部总结 涵盖音视频,gb28181、虚幻引擎、其他编程工具等等。另外还可以在星球提问,我会尽力答复,等于给您多了一个引路人。