首页
/ OBS Studio 后端设计解析:libobs 的插件对象、三大线程与音视频管线全解

OBS Studio 后端设计解析:libobs 的插件对象、三大线程与音视频管线全解

2026-09-04 18:39:40作者:郁楠烈Hubert

OBS Studio 的后端由 libobs 库驱动,本文基于官方设计文档 docs/sphinx/backend-design.rst 并结合仓库源码,完整拆解 libobs 的四大插件对象(Source、Output、Encoder、Service)、三大核心线程(图形/视频/音频线程)、输出通道(Output Channels)机制,以及视频与音频两条数据管线的完整流转过程。读完本文,你将能够准确描述 OBS 中一帧画面和一段音频从采集源到编码器、再到推流/录像输出的全链路,并能在 libobs/ 源码中定位到每个环节对应的实现文件与关键常量。

后端核心:libobs 库

OBS Studio 的后端(Backend)由 libobs 库提供。libobs 承担三项职责(见 docs/sphinx/backend-design.rst 开篇说明):

  • 主处理管线(main pipeline);
  • 视频/音频子系统;
  • 所有插件的通用框架(general framework for all plugins)。

整个 libobs/ 目录即其源码主体,其中 libobs/obs.clibobs/obs-internal.hlibobs/obs-defs.h 是核心实现、内部结构与全局定义的入口;图形渲染则由 libobs-opengl/libobs-d3d11/libobs-metal/ 三个平台适配层实现。

Libobs 的四种插件对象

libobs 被设计为模块化结构:加载模块即添加自定义功能。官方文档明确指出,可以针对以下四种 libobs 对象编写插件:

1. Source(源)——plugins_sources

Source 用于在推流中渲染视频和/或音频:捕获屏幕/游戏/音频、播放视频、显示图像、播放音频等。Source 还可以用来实现音频和视频滤镜。

从源码结构看,仓库内置插件印证了这一分类:

2. Output(输出)——plugins_outputs

Output 用于输出当前渲染中的音频/视频。推流(Streaming)和录像(Recording)是两个最常见的输出类型,但并非全部。Output 既可以接收原始数据(raw data),也可以接收已编码数据(encoded data)。

仓库中的实现包括 plugins/obs-outputs/(高级输出、媒体输出等)与 plugins/obs-ffmpeg/(FFmpeg 录像输出)。

3. Encoder(编码器)——plugins_encoders

Encoder 是 OBS 特有的视频/音频编码器封装,专门配合"使用编码器"的 Output 工作。文档列举的三个典型实现 x264、NVENC、Quicksync 在仓库中均有对应插件目录:

编码器对象的核心封装实现在 libobs/obs-encoder.c(对外头文件为 libobs/obs-encoder.h)。

4. Service(服务)——plugins_services

Service 是流媒体服务的自定义实现,配合"用于推流"的 Output 工作。例如可以针对 Twitch 做一个 Service 实现、针对 YouTube 再做另一个,各自负责登录并调用其 API 来完成"获取 RTMP 服务器地址"或"控制频道"等操作。仓库中 plugins/rtmp-services/ 即为 Twitch、YouTube 等服务的实现。

文档作者注(Author's note):截至文档撰写之时,Service API 尚不完整(incomplete as of this writing)。引用该 API 时请以当前仓库 libobs/obs-service.clibobs/obs-service.h 的实际定义为准。

Libobs 的三大核心线程

libobs 在初始化时创建三个主要线程,分别负责渲染、视频编码/输出、音频处理:

线程 函数 所在文件 职责
图形线程 obs_graphics_thread libobs/obs-video.c 用于渲染(preview 显示 + 最终混合画面)
视频输出线程 video_thread libobs/media-io/video-io.c 用于视频编码/输出
音频线程 audio_thread libobs/media-io/audio-io.c 全部音频处理/编码/输出

三个线程的当前源码位置:

  • obs_graphics_thread:位于 libobs/obs-video.c。函数进入循环前会将线程局部标志 is_graphics_thread 置为 truelibobs/obs-video.c),循环主体由 obs_graphics_thread_loop 驱动,并带有 obs_graphics_thread(x ms) 的性能分析计时点。
  • video_thread:位于 libobs/media-io/video-io.c,即文档所指的"video output handler",其线程函数消费帧缓存队列并向下游分发帧。
  • audio_thread:位于 libobs/media-io/audio-io.c。源码中可以看到,在 Windows 平台上它会调用 AvSetMmThreadCharacteristics(L"Audio", ...) 提升音频线程的系统优先级(见 libobs/media-io/audio-io.c),这解释了为什么音频管线要求严格的周期节拍。

文档作者注:obs_graphics_thread 原名 obs_video_thread,后重命名为现名,以避免与 video_thread 混淆。阅读较早期版本代码时需注意这一点。

输出通道(Output Channels)

视频或音频渲染的起点是输出通道。通过 obs_set_output_source() 函数,把一个 source 分配到指定输出通道;参数 channel 可取 0..(MAX_CHANNELS-1) 中的任意编号。

当前仓库中 MAX_CHANNELS 的取值为 64(定义于 libobs/obs-defs.h,注释为 "Maximum number of source channels for output and per display"),即每个显示/输出最多可挂载 64 个通道的 source。

通道机制与 source 层级结构

初看之下,通道似乎只是"同时显示多个 source"的手段;但官方文档特别指出:source 是层级结构(hierarchical)。像 scene(场景)、transition(转场)这样的 source 可以拥有多个子 source,而这些子 source 又可以继续拥有子 source,层层嵌套。因此典型用法是:使用 scene 将一组 source 作为整体绘制,并为每个子 source 指定各自的 transform(位置/缩放/裁剪)。scene 本身也只是另一种 source 类型。

正是"通道 + 层级 source"这一设计,使得后端可以支撑极其复杂的视频呈现方案。文档同时说明:OBS Studio 前端目前尚未充分利用这一后端设计——渲染时只使用一个输出通道、一次渲染一个场景;但会为"全局音频源"(在音频设置中配置的、跨场景常驻的音频 source)等额外占用其他通道。

文档作者注(重要辨析):"Output channels"(输出通道)不要与 output 对象(output objects)或音频声道(audio channels)混淆:

  • 输出通道:用来声明"你想把哪些 source 送出去";
  • output 对象:实际执行推流/录像等动作的实体;
  • 音频声道:立体声、5.1 等扬声器布局概念。

视频管线总览(General Video Pipeline)

视频图形管线由两条线程协同驱动:

  1. 专用图形线程libobs/obs-video.c 中的 obs_graphics_thread):渲染 preview 显示与最终混合画面(final mix);
  2. 专用视频编码/输出线程libobs/media-io/video-io.c 中的 video_thread)。

完整数据流如下:

  1. 绘制各通道 source。分配到输出通道(0..(MAX_CHANNELS-1))的 source 被依次绘制到最终纹理(final texture)上,该纹理将用于后续输出。

  2. 像素格式转换。所有 source 绘制完成后,最终纹理被转换为 libobs 所配置的后端视频格式(通常是某种 YUV 格式)。

  3. 送入视频处理器。转换后的帧连同其时间戳一起被送往当前视频处理器 obs_core_video::video(结构定义见 libobs/obs-internal.h)。

  4. 入帧缓存队列。视频输出处理器把原始帧放入容量为 MAX_CACHE_SIZE 的队列,随后 post 一个信号量(semaphore);video-io 线程随能力处理队列中的帧。

    源码佐证:MAX_CACHE_SIZE 定义为 16libobs/media-io/video-io.c);struct video_output 中的 struct cached_frame_info cache[MAX_CACHE_SIZE]os_sem_t *update_semaphore 成员正是该队列与信号量的实现(libobs/media-io/video-io.c)。

  5. 队列满时复制末帧。如果视频帧队列已满,会复制(duplicate)队列中最后一帧,以降低视频编码复杂度(从而降低 CPU 占用)。这就是编码器跟不上时你会看到跳帧(frame skipping)现象的根源。

  6. 分发。帧被发送给当前处于活动状态的原始输出(raw outputs)视频编码器

    struct video_input 中还带有 frame_rate_divisor 相关计数器(见 libobs/media-io/video-io.c 的注释),允许以主合成帧率的分数倍输出,例如 60 FPS 合成、30 FPS 编码——文档提到的帧队列机制与此同属 video-io 层的分发逻辑。

  7. 编码与交织。若帧发往视频编码器对象(libobs/obs-encoder.c),编码器完成编码后,把编码包(encoded packet)发送给该编码器所连接的一个或多个输出。若该输出同时接收编码后的视频与音频,则把音视频包放入交织队列(interleave queue),以确保编码包按单调递增的时间戳顺序发出(交织逻辑位于 libobs/obs-output.c)。

  8. 最终送达输出。编码包或原始帧被送往 output 完成写入/发送。

音频管线总览(General Audio Pipeline)

音频管线运行在音频处理器中专用的音频线程上(libobs/media-io/audio-io.c 中的 audio_thread)。

节拍周期(Tick)

假设 AUDIO_OUTPUT_FRAMES 设为 1024(当前仓库取值即 1024,见 libobs/media-io/audio-io.h),则音频线程每 1024 个音频采样"tick"一次(处理一次音频数据)。按 48 kHz 采样率计算,约每 21 毫秒处理一次(1024 / 48000 ≈ 21.3 ms)。

tick 的调用链在源码中清晰可见:audio_thread 循环内 samples += AUDIO_OUTPUT_FRAMES 后以 os_sleepto_ns_fast 精确休眠到目标时间,再调用 input_and_output()libobs/media-io/audio-io.c),后者最终回调到 libobs/obs-audio.c 中的 audio_callback——绝大部分音频处理都在这里完成

同一头文件还定义了音频管线的其他关键上限(libobs/media-io/audio-io.h):

  • MAX_AUDIO_MIXES 6:最多 6 路独立混音流(mix);
  • MAX_AUDIO_CHANNELS 8:最多 8 个音频声道;
  • TOTAL_AUDIO_SIZE:按上述上限计算的总混音缓冲尺寸。

Source 音频的注入:采样率/声道重混与滤镜

带音频的 source 通过 obs_source_output_audio() 函数输出音频(当前实现位于 libobs/obs-source.c),音频数据被追加或插入到该 source 的环形缓冲区 obs_source::audio_input_buf 中。在此过程中:

  • 若 source 的采样率或声道数与后端配置不一致,音频会自动重混/重采样(remix/resample)——底层经由 FFmpeg 的 swresample 组件完成;
  • 插入之前,音频数据还会先经过挂在该 source 上的所有音频滤镜

每个 Tick 的树快照与逐级上混

这是音频管线最精妙的部分,官方文档将其拆为三步:

  1. 引用快照。每个音频 tick,音频线程对音频 source 树取一份引用快照(存储所有输出/处理音频的 source 引用)。
  2. 叶子节点取样。对每个音频叶子(audio source,即真正产生音频的节点),从环形缓冲区 obs_source::audio_input_buf 中取出相对当前音频线程时间戳最接近的那段音频,放入 obs_source::audio_output_buf
  3. 逐级向上传播。叶子节点 audio_output_buf 中的采样数据沿着快照树向父节点传播,在每个层级节点做混音或处理。拥有多个子节点的 source(如 scene、transition)通过 obs_source_info::audio_render 回调(定义于 libobs/obs-source.h自行混音/处理子节点的音频
    • 这一设计允许转场(transition)在两个 source 之间切换时,淡出一个 source 的音频、淡入另一个 source 的音频
    • 混音/处理后的结果同样存入该节点自身的 obs_source::audio_output_buf,过程重复直至音频到达树的根节点

最终混音与输出

当音频到达快照树的基座(base)后,各输出通道内所有 source 的音频被混合为最终混音(final mix),随后发送给当前活动的原始输出音频编码器(分发逻辑位于 libobs/media-io/audio-io.c)。

若发送目标是音频编码器对象(libobs/obs-encoder.c),编码器编码后把编码包发往其连接的一个或多个输出;若输出同时接收编码音视频,则同样进入交织队列,保证编码包按单调时间戳顺序发出(libobs/obs-output.c)。最终,编码包或原始音频数据被送往 output。

源码中还有一个细节可补充文档描述:在 libobs/media-io/audio-io.cclamp_audio_output() 中,最终混音结果会被钳制到 -1.0..1.0,并对 NaN 值做归零处理——这是音频输出前的最后一道数值保护。

关键常量与源码索引速查

常量/符号 取值 定义位置 含义
MAX_CHANNELS 64 libobs/obs-defs.h 每个显示/输出的最大 source 通道数
MAX_CACHE_SIZE 16 libobs/media-io/video-io.c 视频帧缓存队列容量(满则复制末帧)
AUDIO_OUTPUT_FRAMES 1024 libobs/media-io/audio-io.h 音频线程每次 tick 处理的采样数
MAX_AUDIO_MIXES 6 libobs/media-io/audio-io.h 最大独立混音流数量
MAX_AUDIO_CHANNELS 8 libobs/media-io/audio-io.h 最大音频声道数

相关实现文件索引:

小结

OBS Studio 后端设计的精髓可以概括为三点:其一,四种插件对象(Source/Output/Encoder/Service)构成清晰的模块化扩展面,仓库内 plugins/ 目录下的数十个内置插件即为这一框架的实例;其二,三条职责单一的线程(图形、视频输出、音频)把渲染、编码、混音解耦,线程间以帧队列 + 信号量解耦视频数据流;其三,通道 + 层级 source 树的抽象,使同一套后端既能驱动 OBS 前端"单通道渲染单场景"的当前用法,也保留了多通道、任意嵌套的扩展空间。理解上述结构与 docs/sphinx/backend-design.rst 中逐帧、逐 tick 的数据流描述,即可完整掌握 libobs 从 source 到最终输出的全部技术细节。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384