1. 项目概述:为什么我们需要一个iOS上的UE4录制插件?
在移动游戏开发,尤其是使用虚幻引擎4(UE4)开发iOS游戏的过程中,有一个需求一直很“痒”:如何让玩家在游戏内一键录制并分享他们的高光时刻?iOS系统自带的屏幕录制功能虽然能用,但体验割裂——玩家需要手动下拉控制中心、开启录制,再切回游戏,整个过程打断了沉浸感,更别提录制出来的视频可能没有游戏音频,或者音频质量不佳。对于追求高品质和社区分享的现代手游来说,这显然不够。
这就是PsReplayKit诞生的背景。它不是一个简单的封装,而是一个深度集成到UE4引擎内部,专门为iOS平台打造的屏幕与音频录制插件。它的核心目标,是让录制功能像游戏里的一个UI按钮那样自然、可控、高性能。开发者可以决定何时开始录制、何时结束,可以确保录制的画面和游戏内音频完美同步,甚至可以在录制过程中叠加游戏内的UI元素(比如击杀提示、连击数),生成更具观赏性的视频内容。这不仅仅是“录屏”,而是“游戏内内容创作工具”的一部分。
从技术角度看,它要解决几个关键痛点:首先是性能,录制不能导致游戏帧率显著下降;其次是兼容性,需要适配从iPhone 8到最新款iPhone,以及各种iPad型号;最后是易用性,需要提供一套清晰的蓝图和C++接口,让不熟悉iOS底层框架的UE4开发者也能快速集成。如果你正在开发一款希望鼓励玩家分享的iOS游戏,或者需要内置录制功能用于测试反馈、宣传素材制作,那么深入理解PsReplayKit的实现与使用,将为你省下大量重复造轮子的时间。
2. 核心架构与ReplayKit框架深度解析
2.1 iOS ReplayKit框架的工作机制与限制
要理解PsReplayKit,必须先吃透它的基石——苹果的ReplayKit框架。ReplayKit是苹果官方提供的屏幕录制API,从iOS 9开始引入,并随着版本迭代不断强化。它的核心优势在于系统级集成,能够以极高的效率捕获屏幕帧缓冲区和系统音频,这是任何第三方录屏软件都无法比拟的。
ReplayKit主要提供两种使用模式:RPScreenRecorder和RPBroadcastController。前者用于简单的屏幕录制,后者用于直播推流。PsReplayKit主要基于RPScreenRecorder进行构建。其工作流程可以概括为:首先,向系统申请录制权限(这会在第一次使用时弹出用户授权对话框);然后,配置录制参数,如是否录制麦克风音频;最后,开始录制,系统会将捕获的样本(视频帧、音频样本)通过回调函数传递给你的应用。
然而,直接使用ReplayKit与UE4集成存在几个天然障碍:
- 线程模型冲突:ReplayKit的回调通常发生在非游戏主线程(可能是某个GCD队列),而UE4的渲染和游戏逻辑严重依赖其主线程(GameThread)。直接将视频帧从回调线程推到渲染线程或编码线程,极易引发崩溃或数据竞争。
- 数据格式转换:ReplayKit提供的视频样本是
CMSampleBufferRef格式,通常包含的是未压缩的BGRA或YUV像素数据。而UE4内部渲染输出和大多数视频编码库(如硬件编码器)期望的可能是特定的纹理格式(如FTexture2DRHIRef)或编码前的原始数据。这中间需要一次高效的内存拷贝与格式转换。 - 音频同步难题:ReplayKit会分别提供视频和音频样本,并附带时间戳。如何确保音画同步,尤其是在游戏本身音频引擎(如FMOD、Wwise)也在输出声音时,处理起来非常复杂。简单的合并可能导致音画不同步或音频失真。
- 生命周期管理:录制过程需要妥善处理应用进入后台、电话打断、用户手动从控制中心停止录制等异常情况。这些事件的处理必须与UE4的游戏状态机协同工作。
PsReplayKit的设计,正是为了在UE4的架构下,优雅地封装这些复杂性,提供一个稳定、易用的抽象层。
2.2 PsReplayKit的插件架构设计思路
PsReplayKit作为一个UE4插件,其架构遵循了UE4插件的标准模式,同时针对录制任务进行了特殊设计。整体上,它分为三层:iOS原生层(Objective-C/Swift)、JNI桥接层(可选,如果涉及Java,但ReplayKit纯OC)以及UE4模块层(C++/Blueprint)。
iOS原生层:这是插件的核心,用Objective-C(或Swift)编写,直接与ReplayKit框架对话。它负责:
- 初始化
RPScreenRecorder并管理其生命周期。 - 实现
RPPreviewViewControllerDelegate等协议,以处理录制结束后的预览和保存。 - 在ReplayKit的视频/音频样本回调中,将
CMSampleBufferRef转换为更易于处理的内存块(如CVImageBufferRef),并通过一种线程安全的方式(如使用线程安全的队列或UE4的Task Graph系统)将数据传递给UE4层。 - 处理所有iOS特有的权限请求、中断和错误。
- 初始化
UE4模块层:这是插件的主体,用C++编写,暴露给游戏开发者。它进一步分为几个模块:
- FPsReplayKitModule:插件的入口点,负责在引擎启动时初始化iOS原生层,并注册到UE4的模块系统中。
- FPsReplayKitRecorder:核心录制管理器。它是一个UObject,可以在蓝图中访问。它提供了
StartRecording、StopRecording、IsRecording等接口。更重要的是,它内部维护着状态机,管理着从原生层接收到的音视频数据流。 - 视频处理管线:接收来自原生层的视频帧数据。这里的设计是关键。一种高效的做法是,将接收到的BGRA数据直接上传到UE4渲染线程的一个动态渲染目标(
UTextureRenderTarget2D)或一个FTexture2DRHIRef上。这样,游戏画面甚至可以实时显示录制内容(如画中画)。同时,这个纹理可以作为输入,交给一个后台线程进行视频编码(例如使用iOS的VTCompressionSession硬件编码器生成H.264流)。 - 音频处理管线:接收来自原生层的音频PCM样本。这里需要与UE4的音频引擎协作。通常的做法是,将系统音频样本与游戏内音频进行混音。一个更精细的方案是,PsReplayKit可以提供一个可配置的音频路由,让开发者选择是只录系统音频、只录游戏内音频,还是两者混合。混音后的PCM数据会被送入音频编码器(如AAC编码器)。
- 封装与写入:将编码后的H.264视频流和AAC音频流,按照MP4容器格式进行封装,并写入到iOS应用的沙盒目录中。这个过程通常在单独的IO线程进行,避免阻塞主线程。
蓝图与C++ API:插件最终会暴露出一组简洁的蓝图节点和C++函数,例如:
Start Recording (with Microphone):开始录制,参数决定是否包含麦克风。Stop and Save Recording:停止录制并保存文件到相册。On Recording Completed (Success):一个事件分发器,当录制完成(成功或失败)时通知蓝图。Get Recording State:获取当前录制状态(闲置、录制中、保存中)。Get Last Saved Path:获取最后一次保存的视频文件在沙盒中的路径。
注意:线程安全是生命线。在插件开发中,最大的挑战之一是跨线程数据传递。务必使用UE4提供的
AsyncTask、TGraphTask或FRunnable来将原生回调中的重操作(如格式转换、编码)卸到工作线程,并通过线程安全的队列或原子标志与游戏线程通信。直接跨线程操作UObject或渲染资源是未定义行为的根源。
3. 集成与配置:一步步将PsReplayKit接入你的UE4 iOS项目
3.1 插件获取与引擎集成
假设你已经有了PsReplayKit的插件包(通常是一个包含.uplugin文件、Source代码和Resources的文件夹)。集成步骤如下:
放置插件:将整个插件文件夹复制到你的UE4项目的
Plugins目录下。如果项目没有Plugins文件夹,就在项目根目录(与.uproject文件同级)创建它。启用插件:
- 方法一:右键点击你的
.uproject文件,选择“Generate Visual Studio project files”。重新生成解决方案后,在Visual Studio中编译你的项目。然后打开UE4编辑器,进入“编辑” -> “插件”,在“已安装”或“项目”分类下找到“PsReplayKit”,勾选其复选框,重启编辑器。 - 方法二:直接修改项目的
.uproject文件,在"Plugins"数组里添加一项:{ "Name": "PsReplayKit", "Enabled": true },然后重新生成项目文件并编译。
- 方法一:右键点击你的
配置iOS权限:这是至关重要的一步,缺少权限配置会导致录制功能在真机上静默失败。你需要编辑项目的
Info.plist文件(对于UE4项目,通常位于Config/IOS目录下的Info.plist或通过项目设置添加)。必须添加以下两个键值对:Privacy - Microphone Usage Description(NSMicrophoneUsageDescription): 描述为何需要访问麦克风(如果启用麦克风录制)。例如:“用于录制游戏视频时的语音解说”。Privacy - Screen Recording Usage Description: 在iOS 11及更高版本中,ReplayKit需要此权限。描述为何需要录制屏幕。例如:“用于录制和分享您的精彩游戏时刻”。 这些描述文字会显示在系统向用户请求权限的弹窗中,务必填写清晰、友好的描述。
项目构建配置:确保你的项目Build.cs文件(通常是
项目名.Build.cs)正确引用了插件模块。通常插件会自动添加依赖,但检查一下无妨。在PublicDependencyModuleNames数组中,应该包含类似"PsReplayKit"的条目。
3.2 基础功能蓝图实现与参数详解
集成插件后,你就可以在蓝图中使用它了。我们以一个典型的录制-分享流程为例,展示核心节点的用法。
初始化与权限检查:通常,在游戏主菜单或设置界面初始化时,就应该检查录制权限。虽然PsReplayKit可能在第一次调用
StartRecording时自动请求权限,但提前检查可以提供更好的用户体验。你可以设计一个“录制功能”开关,如果用户未授权,则将其置灰。- 目前PsReplayKit可能没有直接提供权限查询节点,这通常需要原生代码扩展。一个变通方法是尝试开始录制并立即停止,监听错误回调。但更优雅的做法是建议插件开发者增加
CheckRecordingAvailability这样的节点。
- 目前PsReplayKit可能没有直接提供权限查询节点,这通常需要原生代码扩展。一个变通方法是尝试开始录制并立即停止,监听错误回调。但更优雅的做法是建议插件开发者增加
开始录制:在玩家进入一局游戏,或者点击某个“开始录制”按钮时调用。
- 关键参数:
Enable Microphone: 布尔值。是否录制麦克风输入。开启后,录制的视频将包含玩家的语音。这对于制作解说视频非常重要。Recording Quality: 枚举值(如High, Medium, Low)。这会影响ReplayKit内部采集的分辨率和码率。高质量(High)通常对应设备屏幕的原生分辨率或接近1080p,码率较高,文件体积大。需要根据游戏性能和设备存储空间权衡。
- 蓝图示例:在一个按钮的
OnClicked事件中,拖出节点Start Recording (PsReplayKit),勾选Enable Microphone,选择Quality为High。然后连接一个Print String节点,输出“录制已开始”,给玩家视觉反馈。
- 关键参数:
录制过程中的处理:录制开始后,插件会在后台工作。你可以:
- 在游戏HUD上显示一个红色的“录制中”图标,提醒玩家。
- 如果游戏有暂停功能,需要确保录制在游戏暂停时也能正常工作(通常ReplayKit录制的是整个屏幕,不受游戏内暂停影响,但游戏画面静止了)。
- 高级技巧:叠加UI。PsReplayKit的一个优势是录制的是纯屏幕内容。这意味着你游戏内所有的UI元素(血条、地图、技能图标)都会被自然录制进去。你甚至可以专门为录制设计一些叠加信息,比如在屏幕角落显示当前回合数、玩家ID等,这些都会成为最终视频的一部分。
停止录制与保存:当一局游戏结束,或者玩家主动点击“结束录制”按钮时调用。
Stop and Save Recording节点被调用后,录制停止。插件会开始将缓冲区中的数据编码并封装为MP4文件。这个过程可能需要几秒钟,取决于录制时长和视频质量。- 监听完成事件:这是至关重要的一步。你必须绑定
On Recording Completed事件。这个事件会返回一个布尔值参数(Success)和一个字符串参数(SavedFilePath)。- 如果
Success为真,SavedFilePath就是视频文件在设备沙盒中的临时路径(例如.../Documents/PsReplayKit/recording_20231027.mp4)。 - 如果
Success为假,你可以从输出日志中查找错误原因(权限不足、磁盘空间不够、录制时间过短等)。
- 如果
分享与后续处理:获得文件路径后,你可以:
- 保存到系统相册:使用iOS的系统功能
UISaveVideoAtPathToSavedPhotosAlbum(这需要插件提供相应节点或自己通过额外插件调用)。保存成功后,视频会出现在用户的“照片”应用中。 - 在游戏内预览:你可以使用一个媒体播放器组件,加载这个临时路径的视频文件,在游戏内提供一个小的预览窗口。
- 分享到社交平台:使用iOS的
UIActivityViewController来唤起系统分享 sheet,让用户选择分享到微信、QQ、抖音等App。同样,这需要插件支持或通过其他方式调用原生分享功能。
- 保存到系统相册:使用iOS的系统功能
实操心得:文件管理。录制生成的视频文件可能会很大(几分钟的1080p视频可能几百MB)。务必在分享或保存到相册后,及时删除沙盒中的临时文件,避免占用用户不必要的存储空间。可以在
On Recording Completed事件成功后,添加一个删除临时文件的逻辑。
4. 高级功能与性能优化实战
4.1 自定义视频源与画中画录制
基础的PsReplayKit录制的是整个屏幕。但有时我们可能需要更灵活的方案,例如:
- 只录制游戏画面,不录制系统状态栏和虚拟Home条。
- 实现画中画(PiP)效果,在录制主游戏画面的同时,在角落显示摄像头画面。
这涉及到“自定义视频源”。ReplayKit本身支持通过RPSampleBufferType.video回调提供视频数据,但默认是全屏。要实现自定义区域录制,需要在插件内部做文章:
- 裁剪画面:在接收到全屏的
CMSampleBufferRef后,根据预设的裁剪区域(CGRect),使用Core Graphics或Core Video的函数(如CVPixelBufferCreateWithBytes配合内存拷贝)创建一个新的、尺寸更小的像素缓冲区。这个过程消耗CPU,必须放在后台线程。 - 画中画合成:这更复杂一些。你需要两个视频源:主屏幕源和摄像头源(通过
AVCaptureSession获取)。在编码之前,你需要将两个视频帧合成到一起。这可以在CPU上通过图像处理库(如libyuv)完成,但更高效的方式是利用iOS的Metal或OpenGL ES进行GPU端的合成。你可以创建一个离屏的Metal纹理,分别将两个源作为纹理渲染上去,然后再从这个合成纹理读取数据并编码。这对插件的图形编程能力要求较高。 - 性能权衡:裁剪和合成都是额外的开销。务必在真机(尤其是旧款iPhone)上严格测试性能影响。如果帧率下降明显,可以考虑降低输出视频的分辨率或帧率(例如从60fps降到30fps)。
4.2 音频路由与混音策略
音频处理是另一个深水区。理想情况下,玩家希望视频里既有震撼的游戏音效和背景音乐,也有队友的语音聊天和自己的解说。
音频源分析:
- 系统音频(游戏内音):由ReplayKit的
RPSampleBufferType.audioApp回调提供。这是游戏通过音频输出设备(扬声器)播放的所有声音的混合。 - 麦克风音频:由
RPSampleBufferType.audioMic回调提供(如果开启麦克风录制)。 - 第三方语音:如集成腾讯云GME或声网的语音SDK。这类SDK通常有独立的音频采集和播放模块,其声音会混入“系统音频”中,也可能需要单独采集作为一路音源。
- 系统音频(游戏内音):由ReplayKit的
混音方案:
- 方案A(简单,推荐):直接使用ReplayKit提供的两路音频(App+Mic)。让ReplayKit在系统层面完成混音。这是最稳定、性能最好的方案。但缺点是,你无法单独控制游戏音和语音聊天的音量比例。
- 方案B(精细控制):禁用ReplayKit的音频采集,完全由插件自己管理音频。这意味着你需要:
- 从UE4音频引擎(通过
Audio Mixer的回调)获取游戏内音频PCM数据。 - 从麦克风采集原始PCM数据。
- 从第三方语音SDK获取语音聊天PCM数据。
- 在内存中,将这三路(或更多路)PCM数据按照指定的音量权重进行混合。
- 将混合后的PCM数据送入软件编码器(如FAAC)或硬件编码器进行AAC编码。 方案B非常灵活,但实现复杂,对音频同步的精度要求极高,且CPU开销大。除非有强烈的多路音频独立控制需求,否则建议从方案A开始。
- 从UE4音频引擎(通过
同步是关键:无论哪种方案,都必须使用音频样本自带的时间戳(
CMSampleBuffer的PresentationTimeStamp)和视频帧时间戳进行严格对齐。编码器(如VTCompressionSession和Audio Converter)在接收数据时都需要携带正确的时间戳,封装器(如AVAssetWriter)才能生成音画同步的MP4文件。PsReplayKit内部必须维护一个稳定的时钟基准,通常使用系统启动时间(mach_absolute_time)来换算和校正时间戳。
4.3 性能监控与调优指南
录制功能是CPU、GPU、内存和I/O的密集操作。在低端设备上,不当的实现会导致游戏卡顿、发热、甚至崩溃。以下是一些关键的监控点和调优建议:
| 监控指标 | 可能的问题 | 调优建议 |
|---|---|---|
| 游戏帧率(FPS)下降 | 视频编码(尤其是软件编码)或画面裁剪/合成占用了过多CPU/GPU时间。 | 1.启用硬件编码:务必使用VTCompressionSession(VideoToolbox)进行H.264硬件编码,它由专用芯片处理,对CPU影响极小。2.降低录制参数:将录制质量从 High调至Medium,或降低录制帧率(如锁30fps)。3.优化处理线程:确保所有视频处理(转换、缩放)都在独立的Worker线程进行,避免阻塞GameThread或RenderThread。 |
| 内存占用飙升 | 视频帧缓冲区堆积。编码速度跟不上采集速度,导致未编码的原始帧在内存中积压。 | 1.设置合理的缓冲区大小:在插件内部实现一个带超时丢弃机制的帧队列。当队列长度超过阈值时,丢弃最老的帧,并记录丢帧数。 2.监控编码速度:在开发阶段输出日志,统计平均编码一帧所需时间,确保其小于采集帧间隔(如60fps下应小于16.7ms)。 3.使用池化内存:避免频繁分配和释放大块内存(如图像缓冲区),使用对象池进行复用。 |
| 录制文件音画不同步 | 音频和视频时间戳处理错误,或编码/写入过程中产生了不可预知的延迟。 | 1.统一时钟源:确保音频和视频样本都使用同一个高精度时钟(如CACurrentMediaTime())来生成和比较时间戳。2.严格校验时间戳:在将样本提交给编码器前,检查其时间戳是否单调递增。对于异常时间戳(如回退)的样本,应进行修正或丢弃。 3.测试长时录制:进行10分钟以上的连续录制测试,播放检查开头、中间、结尾部分的同步情况。 |
| 发热严重 | 持续的高负载运行,硬件编码器、CPU、内存、磁盘I/O全速工作。 | 1.提供录制时长限制:在游戏中提示玩家单次录制建议时长(如5分钟),或自动分段录制。 2.优化写入策略:视频数据写入文件时,使用合适的缓冲区大小,避免频繁的小文件I/O操作。 3.动态调整参数:在插件中集成设备温度检测(需谨慎,涉及私有API),当设备过热时,自动降低录制码率或分辨率。 |
一个实用的调试技巧:在插件的开发版本中,加入丰富的统计信息输出,例如:实时帧率、编码队列长度、平均编码耗时、内存占用、丢帧数等。将这些信息实时显示在屏幕的调试区域,可以非常直观地定位性能瓶颈。
5. 常见问题排查与实战避坑指南
即使按照最佳实践集成和配置,在实际开发中仍会遇到各种问题。下面是一些典型问题及其排查思路。
5.1 权限与初始化失败
- 问题现象:调用
StartRecording后,没有任何反应,或者立即触发On Recording Completed事件且Success为false。 - 排查步骤:
- 检查Info.plist:首先确认
NSMicrophoneUsageDescription和Privacy - Screen Recording Usage Description这两个键值对已经正确添加,并且描述文本不为空。这是最常见的原因。 - 检查真机授权:在设备的“设置”->“隐私与安全性”->“屏幕录制”和“麦克风”中,找到你的App,确保开关是打开的。第一次使用录制功能时,系统会弹窗请求授权,如果用户点了“不允许”,后续调用会静默失败。需要在App内引导用户去设置页开启。
- 检查插件初始化日志:查看Xcode的设备日志(Console),搜索插件名或ReplayKit相关的错误信息。常见的错误如“Screen recording is not available”可能表示设备不支持(极少数旧设备)或当前状态不允许(如正在播放DRM保护内容时)。
- 确保在主线程调用:ReplayKit的API大多要求在主线程(UI线程)调用。确保你的蓝图节点或C++调用是从游戏主线程发起的。
- 检查Info.plist:首先确认
5.2 录制视频黑屏或绿屏
- 问题现象:录制出来的视频文件能播放,但内容是全黑、全绿或花屏。
- 排查步骤:
- 检查像素格式:ReplayKit回调的视频像素格式可能是
kCVPixelFormatType_32BGRA,也可能是kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange(NV12)。PsReplayKit在将数据传递给编码器或UE4纹理时,必须进行正确的格式转换。黑屏通常意味着数据格式不对或内存拷贝失败。 - 检查纹理/渲染目标状态:如果插件采用先将画面渲染到UE4纹理再编码的方案,需要确保这个纹理在录制开始时已经被正确创建和初始化,并且每帧都有内容被渲染上去。使用UE4的“Visualize Texture”工具查看该纹理的内容。
- 检查编码器配置:确认视频编码器(
VTCompressionSession)的配置参数正确,特别是kVTCompressionPropertyKey_RealTime应设为true,kVTCompressionPropertyKey_ProfileLevel应设为适合移动设备的H264_Baseline_AutoLevel或H264_Main_AutoLevel。 - 验证中间数据:在插件代码中,将接收到的
CMSampleBufferRef转换成图像并保存到相册,看看原始数据是否正确。这能帮你定位问题是出在采集阶段还是处理/编码阶段。
- 检查像素格式:ReplayKit回调的视频像素格式可能是
5.3 录制文件无声或音画不同步
- 问题现象:视频有画面但没声音;或者声音和画面逐渐对不上。
- 排查步骤:
- 确认音频采集已开启:检查调用
StartRecording时是否传入了正确的Enable Microphone参数。 - 检查音频会话(Audio Session):iOS的音频会话类别(Category)会影响音频采集。确保在录制前,设置了合适的音频会话类别,例如
AVAudioSessionCategoryPlayAndRecord,并设置了合适的模式(Mode)。同时,要处理好音频中断(如来电),在中断结束后恢复音频会话。 - 审查时间戳逻辑:这是音画不同步的罪魁祸首。仔细检查插件中为视频帧和音频样本生成和传递时间戳的代码。确保使用的是同一个时间基准(
CMClock或mach_absolute_time),并且时间戳是单调递增的。在编码和封装时,时间戳必须原样传递下去,不能随意修改。 - 检查音频编码参数:确认AAC编码器的采样率(如44100Hz)、声道数(立体声为2)和码率设置正确,并与输入PCM数据的参数匹配。
- 确认音频采集已开启:检查调用
5.4 在特定设备或系统版本上崩溃
- 问题现象:插件在较新或较旧的iOS版本,或特定型号的iPad/iPhone上崩溃。
- 排查步骤:
- 系统API可用性检查:ReplayKit在不同iOS版本上有差异。使用
@available宏或respondsToSelector:来检查API是否可用。例如,RPScreenRecorder的某些方法或属性在iOS 10之后才有。 - 内存访问问题:多线程环境下的野指针或内存越界是崩溃的常见原因。使用Xcode的Thread Sanitizer和Address Sanitizer工具进行严格测试。确保所有从Objective-C回调传递到C++的数据,其生命周期都得到妥善管理(使用智能指针如
TSharedPtr)。 - 图形API兼容性:如果插件涉及Metal或OpenGL ES操作,需要检查不同设备的图形特性(Feature Set)。避免使用某些设备不支持的高级特性。
- 符号剥离与链接:确保插件的二进制在打包时包含了所有必要的符号,并且与UE4引擎版本的编译设置(如C++运行时库)兼容。
- 系统API可用性检查:ReplayKit在不同iOS版本上有差异。使用
最后的经验之谈:录制功能涉及系统框架、多媒体处理和引擎底层的深度交互,出问题的概率比普通游戏逻辑高得多。建立一个全面的真机测试矩阵至关重要。你需要在不同性能档次的iPhone和iPad、不同的iOS主要版本上进行录制、停止、保存、分享的全流程测试。记录下每种组合下的行为,才能确保你的玩家获得一致的、可靠的录制体验。