几乎所有的自定义功能都是通过插件模块添加的,插件模块通常是动态库或脚本。捕获和/或输出音频/视频、录制、输出到RTMP流、在x264中编码的能力都是通过插件模块实现的。
插件可以实现源、输出、编码器和服务。
0x0 插件模块头
以下是插件常用的一些值得注意的头文件:
-
libobs/obs-module.h – 用于创建插件模块的主要头文件。该文件自动包括以下文件:
-
libobs/obs.h – libobs 库主要的头文件。该文件自动包括以下文件。
-
libobs/obs-source.h – 用于在插件模块中实现来源
-
libobs/obs-output.h – 用于在插件模块中实现输出
-
libobs/obs-encoder.h – 用于在插件模块中实现编码器
-
libobs/obs-service.h – 用于在插件模块中实现服务
-
libobs/obs-data.h – 用于管理 libobs 对象的设置
-
libobs/obs-properties.h – 用于生成 libobs 对象的属性
-
libobs/graphics/graphics.h – 用于图形渲染
-
-
0x1 通用目录结构和CMakeLists.txt
常见的组织源文件的方式是有一个文件用于插件的初始化,然后为你要实现的每个单独的对象提供特定的文件。例如,如果你要创建一个叫做 "my-plugin "的插件,你会有类似 my-plugin.c 这样的文件来完成插件的初始化,my-source.c 用来定义自定义源,my-output.c 用来定义自定义输出,等等。(当然,这不是一个规则)
这是一个本地插件模块常用目录结构的例子:
my-plugin/data/locale/en-US.ini my-plugin/CMakeLists.txt my-plugin/my-plugin.c my-plugin/my-source.c my-plugin/my-output.c my-plugin/my-encoder.c my-plugin/my-service.c
这是一个与这些文件关联的公共 CMakeLists.txt 文件的示例:
# my-plugin/CMakeLists.txt project(my-plugin) set(my-plugin_SOURCES my-plugin.c my-source.c my-output.c my-encoder.c my-service.c) add_library(my-plugin MODULE ${my-plugin_SOURCES}) target_link_libraries(my-plugin libobs) install_obs_plugin_with_data(my-plugin data)
0x2 本地插件初始化
源是用来在流上渲染视频和/或音频的。诸如捕捉显示/游戏/音频,播放视频,显示图像,或播放音频。源也可以用来实现音频和视频过滤器以及转换。libobs/obs-source.h 文件是实现 Source 的专用头文件。更多信息请参见Source API Reference(obs_source_t)。
例如,要实现一个源对象,您需要定义一个 obs_source_info 结构并填写与您的源相关的信息和回调:
/* my-source.c */ [...] struct obs_source_info my_source { .id = "my_source", .type = OBS_SOURCE_TYPE_INPUT, .output_flags = OBS_SOURCE_VIDEO, .get_name = my_source_name, .create = my_source_create, .destroy = my_source_destroy, .update = my_source_update, .video_render = my_source_render, .get_width = my_source_width, .get_height = my_source_height };
然后,在 my-plugin.c 中,您将在 obs_module_load() 中调用 obs_register_source() 来向 libobs 注册源。
/* my-plugin.c */ [...] extern struct obs_source_info my_source; /* Defined in my-source.c */ bool obs_module_load(void) { obs_register_source(&my_source); [...] return true; }
一些简单的来源示例:
-
Synchronous video source (同步视频源): The image source
-
Asynchronous video source(异步视频源): The random texture test source
-
Audio source(音频源): The sine wave test source
-
Video filter(视频滤镜): The test video filter
-
Audio filter(音频过滤器): The gain audio filter
0x3 输出
输出允许输出当前渲染的音频/视频的能力。流媒体和录音是输出的两个常见例子,但不是唯一的输出类型。输出可以接收原始数据或接收编码数据。libobs/obs-output.h 文件是实现输出的专用头文件。更多信息请参见输出API参考(obs_output_t)。
例如,要实现一个输出对象,您需要定义一个 obs_output_info 结构并填写与您的输出相关的信息和回调:
/* my-output.c */ [...] struct obs_output_info my_output { .id = "my_output", .flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED, .get_name = my_output_name, .create = my_output_create, .destroy = my_output_destroy, .start = my_output_start, .stop = my_output_stop, .encoded_packet = my_output_data, .get_total_bytes = my_output_total_bytes, .encoded_video_codecs = "h264", .encoded_audio_codecs = "aac" };
然后,在 my-plugin.c 中,您将在 obs_module_load() 中调用 obs_register_output() 将输出注册到 libobs。
/* my-plugin.c */ [...] extern struct obs_source_info my_source; /* Defined in my-source.c */ bool obs_module_load(void) { obs_register_source(&my_source); [...] return true; }
一些输出示例:
-
编码的视频/音频输出:
-
原始视频/音频输出:
0x4 编码器
编码器是OBS对视频/音频编码器的特定实现,它与使用编码器的输出一起使用。x264、NVENC、Quicksync 是编码器实现的例子。libobs/obs-encoder.h 文件是实现编码器的专用头文件。参见编码器API参考(obs_encoder_t)以获得更多信息。
例如,要实现一个编码器对象,您需要定义一个 obs_encoder_info 结构并填写与您的编码器相关的信息和回调:
/* my-encoder.c */ [...] struct obs_encoder_info my_encoder_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, .get_video_info = my_encoder_video_info };
然后,在 my-plugin.c 中,您将在 obs_module_load() 中调用 obs_register_encoder() 以向 libobs 注册编码器。
/* my-plugin.c */ [...] extern struct obs_encoder_info my_encoder; /* Defined in my-encoder.c */ bool obs_module_load(void) { obs_register_encoder(&my_encoder); [...] return true; }
重要说明:编码器设置目前有一些预期的通用设置值,具有特定的命名约定:
-
“bitrate” - 这个值应用于视频和音频编码器:比特率,以千位为单位。
-
“rate_control” - 这是一个用于视频编码器的设置。一般来说,它至少应该有一个 "CBR "速率控制。其他常见的速率控制是 "VBR"、"CQP"。
-
“keyint_sec” - 对于视频编码器,设置关键帧的间隔值,以秒为单位,或最接近的值。(作者注:这应该是 "keyint",单位是帧。)
编码器示例:
0x5 服务
服务是流媒体服务的定制实现,它与流媒体的输出一起使用。例如,你可以有一个用于流向 Twitch 的定制实现,另一个用于 YouTube,允许登录并使用他们的 API 来做一些事情,如获取 RTMP 服务器或控制频道。libobs/obs-service.h 文件是实现服务的专用头文件。参见服务API参考(obs_service_t)了解更多信息。
(作者注:截至本文写作时,服务API还不完整)
例如,要实现一个服务对象,您需要定义一个 obs_service_info 结构并填写与您的服务相关的信息和回调:
/* my-service.c */ [...] struct obs_service_info my_service_service = { .id = "my_service", .get_name = my_service_name, .create = my_service_create, .destroy = my_service_destroy, .encode = my_service_encode, .update = my_service_update, .get_url = my_service_url, .get_key = my_service_key };
然后,在 my-plugin.c 中,在 obs_module_load() 中调用 obs_register_service() 向 libobs 注册服务。
/* my-plugin.c */ [...] extern struct obs_service_info my_service; /* Defined in my-service.c */ bool obs_module_load(void) { obs_register_service(&my_service); [...] return true; }
现有的两个服务对象是 plugins/rtmp-services 中的 "普通RTMP服务 "和 "自定义RTMP服务 "对象。
0x6 设置
设置(参见 libobs/obs-data.h)用于获取或设置通常与 libobs 对象关联的设置数据,然后可以通过 Json 文本保存和加载。有关更多信息,请参阅数据设置 API 参考 (obs_data_t)。
obs_data_t 相当于一个 Json 对象,它是一个子对象的字符串表,而 obs_data_array_t 类似地用于存储 obs_data_t 对象的数组,类似于 Json 数组(虽然不完全相同)。
要创建 obs_data_t 或 obs_data_array_t 对象,您需要调用 obs_data_create() 或 obs_data_array_create() 函数。 obs_data_t 和 obs_data_array_t 对象是引用计数的,所以当你完成对象时,调用 obs_data_release() 或 obs_data_array_release() 来释放这些引用。每当函数返回 obs_data_t 或 obs_data_array_t 对象时,它们的引用都会增加,因此每次都必须释放这些引用。
要为 obs_data_t 对象设置值,可以使用下面任一函数:
/* Set functions */ EXPORT void obs_data_set_string(obs_data_t *data, const char *name, const char *val); EXPORT void obs_data_set_int(obs_data_t *data, const char *name, long long val); EXPORT void obs_data_set_double(obs_data_t *data, const char *name, double val); EXPORT void obs_data_set_bool(obs_data_t *data, const char *name, bool val); EXPORT void obs_data_set_obj(obs_data_t *data, const char *name, obs_data_t *obj); EXPORT void obs_data_set_array(obs_data_t *data, const char *name, obs_data_array_t *array);
同样,要从 obs_data_t 对象中获取值,可以使用下面任一函数:
/* Get functions */ EXPORT const char *obs_data_get_string(obs_data_t *data, const char *name); EXPORT long long obs_data_get_int(obs_data_t *data, const char *name); EXPORT double obs_data_get_double(obs_data_t *data, const char *name); EXPORT bool obs_data_get_bool(obs_data_t *data, const char *name); EXPORT obs_data_t *obs_data_get_obj(obs_data_t *data, const char *name); EXPORT obs_data_array_t *obs_data_get_array(obs_data_t *data, const char *name);
与典型的 Json 数据对象不同,obs_data_t 对象还可以设置默认值。这使得我们能够控制当从 Json 字符串或 Json 文件加载数据时,如果没有为 obs_data_t 对象中的特定字符串分配值,则能够控制返回的内容。 每个 libobs 对象还有一个 get_defaults 回调,它允许在创建对象时设置默认设置。
这些函数控制的默认值如下:
/* Default value functions. */ EXPORT void obs_data_set_default_string(obs_data_t *data, const char *name, const char *val); EXPORT void obs_data_set_default_int(obs_data_t *data, const char *name, long long val); EXPORT void obs_data_set_default_double(obs_data_t *data, const char *name, double val); EXPORT void obs_data_set_default_bool(obs_data_t *data, const char *name, bool val); EXPORT void obs_data_set_default_obj(obs_data_t *data, const char *name, obs_data_t *obj);
0x7 特性
属性(参见 libobs/obs-properties.h)用于自动生成用户界面以修改 libobs 对象的设置(如果需要)。 每个 libobs 对象都有一个 get_properties 回调,用于生成属性。 属性 API 定义了链接到对象设置的特定属性,前端使用这些属性来生成小部件,以允许用户修改设置。 例如,如果您有一个布尔值设置,您将使用 obs_properties_add_bool() 来允许用户更改该设置。 有关更多信息,请参阅属性 API 参考 (obs_properties_t)。
这方面的一个例子:
static obs_properties_t *my_source_properties(void *data) { obs_properties_t *ppts = obs_properties_create(); obs_properties_add_bool(ppts, "my_bool", obs_module_text("MyBool")); UNUSED_PARAMETER(data); return ppts; } [...] struct obs_source_info my_source { .get_properties = my_source_properties, [...] };
如果对象存在,则 data 参数是对象的数据。 通常这是未使用的,如果可能的话,可能不应该使用。 如果在没有关联对象的情况下检索属性,则它可以为 null。
还可以根据显示的设置修改属性。 例如,您可以使用 obs_property_set_modified_callback() 函数将某些属性标记为禁用或不可见,具体取决于特定设置的设置。
例如,如果您希望布尔属性 A 隐藏文本属性 B:
static bool setting_a_modified(obs_properties_t *ppts, obs_property_t *p, obs_data_t *settings) { bool enabled = obs_data_get_bool(settings, "setting_a"); p = obs_properties_get(ppts, "setting_b"); obs_property_set_enabled(p, enabled); /* return true to update property widgets, false otherwise */ return true; } [...] static obs_properties_t *my_source_properties(void *data) { obs_properties_t *ppts = obs_properties_create(); obs_property_t *p; p = obs_properties_add_bool(ppts, "setting_a", obs_module_text("SettingA")); obs_property_set_modified_callback(p, setting_a_modified); obs_properties_add_text(ppts, "setting_b", obs_module_text("SettingB"), OBS_TEXT_DEFAULT); return ppts; }
0x8 本地化
通常,大多数与 OBS Studio 捆绑的插件将使用简单的 ini 文件本地化方法,其中每个文件都是不同的语言。 使用此方法时,将使用 OBS_MODULE_USE_DEFAULT_LOCALE() 宏,该宏将自动加载/销毁区域设置数据,而无需对插件进行额外操作。 然后在需要文本查找时使用 obs_module_text() 函数(由 libobs/obs-module.h 自动声明为 extern)。
用于加载/销毁语言环境的模块有两个导出:obs_module_set_locale() 导出和 obs_module_free_locale() 导出。 libobs 调用 obs_module_set_locale() 导出来设置当前语言,然后 libobs 在破坏模块时调用 obs_module_free_locale() 导出。 如果您希望为您的插件实现自定义语言环境实现,您需要自己定义这些导出以及 obs_module_text() 外部,而不是依赖 OBS_MODULE_USE_DEFAULT_LOCALE() 宏。