Part1前言
在虚幻引擎程序运行时,如果将画面保存为mp4的文件?通过InVideo插件的一个函数即搞定。本文主要介绍其实现思路。
Part2UGameViewportClient
游戏视区(FViewport)是平台特定渲染、音频和输入子系统的高级抽象接口。GameViewportClient是引擎与游戏视口的接口。为每个游戏实例创建一个GameViewportClient。我们能看到的画面都可以通过重载Draw函数进行获取。
代码语言:javascript复制virtual void Draw(FViewport* InViewport, FCanvas* SceneCanvas) override;
获取画面的宽高,通过如下方法
代码语言:javascript复制 int BitmapX = InViewport->GetSizeXY().X;
int BitmapY = InViewport->GetSizeXY().Y;
获取画面的rgb数据,通过如下方法
代码语言:javascript复制SceneViewport->ReadPixels(Bitmap, FReadSurfaceDataFlags());
Part3opencv保存mp4
这里我们将获取到的rgb数据,先转成cv::Mat,在通过cv::VideoWriter进行写mp4。虚幻的图像数据转成cv::Mat格式如下
代码语言:javascript复制 int length = Bitmap.Num() * 3;
m_ImageBuf = new char[length];
int count = 0;
for (int i = 0; i < Bitmap.Num(); i )
{
m_ImageBuf[count] = Bitmap[i].B;
m_ImageBuf[count 1] = Bitmap[i].G;
m_ImageBuf[count 2] = Bitmap[i].R;
count = 3;
}
cv::Mat img(m_ImageY,m_ImageX,CV_8UC3, (unsigned char*)m_ImageBuf);
这里需要特别注意,在生成Mat的时候需要设置为CV_8UC3格式。因为我们是rgb三种颜色。Mat不会重新创建一段内存,会复用之前的m_ImageBuf内存空间。如果要用Mat的内部内存管理机制,需要自己重新深拷贝一份。
代码语言:javascript复制auto newImg = img.clone();
有了Mat格式之后,我们就可以保存视频了,流程如下 先调用open
代码语言:javascript复制m_WrapOpenCv->m_VideoWriter.open(cvFilePath, cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), m_Fps, cv::Size(m_ImageX, m_ImageY));
之后每一帧过来,都写进去
代码语言:javascript复制m_WrapOpenCv->m_VideoWriter.write(img);
结束之后,调用关闭命令
代码语言:javascript复制m_WrapOpenCv->m_VideoWriter.release();
Part4存在问题
上面的做法,是在游戏线程进行mp4文件的录制,这样最大的问题是会影响游戏的帧率,因为视频编码其实是一个非常耗费资源的事情,所以我们需要将其移植到子线程来。 这里引入了FRunnable和TQueue。FRunnable用来实现一个子线程,TQueue用来实现一个多线程安全的队列,方便我们进行数据在多线程的传递。 创建线程如下:
代码语言:javascript复制m_Thread = FRunnableThread::Create(this, TEXT("SceneRecord Thread"));
增加数据到队列
代码语言:javascript复制m_WrapOpenCv->m_ImageQueue.Enqueue(newImg);
子线程取出数据并处理
代码语言:javascript复制 if (false == m_WrapOpenCv->m_ImageQueue.IsEmpty())
{
cv::Mat img;
m_WrapOpenCv->m_ImageQueue.Dequeue(img);
m_WrapOpenCv->m_VideoWriter.write(img);
continue;
}
Part5总结
本文主要实现了如何在运行时保存虚幻引擎的画面成mp4,考虑到视频编码对性能的消耗较大,我们将整个mp4视频的保存放到了子线程中进行,这样会游戏线程的帧率几乎没有影响。github地址如下:https://github.com/inveta/InVideo/ 欢迎点赞分享。