news 2026/10/29 11:11:39

obs录屏

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
obs录屏

【干货】把 OBS 拆到骨头:手把手带你用 libobs 撸一个 40MB 的轻量录屏工具

收藏吃灰警告 ⚠️:本文不是「怎么用 OBS」,而是「怎么把 OBS 当库用」的保姆级拆解,含 5 个让你少走弯路的踩坑经验。建议先点赞收藏,慢慢看~


📌 目录

  • 前言
  • 一、为什么 OBS 那么重?
  • 二、核心思路:OBS 其实是一个「库」
  • 三、架构总览:一条最小的录制管线
  • 四、踩坑①:libobs 的初始化顺序
  • 五、踩坑②:编码器回退链与参数不统一
  • 六、踩坑③:宿主内注册鼠标点击特效源
  • 七、踩坑④:异步停止与 MKV 崩溃恢复
  • 八、踩坑⑤:轻量靠打包,不靠少编译
  • 九、那些「双击没反应」级别的工程细节
  • 总结
  • 参考资料

前言

大家好,我是博主的自研宿主小项目分享。😄

很多小伙伴私信问我:OBS 功能那么强,但我只想录个屏,每次打开它都要等半天,还带一堆用不到的东西,有没有更轻的办法?

答案是有的——而且办法比你想的更硬核:直接放弃 OBS 的前端,把它最核心的libobs当库来用,自己写一个宿主程序。最终成果是一个40MB 出头的绿色免安装目录,没有浏览器、没有推流、没有插件市场,只有一个目标:把屏幕录下来。

这篇文章就带你完整走一遍这个思路,以及过程中踩过的 5 个大坑。全程干货,建议配好水。💧


一、为什么 OBS 那么重?

先说说问题出在哪。

OBS Studio 是桌面录屏/直播的事实标准,强大、免费、插件生态丰富。但它有个公开的秘密:重。

  • 完整安装包动辄200MB+
  • 启动会拉起CEF 浏览器内核(为了浏览器源)
  • 自带WebSocket 服务、虚拟摄像头、推流、插件市场……
  • 一堆你可能一辈子用不到的模块

而真相是:大多数人打开 OBS,只想录个屏。

所以问题就变成了:我能不能只留「录屏」这一条能力,把其余的统统砍掉?

💡划重点:这里的「轻量」不是优化代码,而是做减法——搞清楚你真正需要什么,然后把其余全部拿掉。


二、核心思路:OBS 其实是一个「库」

这是本文最重要的一句话,请务必记住:

OBS 的精髓libobs是一个独立的动态库,obs64.exe加 Qt 前端只是它上面的一层皮。

libobs对外暴露的是一套纯 C API:

API作用
obs_startup/obs_shutdown启动与销毁
obs_reset_video/obs_reset_audio视频 / 音频子系统
obs_source_create创建采集源(显示器、窗口、WASAPI、摄像头…)
obs_encoder_create/obs_output_create创建编码器与输出
obs_load_all_modules2加载插件模块(win-capture、obs-ffmpeg、obs-nvenc…)

也就是说,你完全可以绕开obs-frontend-api、不构建obs64.exe,自己写一个宿主程序,把这套 C API 串起来。

这就是「轻量」的全部秘密:把 OBS 庞大的前端及其配套(浏览器源、推流、插件管理、虚拟摄像头)一次性剔除,只保留一条录制管线。✅


三、架构总览:一条最小的录制管线

先来看一张整体架构图(收藏这张图就够了):

┌──────────────────── minirec.exe(自研宿主,单进程 UI)────────────────────┐ │ UI 层 (Qt6 Widgets):MainWindow / SettingsDialog / RecordingOverlay │ │ │ 信号槽 │ │ 编排层:RecorderController(状态机 + 门面,UI 只和它打交道) │ │ LibobsRuntime · SceneBuilder · EncoderFactory · OutputController · Remux │ │ │ 直接调用 libobs C API │ │ libobs 核心:obs.dll / libobs-d3d11.dll(场景→源→混音→编码→输出) │ │ │ 白名单加载的插件模块 │ │ win-capture · win-wasapi · win-dshow · obs-ffmpeg · obs-outputs │ │ obs-x264 · obs-nvenc · obs-qsv11 │ └──────────────────────────────────┬─────────────────────────────────────────┘ │ 编码后裸流经 IPC 管道 obs-ffmpeg-mux.exe(独立子进程,封装写 MKV) │ 停止后:宿主内 media-remux 流拷贝 → MP4(movflags=+faststart)

核心就一件事:自研 Qt6 宿主,直接调用 libobs 的 C API,组装「采集 → 编码 → 落盘」的最小管线。

下面开始上硬菜,5 个坑,一个比一个隐蔽。🔥


四、踩坑①:libobs 的初始化顺序

libobs 不是「随便调一下就能用」的,初始化顺序错了,轻则功能异常,重则直接崩溃。

在LibobsRuntime里,顺序严格对齐 OBS 前端:

// 1. 工作目录必须是 exe 所在目录——libobs 在 Windows 上靠**相对路径**// 查找核心数据(../../data/libobs)与默认插件目录。SetCurrentDirectoryW(exeDir);// 2. 自检:obs.dll / libobs-d3d11.dll / default.effect / 插件目录 / mux.exe 都在,// 缺了直接给明确中文报错,而不是"双击没反应"。// 3. 启动obs_startup("zh-CN",configDir,nullptr);// 4. 先 reset 音频/视频(图形模块在此加载),再 load 插件模块obs_reset_audio(&aoi);// 48000Hz / 立体声obs_reset_video(&ovi);// 此时加载 libobs-d3d11obs_load_all_modules2(&failure);obs_post_load_modules();

⚠️这里有个非显而易见的顺序陷阱:必须先obs_reset_video再obs_load_all_modules2。

原因是win-capture(窗口/显示器捕获插件)在自己的obs_module_load阶段要探测 D3D11 与 WGC(Windows Graphics Capture)能力——如果你还没加载图形模块就去 load 插件,它探测不到,采集能力会静默降级。

视频参数里还埋着一个硬编码零拷贝的前提:

ovi.output_format=VIDEO_FORMAT_NV12;// NV12 + GPU 转换是硬编零拷贝的前提ovi.gpu_conversion=true;ovi.colorspace=VIDEO_CS_709;ovi.range=VIDEO_RANGE_PARTIAL;ovi.scale_type=OBS_SCALE_BICUBIC;ovi.graphics_module="libobs-d3d11";

💡小贴士:这里如果不用 NV12,走 NVENC 硬编码时,帧数据就得多一次 GPU↔CPU 的搬运,白白烧掉性能和延迟。


五、踩坑②:编码器回退链与参数不统一

OBS 支持一堆硬编方案,但不是每台机器都有——老显卡、缺驱动、精简系统,随时可能翻车。

所以编码器不能写死,得做成一条优先级链,创建成功就用,失败立刻下一个:

return{"obs_nvenc_h264_tex",// NVIDIA NVENC(GPU 纹理直通)"h264_texture_amf",// AMD AMF"obs_qsv11_v2",// Intel Quick Sync"obs_x264",// 软件兜底};

⚠️划重点:判断「真可用」不能只看插件注册了没有,得实际obs_video_encoder_create()试探一次——显卡/驱动不支持时,注册了也会创建失败。

更烦人的坑是各家硬编对设置键的命名和取值不统一,尤其是码控rate_control:

// NVENC:preset 用 p4/p5,multipass 用 qresobs_data_set_string(settings,"rate_control","CQP");obs_data_set_string(settings,"preset",highQuality?"p5":"p4");obs_data_set_string(settings,"multipass",highQuality?"qres":"disabled");// QSV:target_usage 用 TU4/TU7(大小写敏感,写错直接不生效甚至创建失败)obs_data_set_string(settings,"target_usage",highQuality?"TU4":"TU7");// x264:preset 换一套名字obs_data_set_string(settings,"preset",highQuality?"faster":"veryfast");

💡小贴士:这堆「家族专属」的参数填充,是硬编码最容易翻车的暗礁。MiniRec 的做法是统一走CQP(恒定质量)码控,再按家族分别填键——比「一刀切填一套参数」可靠得多。


六、踩坑③:宿主内注册鼠标点击特效源

点击涟漪是很多录屏工具的标志性功能。最「轻」的做法是不额外写插件 DLL,直接在宿主里注册一个obs_source_info,然后用内嵌 HLSL 着色器画圆环:

// 内嵌字符串着色器:按到圆心的距离画一圈环,半径/透明度随时间衰减。// 内嵌字符串可避免额外的 .effect data 文件依赖(gs_effect_create 直接编译)。constchar*kEffectSource=R"( uniform float4x4 ViewProj; uniform float2 quad_size; uniform float2 center; uniform float radius; uniform float thickness; uniform float4 color; ... float4 PSRing(VertInOut vert_in) : TARGET { float2 pixel = vert_in.uv * quad_size; float dist = distance(pixel, center); float band = 1.0 - saturate(abs(dist - radius) / max(thickness, 0.5)); float core = 1.0 - smoothstep(0.0, max(radius * 0.5, 1.0), dist); float alpha = saturate(band + core * 0.35); return float4(color.rgb, color.a * alpha); } )";

这里有两个隐藏坑,都是「日志报错看起来很玄学」的那种:

  1. gs_effect_create必须在图形上下文里调用。源是在主线程通过obs_source_create创建的,此刻 libobs 并不持有图形上下文——直接编译着色器会失败,日志里是「called while not in a graphics context」,而且error还是空的。解法是手动obs_enter_graphics()/obs_leave_graphics()包一层。

  2. 点击事件不能碰图形接口。鼠标点击用SetWindowsHookEx(WH_MOUSE_LL)全局低级钩子采集,回调里只入队、绝不碰图形。队列是个无锁环形队列(volatile LONG头尾指针 +InterlockedExchange,容量 128,满了丢最旧事件)——宁可丢几个特效帧,也不阻塞用户输入。

在video_render里,把屏幕物理坐标映射到源坐标,过滤掉采集范围外的点击(比如点了副屏),然后「半径由小变大、透明度由强变弱」逐涟漪绘制:

constfloatscaleX=fx->captureW>0?fx->width/fx->captureW:1.0f;ripple.x=(events[i].x-fx->captureX)*scaleX;ripple.y=(events[i].y-fx->captureY)*scaleY;

这个源作为独立 scene item 叠在采集画面之上(后加入 → 绘制在上层),铺满整块画布对齐像素。✅


七、踩坑④:异步停止与 MKV 崩溃恢复

录屏工具最怕两件事:停止时卡死 UI,以及崩溃后文件打不开。

停止是异步的。obs_output_stop()只是发出停止请求,真正收尾发生在 libobs 输出线程的回调里。如果傻等,UI 线程会直接冻住。MiniRec 的做法是等stop信号回来,再用QMetaObject::invokeMethod(..., QueuedConnection)投递回主线程收尾。

录制中一律写 MKV。这是 OBS 的默认策略:MKV 边写边封装,崩溃/断电后文件仍可播放;而直接写 MP4 一旦中断,moov头没落盘,整个文件就废了。停止后再用 libobs 自带的media_remux_job_*做流拷贝转 MP4(movflags=+faststart,方便网页秒开),成功后可删 MKV。

配套的还有一层崩溃恢复保险:录制开始时写一个recording.lock标记(记录 MKV 路径),正常结束删除;下次启动若发现残留标记,提示用户上次异常结束、目录里可能有待验证的 MKV。

整条流程被收敛成一个状态机,UI 只订阅stateChanged:

Idle → Countdown → Starting → Recording ⇄ Paused → Stopping → Remuxing → Idle

八、踩坑⑤:轻量靠打包,不靠少编译

一个反直觉的结论:OBS 的 install 规则会覆盖所有已配置 target,所以「少编译」几乎做不到——build-obs.ps1实际还是整包编译的。真正的「轻量」发生在打包阶段。

package.ps1做两件关键的事:

① 白名单裁剪

只保留这 8 个插件,其余(浏览器、推流、VLC、AJA、DeckLink、虚拟摄像头、VST…)全砍:

win-capture · win-wasapi · win-dshow · obs-ffmpeg · obs-outputs · obs-x264 · obs-nvenc · obs-qsv11

② 依赖 DLL 补齐

OBS 的_bundle_dependencies只挂在自带前端目标上,而本工程不构建前端,所以得自己用dumpbin /dependents扫导入表(含传递依赖),从 obs-deps / Qt / VC 运行时分发里循环补齐,直到不再新增。

⚠️这里极易踩的坑:千万别删obs-nvenc-test.exe/obs-qsv-test.exe/obs-amf-test.exe。

NVENC/QSV 在obs_module_load阶段会CreateProcess拉起这些小工具探测驱动——删了它们,硬件编码会静默退回 x264,你还以为硬编生效了。

另外,保持 OBS 原生目录结构(bin/64bit+data/+obs-plugins/64bit)是硬约束,因为 libobs 靠相对路径找数据,动了目录就找不到着色器。


九、那些「双击没反应」级别的工程细节

做 GUI 程序最怕的就是用户双击后没反应、还没控制台可看。MiniRec 为此做了几层防御:

  • ✅自检报错:缺关键文件直接弹明确中文报错(“缺少 libobs 核心库:…”),而不是默默退出。
  • ✅双写日志:正式日志写%APPDATA%\MiniRec\logs\(带 UTF-8 BOM,记事本能正确显示中文,保留 7 天);兜底日志写 exe 同级的minirec-startup.log——即使%APPDATA%不可写,也能查清「双击没反应」的原因。
  • ✅DPI 声明PerMonitorV2:多显示器独立缩放,否则区域录制的坐标会错位。
  • ✅画布偶数化:所有宽高向下取偶,否则 H.264 编码奇数宽高直接报错。
  • ✅配置防御性校验:fps / 分辨率 / 倒计时超范围时回落,用 libobs 的obs_data_save_json_safe做 tmp/bak 原子写。

总结

来,一张表帮你把核心要点收走:

主题要点
核心思路OBS 是「库」不是「App」,绕开前端直调 libobs C API
初始化先 reset_video 再 load_modules,否则 win-capture 探测不到 D3D11/WGC
编码优先级链 + 实际创建试探,各家族 rate_control 键名不统一要分别填
鼠标特效宿主内注册 source + 内嵌 HLSL,注意图形上下文与无锁队列
停止异步收尾 + MKV 录制 + 流拷贝转 MP4(faststart)
打包白名单裁剪 + dumpbin 扫依赖,别删 *-test.exe

最终产物是一个约40MB 的绿色免安装目录:录全屏 / 指定窗口 / 区域,系统声音 + 麦克风独立开关,NVENC / QSV / AMF / x264 自动回退,画质档一键预设,托盘 + 全局热键(F9 开始/停止、F10 暂停),倒计时,录制中悬浮控制条,摄像头画中画,鼠标点击涟漪,MKV 录制 + 自动转 MP4(faststart)。

代价是明确的:没有直播推流、没有浏览器源、没有虚拟摄像头、没有插件市场、没有剪辑、没有云上传、也没有游戏捕获。这些都被有意砍掉了——不是做不了,而是「录屏工具」这个定位不需要它们。


参考资料

  • 源码与实现细节:
    • 初始化:minirec/src/core/LibobsRuntime.cpp
    • 编码器回退:minirec/src/core/EncoderFactory.cpp
    • 鼠标特效:minirec/src/core/MouseFxSource.cpp+MouseEventHook.cpp
    • 状态机:minirec/src/core/RecorderController.h
    • 打包:minirec/packaging/package.ps1
  • 项目说明:README.md

📢声明:本文为博主原创,基于个人项目实践经验整理,转载请注明出处。

如果这篇文章对你有帮助,点赞 + 收藏 + 关注走一波~ 有问题欢迎在评论区留言,看到必回。💬

🚀 下一篇预告:如果你想「文件少到只剩一个 exe」,我会讲讲单文件打包的三条路线(7-Zip SFX / Enigma Virtual Box / 自研资源内嵌)的利弊对比,敬请期待~
执行文件 https://download.csdn.net/download/lg15273112290/93764456

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 11:11:37

物理AI的核心挑战在于获取符合物理规律的训练数据

2026年10月24日至25日,CSDN在长沙世界计算长沙智谷举办了"2026长沙1024程序员日暨AI构建者大会",主题为"具身同行,智构未来",线下参会人数超1500人。 大会以具身智能与物理AI为主线,设置了开幕式暨…

作者头像 李华
网站建设 2026/10/29 11:10:47

VCP-CLIP

文章目录AbstractIntroductionRelated WorkPrompt learningZero-shot anomaly segmentationMethodProblem DefinitionThe design of baseline、The design of VCP-CLIPPre-VCPPost-VCPTraining and InferenceLoss FunctionInferenceExperimentExperimental SetupComparison wit…

作者头像 李华
网站建设 2026/10/29 11:10:33

和弦图分析

和弦图分析:学生成绩数据一、什么是和弦图和弦图是一种用“环状节点 连接弦线”来展示多个对象之间关系的图表。通常所有对象均匀分布在一个圆周上,任意两个对象之间若有联系,就用一条从一方弧向另一方的弦连接起来。和弦图常用来呈现相关性…

作者头像 李华
网站建设 2026/10/29 11:09:24

港口机械视觉实战:从集装箱箱号OCR到岸桥吊装监控的完整方案设计

港口机械视觉实战:从集装箱箱号OCR到岸桥吊装监控的完整方案设计 机器视觉选型笔记 行业应用实战第 11 篇 **阅读提示:**本文约 6300 字,预计阅读 16 分钟。如果你正在做码头岸桥/场桥的箱号识别、闸口 OCR 或者吊装安全监控方案&#xff0…

作者头像 李华
网站建设 2026/10/29 11:09:04

AI Agent下沉,OPC接单:个体级工具背后,看得还是交付能力

AI Agent再也不是大企业采购清单上的一个条目,而是开始以极低的门槛进入个体经营者的日常工作流。OPC(一人公司)这个词也因此被反复提起,一个人加一组AI工具,接单、交付、结算,理论上可以跑通过去需要一支团…

作者头像 李华