简介:面向UE5开发者的实时录屏方案资料包,基于FFmpeg实现跨平台(Windows/Linux)屏幕捕获与视频编码,弥补UE5原生不带录屏功能的短板。包内共570个文件,以h头文件、c/cpp源码、dll/lib/a/so等静态与动态库为主体,并包含pdb调试符号和docx、md、html使用文档,压缩包大小约164MB,集成时可直接参考库结构与示例。已有3005人学习下载。该资源并非单纯脚本,而是成体系的插件工程:uplugin接入文件、封装好的FFmpeg接口类、多平台预编译库及详细说明文档一并呈现,可省去自行编译FFmpeg、梳理API的繁琐;按文档配置分辨率、帧率、编码格式即可在UE5中完成实时录制,适合需要快速落地录屏功能或深入研究UE渲染与FFmpeg编码原理的中高级开发者。 用UE5做实时录屏,绕不开一个真问题:引擎自带方案要么不够快,要么不够灵活。我之前在项目里试过Movie Render Queue、UMG截图、甚至直接录屏软件,折腾一圈下来,还是决定基于FFmpeg自己封装一个UE5实时录屏插件。这篇文章把我踩过的坑、调过的参数、验证过的流程都整理出来,涵盖选型理由、像素数据链路、编码参数、音频处理和实测数据,希望能帮准备做同样事情的朋友少走弯路。
1. 为什么UE5内置方案满足不了"实时"两个字
1.1 Movie Render Queue:画质拉满,但和实时无关
Movie Render Queue是UE5里很多人第一个想到的录屏方案。它确实强大,支持TAA、光追、高质量抗锯齿、分帧渲染,输出画面可以达到电影级。但它的问题也非常明显:它不是为"实时"设计的。哪怕只是1080P分辨率,用Movie Render Queue渲染一帧可能就需要几十毫秒甚至几百毫秒,而且它会暂停或显著降低游戏主循环的运行频率,保证每帧都是最高质量。
这意味着两件事:第一,录制过程中玩家或测试人员的操作会明显卡顿,甚至出现输入延迟;第二,录出来的视频帧率不是稳定的60帧,而是"渲染完成多少帧就记录多少帧",后期还得重新对齐时间轴。做产品演示、操作录屏、自动化测试留档的时候,这种体验很难接受。
1.2 实时录屏的三个硬指标
我理解的实时录屏,至少要满足三个硬指标:
- 录制过程不阻塞主线程:游戏画面和逻辑继续流畅运行,帧率不能有明显掉落。
- 输出帧率稳定可控:不管场景有多复杂,最终生成的视频应该保持设定帧率,比如30FPS或60FPS。
- 内容与视口一致:记录的是玩家实际看到的画面,包括UI、瞄准镜、准星等HUD元素。
Movie Render Queue满足不了第三点(它默认不捕获UMG),更满足不了第一点。UE5自带的Scene Capture 2D组件倒是可以实时捕获场景,但它捕获的是单独的SceneCapture渲染目标,需要自己处理HUD叠加、分辨率适配、编码输出,等于把半个播放器功能全部重写一遍。相比之下,直接对最终视口做像素拷贝,再把数据喂给FFmpeg,才是更务实的技术路线。
2. FFmpeg接入前的选型与环境准备
2.1 为什么绕不开FFmpeg
有人可能会问:直接用Windows的Media Foundation,或者用一个现成的录屏库,不是更简单吗?确实可以,但FFmpeg的优势在于它把"编码器"和"容器"完全解耦。你只需要给它原始像素数据,它就能输出MP4、MOV、MKV、TS、FLV,编码器可以是H.264、H.265、VP9,甚至可以走RTMP协议推流。这意味着同一条像素数据管线,既能落盘成文件,也能直播出去。
另外,FFmpeg的硬件编码支持非常成熟。NVIDIA显卡用h264_nvenc,AMD显卡用h264_amf,Intel核显用h264_qsv,实测下来编码器的CPU占用可以压得非常低。我用NVIDIA RTX 3060跑1080P 60帧录制,h264_nvenc的CPU占用基本在2%到5%之间,几乎没有感知。这点对游戏项目来说非常重要,编码环节如果吃掉大量CPU,游戏本身的帧率就会崩。
2.2 三个平台的环境准备
FFmpeg的接入方式取决于目标平台,我这里主要讲最常见的三种:
Windows:从FFmpeg官网下载static build版本,解压后把bin目录加入系统PATH。然后把FFmpeg程序路径写进插件配置项,这样在引擎里通过FPlatformProcess::CreateProc拉起进程时,能直接通过文件名找到可执行文件。下载时注意选择win64版本,不要选win32,UE5打包出来的目标基本都是64位。
Linux:多数发行版可以直接通过apt或yum安装,比如CentOS 7上用
yum install ffmpeg,Ubuntu上用apt install ffmpeg。但要注意,默认源里的FFmpeg版本通常比较旧,如果想用较新的硬件编码特性,推荐自己编译,编译时加上--enable-nvenc --enable-cuda --enable-nonfree这些选项。Android:安卓端接入FFmpeg要复杂一些,通常需要交叉编译FFmpeg的so库,再通过JNI调用。这条路实现成本高,但如果项目确实需要在移动端实时录屏,可以用RenderDoc或者系统级录屏API做替代方案,不一定要硬啃FFmpeg。我自己的项目在移动端优先用Android原生MediaCodec,FFmpeg方案只保留在PC端。
2.3 启动FFmpeg进程的两种姿势
在UE5里启动FFmpeg,常见有两条路:
一种是直接用FPlatformProcess::CreateProc启动一个独立的ffmpeg.exe进程,把参数通过命令行传给它。这种方式最简单,FFmpeg进程独立于游戏进程,崩溃也不会连带游戏崩溃,而且编码过程天然不占用游戏线程。缺点是需要管理进程生命周期,录制结束时必须向它的stdin发送q命令或关闭管道,否则FFmpeg可能一直等数据。
另一种是把FFmpeg静态链接进插件,通过调用libavcodec、libavformat的API直接在进程内编码。这种方式控制力最强,没有进程间通信的开销,但因为要把整个FFmpeg库编进项目中,工程配置复杂,还牵扯到很多许可证和链接参数问题。对多数项目来说,第一种方式"外挂进程+管道喂数据"已经足够稳定,我最终选的就是这个方案。
3. 插件核心链路:像素、管道与编码参数
3.1 拿像素:RenderTarget 与 RHI ReadPixels 的选择
要把画面实时喂给FFmpeg,第一步是拿到当前帧的像素数据。最直接的方案是用USceneCaptureComponent2D捕获到RenderTarget,再调用RenderTarget的ReadPixels把像素读回CPU内存。但这个方案有个坑:ReadPixels在内部会等待渲染线程完成所有GPU工作,读取期间游戏线程会被阻塞,高分辨率下这个阻塞时间非常可观。
更好的做法是使用RHI层的FTexture2DRHIRef和RHILockTexture2D,在RenderThread上直接锁纹理并读取像素,把数据拷贝到共享缓冲区,再通过异步队列交给业务线程处理。这个流程虽然代码量大一些,但好处是读取操作不阻塞游戏线程的逻辑,帧率波动小很多。项目里如果允许一定延迟,也可以考虑在渲染线程做ENQUEUE_RENDER_COMMAND,把像素数据拷到环形缓冲区,然后由独立线程统一写入FFmpeg管道。
3.2 喂数据:管道缓冲与阻塞控制
拿到像素数据之后,接下来就是把它写进FFmpeg标准输入管道。Windows上这里要注意一个细节:不能用标准的fopen("pipe:")来做,因为FFmpeg从stdin读取数据是典型的生产者消费者模型,游戏线程如果无脑往管道里写,而编码器一时处理不过来,管道缓冲区满了之后写操作会阻塞整个游戏线程。解决办法就是开一个独立的输出线程,专门负责从像素环形缓冲区取出数据并写入管道。游戏线程只做"入队",输出线程负责"出队+写管道",两者之间用无锁队列或条件变量做同步。
实测中1080P 60帧的裸像素数据量大约是1920×1080×4×60,约497MB每秒,管道吞吐压力不小。建议把像素格式设为RGBA或BGRA,并配合FFmpeg的-f rawvideo输入格式,不用额外做像素格式转换,能省下不少CPU开销。可以在写入管道前先记录WriteFile的返回值和错误码,一旦出现管道关闭,立刻停止写入并通知录制线程结束。
3.3 音频:最容易翻车的环节
视频画面做通了,音频往往才是翻车高发地。若直接录系统输出音频,Windows下需要借助WASAPI loopback,这需要写C++代码通过Core Audio API抓取默认音频设备的数据。这么做的问题在于:当系统采样率不是44.1kHz或48kHz时,数据对齐和重采样很容易出问题,时间一长音画不同步就非常明显。
我当时的做法是引擎内直接拿音频回调里的PCM数据,也就是通过FAudioDevice的混音回调抓取最终混音输出,再按固定采样率把PCM写入FFmpeg。这样音源来自引擎内部,和画面天然同步,不依赖操作系统音频架构。如果只想录麦克风声音或伴奏音乐,也可以在这个回调上做数据混合。注意写音频数据时,也要走独立线程,避免混音回调里直接做文件Io调用。
3.4 一套可以直接抄的 FFmpeg 命令模板
把像素和音频数据都准备好之后,FFmpeg命令行可以这样组织:
ffmpeg -y \ -f rawvideo -pix_fmt bgra -s 1920x1080 -r 60 -i pipe:0 \ -f s16le -ar 48000 -ac 2 -i pipe:1 \ -c:v h264_nvenc -preset p1 -b:v 24M -maxrate 28M -bufsize 48M \ -g 120 -bf 0 \ -c:a aac -b:a 192k \ -movflags +faststart \ output.mp4几个参数我解释一下,避免后面大家踩坑:
-y:强制覆盖已存在的输出文件。如果不加这个参数,FFmpeg发现目标文件已存在时会停下来等待用户输入,导致进程卡住,游戏线程也可能跟着挂起。-f rawvideo:输入格式是原始视频流,不是某个具体封装格式。-c:v h264_nvenc:使用NVIDIA硬件编码。没有N卡可以换成h264_amf或h264_qsv。-preset p1:NVENC的快速预设,对实时场景友好。这里p1是延迟最低的一档,画质相比p7略低,但实时录制足够用了。-g 120:关键帧间隔为120帧,也就是每2秒一个关键帧。这样视频拖动进度条时定位更快。-bf 0:关闭B帧。B帧会引入额外的解码顺序和延迟,对实时录屏来说不是必需的,关闭之后兼容性也更好。
4. 实测性能与高频坑的完整排查
4.1 1280、1080P、4K 三档实测
我在一个普通的中型场景里跑了三档分辨率的实测,配置是i5-12400F + RTX 3060 + 16GB内存,场景内有动态光源、粒子特效和若干粒子系统。结果如下:
| 分辨率 | 帧率目标 | 录制时游戏帧率 | 编码器CPU占用 | 输出文件大小(10秒) |
|---|---|---|---|---|
| 1280x720 | 60 | 59~60 | 2%~4% | 约18MB |
| 1920x1080 | 60 | 56~60 | 3%~6% | 约30MB |
| 3840x2160 | 30 | 28~30 | 8%~12% | 约52MB |
需要注意,4K分辨率下即使帧率目标只有30帧,像素读取和管道写入的开销也明显增大,主要原因在于ReadPixels过程涉及大块显存数据回读,GPU的同步等待周期变长。如果项目必须4K实时录屏,建议把像素读取频率降到30帧,或者改用GPU直拷贝(如CUDA互操作)的进阶方案。
4.2 坑一:录出来的视频只有前几帧
这个坑出现的频率极高。现象是视频文件能生成,但打开一看只有前几帧,后面全黑或者直接结束。
排查链路是这样的:先确认FFmpeg进程是否正常启动,再看管道是否关闭。正常情况下,如果游戏线程写入速度跟不上,管道缓冲区会阻塞;但FFmpeg读不到数据时会报pipe:0: Input/output error,然后直接退出,退出之后写入端自然失败,文件只保留已写入的数据。这个问题的根因往往是输出线程没有及时启动,或者写入数据的格式和-s、-pix_fmt参数不一致,导致FFmpeg解析失败后退出。
我当时的修复方式是把写入线程的优先级调高,并且在写入前做一次数据长度校验,确保每次写入的一帧数据字节数等于width * height * 4。同时加了一个心跳监测:如果5秒内FFmpeg没有产出任何数据,就把它的进程信息和退出码记录到日志里。
4.3 坑二:内存持续上涨
接上FFmpeg之后,如果不做任何处理直接跑,一段时间后内存占用会以肉眼可见的速度往上涨。这个问题的原因通常是两个:
一是每次ReadPixels都新建了FColor数组,但释放时机拖到了GC,导致内存堆积。应当使用对象池或者复用同一个TArray<FColor>,每次读取前Reset,这样分配次数会大幅减少。
二是FFmpeg管道写入端读取得慢,像素数据在环形缓冲区里堆积。环形缓冲区的设计容量如果不受限,视频数据就会越堆越多。解决办法是缓冲区满时主动丢帧,而不是无限等待。对实时录屏来说,偶尔丢一帧比内存溢出好得多。我后来在环形缓冲区里加了一个"最大滞留帧数"参数,超过该值时直接覆盖最旧数据,实测效果很稳定。
4.4 坑三:音频漂移与画面不同步
音频漂移的经典表现是:视频开头音画同步,5分钟之后声音滞后画面一两秒。这个问题多半是因为音频写线程和视频写线程使用了不同的时间基准。
用引擎音频回调拿PCM数据时,音频是按固定采样率(比如48000Hz)产生的,理论上每秒采样数是恒定的。但如果系统音频设备切换了采样率,或者引擎的音频缓冲区配置被改动,实际写入的PCM数据总时长就会和视频帧数对不上。
我当时在插件里做了一个简单的时钟校准:每写入一个音频包,就统计已写入的采样数;每写入一帧视频数据,就统计已写入的帧数。通过已写入采样数 / 采样率和已写入帧数 / 帧率这两个绝对时间戳做差,如果偏差超过200毫秒,就丢弃或补齐一段静音数据,强行把时间轴拉回来。这个方法虽然有点暴力,但在实测中效果非常好,长时间录制也不会漂移。
4.5 坑四:fade滤镜没有渐隐效果
使用FFmpeg做后期处理时,很多人会在录制命令里加-vf fade=t=in:st=0:d=0.5,但实测发现视频并没有出现渐隐效果。我之前排查发现,问题往往不是命令写错,而是滤镜插入的位置不对。
FFmpeg的滤镜可以作用在编码前,也可以作用在输出端。如果同时使用了scale和fade,比如-vf scale=1280:720,fade=t=in:st=0:d=0.5,处理顺序是从左到右,先缩放再渐隐,这本身没问题。但如果把fade放在某个不支持透明通道的格式之后,或者滤镜数量过多导致被系统忽略,就容易出现"看起来没效果"的情况。建议单独测试滤镜链,不用rawvideo输入的时候,先拿一个普通视频文件验证fade是否正常,再回到录制命令里排查。
4.6 关于MovieWriter ffmpeg unavailable的提示
如果你用的是UE5编辑器自带的Movie Render Queue录制,并安装了FFmpeg相关的MovieWriter插件,可能会遇到ffmpeg unavailable的报错。这个报错多数情况是引擎路径里找不到ffmpeg可执行文件。去项目设置里检查MovieWriter插件配置中的FFmpeg路径是否正确,并把目录加入系统PATH再重启编辑器,基本能解决。
5. 从录制到直播:管线的进一步扩展
5.1 录制改推流,真的只差一行参数
写本地MP4的命令和推流的命令,差别其实很小。只要把输出部分改成RTMP地址,FFmpeg就会自动切换封装:
ffmpeg -y \ -f rawvideo -pix_fmt bgra -s 1920x1080 -r 60 -i pipe:0 \ -f s16le -ar 48000 -ac 2 -i pipe:1 \ -c:v h264_nvenc -preset p1 -b:v 6M -maxrate 8M -bufsize 12M \ -c:a aac -b:a 128k \ -f flv rtmp://your-server/live/stream_key注意推流场景下码率要控制得更保守一些。本机录制可以开24Mbps,直播推流如果带宽不够,24Mbps会导致画面花屏或断流。我在实测中把1080P推流码率设置在6Mbps左右,配合-preset p1的硬编码延迟,整体延迟可以控制在1到2秒内,用于项目演示直播完全够用。
5.2 画中画、水印与分片录制
视频处理管线里还可以加画中画和文字水印,需要用到-filter_complex。例如:
ffmpeg -i pipe:0 -i logo.png \ -filter_complex "[0:v][1:v]overlay=20:20[out]" \ -map "[out]" -map 0:a \ -c:v h264_nvenc -preset p1 \ output.mp4这里把logo.png叠加在视频左上角(20, 20)的位置。画中画同理,可以用两个视频输入,用overlay滤镜把第二个画面叠加到主画面右下角。这个功能在做"游戏画面+摄像头画面"的产品演示时非常实用。
如果录制时长很长,还可以用FFmpeg的HLS muxer边录边切片:
ffmpeg [...] -f hls -hls_time 10 -hls_list_size 0 output.m3u8这样即使录制过程中程序意外退出,已经生成的TS切片也不会丢失,恢复后还能继续拼接。
5.3 把录制控制接入外部系统
录屏插件不能只靠界面按钮控制。我在项目中通过UE5的WebSocket和串口通讯来接收外部指令,比如在自动化测试脚本里通过WebSocket发一条"start_record"消息,插件收到后就开始拉UE5的画面数据并启动FFmpeg进程。这样录屏动作可以和测试流程、设备状态联动,不需要人一直盯着编辑器。
这种方式对做长期无人值守的演示项目特别有用。可以做成一个常驻的采集节点,接收外部命令,控制录制开始、停止、推流切换,甚至上报录屏状态和磁盘剩余空间。往外延伸一点,就是用UE5 Python脚本驱动录制参数。FFmpeg的命令行参数可以通过Python脚本动态生成,再塞给插件去拉起进程,这样产品在迭代过程中调整码率、分辨率、输出目录,都不用重新编译插件,只改配置脚本就行。
写在最后
这套UE5实时录屏插件方案做下来,我最大的感受是:实时录屏本质上是渲染、编码、存储三者的三角平衡。不要追求无损画质,编码是耗时的核心,选对硬件编码器才是关键;不要追求所有分辨率通吃,先跑通1080P稳定的链路,再逐步往4K和推流方向扩展;音频和视频的时间基准一定要统一,否则后面所有处理和剪辑都会出问题。
如果你正打算在UE5里接FFmpeg做录屏,我建议第一步不要急着写大量C++代码,先手动跑一个FFmpeg裸视频输入的测试,确认编码参数和管道方式没问题,再往插件里搬。这样排查问题时至少能明确问题是在FFmpeg侧还是在UE5侧,能省下大量调试时间。
本文还有配套的精品资源,点击获取