2 / 32 课程导览与音视频基础

第 1 课:认识 OBS 与它的源码全景

# 第 1 课:认识 OBS 与它的源码全景

本课目标:把这套源码真正编译运行起来,亲手得到一个能跑的 obs64.exe; 然后把第 0 课那张「四大支柱」地图填上完整细节 —— 顶层每个目录是干嘛的,引擎和界面内部又是怎么分块的。 从这一课开始,我们动手了。

上一课我们建立了两样东西:一条流水线(采集→合成→编码→封装→输出)和一张源码地图(四大支柱)。这一课不引入新的音视频概念,而是把「地图」走实 —— 因为后面每一课都要回到这套源码里翻代码,你得先能把它跑起来、找得到路。


# 1.1 先补一点背景:一个 C/C++ 项目是怎么「变成」程序的

📍我们在哪:这一课不碰新的音视频概念,只把「地图」走实。开头先补个背景 —— C/C++ 源码是怎么一步步变成能跑的程序的。

如果你之前只写过 Python、JavaScript 这类「写完直接跑」的语言,那么 C/C++ 项目的「构建」过程可能有点陌生。先花两分钟把它讲清楚,后面才不会懵。

C/C++ 是编译型语言:你写的源码(.c / .cpp 文本文件)电脑没法直接执行,必须先经过两步,翻译成机器能跑的二进制:

  1. 编译(compile):把每个源文件翻译成「目标文件」(机器码片段);
  2. 链接(link):把所有目标文件、加上用到的第三方库(比如负责编解码的 FFmpeg、负责界面的 Qt),拼装成最终的可执行文件 .exe 和动态库 .dll

这里有三个新手常卡住的概念,用一个「盖房子」的比喻一次说清:

概念 是什么 盖房子比喻
源码 你写的 .c / .cpp 设计图纸
依赖库(dependencies) 别人写好的现成功能(FFmpeg、Qt…) 预制好的门窗、水管
编译器(MSVC / Clang / GCC) 把源码翻译成机器码的工具 施工队
构建系统(CMake) 指挥「先编什么、后链接什么、去哪找依赖」 施工说明书 / 总包

OBS 用 CMake 当「施工说明书」。你不直接跟编译器打交道,而是告诉 CMake「我要在 Windows 上构建」,它替你生成一份 Visual Studio 工程,再驱动编译器干活。

关键的好处:同一份 CMake 说明书,在 Windows 上生成 VS 工程、在 macOS 上生成 Xcode 工程、在 Linux 上生成 Ninja 工程 —— 一套源码,三个平台都能构建。这就是第 0 课说的「跨平台」在工程上的落地方式。


# 1.2 依赖从哪来:你不用自己编译 FFmpeg

📍承上启下:知道了要「编译 + 链接」,那 FFmpeg、Qt 这些大零件从哪来?这一节讲 OBS 怎么替你把依赖自动拉下来。

新手做 C/C++ 多媒体项目,最大的拦路虎往往是「依赖地狱」—— 光是把 FFmpeg、Qt 这些大块头编译出来就能耗掉一整天。

OBS 的做法很贴心:这些大依赖你完全不用自己编译,构建时会自动下载官方预编译好的包。 我们来看看这套机制长什么样。

打开仓库根目录的 CMakePresets.json,里面有一段 dependencies,把每个依赖的版本和哈希值钉得死死的:

// CMakePresets.json(节选)
"prebuilt": {                       // 通用依赖:FFmpeg、x264、curl…
    "version": "2025-08-23",
    "hashes": { "windows-x64": "8de229cff6f1..." }
},
"qt6": {                            // 界面框架 Qt6
    "version": "2025-08-23",
    "hashes": { "windows-x64": "c62e82483bc7..." }
},
"cef": {                            // 浏览器源用的 Chromium 内核
    "version": "6533", ...
}
1
2
3
4
5
6
7
8
9
10
11
12

那「下载」这个动作是谁、什么时候触发的?答案在构建脚本里。顶层 CMakeLists.txtinclude(defaults),而在 cmake/windows/defaults.cmake:24 有这么一行:

# cmake/windows/defaults.cmake:24
include(buildspec)
1
2

这个 buildspec 模块的结尾(cmake/windows/buildspec.cmake:84_check_dependencies_windows())会在你配置(configure)阶段自动:读取上面那些版本和哈希 → 从 OBS 官方服务器下载对应的 zip → 校验哈希 → 解压到项目根目录的 .deps/ 文件夹。

下载解压完,.deps/ 大概是这样:

.deps/
├── obs-deps-2025-08-23-x64/        # FFmpeg、x264、curl、librist… 一大堆通用库
├── obs-deps-qt6-2025-08-23-x64/    # Qt6 界面框架
└── windows-deps-*.zip              # 下载下来的原始压缩包(缓存)
1
2
3
4

一句话:.deps/ 不是源码,是构建时自动拉下来的「预制零件」,不需要你手动管。 这也是为什么这个目录通常不进版本库。


# 1.3 动手:把 OBS 编译运行起来

📍承上启下:背景和依赖都清楚了,这一节真刀真枪跑一遍 —— 四条命令,把源码编成一个能启动的 obs64.exe。

理论铺垫够了,现在真刀真枪跑一遍。下面以本课环境 Windows x64 为例。

# 前置工具

  • Visual Studio 2022(含「使用 C++ 的桌面开发」工作负载,自带 MSVC 编译器和较新的 Windows SDK)
  • CMake ≥ 3.28(VS 2022 一般自带,也可单独装)
  • Git

# 四步走

# 1) 拉源码 —— 注意 --recursive,OBS 有几个子模块(下面 1.3 会解释)
git clone --recursive https://github.com/obsproject/obs-studio.git
cd obs-studio

# 2) 配置:用预设生成 Visual Studio 工程;依赖会在这一步自动下载到 .deps/
cmake --preset windows-x64

# 3) 编译:把引擎、所有插件、界面一次性全部编出来
cmake --build --preset windows-x64
1
2
3
4
5
6
7
8
9

这套「配置 → 编译 → 产物」的流程,正是第 0 课那条流水线在构建层面的样子:

从源码到可运行程序的构建流程

第 4 步:运行。 编译产物全在 build_x64/rundir/<配置>/ 下,双击 build_x64/rundir/RelWithDebInfo/bin/64bit/obs64.exe(或 Debug/,取决于你编的配置)就能启动。

偏好图形界面?第 2 步之后,直接用 Visual Studio 打开 build_x64/obs-studio.sln,把 obs-studio 设为启动项目,按 F5 即可 —— 因为 windows-x64 预设用的就是「Visual Studio 17 2022」生成器。

# 关于子模块:为什么要 --recursive

刚才让你加 --recursive,是因为 OBS 把几个组件以 git 子模块的形式挂在仓库里,源码并不直接躺在主仓库中。看 .gitmodules:

# .gitmodules
[submodule "plugins/obs-browser"]      # 浏览器源(基于 CEF)
[submodule "plugins/obs-websocket"]    # WebSocket 远程控制
[submodule "plugins/win-dshow/libdshowcapture"]  # DirectShow 采集库
1
2
3
4

如果忘了 --recursive,这几个目录会是空的,构建时报错。补救命令:

git submodule update --init --recursive
1

⚠️ 顺带记一条坑:.github/scripts/Build-Windows.ps1给 CI 自动化用的,它开头就检查 $env:CI,在你本地直接跑会报错退出。本地开发请用上面的 cmake --preset 命令,别去碰那个脚本。

# 一次成功的构建产出了什么

构建跑完,build_x64/rundir/<配置>/ 就是一个自包含的、可直接运行的 OBS:

一次构建产生的可运行目录

  • bin/64bit/ —— 主程序 obs64.exe 和它运行所需的一堆 DLL(Qt 界面框架、FFmpeg、三套渲染后端 libobs-d3d11/opengl/winrt…);
  • obs-plugins/64bit/ —— 编译出来的 26 个插件 DLL(屏幕采集、x264 编码、RTMP 推流、各种滤镜……),OBS 启动时会扫描并加载它们;
  • data/ —— 运行时资源:主题、多语言文案、内置着色器(.effect)、脚本运行时等。

把这三块放在一起,就是你平时双击运行的那个 OBS。注意「程序」和「插件」是分开的两块 —— 这个「功能即插件」的设计,是理解 OBS 的关键,模块 2 会专门讲。


# 1.4 填满地图(一):顶层目录全景

📍接上一节:程序能跑起来了,回头把第 0 课那张「四大支柱」草图,填成完整的顶层目录清单。

能跑起来了,现在把第 0 课的「四大支柱」展开成完整的顶层目录清单。第 0 课我们说过,这张图几乎就写在顶层 CMakeLists.txt:22add_subdirectory(...) 列表里:

仓库顶层目录全景

按职责分成三组看:

  • 引擎核心与渲染后端:libobs 是发动机;libobs-d3d11(Windows)、libobs-opengl(跨平台)、libobs-metal(macOS)是三套显卡渲染后端,运行时挑一套用;libobs-winrt 封装 Windows 特有能力。
  • 应用层与扩展:frontend(界面)、plugins(功能插件)、shared(公共库)。我们日常开发改动最多的就是这三块。
  • 依赖、构建与文档:deps(随源码自带的小型第三方库,和上面自动下载的大依赖不是一回事)、cmake(构建脚本)、testdocs

小心区分两个「依赖」:

  • deps/ —— 随源码自带的小型库(blake2、glad、json11…),直接参与编译;
  • .deps/ —— 构建时自动下载的大型预编译包(FFmpeg、Qt…)。

一个带点(隐藏目录)、一个不带,别搞混。


# 1.5 填满地图(二):拆开引擎 libobs

📍承上启下:顶层看完,钻进最重要的那块 —— 引擎 libobs,看它内部怎么分「核心对象」和「底层系统」两层。

libobs 是整门课的主战场(模块 2~6 几乎都在它里面打转),值得现在就拆开看看内部结构:

libobs 内部解剖

它分两层:

顶层的 obs-*.c 文件 = 核心对象的实现。 还记得第 0 课在 libobs/obs.h:60 看到的那几个主角吗?它们各自的实现就在这里:obs-source.c(源)、obs-scene.c(场景)、obs-output.c(输出)、obs-encoder.c(编码器)、obs-service.c(服务)。文件名和概念一一对应,非常好找。

子目录 = 支撑这些对象的底层系统:

  • util/(57 个文件)—— C 语言工具层:内存管理、线程、动态数组、obs-data(类 JSON 的配置载体);
  • graphics/ —— 渲染抽象:纹理、着色器(.effect 文件)、矩阵运算;
  • media-io/ —— 音视频帧的管线:audio-iovideo-io、格式转换、重采样 —— 这是流水线里「数据怎么流动」的地基;
  • callback/ —— 信号与回调系统(模块 2 的重点);
  • audio-monitoring/ —— 音频监听回放;
  • data/ —— 内置着色器和多语言文案。

阅读引擎时,libobs/obs.h 就是大门 —— 它把所有核心对象一次性声明齐全,从它出发顺藤摸瓜最省力。


# 1.6 填满地图(三):界面 frontend

📍收束:最后扫一眼界面这一侧 frontend,把地图的最后一块补齐 —— 记住 main() → OBSApp → OBSBasic 这条启动线就够了。

最后看一眼界面这一侧。frontend 是用 C++ / Qt6 写的桌面程序,它的结构可以先建立个印象(细节留到模块 7):

frontend 内部结构

启动链路就三步,记住这条线,以后想从界面追代码就有了起点:

frontend/obs-main.cpp:857  →  OBSApp  →  OBSBasic
   main() 入口               Qt 应用      主窗口(你看到的一切)
                          初始化 libobs
1
2
3

程序从 frontend/obs-main.cpp:857main() 启动,创建 OBSApp(它继承自 Qt 的应用类,负责初始化 libobs),最后把主窗口 OBSBasic 显示出来。

界面的其余部分按功能拆成一堆目录:widgets/(主窗口和控件)、dialogs/(对话框)、docks/(可停靠面板)、settings/(设置)、components/(可复用组件)、forms/(Qt Designer 的 .ui 界面文件)、api/(给前端插件用的 obs-frontend-api)等。

你可能会好奇:主窗口 OBSBasic 怎么会有 OBSBasic_Streaming.cppOBSBasic_Recording.cppOBSBasic_Scenes.cpp 这么多文件?那是因为主窗口功能极多,OBS 把同一个类按功能切分到几十个 .cpp 文件里实现,避免单个文件几万行。这是大型 Qt 项目的常见手法,模块 7 细讲。


# 1.7 本课小结

  • C/C++ 项目要经过编译 + 链接才变成可执行文件;OBS 用 CMake 当「施工说明书」统一指挥,从而做到一套源码跨三平台构建。
  • 大依赖(FFmpeg / Qt / CEF)不用自己编译:configure 阶段由 buildspecCMakePresets.json 里钉死的版本和哈希,自动下载预编译包到 .deps/
  • 本地构建就四步:git clone --recursivecmake --preset windows-x64cmake --build --preset windows-x64 → 运行 build_x64/rundir/<配置>/bin/64bit/obs64.exe。(Build-Windows.ps1 是 CI 专用,本地别用。)
  • 一次构建产出一个自包含可运行目录:bin/(主程序+DLL)、obs-plugins/(26 个插件)、data/(资源)。
  • 顶层目录可归为三组:引擎与渲染后端 / 应用层与扩展 / 依赖构建文档;引擎 libobs 内部是「顶层 obs-*.c 核心对象 + 子目录底层系统」;界面从 obs-main.cppmain()OBSAppOBSBasic

# 1.8 动手 / 观察(本课作业)

  1. 跑通构建(有环境的话):按 1.3 的四步编译出 obs64.exe 并运行。第一次构建会下载依赖、耗时较长,泡杯茶等它。
  2. 数插件:进到 build_x64/rundir/<配置>/obs-plugins/64bit/,数一数有多少个 .dll;再到 data/obs-plugins/ 看看每个插件还带了哪些资源文件。
  3. 认一个插件:打开 plugins/win-capture/(屏幕采集),看一眼它的 CMakeLists.txt 和源码文件名 —— 不用读懂,只要感受一下「一个插件大概由哪些文件组成」。我们模块 3 会真正把它拆开。

# 下一课预告

铺垫到此结束,从下一课起进入正题

第 2 课:视频的本质就是连续的图片 —— 我们会离开源码一小会儿,先把「像素、分辨率、帧、帧率」这些最基础的视频概念用大白话讲透,再回到 libobs/media-io/ 看 OBS 是怎么定义「一帧」的。这是理解整条视频链路的第一块砖。


📁 本课配图:imgs/01-01 ~ imgs/01-05 📌 源码锚点:CMakePresets.jsoncmake/windows/defaults.cmake:24cmake/windows/buildspec.cmake:84CMakeLists.txt:22.gitmoduleslibobs/obs.h:60frontend/obs-main.cpp:857

上次更新: 2026/07/14, 19:37:40

社区交流

讨论与留言

前往 GitHub Issues →

本留言区仅对应当前文章,欢迎补充观点、提出问题或帮助修正文中疏漏。 留言由 GitHub/Gitalk 提供,需要使用 GitHub 登录。

最近更新
第 1 课:专栏导论与安全边界
07-01
第 3 课:安装编译与调试环境
07-01
第 4 课:第三方库下载、编译与依赖管理
07-01
更多文章>