1. 屏幕录制技术选型从Web到桌面的三种路径在Electron/Chromium环境下实现屏幕录制本质上是在Web技术与桌面能力之间寻找平衡点。根据我的踩坑经验目前主流方案可以归纳为三类技术路线rrweb方案纯前端录制的神器通过DOM序列化增量快照实现。优点是轻量仅需引入JS库、跨平台、录制文件小JSON格式。但致命缺陷是无法捕获系统级弹窗、GPU加速内容如视频播放器以及跨进程窗口。实测在Electron中录制PPT全屏演示时rrweb只能抓到空白区域。WebRTC API方案浏览器原生支持的getDisplayMediaAPI是Chromium内核的标配。代码简洁到令人发指const stream await navigator.mediaDevices.getDisplayMedia({ video: { frameRate: 30 }, audio: true });但实际使用中会发现三个深坑Windows系统下无法单独录制某个窗口的音频必须全局捕获多显示器环境会强制显示选择提示框无法静默指定屏幕4K分辨率下Chrome会偷偷降低帧率到15fpsFFmpeg方案Electron作为Node.js运行时可以直接调用FFmpeg实现底层录制。这是最灵活的方式但需要处理ffmpeg -f gdigrab -framerate 30 -i desktop -c:v libx264 -preset ultrafast output.mp4的魔鬼参数gdigrab在Windows 11上会导致鼠标指针闪烁必须手动处理-offset_x和-offset_y参数来定位多显示器音频采集需要额外启用dshow设备关键选择建议需要录制浏览器内容用WebRTC要捕获游戏/桌面应用选FFmpeg做操作回放考虑rrwebElectron混合方案2. Electron环境下的特殊陷阱与破解之道2.1 多进程架构引发的权限问题Chromium的沙箱机制与Electron的主渲染进程分离设计会导致getDisplayMedia在子窗口调用时抛出NotAllowedError。解决方案是在主进程预加载脚本中注入contextBridge.exposeInMainWorld(electronAPI, { getDisplayMedia: () ipcRenderer.invoke(get-display-media) })然后在主进程实现真正的媒体捕获。这个坑花了我两天时间调试——控制台没有任何错误提示只是静默拒绝。2.2 高DPI屏幕的噩梦当用户使用250%缩放比例的4K屏幕时rrweb录制的坐标会完全错乱。必须通过webFrame.setZoomFactor(1)强制重置缩放录制完成后再恢复。更隐蔽的是某些Windows笔记本在接外屏时两块屏幕的DPI缩放可能不同此时需要screen.getAllDisplays().forEach(display { if (display.scaleFactor ! 1) { require(electron).nativeImage.createEmptyBitmap() } })来触发系统级重绘。2.3 内存泄漏的幽灵连续录制30分钟以上时Chromium的内存占用可能突破4GB。这是因为WebRTC的MediaRecorder默认不会自动释放编码帧。必须手动设置const recorder new MediaRecorder(stream, { mimeType: video/webm;codecsvp9, bitsPerSecond: 2500000, videoBitsPerSecond: 2000000 }); // 每5秒强制清理一次 setInterval(() { recorder.requestData(); }, 5000);3. 性能优化从能用到好用的关键跳跃3.1 帧率稳定的黑科技测试发现当系统负载较高时requestAnimationFrame的实际回调间隔会从16.7ms(60fps)暴跌到33ms(30fps)。解决方案是改用WebWorker运行独立计时器// worker.js let lastTime performance.now(); setInterval(() { const now performance.now(); postMessage(now - lastTime); lastTime now; }, 16);主线程根据这个精确时钟驱动录制流程。实测可将帧率波动控制在±2fps内。3.2 鼠标轨迹的平滑处理原生mouseevent的坐标是离散值直接录制会产生锯齿状移动。采用卡尔曼滤波算法处理后const kalmanFilter new KalmanFilter({ R: 0.01, Q: 3 }); function smoothMouse(x, y) { return { x: kalmanFilter.filter(x), y: kalmanFilter.filter(y) }; }效果堪比专业录屏软件的平滑追踪代码已开源在GitHub。3.3 音频同步的原子钟当视频和音频分开采集时如FFmpeg方案不同步问题会随时间累积。我的土方法是利用Electron的globalShortcut模块globalShortcut.register(CommandOrControlAltS, () { const now performance.now(); fs.appendFileSync(sync.log, ${now}\n); });录制开始和结束时让用户按下快捷键后期处理时以这两个时间点为基准进行音视频对齐。4. 实战中的玄学问题排查记录4.1 神秘的黑屏现象某次更新Chromium 112后部分用户反馈录制内容全黑。最终定位到是Windows图形堆栈的改动导致。解决方案是在webPreferences中强制关闭硬件加速new BrowserWindow({ webPreferences: { disableHardwareAcceleration: true } });但这样会损失30%性能折中方案是动态检测if (process.platform win32 parseInt(os.release().split(.)[0]) 10) { app.disableHardwareAcceleration(); }4.2 中文输入法的幽灵弹窗使用robotjs模拟键盘输入时中文输入法会在后台生成不可见的候选词窗口导致rrweb录制区域出现空白。通过Hook系统API解决// native_module.cpp HHOOK g_hook SetWindowsHookEx(WH_CBT, [](int code, WPARAM wParam, LPARAM lParam) { if (code HCBT_CREATEWND) { auto cls ((LPCBT_CREATEWND)lParam)-lpcs-lpszClass; if (strstr(cls, IME)) return -1; } return CallNextHookEx(g_hook, code, wParam, lParam); }, NULL, GetCurrentThreadId());4.3 杀毒软件的拦截之谜某次发布后10%的用户无法启动录制功能。最终发现是某杀毒软件将libffmpeg.dll误报为病毒。解决方案是对FFmpeg进行代码签名每年$400改用WASM版本的FFmpeg性能损失50%引导用户添加杀毒软件白名单成功率30%最后选择在安装包内附带检测脚本$signature Get-AuthenticodeSignature lib\ffmpeg.dll if ($signature.Status -ne Valid) { Start-Process msiexec.exe /x {产品GUID} /qn }在ElectronChromium的屏幕录制领域每个看似简单的问题背后都可能藏着操作系统、图形驱动、安全策略的多重陷阱。这些经验都是用无数个通宵换来的——希望你能少走些弯路。