首页
/ OBS Studio 输出 API 详解:从 obs_output_info 到数据捕获的完整机制

OBS Studio 输出 API 详解:从 obs_output_info 到数据捕获的完整机制

2026-09-04 10:12:11作者:姚月梅Lane

本文围绕 libobs 的 Output API 参考文档展开,系统讲解 obs_output_t 输出对象的定义结构(obs_output_info)、输出信号体系、通用控制函数以及输出实现内部使用的数据捕获接口,并结合仓库中 obs-output.hobs-output.cobs-outputs 插件 的真实实现,帮助开发者从零实现并正确驱动一个 OBS 输出。

1. 输出对象与对象模型

输出(Output)是 libobs 中负责把当前正在渲染的音频/视频数据送往外部目的地的对象。直播推流和录像是两种最常见的输出类型,但这并非全部——输出既可以接收原始(raw)音视频数据,也可以接收已编码(encoded)的数据。实现输出所依赖的专用头文件是 libobs/obs-output.h,核心头文件入口为 obs.h

#include <obs.h>

输出对象是引用计数对象,libobs 提供两种引用形态:

  • obs_output_t:强引用,引用计数为 0 时对象销毁;
  • obs_weak_output_t:弱引用,用于在回调、异步线程中避免悬空指针。

配套的弱引用管理函数包括:

函数 作用
obs_output_get_ref(output) 若对象仍有效则返回加一后的强引用,否则返回 NULL
obs_output_release(output) 释放一个强引用,最后一个引用释放后销毁对象
obs_output_get_weak_output(output) / obs_weak_output_get_output(weak) 强引用与弱引用互相转换;对象已销毁时后者返回 NULL
obs_weak_output_addref(weak) / obs_weak_output_release(weak) 增加/释放弱引用
obs_weak_output_references_output(weak, output) 判断弱引用是否指向指定输出

这种强/弱双引用模式是 libobs 中所有长生命周期对象(source、encoder、service、output)的统一做法,跨线程持有输出时必须先转弱引用。

2. 输出定义结构 obs_output_info

obs_output_info 是注册输出类型时填写的定义结构,完整字段与 obs-output.h 中的 struct obs_output_info 一一对应。

2.1 能力标志 flags(必填)

flags 是位或组合的能力标志(文档作者注:此名应叫 capability_flags),由 obs-output.h 定义:

#define OBS_OUTPUT_VIDEO (1 << 0)
#define OBS_OUTPUT_AUDIO (1 << 1)
#define OBS_OUTPUT_AV (OBS_OUTPUT_VIDEO | OBS_OUTPUT_AUDIO)
#define OBS_OUTPUT_ENCODED (1 << 2)
#define OBS_OUTPUT_SERVICE (1 << 3)
#define OBS_OUTPUT_MULTI_TRACK (1 << 4)
#define OBS_OUTPUT_CAN_PAUSE (1 << 5)

各标志的语义与约束:

  • OBS_OUTPUT_VIDEO / OBS_OUTPUT_AUDIO / OBS_OUTPUT_AV:声明输出能接收视频、音频或两者(AV 为前两者组合)。
  • OBS_OUTPUT_ENCODED:输出接收已编码数据。设置该标志后,输出必须通过 obs_output_set_video_encoder() 和/或 obs_output_set_audio_encoder() 绑定编码器才能启动。
  • OBS_OUTPUT_SERVICE:输出需要一个服务对象。设置后必须通过 obs_output_set_service() 绑定 service 才能启动,通常用于向特定平台推流的直播输出。
  • OBS_OUTPUT_MULTI_TRACK:支持多音轨,即同时输出多路编码音频轨。
  • OBS_OUTPUT_CAN_PAUSE:支持暂停。暂停时原始或编码的音视频数据会在最接近的视频帧处精确停止,音频数据会按该视频帧时间点被精确截断。

2.2 回调函数族

必填回调

回调 说明
get_name(type_data) 返回输出类型的本地化显示名
create(settings, output) 创建输出的实现数据(implementation data),返回实现指针
destroy(data) 销毁实现数据
start(data) 启动输出。允许先起线程、立即返回 true,之后通过信号通知失败
stop(data, ts) 请求在指定时间 ts 停止。实际停止发生在 obs_output_end_data_capture()obs_output_signal_stop() 被调用时;ts 为 0 表示立即停止

数据回调(按输出类型二选一)

  • raw_video(data, frame) / raw_audio(data, frames):接收原始视频/音频帧,仅用于非编码输出。注意 raw_audio 必须用于单轨原始输出
  • raw_audio2(data, idx, frames):多轨原始输出的音频回调,idx 为音轨索引;
  • encoded_packet(data, packet):接收编码后的视频/音频包,仅用于编码输出。包总是按单调时间戳顺序送达;若 packetNULL,说明发生了编码器错误,输出应调用 obs_output_signal_stop() 并传入错误码 OBS_OUTPUT_ENCODE_ERROR

可选回调与成员

成员 说明
update(data, settings) 运行时更新设置
get_defaults(settings) / get_defaults2(type_data, settings) 通过 obs_data_set_default* 系列函数填充默认设置
get_properties(data) / get_properties2(data, type_data) 返回属性表,供前端自动生成设置 UI
unused1 已弃用的占位回调
get_total_bytes(data) 返回自启动以来处理的总字节数
get_dropped_frames(data) 返回因网络拥塞丢掉的帧数
type_data / free_type_data(type_data) 私有类型数据。它与实现数据不同,用于在多个输出类型复用同一组回调时加以区分
get_congestion(data) 返回当前拥塞度(0.0f~1.0f),用于可视化推流输出的积压情况
get_connect_time_ms(data) 返回连接服务器所耗毫秒数
encoded_video_codecs / encoded_audio_codecs 以分号分隔声明支持的编码器;设置 OBS_OUTPUT_SERVICE 时必填,否则建议填写
protocols 以分号分隔声明支持的协议;仅在设置 OBS_OUTPUT_SERVICE 时必填(29.1 起)

仓库中 RTMP 输出的真实定义展示了这些字段的典型填法(rtmp-stream.c):

struct obs_output_info rtmp_output_info = {
	.id = "rtmp_output",
	.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_SERVICE | OBS_OUTPUT_MULTI_TRACK_AV,
	.protocols = "RTMP;RTMPS",
	.encoded_video_codecs = "h264;hevc;av1",
	.encoded_audio_codecs = "aac",
	.get_name = rtmp_stream_getname,
	.create = rtmp_stream_create,
	...
	.encoded_packet = rtmp_stream_data,
	.get_congestion = rtmp_stream_congestion,
	.get_connect_time_ms = rtmp_stream_connect_time,
};

而录像输出 mp4_output 则演示了另一组组合:无 service、支持暂停(mp4-output.c):

struct obs_output_info mp4_output_info = {
	.id = "mp4_output",
	.flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_MULTI_TRACK_AV | OBS_OUTPUT_CAN_PAUSE,
	.encoded_video_codecs = "h264;hevc;av1",
	.encoded_audio_codecs = "aac;alac;flac;opus",
	...
};

3. 输出信号(Signals)

每个输出对象自带信号处理器,用于通知前端输出的生命周期状态。可用 obs_output_get_signal_handler() 获取(其生命周期由 libobs 管理,不应手动释放)。

信号清单:

信号 触发时机
starting (ptr output) 输出正在启动
start (ptr output) 输出已启动
activate (ptr output) 输出激活,开始捕获数据
deactivate (ptr output) 输出去激活,停止捕获数据
stopping (ptr output) 输出正在停止
stop (ptr output, int code) 输出已停止,code 为停止原因码
pause / unpause (ptr output) 输出暂停 / 取消暂停
reconnect (ptr output) 输出正在重连
reconnect_success (ptr output) 重连成功

stop 信号的 code 参数取值在 obs-defs.h 中有明确定义:

#define OBS_OUTPUT_SUCCESS 0            /* 成功停止 */
#define OBS_OUTPUT_BAD_PATH -1          /* 路径无效 */
#define OBS_OUTPUT_CONNECT_FAILED -2    /* 连接服务器失败 */
#define OBS_OUTPUT_INVALID_STREAM -3    /* 流地址无效 */
#define OBS_OUTPUT_ERROR -4             /* 一般错误 */
#define OBS_OUTPUT_DISCONNECTED -5      /* 意外断开 */
#define OBS_OUTPUT_UNSUPPORTED -6      /* 设置/格式/编码器不受支持 */
#define OBS_OUTPUT_NO_SPACE -7          /* 磁盘空间不足 */
#define OBS_OUTPUT_ENCODE_ERROR -8      /* 编码器错误 */

从源码结构看,输出内部还维护 activereconnectingstoppingdelay_active 等原子状态位(见 obs-output.c),配合上述信号构成完整的状态机。

4. 注册与创建

4.1 注册

void obs_register_output(struct obs_output_info *info);

通常在 obs_module_load() 或程序初始化阶段调用。仓库中的 obs-outputs 插件 即是在模块加载时集中注册 rtmp_outputflv_outputmp4_outputnull_output 等类型。注意 obs-output.h 中实际导出的是带结构体尺寸参数的 obs_register_output_s(info, size)obs_register_output 只是自动传入 sizeof(struct obs_output_info) 的宏,这一设计允许库在不破坏 ABI 的前提下扩展结构体字段(如 raw_audio2protocols)。

4.2 创建与查询

obs_output_t *obs_output_create(const char *id, const char *name,
                                obs_data_t *settings, obs_data_t *hotkey_data);
  • id:输出类型字符串标识;
  • name:期望的名称,若非唯一会被自动改名为唯一值;
  • settings:初始化设置,可为 NULL
  • hotkey_data:已保存的快捷键数据,可为 NULL

创建成功后必须用 obs_output_release() 配对释放。其他查询函数:

  • obs_output_get_display_name(id):调用 get_name 回调返回本地化显示名;
  • obs_output_get_name(output) / obs_output_get_id(output):获取实例名与类型标识;
  • obs_output_defaults(id):返回默认设置(需 obs_data_release() 释放);
  • obs_output_properties(output) / obs_get_output_properties(id):返回属性表(用 obs_properties_destroy() 释放),前端可用它自动生成设置界面控件;
  • obs_output_update(output, settings):更新实例设置。

5. 生命周期控制:启动、停止、暂停

5.1 启动与停止

bool obs_output_start(obs_output_t *output);
void obs_output_stop(obs_output_t *output);
void obs_output_force_stop(obs_output_t *output);
bool obs_output_active(const obs_output_t *output);
  • obs_output_start 返回 true 表示启动成功;失败时可通过 obs_output_get_last_error() 获取具体错误字符串。由于 start 回调允许异步失败(先返回 true 再用信号报错),启动结果最终体现在 start/stop 信号上;
  • obs_output_stop优雅停止:输出会先把调用时刻之前的数据全部发送完毕,停止成功后才发出 stop 信号;
  • obs_output_force_stop 则跳过等待,尝试立即停止。

5.2 暂停

bool obs_output_can_pause(const obs_output_t *output);
bool obs_output_pause(obs_output_t *output, bool pause);
bool obs_output_paused(const obs_output_t *output);

仅当定义时声明 OBS_OUTPUT_CAN_PAUSE 时才支持。仓库中的 mp4_outputmov_output 都声明了该标志(mp4-output.c),这正是 OBS 录像界面支持"暂停录制"的底层能力来源。

5.3 延迟(Delay)

void obs_output_set_delay(obs_output_t *output, uint32_t delay_sec, uint32_t flags);
uint32_t obs_output_get_delay(const obs_output_t *output);
uint32_t obs_output_get_active_delay(const obs_output_t *output);

set_delay 设置秒级延迟;若延迟已在生效中,新值只影响下一次激活。flags 可取 0 或 OBS_OUTPUT_DELAY_PRESERVE——重连时从断点继续,但代价是等待重连期间延迟缓冲区持续增长、消耗额外内存。get_active_delay 返回当前实际生效的延迟值(开启 PRESERVE 后该值可能增长)。

5.4 重连

void obs_output_set_reconnect_settings(obs_output_t *output,
                                       int retry_count, int retry_sec);
bool obs_output_reconnecting(const obs_output_t *output);

retry_count 为 0 表示禁用重连;重试间隔每次翻倍以避免压垮服务端。从源码看,libobs 对重连等待还设有上限与增长因子:RECONNECT_RETRY_MAX_MSEC(15 分钟)与 RECONNECT_RETRY_BASE_EXP(1.5f),见 obs-output.c——文档描述的"翻倍"是对外语义,内部实现采用 1.5 倍指数增长并以 15 分钟封顶。

31.1 起还提供 obs_output_set_reconnect_callback(),回调在每次重连决策前被调用,可用于动态更新过期的推流密钥,返回 false 可放弃重连;传入 NULL 即移除回调。

6. 数据路由:媒体、混音器、编码器与 Service

6.1 原始输出的媒体绑定

void obs_output_set_media(obs_output_t *output, video_t *video, audio_t *audio);
video_t *obs_output_video(const obs_output_t *output);
audio_t *obs_output_audio(const obs_output_t *output);

set_media 通常为输出绑定 obs_get_video() / obs_get_audio(),使原始输出能挂接到原始视频/音频帧回调上。编码输出不需要此步,其数据来自编码器。

6.2 音频混音器选择

void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx);
size_t obs_output_get_mixer(const obs_output_t *output);
void obs_output_set_mixers(obs_output_t *output, size_t mixers);
size_t obs_output_get_mixers(const obs_output_t *output);

这两个接口仅对非编码输出有意义,用于选择参与该输出的音频混音轨。set_mixer 等价于"掩码中只保留指定索引";set_mixers 使用位掩码,单轨输出会取掩码中第一个置位的轨道(若掩码为空则取第一轨)。

6.3 编码器与 Service 绑定

void obs_output_set_video_encoder(obs_output_t *output, obs_encoder_t *encoder);
void obs_output_set_audio_encoder(obs_output_t *output, obs_encoder_t *encoder, size_t idx);
obs_encoder_t *obs_output_get_video_encoder(const obs_output_t *output);
obs_encoder_t *obs_output_get_audio_encoder(const obs_output_t *output, size_t idx);

void obs_output_set_service(obs_output_t *output, obs_service_t *service);
obs_service_t *obs_output_get_service(const obs_output_t *output);
  • 音频编码器按 idx 索引,支持多音频流场景;
  • getter 返回的引用不加引用计数,不要自行释放;
  • service 绑定针对 RTMP 这类需要推送目标的服务型输出。

obs-output.h 中还定义了两个上限常量:MAX_OUTPUT_AUDIO_ENCODERS 6MAX_OUTPUT_VIDEO_ENCODERS 10,即多轨场景下可同时挂载的音频/视频编码器数量上限。

6.4 缩放、码流统计与拥塞

void obs_output_set_preferred_size(obs_output_t *output, uint32_t width, uint32_t height);
uint32_t obs_output_get_width(const obs_output_t *output);
uint32_t obs_output_get_height(const obs_output_t *output);

uint64_t obs_output_get_total_bytes(const obs_output_t *output);
int obs_output_get_frames_dropped(const obs_output_t *output);
int obs_output_get_total_frames(const obs_output_t *output);

float obs_output_get_congestion(const obs_output_t *output);
int obs_output_get_connect_time_ms(const obs_output_t *output);

set_preferred_size 设置首选缩放分辨率(宽高均为 0 表示禁用缩放):若输出使用编码器,启动前会调用 obs_encoder_set_scaled_size;若编码器已激活则仅告警并不生效。get_congestion 返回 0.0f(无拥塞)到 1.0f(完全拥塞)的积压度量,是推流状态栏的核心数据来源。

6.5 字幕

void obs_output_output_caption_text1(obs_output_t *output, const char *text);
void obs_output_output_caption_text2(obs_output_t *output, const char *text,
                                     double display_duration);

向输出注入字幕文本。text1 等价于 display_duration 固定为 2.0 秒的 text2display_duration 是该条字幕进入队列后的最短显示时长。libobs 内部依赖 deps/libcaption 完成字幕封装。

7. 协议与编码器能力查询(29.1 起)

const char *obs_output_get_supported_video_codecs(const obs_output_t *output);
const char *obs_get_output_supported_video_codecs(const char *id);
const char *obs_output_get_supported_audio_codecs(const obs_output_t *output);
const char *obs_get_output_supported_audio_codecs(const char *id);

const char *obs_output_get_protocols(const obs_output_t *output);
bool obs_is_output_protocol_registered(const char *protocol);
bool obs_enum_output_protocols(size_t idx, char **protocol);
void obs_enum_output_types_with_protocol(const char *protocol, void *data,
                                         bool (*enum_cb)(void *data, const char *id));
uint32_t obs_output_get_flags(const obs_output_t *output);
uint32_t obs_get_output_flags(const char *id);
  • 前四个函数返回分号分隔的支持编码器列表(实例级与类型级两种入口);
  • get_protocols 返回分号分隔的协议列表,非 OBS_OUTPUT_SERVICE 输出恒为 NULL
  • 协议注册表 API 允许前端按协议(如 RTMPS)反查可用的输出类型:obs_is_output_protocol_registered 判断、obs_enum_output_protocols 枚举全部协议、obs_enum_output_types_with_protocol 通过回调枚举指定协议下的所有输出类型 id,回调返回 false 可提前终止枚举。

这套能力让上层程序(如脚本插件)可以在运行时决定"能否以 RTMPS 推流",而无需硬编码输出类型 id。

8. 输出内部使用的函数(实现者视角)

以下函数是输出实现内部调用的工具函数,用于把 libobs 的原始媒体流接入自己的管线。

8.1 错误上报

void obs_output_set_last_error(obs_output_t *output, const char *message);
const char *obs_output_get_last_error(obs_output_t *output);

设置/获取展示给用户的本地化错误信息,常用于连接失败、无法连接等场景,可配合 obs_output_signal_stop() 的错误码提供更细粒度的诊断信息。

8.2 启动前的三步握手

编码输出的 start 回调内部应按顺序调用:

bool obs_output_can_begin_data_capture(const obs_output_t *output, int flags);
bool obs_output_initialize_encoders(obs_output_t *output, int flags);
bool obs_output_begin_data_capture(const obs_output_t *output, int flags);
void obs_output_end_data_capture(obs_output_t *output);
void obs_output_signal_stop(obs_output_t *output, int code);
  1. can_begin_data_capture:在任何输出状态初始化之前先检查能否开始捕获,flags 为保留位,传 0;
  2. initialize_encoders编码输出必须在 begin_data_capture 之前调用,用于初始化关联的编码器/service;
  3. begin_data_capture:真正开始从原始媒体或编码器接收数据,输出在内部"激活",随后视频/音频数据开始送达回调;
  4. end_data_capture:结束捕获,数据停止送达,输出以 OBS_OUTPUT_SUCCESS 码触发 stop 信号;
  5. signal_stop:异常停止入口——服务器掉线、写文件出错等场景下,用它带着错误码终止捕获并触发带码的 stop 信号。

8.3 原始输出的音视频转换

void obs_output_set_video_conversion(obs_output_t *output,
                                     const struct video_scale_info *conversion);
const struct video_scale_info *obs_output_get_video_conversion(obs_output_t *output);
void obs_output_set_audio_conversion(obs_output_t *output,
                                     const struct audio_convert_info *conversion);

仅原始输出使用,用于声明自己期望的输入格式,libobs 会代为完成格式转换。相关数据类型的核心定义:

struct video_scale_info {
	enum video_format     format;     /* 如 VIDEO_FORMAT_I420、NV12、YUY2、RGBA 等 */
	uint32_t              width;
	uint32_t                height;
	enum video_range_type range;     /* PARTIAL / FULL */
	enum video_colorspace colorspace; /* 601 / 709 / 2100_PQ / 2100_HLG 等 */
};

struct audio_convert_info {
	uint32_t            samples_per_sec;
	enum audio_format   format;     /* 16BIT、FLOAT 及各自 PLANAR 变体 */
	enum speaker_layout speakers;   /* MONO、STEREO、5POINT1、7POINT1 等 */
};

video_format 枚举覆盖 4:2:0/4:2:2/4:4:4 的平面与打包格式、灰度、10/12/16 bit 高位深格式(I010、P010、I210、P216、P416、V210 等),色彩空间包含 BT.601、BT.709、BT.2100 PQ/HLG。

8.4 暂停偏移

uint64_t obs_output_get_pause_offset(obs_output_t *output);

返回当前暂停偏移量。原始输出在使用"计算时间戳"(calculated timestamps)计算系统时间戳时需要减去该偏移——文档以 FFmpeg 输出为例说明:若支持暂停的录像中途暂停过,写出的时间轴需要补偿暂停期间的时间空洞。

8.5 包级回调(31.0 起)

void obs_output_add_packet_callback(obs_output_t *output,
	void (*packet_cb)(obs_output_t *output, struct encoder_packet *pkt,
	                    struct encoder_packet_time *pkt_time, void *param),
	void *param);
void obs_output_remove_packet_callback(obs_output_t *output, void (*packet_cb)(...), void *param);

add_packet_callback 在每个压缩包发送至 service 之前触发回调,是 libobs 官方推荐的所有"包级处理"(如水印注入、码流改写)扩展方式——这些逻辑不必内置于 libobs 核心。使用约束:

  • 若需重新分配包缓冲区,必须使用 libobs/util/bmem.h 中的函数,否则内存泄漏;
  • 严禁对包缓冲区调用 memset() 清零,因为缓冲区数据要供后续回调继续处理。

9. 小结:从注册到收包的最小闭环

综合文档与仓库实现,一个编码输出的标准生命周期为:

  1. 填写 obs_output_info(flags、回调、编码器/协议声明),在模块加载时 obs_register_output
  2. 前端 obs_output_create 创建实例,经 set_video_encoder/set_audio_encoder/set_service 绑定依赖;
  3. obs_output_startstart 回调中依次 can_begin_data_captureinitialize_encodersbegin_data_capture,发出 activate
  4. 编码包按单调时间戳顺序经 encoded_packet 回调送达(31.0 起还可叠加 add_packet_callback);
  5. obs_output_stop 或异常时 signal_stopdeactivate → 带错误码的 stop 信号。

仓库中的 obs-outputs 插件 提供了 rtmp、flv、mp4、mov、null 等完整参照实现,配合 obs-outputs.c 的注册入口与 rtmp-stream.cmp4-output.c 的定义结构,是阅读 Output API 文档时最值得对照的源码样本。

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

项目优选

收起
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.78 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
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384