前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >视频无法输出?来一键安装InVideo插件

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

作者头像
Jean
发布2022-11-25 19:29:11
4230
发布2022-11-25 19:29:11
举报
文章被收录于专栏:Web行业观察Web行业观察

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-10-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WebHub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Part1前言
  • Part2UGameViewportClient
  • Part3opencv保存mp4
  • Part4存在问题
  • Part5总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档