首页
/ OBS Studio 前端 API 深度解析:obs-frontend-api.h 的事件回调、场景/配置控制与 Qt 主窗口实现

OBS Studio 前端 API 深度解析:obs-frontend-api.h 的事件回调、场景/配置控制与 Qt 主窗口实现

2026-09-04 18:46:44作者:庞眉杨Will

OBS Studio 的 libobs 核心负责采集、渲染与输出,而插件若需要操作界面本身——切换场景、启停推流、注册事件回调、添加 Dock——则必须依赖 Frontend API。本文以官方 API 参考 reference-frontend-api.rst 为主体,逐一覆盖其定义的 obs_frontend_event 事件枚举、obs_frontend_source_list 结构与全部 API 函数,并结合 frontend/api/ 目录的源码实现(分发器模式、OBSStudioAPI 对 Qt 主窗口的桥接),讲清楚该 API 的调用链路、内存管理与线程安全约定,帮助你写出可稳定嵌入 OBS Studio 的 C/C++ 插件。

一、Frontend API 的定位与整体架构

Frontend API 是 OBS Studio 自身(而非 libobs 核心)提供的 API,使用方式非常直接:

#include <obs-frontend-api.h>

从源码结构看,它的分层非常清晰,一次典型调用会经过四层:

  1. C 语言导出层obs-frontend-api.h 声明全部 EXPORT 函数,并以 extern "C" 暴露,供 C/C++ 插件链接;
  2. 分发层obs-frontend-api.cpp 持有一个 static unique_ptr<obs_frontend_callbacks> c,每个导出函数先经 callbacks_valid() 校验再转发给该指针;
  3. 纯虚接口层obs-frontend-internal.hpp 定义 obs_frontend_callbacks 抽象类,把整个 API 面抽象为一组纯虚函数,实现端还包括 on_load/on_preload/on_save/on_event 四个内部钩子;
  4. Qt 实现层OBSStudioAPI.hpp 中的 OBSStudioAPI 结构体实现该接口,内部持有 OBSBasic *main(即 OBSBasic.hpp 定义的主窗口类),通过 QMetaObject::invokeMethod 把跨线程请求安全地投递回 UI 线程。

前端启动时由 OBSStudioAPI.cppInitializeAPIInterface 完成装配:

obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main)
{
	obs_frontend_callbacks *api = new OBSStudioAPI(main);
	obs_frontend_set_callbacks_internal(api);
	return api;
}

退出时 OBSBasic.cpp 会调用 obs_frontend_set_callbacks_internal(nullptr) 注销回调,此后任何前端调用都会在分发层被拦截并记录 "Tried to call %s with no callbacks!" 错误日志(见 obs-frontend-api.cpp)。

构建方面,frontend/api/CMakeLists.txtobs-frontend-api 编译为 SHARED 库、链接 OBS::libobs,并以 obs-frontend-api.hPUBLIC_HEADER 对外发布头文件。因此插件工程链接 OBS::frontend-api 即可使用整套 API。

需要说明的前提:Frontend API 只有在带 Qt 前端的 OBS Studio 中才有实现;返回值中的 void * 实际是 Qt 对象(QMainWindow *QWidget *QAction * 等),在 C 侧被当作不透明指针处理。

二、核心数据结构与类型

2.1 obs_frontend_source_list:场景/过渡源列表

文档给出的核心结构是一个基于 DARRAY 的源指针数组。在 obs-frontend-api.h 中的实际定义如下,obs_frontend_source_list_free 本身就是一个头文件内联函数:

struct obs_frontend_source_list {
	DARRAY(obs_source_t *) sources;
};

static inline void obs_frontend_source_list_free(struct obs_frontend_source_list *source_list)
{
	size_t num = source_list->sources.num;
	for (size_t i = 0; i < num; i++) {
		obs_source_release(source_list->sources.array[i]);
	}
	da_free(source_list->sources);
}

文档中的标准用法示例(务必完整遵循其释放纪律):

struct obs_frontend_source_list scenes = {0};

obs_frontend_get_scenes(&scenes);

for (size_t i = 0; i < scenes.sources.num; i++) {
      /* Do NOT call `obs_source_release` or `obs_scene_release`
       * on these sources
       */
      obs_source_t *source = scenes.sources.array[i];

      /* Convert to obs_scene_t if needed */
      obs_scene_t *scene = obs_scene_from_source(source);

      [...]
}

obs_frontend_source_list_free(&scenes);

引用计数的规则在文档中写得很明确,源码也印证了这一点:

  • obs_frontend_get_scenes 返回的是已增加引用的场景,与 Scenes dock 的显示顺序一致;
  • 不得在遍历中对列表内元素单独调用 obs_source_release / obs_scene_release,否则会造成双重释放、甚至导致场景被删除;统一用 obs_frontend_source_list_free 收尾;
  • 若需要长期持有某个场景,应先用 obs_source_get_ref / obs_scene_get_ref 增引用,释放时只调用其中一种(两者释放的是同一对象)。

obs_frontend_get_transitions 也使用同一结构接收“引用已增的过渡源列表”,释放方式相同。

2.2 回调函数类型

文档定义了五类回调原型,均带 void *private_data 用户数据(翻译回调除外):

类型 原型 用途
obs_frontend_cb void (*)(void *private_data) 前端“工具”菜单项点击回调
obs_frontend_event_cb void (*)(enum obs_frontend_event, void *private_data) 前端事件回调
obs_frontend_save_cb void (*)(obs_data_t *save_data, bool saving, void *private_data) 场景集保存/加载回调(saving 区分方向)
obs_frontend_translate_ui_cb bool (*)(const char *text, const char **out) UI 翻译拦截回调
undo_redo_cb void (*)(const char *data) 撤销/重做回调,携带数据字符串

2.3 obs_frontend_event:前端事件枚举

obs_frontend_event 枚举(定义见 obs-frontend-api.h)是插件与界面同步的核心。文档覆盖的完整事件集合如下,按功能分组:

直播(Streaming)

事件 触发时机
OBS_FRONTEND_EVENT_STREAMING_STARTING 直播启动时
OBS_FRONTEND_EVENT_STREAMING_STARTED 直播成功启动后
OBS_FRONTEND_EVENT_STREAMING_STOPPING 直播停止时
OBS_FRONTEND_EVENT_STREAMING_STOPPED 直播完全停止后

录像(Recording)

事件 触发时机
OBS_FRONTEND_EVENT_RECORDING_STARTING 录像启动时
OBS_FRONTEND_EVENT_RECORDING_STARTED 录像成功启动后
OBS_FRONTEND_EVENT_RECORDING_STOPPING 录像停止时
OBS_FRONTEND_EVENT_RECORDING_STOPPED 录像完全停止后
OBS_FRONTEND_EVENT_RECORDING_PAUSED 录像被暂停时
OBS_FRONTEND_EVENT_RECORDING_UNPAUSED 录像恢复(取消暂停)时

场景与过渡(Scene / Transition)

事件 触发时机
OBS_FRONTEND_EVENT_SCENE_CHANGED 当前场景改变时
OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED 用户添加/删除/重排场景时
OBS_FRONTEND_EVENT_TRANSITION_CHANGED 用户更改当前过渡时
OBS_FRONTEND_EVENT_TRANSITION_STOPPED 一次过渡执行完成时
OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED 用户添加/删除过渡时
OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED 用户更改过渡时长时
OBS_FRONTEND_EVENT_TBAR_VALUE_CHANGED 过渡 T 条被拖动时

场景集 / 配置档(Scene Collection / Profile)

事件 触发时机
OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING 当前场景集即将切换时
OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED 当前场景集已切换后
OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED 场景集被添加或删除时
OBS_FRONTEND_EVENT_SCENE_COLLECTION_RENAMED 场景集被重命名时
OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP 场景集被完全卸载(即将加载新场景集或即将退出)时
OBS_FRONTEND_EVENT_PROFILE_CHANGING 当前 profile 即将切换时
OBS_FRONTEND_EVENT_PROFILE_CHANGED 当前 profile 已切换后
OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED profile 被添加或删除时
OBS_FRONTEND_EVENT_PROFILE_RENAMED profile 被重命名时

回放缓冲 / 虚拟摄像头 / Studio Mode

事件 触发时机
OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING 回放缓冲启动时
OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED 回放缓冲成功启动后
OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING 回放缓冲停止时
OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED 回放缓冲完全停止后
OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVING 回放缓冲正在保存时
OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED 回放缓冲已保存后
OBS_FRONTEND_EVENT_VIRTUALCAM_STARTED 虚拟摄像头启动时
OBS_FRONTEND_EVENT_VIRTUALCAM_STOPPED 虚拟摄像头停止时
OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED 用户开启 Studio Mode(预览/节目)
OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED 用户关闭 Studio Mode
OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED Studio Mode 下预览场景改变时

程序生命周期与杂项

事件 触发时机 版本
OBS_FRONTEND_EVENT_FINISHED_LOADING 程序完成加载时 基础
OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN 脚本需要在 OBS 退出前得知时。通常 OBS_FRONTEND_EVENT_EXIT 在脚本被销毁之后才触发 基础
OBS_FRONTEND_EVENT_EXIT 程序即将退出。这是最后调用任何前端 API 做保存/清理的机会,回调返回后不得再发起任何前端 API 调用 基础
OBS_FRONTEND_EVENT_THEME_CHANGED 主题切换时 29.0.0
OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN 截图完成时 29.0.0

补充一个源码层面的细节:头文件枚举中还额外定义了 OBS_FRONTEND_EVENT_CANVAS_ADDEDOBS_FRONTEND_EVENT_CANVAS_REMOVEDobs-frontend-api.h),配合多画布(canvas)能力使用,官方 RST 参考目前未将其列入正文。

三、API 函数参考(按功能分组)

以下函数签名与文档一致,全部声明于 obs-frontend-api.h

3.1 场景列表与当前场景

函数 说明
void obs_frontend_source_list_free(struct obs_frontend_source_list *source_list) 释放列表内所有源并释放列表本身
void *obs_frontend_get_main_window(void) 返回 OBS Studio 主窗口的 QMainWindow *
void *obs_frontend_get_main_window_handle(void) 返回主窗口的原生窗口句柄
char **obs_frontend_get_scene_names(void) 返回以 NULL 结尾的场景名列表,顺序与 Scenes dock 显示一致。列表存于单一连续内存段,用 bfree() 释放基指针即可释放整个列表
void obs_frontend_get_scenes(struct obs_frontend_source_list *sources) 填充“引用已增”的场景列表(见 2.1 节的释放纪律)
obs_source_t *obs_frontend_get_current_scene(void) 返回当前激活场景的新引用,用 obs_source_release() 释放
void obs_frontend_set_current_scene(obs_source_t *scene) 设置当前场景

源码印证:OBSStudioAPI.cppobs_frontend_get_scenes 正是遍历 Scenes dock 的列表项(main->ui->scenes)逐个 da_push_back,因此“顺序与 Scenes dock 一致”是有源码依据的;而 obs_frontend_set_current_scene 在 Studio Mode 下会走 TransitionToScene 触发过渡,否则直接调用 SetCurrentSceneOBSStudioAPI.cpp)。

3.2 过渡(Transition)与 T 条

函数 说明
void obs_frontend_get_transitions(struct obs_frontend_source_list *sources) 接收“引用已增”的过渡源列表,用 obs_frontend_source_list_free 释放
obs_source_t *obs_frontend_get_current_transition(void) 返回当前过渡的新引用,用 obs_source_release() 释放
void obs_frontend_set_current_transition(obs_source_t *transition) 设置当前过渡
int obs_frontend_get_transition_duration(void) 返回 UI 中当前设置的过渡时长(毫秒)
void obs_frontend_set_transition_duration(int duration) 设置过渡时长(毫秒)
void obs_frontend_release_tbar(void) 模拟鼠标在 T 条上松开,确定过渡状态
void obs_frontend_set_tbar_position(int position) 设置 T 条数值,取值范围 0–1023
int obs_frontend_get_tbar_position(void) 获取 T 条数值,范围 0–1023

从实现看,set_current_transitionset_transition_durationrelease_tbarset_tbar_position 均通过 QMetaObject::invokeMethod 投递到 UI 线程(OBSStudioAPI.cpp),插件可在非 UI 线程安全调用这些“写”类接口。

3.3 场景集(Scene Collection)

函数 说明
char **obs_frontend_get_scene_collections(void) 场景集名称列表,NULL 结尾、单段内存,bfree() 释放
char *obs_frontend_get_current_scene_collection(void) 当前场景集名的新指针,bfree() 释放
void obs_frontend_set_current_scene_collection(const char *collection) 激活指定名称的场景集
bool obs_frontend_add_scene_collection(const char *name) 新建场景集并切换到它;返回是否成功

3.4 配置档(Profile)

函数 说明
char **obs_frontend_get_profiles(void) profile 名称列表,NULL 结尾、单段内存,bfree() 释放
char *obs_frontend_get_current_profile(void) 当前 profile 名的新指针,bfree() 释放
char *obs_frontend_get_current_profile_path(void) 当前 profile 的文件系统路径,bfree() 释放
void obs_frontend_set_current_profile(const char *profile) 激活指定 profile
bool obs_frontend_create_profile(const char *name) 创建新 profile(名称必须唯一)
bool obs_frontend_duplicate_profile(const char *name) 复制当前 profile 为指定新名称(必须唯一)
void obs_frontend_delete_profile(const char *profile) 删除指定 profile

3.5 UI 扩展:工具菜单与 Dock

函数 说明
void *obs_frontend_add_tools_menu_qaction(const char *name) 向“工具”菜单添加 QAction 并返回其指针
void obs_frontend_add_tools_menu_item(const char *name, obs_frontend_cb callback, void *private_data) 添加菜单项并把 ::clicked 信号连接到回调
bool obs_frontend_add_dock_by_id(const char *id, const char *title, void *widget) QWidget 添加 Dock,并在“停靠窗口”菜单生成开关项。Dock 关闭时会向该控件发送类型为 QEvent::User + QEvent::Close 的自定义事件,便于其释放资源;显示时默认已有通用 QShowEvent。id 已占用时返回 false。30.0 加入
void obs_frontend_remove_dock(const char *id) 从 UI 移除指定 id 的 Dock。30.0 加入
bool obs_frontend_add_custom_qdock(const char *id, void *dock) 添加不带菜单开关的自定义 QDockWidget。30.0 加入

3.6 事件回调与保存/预加载回调

函数 说明
void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data) 注册前端事件回调
void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, void *private_data) 移除事件回调
void obs_frontend_add_save_callback(obs_frontend_save_cb callback, void *private_data) 注册场景集保存/加载回调
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, void *private_data) 移除保存/加载回调
void obs_frontend_add_preload_callback(obs_frontend_save_cb callback, void *private_data) 注册“场景集加载前”的回调
void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback, void *private_data) 移除预加载回调

保存/预加载/事件三组回调在 OBSStudioAPI.hpp 中分别以 saveCallbackspreloadCallbackscallbacks 三个向量管理,回调及其 private_data 被打包进 OBSStudioCallback<T>。事件分发的一个值得注意的细节在 OBSStudioAPI.cpp:当主窗口处于禁用保存状态(main->disableSaving)时,除 SCENE_COLLECTION_CLEANUPEXIT 之外的所有事件都会被过滤,保证插件在清理阶段仍能收到收尾事件。

3.7 UI 翻译拦截

函数 说明
void obs_frontend_push_ui_translation(obs_frontend_translate_ui_cb translate) 压入 UI 翻译回调,允许前端插件拦截 Qt 自动生成翻译文本的过程,通常传入 obs_module_get_string
void obs_frontend_pop_ui_translation(void) 弹出当前 UI 翻译回调

obs-frontend-api.h 中的注释明确提醒:OBS UI 绕过了 Qt 的标准本地化机制,插件 UI 不应直接使用 Qt 的翻译方法,而应在文本即将被翻译时 push、翻译完成后 pop

3.8 直播、录像与回放缓冲控制

函数 说明
void obs_frontend_streaming_start(void) 启动直播
void obs_frontend_streaming_stop(void) 停止直播
bool obs_frontend_streaming_active(void) 直播是否激活
void obs_frontend_recording_start(void) 启动录像
void obs_frontend_recording_stop(void) 停止录像
bool obs_frontend_recording_active(void) 录像是否激活
void obs_frontend_recording_pause(bool pause) true 暂停录像,false 取消暂停
bool obs_frontend_recording_paused(void) 录像是否处于暂停
bool obs_frontend_recording_split_file(void) 请求拆分当前录像文件。true 仅代表“请求成功”(不保证已完成或确实拆分),录像未激活/已暂停或拆分功能被禁用时返回 false
bool obs_frontend_recording_add_chapter(const char *name) 在当前输出时刻插入章节标记。name 可为 NULL(使用自动名 “Unnamed <章节号>” 或本地化等价名)。录像未激活、暂停或当前输出不支持章节时返回 false。30.2 加入
void obs_frontend_replay_buffer_start(void) 启动回放缓冲
void obs_frontend_replay_buffer_stop(void) 停止回放缓冲
void obs_frontend_replay_buffer_save(void) 回放缓冲激活时保存一次回放
bool obs_frontend_replay_buffer_active(void) 回放缓冲是否激活

从源码看,streaming_active/recording_active 等状态查询是原子地读取 volatile bool 标志位(如 OBSStudioAPI.cpp 使用 os_atomic_load_bool(&streaming_active)),因此这些“读”类接口可以安全地在任意线程调用;而启停操作则通过 invokeMethod 回到 UI 线程执行。

3.9 投影仪窗口(Projector)

函数 说明
void obs_frontend_open_projector(const char *type, int monitor, const char *geometry, const char *name) 打开投影仪。type 取值不区分大小写:"Preview""Source""Scene""StudioProgram""Multiview"monitor-1 时打开为普通窗口,此时 geometry 生效(Base64 编码的 Qt 几何信息);type"Source""Scene"name 指定要显示的源或场景名

3.10 输出对象、配置与推流服务

函数 说明
void obs_frontend_save(void) 保存当前场景集
obs_output_t *obs_frontend_get_streaming_output(void) 当前直播输出的新引用,用 obs_output_release() 释放
obs_output_t *obs_frontend_get_recording_output(void) 当前录像输出的新引用
obs_output_t *obs_frontend_get_replay_buffer_output(void) 当前回放缓冲输出的新引用
config_t *obs_frontend_get_profile_config(void) 当前 profile 对应的 config_t *(不拥有所有权)
config_t *obs_frontend_get_global_config(void) 31.0 起弃用:原返回全局配置(global.ini)。实现中会打印弃用警告并转发到 obs_frontend_get_app_configobs-frontend-api.cpp
config_t *obs_frontend_get_app_config(void) 系统级设置(global.ini)对应的 config_t *。31.0 加入
config_t *obs_frontend_get_user_config(void) 用户设置(user.ini)对应的 config_t *。31.0 加入
void obs_frontend_set_streaming_service(obs_service_t *service) 设置当前推流服务
obs_service_t *obs_frontend_get_streaming_service(void) 当前推流服务对象(不增加引用
void obs_frontend_save_streaming_service(void) 保存当前推流服务数据

3.11 Studio Mode(预览/节目)

函数 说明
bool obs_frontend_preview_program_mode_active(void) Studio Mode 是否激活
void obs_frontend_set_preview_program_mode(bool enable) 开启/关闭 Studio Mode
void obs_frontend_preview_program_trigger_transition(void) Studio Mode 激活时触发“预览到节目”过渡
obs_source_t *obs_frontend_get_current_preview_scene(void) Studio Mode 激活时返回当前预览场景的新引用(否则 NULL),用 obs_source_release() 释放
void obs_frontend_set_current_preview_scene(obs_source_t *scene) 设置 Studio Mode 下的预览场景;非 Studio Mode 时不生效
void obs_frontend_set_preview_enabled(bool enable) 设置预览画面开关状态,仅在 Studio Mode 关闭时相关
bool obs_frontend_preview_enabled(void) 预览画面是否启用

源码印证:obs_frontend_get_current_scene 在 Studio Mode 下返回的是 programScene(节目场景)而非预览场景(OBSStudioAPI.cpp),这一点在写自动化脚本时需要特别注意。

3.12 截图、虚拟摄像头与视频重置

函数 说明
void *obs_frontend_take_screenshot(void) 对 OBS 主输出截图,返回图像数据(QImage *
void *obs_frontend_take_source_screenshot(obs_source_t *source) 对指定源截图
obs_output_t *obs_frontend_get_virtualcam_output(void) 当前虚拟摄像头输出的新引用
void obs_frontend_start_virtualcam(void) 启动虚拟摄像头
void obs_frontend_stop_virtualcam(void) 停止虚拟摄像头
bool obs_frontend_virtualcam_active(void) 虚拟摄像头是否激活
void obs_frontend_reset_video(void) 依据当前 profile 的最新数据重载 UI 画布并重置 libobs 视频

3.13 源窗口、输出路径、本地化与主题

函数 说明
void *obs_frontend_open_source_properties(obs_source_t *source) 打开指定源的属性窗口
void *obs_frontend_open_source_filters(obs_source_t *source) 打开指定源的滤镜窗口
void *obs_frontend_open_source_interaction(obs_source_t *source) 打开指定源的交互窗口;仅当源具有 OBS_SOURCE_INTERACTION 输出标志时才可调用
void *obs_frontend_open_sceneitem_edit_transform(obs_sceneitem_t *item) 打开指定 scene item 的变换编辑窗口。29.1 加入
char *obs_frontend_get_current_record_output_path(void) 当前录像输出路径的新指针,bfree() 释放
const char *obs_frontend_get_locale_string(const char *string) 获取给定字符串的前端翻译
bool obs_frontend_is_theme_dark(void) 当前主题是否为深色。29.0.0 加入
char *obs_frontend_get_last_recording(void) 最后一次录像的文件路径,bfree() 释放。29.0.0 加入
char *obs_frontend_get_last_screenshot(void) 最后一次截图的文件路径,bfree() 释放。29.0.0 加入
char *obs_frontend_get_last_replay(void) 最后一次回放缓冲保存的文件路径,bfree() 释放。29.0.0 加入

3.14 撤销/重做与场景项复制粘贴

函数 说明
void obs_frontend_add_undo_redo_action(const char *name, const undo_redo_cb undo, const undo_redo_cb redo, const char *undo_data, const char *redo_data, bool repeatable) 注册一个撤销/重做动作。repeatabletrue 时,同名的多个动作可合并为一个撤销/重做动作(撤销取第一个、重做取最后一个)。29.1 加入
void obs_frontend_copy_sceneitem(obs_sceneitem_t *item) 复制指定场景项。32.2 加入
bool obs_frontend_can_paste_sceneitem(bool duplicate) 查询已复制的场景项能否粘贴(duplicate 用于检查所复制源是否允许复制方式粘贴)。32.2 加入
void obs_frontend_paste_sceneitem(obs_scene_t *scene, bool duplicate) 粘贴到指定场景:true 为粘贴副本,false 为粘贴引用。32.2 加入

四、内存管理约定(务必遵守)

Frontend API 的字符串与对象返回遵循三套明确的释放规则,obs-frontend-api.h 中的注释与分发层实现共同确定了这套契约:

  1. char ** 字符串列表是“单次分配”。以 obs-frontend-api.cppconvert_string_list 为例:它先用 bmalloc 分配一段连续内存,前部存放 char * 指针数组(末尾置 nullptr),后部紧跟各字符串数据(含终止符)。因此只需对基指针调用一次 bfree(),整个列表(含所有字符串)即被释放——不要对单个元素再 free。
  2. char * 单串返回值(如 obs_frontend_get_current_profileobs_frontend_get_current_profile_pathobs_frontend_get_current_record_output_pathobs_frontend_get_last_* 系列)均为新分配指针,统一用 bfree() 释放。实现侧使用 bstrdup 复制字符串(OBSStudioAPI.cpp),确认了“返回新指针、调用方负责释放”的语义。
  3. libobs 引用计数对象obs_source_t *obs_output_t * 等):get_current_sceneget_current_transitionget_*_output 均返回新引用,用对应 obs_*_release 释放;而 obs_frontend_get_streaming_service 明确不增加引用,这是所有 get 函数中唯一的例外,文档已特别注明。
  4. 事件与退出顺序OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN 在脚本体系销毁前触发,供脚本感知退出;OBS_FRONTEND_EVENT_EXIT 是程序退出的最后通知,回调返回之后不允许再调用任何前端 API——这与分发层“退出时注销回调”的实现(OBSBasic.cpp)相互印证。

五、源码实现要点与线程安全

分发器模式。 obs-frontend-api.cpp 中所有导出函数都是薄封装:先 callbacks_valid() 校验(失败则 blog(LOG_ERROR, ...) 并返回空/false/0),再转发给 obs_frontend_callbacks。这使得前端 API 库可以独立于 Qt 实现构建,也解释了为什么插件在未装配前端(例如纯 libobs 环境)中调用这些函数不会崩溃,而是得到错误日志加空值。

跨线程 UI 操作。 写 UI 的操作在 OBSStudioAPI.cpp 中普遍采用 QMetaObject::invokeMethod(main, ..., WaitConnection(), ...) 形式,即阻塞式地把方法调用投递到主窗口的 UI 线程并等待完成。obs_frontend_add_scene_collection 甚至通过 lambda 捕获出参 success 的方式把 UI 线程的结果带回调用方(OBSStudioAPI.cpp)。可以推断:插件从非 UI 线程调用这些接口是受支持的,但会短暂阻塞等待 UI 线程。

回调注册/注销的匹配规则。 回调以“函数指针 + private_data”二元组识别(OBSStudioAPI.cppGetCallbackIdx),移除回调时两组参数都必须与注册时完全一致。

弃用演进。 obs_frontend_get_global_config 在 31.0 被 OBS_DEPRECATED 标记,实现层会输出弃用警告并建议显式使用 obs_frontend_get_app_configobs_frontend_get_user_configobs-frontend-api.cpp),新代码应直接采用后两者。

SWIG 边界。 头文件中 obs_frontend_source_listobs_frontend_canvas_list 及其内联释放函数被 #ifndef SWIG 包裹(obs-frontend-api.h),说明脚本绑定(Python 等)走的是另一套适配路径,C/C++ 插件则直接使用这些结构。

六、版本演进小结与适用前提

综合文档中的 versionadded 标注,该 API 的主要演进节点为:

版本 新增能力
29.0.0 OBS_FRONTEND_EVENT_THEME_CHANGEDOBS_FRONTEND_EVENT_SCREENSHOT_TAKENobs_frontend_is_theme_darkobs_frontend_get_last_recording/screenshot/replay
29.1 obs_frontend_open_sceneitem_edit_transformobs_frontend_add_undo_redo_action
30.0 Dock 管理三件套:obs_frontend_add_dock_by_idobs_frontend_remove_dockobs_frontend_add_custom_qdock
30.2 obs_frontend_recording_add_chapter
31.0 obs_frontend_get_app_configobs_frontend_get_user_configobs_frontend_get_global_config 弃用
32.2 场景项复制粘贴:obs_frontend_copy_sceneitemobs_frontend_can_paste_sceneitemobs_frontend_paste_sceneitem

适用前提与限制:

  • 该 API 面向运行中的 OBS Studio(Qt 前端);返回值中的 void * 是 Qt 对象指针,在纯 C 环境中只能当不透明句柄传递;
  • 头文件 obs-frontend-api.h 中还包含少量文档未覆盖的函数(如 obs_frontend_get_system_trayobs_frontend_defer_save_begin/end 及 canvas 管理函数),本文以官方 RST 参考文档列出的函数为准,额外函数请直接查头文件确认签名;
  • 插件工程侧只需链接构建产物中的 OBS::frontend-api 目标(见 frontend/api/CMakeLists.txt),无需自行编译 OBS 前端代码。

参考文件docs/sphinx/reference-frontend-api.rstfrontend/api/obs-frontend-api.hfrontend/api/obs-frontend-api.cppfrontend/api/obs-frontend-internal.hppfrontend/OBSStudioAPI.hppfrontend/OBSStudioAPI.cppfrontend/widgets/OBSBasic.hpp

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