使用 Electron RTC SDK 时,在视频渲染和编码传输前,你可以自定义逻辑,对视频帧进行处理。
注意:
RTC SDK 和 CV SDK 进行了深度整合,联合提供强大且较下述方案更易集成的 RTC-CV 联合集成方案,强烈建议你使用联合方案。
macOS、Windows 下的 Electron 开发框架
此功能在视频处理链路的位置如下:
你需要自行构建视频处理器插件,并编译成动态库文件。在 Electron 应用项目中,调用 Electron RTC SDK 插件相关接口,指定和使用自定义插件,完成视频自定义处理。
你可以借助 插件示例项目.zip 构建自定义的视频处理插件。
插件代码结构说明如下:
. ├──3rd │ ├── Common // 公共的资源 │ │ └── assets │ │ ├── *.bundle. // 放模型资源 │ ├── Mac // Mac 平台的第三方美颜库 │ │ └── Beauty SDK │ │ ├── include │ │ ├── lib │ ├── Windows // Windows 平台的第三方美颜库 │ │ └── Beauty SDK │ │ ├── include │ │ ├── lib ├──scripts │ ├── release_win_win32.bat // 编译插件脚本 ├──src │ ├── common // 公共的代码,比如日志,utils 等 │ │ └── log.h │ │ └── log.cpp │ │ └── rapidjson // rapidjson 用于解析 JSON │ ├── windows // Windows 平台特有的代码 │ │ └── dllmain.cpp // Windows 动态库入口 │ ├── IVideoPlugin.h // 定义插件,详见下文示例 │ ├── veRTCFUPlugin.h // 定义处理器方法,详见下文示例 │ ├── veRTCFUPlugin.cpp //实现处理器方法,详见下文示例 ├──tools // 打包工具 │ ├── 7z.exe ├──CMakeLists.txt // cmake 工程文件
IVideoPlugin.h
,实现 IVideoPlugin
纯虚方法,进行视频帧前处理。/* * @brief 视频插件接口类 */ #pragma once #include <stdint.h> #if defined(_WIN32) #define DLL_EXPORTS __declspec(dllexport) #else #define DLL_EXPORTS #endif namespace bytertc { /** * @type keytype * @brief 自定义视频插件帧 */ struct VideoPluginFrame { int width; // 视频帧宽,单位:像素 int height; // 视频帧高,单位:像素 int yStride; // Y 数据行的长度 int uStride; // U 数据行的长度 int vStride; // V 数据行的长度 uint8_t* yBuffer; // Y 数据缓冲区 uint8_t* uBuffer; // U 数据缓冲区 uint8_t* vBuffer; // V 数据缓冲区 int rotation; // 视频帧旋转角度 {0, 90, 180, 270} int64_t timestampUs; // 频帧时间戳,单位:微秒 }; /** * @type api * @brief 视频插件 API */ class IVideoPlugin { public: virtual bool init(const char* path) = 0; virtual void uninit() = 0; virtual bool setParameter(const char* param) = 0; virtual const char* getParameter(const char* key) = 0; virtual void release() = 0; public: virtual bool processVideoFrame(VideoPluginFrame* videoFrame) = 0; }; } /** * @type type * @brief 定义函数类型 */ typedef bytertc::IVideoPlugin* (*createByteVideoPlugin)(); /** * @type api * @brief 创建插件 */ extern "C" DLL_EXPORTS bytertc::IVideoPlugin* createVideoPlugin();
将 processVideoFrame 放在一个单独的线程中。如果 OpenGL 环境不能切换线程,建议在回调里进行初始化。
#pragma once #include "IVideoPlugin.h" class VeRTCFUPlugin : public bytertc::IVideoPlugin { public: VeRTCFUPlugin() {} ~VeRTCFUPlugin() {} public: bool init(const char* path) override; void uninit() override; bool setParameter(const char* param) override; const char* getParameter(const char* key) override {} // unused void release() override {} // unused public: bool processVideoFrame(bytertc::VideoPluginFrame* videoFrame) override; private: bool initEnv(); bool initOpenGL(); void makeCurrent(); void doneCurrent(); private: static bool m_envInited; bool m_inited = false; bool m_loadBundles = false; bool m_updateBundles = false; };
#include "veRTCFUPlugin.h" bytertc::IVideoPlugin* createVideoPlugin() { return new VeRTCFUPlugin(); } bool VeRTCFUPlugin::init(const char* path) { // Add codes to initialize the plugin. return true; } void VeRTCFUPlugin::uninit() { // Add codes to release memory. } bool VeRTCFUPlugin::setParameter(const char* param) { // Add code to parse json string. return true; } bool VeRTCFUPlugin::processVideoFrame(bytertc::VideoPluginFrame* videoFrame) { // Add code to process video frames // Initialize OpenGL. Load model, and etc. return true; }
调用 Electron SDK 接口,注册和启动插件。
const rtcVideo= new veRTCVideo(); rtcVideo.startVideoCapture();
let ret = rtcVideo.initializePluginManager();
// 指定插件目录。即上一步骤中编译好的动态库文件存放路径。 let libPath = path.resolve(__static, 'vertc-mac-x86-64-fu-plugin/libveRTCFUPlugin.dylib'); let result = rtcVideo.registerPlugin({ id: 'fu-mac', path: libPath });
const plugin = rtcVideo.getPlugin('fu-mac'); if (!plugin) { console.warn('plugin is null.') return; }
let ret = plugin.setEnabled(true);
本文以第三方美颜插件为例,说明如何将数据传入插件,进行自定义视频处理。JSON
字符串的 key
和 value
需要与所使用的插件进行协定,本节步骤和代码均为示例。
let fuAuth = 'xxx'; plugin.setParameter(JSON.stringify({ "plugin.fu.authdata": JSON.parse(fuAuth) }));
plugin.setParameter(JSON.stringify({"plugin.fu.bundles.load": [{ bundleName: "face_beautification.bundle", bundleOptions: { "filter_name": "origin", "filter_level": 1.0, ... } },{ bundleName: "bg_segment.bundle", bundleOptions: { "picture_path": "", } }]}));
plugin.setParameter(JSON.stringify({"plugin.fu.bundles.update": { bundleName: "face_beautification.bundle", bundleOptions: { // 滤镜 "filter_name": "lengsediao1", "filter_level": 1.0, // 美白 "color_level": 0.3, // 0.0-1.0 // 磨皮 "blur_level": 4.2, // 0.0-6.0 // 大眼 "eye_enlarging": 0.5, // 0.0-1.0 ... } }}));
let vbgPath = path.resolve(__static, 'vertc-mac-x86-64-fu-plugin/bg.png'); plugin.setParameter(JSON.stringify({"plugin.fu.bundles.update": { bundleName: "bg_segment.bundle", bundleOptions: { "picture_path": vbgPath, } }}));
调用 Electron SDK 接口,关闭插件,释放资源。
let ret = plugin.setEnabled(false);
let result = rtcVideo.unregisterPlugin('fu-mac');
let ret = rtcVideo.releasePluginManager();