背景:为什么放弃 Electron
Huafeirong Studio 最初基于 Electron + Vite + React + TypeScript 构建,前端用 Web 技术栈,底层通过 C++ Addon (Node.js N-API) 调用 libobs 视频引擎。项目推进到 60+ 源文件后,我们遇到了几个根本性问题:
- 进程间通信延迟:Electron 主进程 → C++ Addon → libobs 链路,每帧视频预览需要跨多个进程边界,延迟高达 20-40ms
- GPU 渲染困境:libobs 通过 D3D11 渲染,Electron 的 Chromium 渲染管线无法直接共享 GPU 纹理,必须走 Read-back → Copy → Upload 的慢路径
- 内存开销:Electron + Chromium 启动占用 300MB+,而 OBS Studio 原生启动仅约 80MB
新架构设计
Native 版采用经典的两层架构:C++ 引擎层负责所有视频处理,C# WinUI 3 负责用户界面。两者通过 C API + P/Invoke 桥接:
┌─────────────────────────────────────────┐
│ WinUI 3 GUI (C#) │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ │
│ │ MainWin │ │Broadcast │ │ Settings │ │
│ └─────────┘ └──────────┘ └──────────┘ │
│ │ P/Invoke (engine.dll) │
├─────────┼───────────────────────────────┤
│ C API │ engine_api.h │
│ │ engine_init / engine_shutdown │
│ │ engine_* (116 API functions) │
├─────────┼───────────────────────────────┤
│ Engine │ libobs-hfr (C++20) │
│ ┌──────┐ ┌───────┐ ┌────────┐ │
│ │Video │ │Audio │ │Output │ │
│ │Pipe │ │Mixer │ │Stream │ │
│ └──────┘ └───────┘ └────────┘ │
│ │ │
│ ┌──────┴──────────────────────────┐ │
│ │ libobs (OBS Studio SDK) │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────┘
跨语言桥接:C API + P/Invoke
核心设计原则:C API 是最稳定的 FFI (Foreign Function Interface) 边界。我们选择 extern "C" 导出纯 C 函数,而非 C++/CLI 或 COM,原因如下:
- 单一定义规则:extern "C" 避免 C++ name mangling,P/Invoke 的 EntryPoint 匹配确定性高
- ABI 稳定:C ABI 在所有主流编译器中一致,不依赖 C++ 标准库版本
- 内存安全:DLL 边界不传递 C++ 对象,只传递 POD 结构体和 opaque handle
一个典型的 API 调用链:
// C API (engine_api.h)
extern "C" __declspec(dllexport) int engine_scene_create(const char* name);
// C# P/Invoke
[DllImport("engine.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int engine_scene_create(string name);
// C# 封装
public Scene CreateScene(string name) {
var id = engine_scene_create(name);
if (id < 0) throw new EngineException(engine_get_last_error());
return new Scene { Id = id, Name = name };
}
性能对比
在相同硬件条件下(i7-13700K + RTX 4070),Electron 版 vs Native 版的关键指标:
| 指标 | Electron 版 | Native 版 | 改善 |
|---|---|---|---|
| 启动时间 | 3.2s | 0.8s | 4x |
| 内存占用(空闲) | 320 MB | 85 MB | 3.8x |
| 视频预览延迟 | 32ms | 2ms | 16x |
| 1080p60 编码 CPU | 18% | 8% | 2.3x |
| GPU 纹理共享 | ❌ 慢路径 | ✅ D3D11 共享 | — |
| 包体积 | 180 MB | 42 MB | 4.3x |
关键技术决策
1. CMake + ninja 构建 C++ 引擎
放弃 Visual Studio .sln 手动管理,采用 CMake 生成 ninja 构建文件。好处是 CI/CD 友好、增量编译更快、依赖管理清晰。
cmake -G Ninja \
-DCMAKE_CXX_STANDARD=20 \
-DCMAKE_BUILD_TYPE=Release \
-DOBS_SOURCE_DIR=../obs-studio \
-B build && \
cmake --build build
2. SwapChainPanel 原生集成
WinUI 3 的 SwapChainPanel 提供了 D3D11 交换链的原生集成能力。我们通过 libobs 的 obs_display_create 将渲染目标直接绑定到 SwapChainPanel 的交换链,实现了零拷贝视频预览。这比 Electron 版需要 Read-back → Copy → Canvas 的路径快了 16 倍。
3. 双预览管线 (PVW/PGM)
专业导播需要预监 (Preview/PVW) 和节目 (Program/PGM) 两个独立视频预览。我们扩展了 obs_source_info,在引擎层创建两个独立 display context,通过 SwapChainPanel 分别渲染到不同 UI 区域。
4. 转场特效引擎
基于 libobs 的 source transition 机制,实现了 cut(硬切)、fade(淡入淡出)、swipe(推拉)三种转场,支持自定义时长(200-2000ms)。转场方向支持 left/right/up/down 四个方向。
116 个引擎 API
Native 版共导出 116 个 C API 函数,覆盖以下功能域:
| 功能域 | API 数量 | 核心能力 |
|---|---|---|
| 生命周期 | 4 | init / shutdown / reset / get_version |
| 场景管理 | 8 | 创建/删除/重命名/切换/预览/收藏夹 |
| 源管理 | 18 | 添加/删除/属性/变换/层级/12 种源类型 |
| 音频控制 | 12 | 混音/静音/音量/VU表/滤镜/监听 |
| 视频管线 | 6 | PVW/PGM 预览/渲染/输出设置 |
| 转场特效 | 8 | 类型/时长/方向/颜色/自定义参数 |
| 推流录制 | 14 | RTMP 推流/录制/编码器配置/状态 |
| 美颜滤镜 | 10 | 磨皮/美白/大眼/瘦脸/自定义强度 |
| 虚拟摄像头 | 4 | 启动/停止/状态/输出设备 |
| 快捷键 | 6 | 注册/绑定/触发/清除/列表 |
| 其他 | 26 | 诊断/统计/DLL管理/错误处理 |
踩过的坑
坑 1: NuGet restore 崩溃
沙箱环境中的 dotnet CLI NuGet restore 存在 ArgumentNullException 问题。最终方案:使用 VS2022 MSBuild 直接 restore/build,绕过了 CLI 的 NuGet 集成 bug。
坑 2: XAML 编译器与 WindowsAppSDK 版本不匹配
WinUI 3 的 XAML 编译需要版本精确匹配的 WinRT runtime。在非标准环境中,XamlCompiler.exe 会因找不到正确的 Windows SDK 而崩溃。解决方案是切换到进程内编译模式。
坑 3: DLL 运行时依赖地狱
engine.dll 依赖 20+ OBS/OBS-plugins DLL。初版部署脚本遗漏了 5 个运行时 DLL(avcodec/avformat/swresample/swscale/avutil),导致 GUI 启动即崩溃。现在的 package.ps1 脚本自动扫描并部署所有依赖。
总结
Electron → Native 迁移是一次正确的架构决策。对于视频处理桌面软件,原生 + GPU 纹理共享带来的性能提升是质的飞跃。116 个 C API 通过 P/Invoke 与 C# WinUI 3 无缝桥接,代码清晰、维护成本可控。
下一步计划:
- 在物理 GPU 机器上完成端到端 runtime 测试
- 实现 NDI 网络视频输出
- 添加 PTZ 摄像机控制协议
- MSIX 正式打包与签名