Obs 插件开发

这篇博客详细介绍了如何为OBS Studio开发插件,涵盖了创建插件模块的基本步骤,包括源、输出、编码器和服务的实现。插件模块通常使用动态库或脚本编写,通过头文件如libobs/obs-module.h、libobs/obs-source.h等来实现不同功能。文章列举了示例代码和目录结构,展示了如何定义结构体和回调函数,以及如何注册这些对象到libobs。此外,还讨论了设置管理和本地化的方法。
摘要由CSDN通过智能技术生成

几乎所有的自定义功能都是通过插件模块添加的,插件模块通常是动态库或脚本。捕获和/或输出音频/视频、录制、输出到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;
}

一些简单的来源示例:

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() 宏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值