OBS 插件开发实战:5 步写出实时屏幕标注滤镜

OBS 插件开发实战:5 步写出实时屏幕标注滤镜 OBS 插件开发实战5 步写出实时屏幕标注滤镜【免费下载链接】obs-studioOBS Studio - Free and open source software for live streaming and screen recording项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio远程上课你只想在直播画面上随手画个圈强调重点——这个圈得直接落在推流画面上而不是另一个窗口里。这是典型的屏幕标注问题也是一个 OBS 插件开发能解决的典型问题挂一个滤镜在源画面上叠加 GPU 绘制的笔画。跟着走一遍就能从零搭出完整链路。先看看最终效果给场景里的任意源加一个屏幕标注滤镜右侧出现一个小工具栏画笔、橡皮、清空、撤销。鼠标在预览窗口上移动就开始画笔画实时叠加在源画面顶层随画面一起编码推出去观众看到的就是你已经圈好重点的屏幕。整个过程不需要切窗口、不需要截图粘贴。最薄的插件壳我们先搭个能跑的空壳。OBS 里所有源包括滤镜的入口都是obs_source_info结构体仓库里的核心滤镜就是靠 libobs/obs-source.h 里这个结构体注册的官方插件文档 里对模块加载流程也有说明。OBS 滤镜怎么注册最小骨架长这样一个结构体 一行注册static struct obs_source_info screen_annotation { .id screen_annotation, .type OBS_SOURCE_TYPE_FILTER, .output_flags OBS_SOURCE_VIDEO, .get_name annotation_name, .create annotation_create, .destroy annotation_destroy, .update annotation_update, .video_render annotation_render }; bool obs_module_load(void) { return obs_register_source(screen_annotation); }回调的时机基本就是全部约定create在用户把滤镜加到源上时调用destroy在移除时调用update在设置面板改动时调用video_render则是每一帧渲染时调你。注意create/destroy/update里涉及图形资源的地方要包在obs_enter_graphics()/obs_leave_graphics()之间这是 OBS 对图形 API 调用线程的硬性要求仓库里每个滤镜比如plugins/obs-filters/scroll-filter.c都是这个写法。让笔尖真正落在画面上接下来是最短的可用链路捕获输入 → 归一化坐标 → 存点。OBS 把鼠标事件以struct obs_mouse_event的形式派发给源里面就三个有用的字段修饰键、x、y像素坐标。我们只需要把每个点转成 0–1 的归一化坐标存下来static void append_point(struct annotation_data *a, int x, int y) { float nx x / (float)a-width; float ny y / (float)a-height; a-points[a-point_count] (point){ nx, ny, 1.0f }; }这里有个值得说清的设计取舍为什么存 0–1 归一化坐标而不是像素值因为像素坐标绑死分辨率。用户把基础分辨率从 1080p 改成 1440p或者换了采集窗口大小存像素值的笔画就整体漂移了存归一化坐标则天然跟着画面走存档、加载、跨设备都不用换算。OBS 自带的滚动滤镜scroll-filter.c里累计偏移量用的也是同一套 0–1 思路。按下左键开一笔移动时append_point松开收笔——到这里你已经能画了虽然还谈不上画得不卡。从能画到画得不卡CPU 上逐点画线每帧几百上千个点帧率直接掉到个位数你的观众会先于你发现。所以渲染必须走 GPU 加速绘制这条路而且 OBS 已经把最难的部分铺好了用.effect文件而不是裸 GL 代码。OBS 自带一套跨 D3D11/OpenGL/Metal 的着色器抽象create时用gs_effect_create_from_file加载一个.effect文件拿好gs_effect_t *和参数句柄就行三行代码替代一堆glGen*。video_render 里两段式合成先用 OBS 传入的 effect 把原始画面画出来再把自己的线条画在顶层static void annotation_render(void *data, gs_effect_t *effect) { struct annotation_data *a data; draw_base_image(effect); // 1. 原始源画面 for (size_t i 0; i a-stroke_count; i) draw_stroke(a, a-strokes[i]); // 2. 叠加笔画 }批量绘制别每笔重传缓冲。关键问题是每一笔都重新上传整个顶点缓冲你猜帧率会怎样正确姿势是把笔画点序列展开成 GPU 上的顶点条带只有正在书写中的那一笔每帧增量上传新点已完成的笔画顶点常驻显存不动。一笔画几百个点代价从每帧全量上传所有笔画降到每帧上传几个点。线宽和圆角交给着色器。每个线段在片元阶段按距离线段中心的距离做 smoothstep 衰减就得到抗锯齿的圆头线条比在 CPU 里算好纹理快得多也好看得多。让工具真正好用的那些细节骨架通了之后差距在细节。这几项都不难但缺一个用户就会觉得糙压感数位笔的压感值不要只影响整笔粗细而是逐点记录——同一个点结构里多存一个压力字段展开顶点时按点的压力缩放线宽粗细分界才自然。多笔刷实线、高亮、矩形其实共用同一条渲染路径差异只是顶点布局和着色器参数一个枚举就够。撤销/重做命令不用设计得多复杂——新增一笔是唯一的写操作撤销就是弹出最后一条笔画引用重做再压回去。别深拷贝整条轨迹。多场景标注数据挂在源实例上场景切换天然隔离想跨场景共享就给每个场景名挂一份数据切换时存档/恢复。快捷键走 OBS 自带的 hotkey 注册CtrlZ 撤销、一键清空别让工具栏按钮独占交互。别让标注拖垮你的直播功能全之后上线前按 OBS 插件性能优化最常见的三处过一遍帧率自适应用os_gettime_ns()算帧间隔连续几帧低于 30fps 就切简化模式——关掉纹理笔刷和动态效果只画纯色线条恢复后自动切回。内存上限笔画数组设硬上限超了丢最旧的一笔顶点缓冲按笔画增长而不是无限预分配。资源生命周期每个gs_*资源创建必对应 destroy 里的一次释放尤其是update里重建 sampler 时先 destroy 旧的——这是滤镜里最容易泄漏的点scroll-filter.c 里gs_samplerstate_destroy再 create 的写法值得抄。故障现象可能原因处理标注内容闪烁资源在 video_render 中间被重建资源创建移出渲染回调只在 create/update 里动笔画多了帧率骤降每帧全量上传顶点缓冲只对当前笔做增量上传移除滤镜后显存不降destroy 里漏释放 gs 资源每个 create 配对一次 destroy编译、丢进 plugins 目录、验证构建走 OBS 主工程的标准流程插件作为一个子模块编出来git clone https://gitcode.com/GitHub_Trending/ob/obs-studio cd obs-studio mkdir build cd build cmake .. make -j$(nproc) cp -r ../../plugins/screen-annotation $OBS_PLUGIN_DIR/验证顺序先确认 OBS 日志里模块加载成功没有obs_register_source的报错再往任意源上挂滤镜画一笔看预览和推流画面是否一致最后连画几分钟观察显存和帧率曲线不漂移就算过关。源纹理 GPU 批绘叠加这套架构和标注本身没强绑定字幕叠加、动态水印、实时画面滤镜换一套着色器参数和顶点布局就是另一个插件骨架原样复用。【免费下载链接】obs-studioOBS Studio - Free and open source software for live streaming and screen recording项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考