☰
OBS Studio 如何用 obs_encoder_info 实现自定义视频编码器?
2026/10/19 17:47:57 网站建设 项目流程

OBS Studio 如何用 obs_encoder_info 实现自定义视频编码器?

【免费下载链接】obs-studioOBS Studio - Free and open source software for live streaming and screen recording项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio

如果你需要让 OBS Studio 的推流/录像输出支持一个新的视频编码实现,而不是替换整个输出模块,正确的做法是编写一个插件模块,用obs_encoder_info结构体描述你的编码器,并在模块加载时注册到 libobs。本文基于仓库内的 插件开发文档、编码器 API 参考 以及内置的 obs-x264 编码器插件 源码,给出从定义编码器结构到注册、构建、验证的完整路径。

适用前提:你能编译 C/C++ 代码并构建 OBS 插件模块;插件机制文档位于 docs/sphinx/plugins.rst,编码器专用头文件是 libobs/obs-encoder.h。官方文档说明编码器的定位是"OBS 专用的音视频编码器实现,配合使用编码器的输出工作",通常面向 h264/aac 这类流媒体与录像场景。

插件模块的目录结构与 CMake 构建

插件模块可以实现的 libobs 对象包括 sources、outputs、encoders 和 services。文档给出的常规组织方式是一个文件负责插件初始化,另外的文件分别定义各对象。对只包含一个编码器的最小插件,目录可以是:

my-encoder-plugin/data/locale/en-US.ini my-encoder-plugin/CMakeLists.txt my-encoder-plugin/my-plugin.c my-encoder-plugin/my-encoder.c

对应的 CMakeLists.txt(文档示例,见 plugins.rst):

# my-plugin/CMakeLists.txt project(my-plugin) set(my-plugin_SOURCES my-plugin.c my-encoder.c) add_library(my-plugin MODULE ${my-plugin_SOURCES}) target_link_libraries(my-plugin libobs) install_obs_plugin_with_data(my-plugin data)

如果编码器依赖第三方编解码库,可以参考内置 x264 插件的真实 CMakeLists.txt:

cmake_minimum_required(VERSION 3.28...3.30) find_package(Libx264 REQUIRED) if(NOT TARGET OBS::opts-parser) add_subdirectory("${CMAKE_SOURCE_DIR}/shared/opts-parser" "${CMAKE_BINARY_DIR}/shared/opts-parser") endif() add_library(obs-x264 MODULE) add_library(OBS::x264 ALIAS obs-x264) target_sources(obs-x264 PRIVATE obs-x264.c obs-x264-plugin-main.c) target_link_libraries(obs-x264 PRIVATE OBS::opts-parser Libx264::Libx264)

它展示了三个要点:用find_package定位外部依赖(Libx264 REQUIRED)、用add_library(... MODULE)产出动态库、用target_link_libraries链接依赖。

填写 obs_encoder_info 结构体

编码器定义集中在 libobs/obs-encoder.h 的struct obs_encoder_info。按头文件注释,字段分为"Required implementation(必选)"和"Optional implementation(可选)"两部分:

必选字段:

字段说明
id编码器唯一字符串标识,文档明确标注 required
type编码器类型,视频编码器填OBS_ENCODER_VIDEO,音频填OBS_ENCODER_AUDIO
codec编解码器字符串,如 "h264"
get_name返回编码器的可翻译名称
create用 settings 创建实现数据;初始化失败返回 NULL
destroy销毁实现数据
encode编码音视频帧,输出encoder_packet
get_frame_size仅音频编码器使用:返回每帧的采样数(如 AAC 为 1024)

可选字段(视频编码器常用的):get_defaults(在 settings 上调用obs_data_set_default*系列函数设置默认值)、get_properties(生成属性列表,前端可据此自动生成设置界面)、update(更新设置,通常用于运行中改变码率)、get_extra_data(通常返回编码器头数据)、get_sei_data(返回 SEI 数据)、get_video_info(告知后端输入视频需要转换的格式或尺寸)、caps(能力标志,按位或组合)。

caps的取值直接来自 obs-encoder.h:

#define OBS_ENCODER_CAP_DEPRECATED (1 << 0) #define OBS_ENCODER_CAP_PASS_TEXTURE (1 << 1) #define OBS_ENCODER_CAP_DYN_BITRATE (1 << 2) #define OBS_ENCODER_CAP_INTERNAL (1 << 3) #define OBS_ENCODER_CAP_ROI (1 << 4) #define OBS_ENCODER_CAP_SCALING (1 << 5) #define OBS_ENCODER_CAP_MULTITRACK_DYN_BITRATE (1 << 6)

文档给出的最小示例编码器(示例代码,来自 plugins.rst):

/* my-encoder.c */ struct obs_encoder_info my_encoder = { .id = "my_encoder", .type = OBS_ENCODER_VIDEO, .codec = "h264", .get_name = my_encoder_name, .create = my_encoder_create, .destroy = my_encoder_destroy, .encode = my_encoder_encode, .update = my_encoder_update, .get_extra_data = my_encoder_extra_data, .get_sei_data = my_encoder_sei_data, .get_video_info = my_encoder_video_info };

对照内置 x264 编码器的真实注册结构(obs-x264.c),可以看到完整字段组合:

struct obs_encoder_info obs_x264_encoder = { .id = "obs_x264", .type = OBS_ENCODER_VIDEO, .codec = "h264", .get_name = obs_x264_getname, .create = obs_x264_create, .destroy = obs_x264_destroy, .encode = obs_x264_encode, .update = obs_x264_update, .get_properties = obs_x264_props, .get_defaults = obs_x264_defaults, .get_extra_data = obs_x264_extra_data, .get_sei_data = obs_x264_sei, .get_video_info = obs_x264_video_info, .caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_ROI, };

两个实现细节值得注意:

  • get_properties的data参数可能为 NULL——当对"编码器类型"而不是某个实例调用obs_get_encoder_properties()时会发生,文档要求实现方妥善处理这一情况。
  • encode的返回值语义:true表示成功,false表示 critical failure(严重失败)。

encode 回调与 encoder_packet

encode的原型是bool (*encode)(void *data, struct encoder_frame *frame, struct encoder_packet *packet, bool *received_packet)。输入帧结构 encoder_frame 包含原始数据平面data[MAX_AV_PLANES]、每个平面的行步长linesize、音频帧数frames(仅音频)和呈现时间戳pts。

输出要填写 encoder_packet,其中由编码器实现方负责设置的字段是:data、size、pts、dts、timebase_num、timebase_den、type(填OBS_ENCODER_VIDEO)和keyframe。文档明确标注以下字段"should not be set by the encoder implementation",由 libobs 内部填充:dts_usec、sys_dts_usec、priority(已不再使用)、drop_priority、track_idx、encoder。

*received_packet需要你在每次调用中显式设置:本次调用是否产出了一个 packet。内置 x264 编码器的处理方式(obs-x264.c):

*received_packet = (nal_count != 0); parse_packet(obsx264, packet, nals, nal_count, &pic_out); return true;

即按实际产出的 NAL 数量决定是否置位received_packet,随后填充 packet 并返回true。

另外,如果编码器运行中会输出头数据(如 SPS/PPS),实现get_extra_data返回true并填好extra_data与size;没有头数据时返回false。x264 的实现(obs-x264.c)就是在上下文存在时返回缓存的extra_data,否则返回false。

在 obs_module_load 中注册编码器

插件初始化文件的职责是声明模块并在obs_module_load()中注册对象。内置 x264 插件的完整初始化文件只有 16 行(obs-x264-plugin-main.c):

#include <obs-module.h> OBS_DECLARE_MODULE() OBS_MODULE_USE_DEFAULT_LOCALE("obs-x264", "en-US") MODULE_EXPORT const char *obs_module_description(void) { return "x264 based encoder"; } extern struct obs_encoder_info obs_x264_encoder; bool obs_module_load(void) { obs_register_encoder(&obs_x264_encoder); return true; }

要点:

  • #include <obs-module.h>会自动引入obs.h,而obs.h又自动包含obs-encoder.h、obs-data.h、obs-properties.h等,所以编码器插件不需要单独 include 编码器头文件(见 plugins.rst 的 "Plugin Module Headers" 一节)。
  • obs_register_encoder()通常在obs_module_load()中调用。宏obs_register_encoder(info)实际展开为obs_register_encoder_s(info, sizeof(struct obs_encoder_info))(见 obs-encoder.h),按结构体大小注册以兼容结构体扩展。
  • obs_module_load()的返回值就是模块加载判定:返回true继续加载模块,返回false表示失败并触发模块卸载(reference-modules.rst)。

如何验证编码器注册成功

文档提供的验证路径分两层:

  1. 模块加载层面:前端通过obs_open_module()打开模块镜像,通过obs_init_module()触发obs_module_load()。obs_open_module会返回明确的失败码,包括MODULE_SUCCESS、MODULE_FILE_NOT_FOUND(找不到模块)、MODULE_MISSING_EXPORTS(缺少必需导出函数)、MODULE_INCOMPATIBLE_VER(版本不兼容)等;obs_init_module返回true表示模块加载成功。如果你的obs_module_load里注册逻辑出错并返回false,模块会被卸载,这一条就是最基本的失败信号。
  2. 编码器对象层面:注册完成后,可以用 reference-encoders.rst 中的类型级接口按id反查编码器:obs_encoder_defaults(id)取默认设置、obs_get_encoder_properties(id)取属性列表、obs_get_encoder_type(id)确认类型;最终用obs_video_encoder_create(id, name, settings, hotkey_data)创建编码器实例,创建失败会返回NULL。也就是说,obs_video_encoder_create对你的id能返回非 NULL,说明注册、create回调整条链路都工作正常。

设置命名约定与能力声明的边界

文档(plugins.rst 的 "IMPORTANT NOTE")对编码器的通用设置项给出了命名约定,实现时应遵守以便输出模块和前端正确识别:

设置名适用含义
"bitrate"视频与音频编码器码率,单位为千比特(kilobits)
"rate_control"视频编码器码率控制方式,至少应提供 "CBR",其他常见值为 "VBR"、"CQP"
"keyint_sec"视频编码器关键帧间隔,单位为秒或最接近的近似值

两条边界需要明确:

  • 头文件注释(obs-encoder.h)说明编码器的使用范围是"有限且特定的",一般面向流媒体和录像场景的 h264/aac 实现;如果你的目标不属于这类用途,文档没有给出支持承诺。
  • OBS_ENCODER_CAP_SCALING表示编码器自行实现缩放逻辑、希望接收未缩放的输入帧;OBS_ENCODER_CAP_ROI表示支持感兴趣区域(ROI,自 30.1 版本引入,见 reference-encoders.rst 的obs_encoder_roi部分)。这些能力标志声明后,对应的行为(如 ROI 区域在开启缩放时按缩放后尺寸回调)由 libobs 按声明调用,不能只声明标志而不在实现中处理。

完成以上步骤后,你的编码器插件在 OBS 构建中作为MODULE动态库产出并随插件目录安装,前端加载插件目录中的模块文件即会触发注册;后续深入可参考 obs-outputs 插件 中消费编码后 packet 的输出实现,理解编码数据如何流向最终输出。

【免费下载链接】obs-studioOBS Studio - Free and open source software for live streaming and screen recording项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询