视频无法输出?来一键安装InVideo插件

2022-11-25 19:29:11 浏览数 (1)

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/ 欢迎点赞分享。

0 人点赞