如何使用 Python 脚本操作 OBS 来源?OBS 来源对象介绍
Python 脚本中的 OBS 来源对象
通过 OBS 来源对象(Source Objects)以及obspython
模块提供的函数,你可以在 Python 脚本中操作 OBS 的来源。
什么是 OBS 来源?
OBS 中的来源(Sources)主要用于渲染视频流和音频流,这包括显示器采集,窗口采集,图像,场景,滤镜,转场特效等。
什么是 OBS 私有来源?
与一般来源不同,OBS 用户无法直接创建私有来源。私有来源无法被obs_enum_sources
函数枚举,也无法被obs_save_sources
函数保存,这意味任何涉及保存场景集合的操作,都将忽略私有来源和由其产生的场景项。
OBS 私有来源和 OBS 非私有来源的命名冲突问题
由于存在 OBS 来源的创建和复制操作,因此来源之间可能会发生命名上的冲突,无论这是来自于 OBS 用户还是 Python 脚本,他们大体上会遵守以下规则。私有来源之间,以及私有来源与非私有来源之间不会检测命名冲突。非私有来源之间会检测命名冲突,不同的非私有来源不能具有相同的名称。
虽然允许 OBS 私有来源与 OBS 非私有来源同名,但这种情况应尽量避免,因为他们可能导致一些诡异的问题。
使用 Python 脚本创建 OBS 来源
OBS 的obspython
模块提供了以下函数,用于创建新的 OBS 来源。
obs_source_create
和obs_source_create_private
函数,可以使用指定的 OBS 来源类型和 OBS 来源设置创建 OBS 来源,创建失败时会返回空值None
。两者的区别在于,obs_source_create_private
函数会创建私有 OBS 来源。
obs_source_create(id, name, settings, hotkey_data)
obs_source_create_private(id, name, settings)
- id 参数
id
参数为来源类型标识符,他将决定创建来源的类型。- name 参数
name
参数为创建来源的期望名称,当发生命名冲突时,OBS 会修改期望名称,直到冲突消失。- settings 参数
settings
参数是一个 OBS 数据设置对象,他表示了来源的设置,其包含的内容由来源类型确定。如果指定为None
,则会采用来源的默认配置。- hotkey_data 参数
hotkey_data
参数是一个 OBS 数据设置对象,他表示了来源对应的快捷键,可以被指定为None
。
什么是 OBS 来源设置?
和脚本设置类似,OBS 来源设置也是一个 OBS 数据设置对象,顾名思义,他决定了 OBS 来源的相关设置,比如,图片来源对应的图片文件路径。
什么是 OBS 来源类型标识符?
OBS 的每一种来源都对应了一个来源类型标识符(Source Type Identifiers),该标识符可以有效区分不同类型的 OBS 来源。比如,文本(GDI+)的来源类型标识符为text_gdiplus
,图像的来源类型标识符为image_source
。
使用 obs_source_release 函数释放在 Python 脚本中创建的 OBS 来源对象
对于使用obs_source_create
或obs_source_create_private
函数创建的 OBS 来源对象,需要通过obs_source_release
释放引用,否则 OBS 可能会出现错误。
我们尝试在按钮的回调函数test
中,创建一个私有文本(GDI+)来源,并通过 OBS 数据设置对象对来源进行设置,最后将文本(GDI+)作为场景项添加到场景Scene
中,假设Scene
存在。这里涉及到与场景相关的函数,但由于篇幅限制,不再进行说明。
# 导入模块 obspython
import obspython as obs
def test(props, prop):
# 创建一个名称为 my_text 的私有文本(GDI+)来源,并将字符串 "今天天气不错!" 设置为文本
settings = obs.obs_data_create_from_json('{"text":"今天天气不错!"}')
source_text = obs.obs_source_create_private('text_gdiplus', 'my_text', settings)
# 将文本(GDI+)来源,添加至名为 Scene 的场景
source_scene = obs.obs_get_source_by_name('Scene')
scene = obs.obs_scene_from_source(source_scene)
obs.obs_scene_add(scene, source_text)
# 释放来源对象和来源设置对象
obs.obs_source_release(source_scene)
obs.obs_source_release(source_text)
obs.obs_data_release(settings)
# 为脚本添加一个用于测试的按钮,回调函数为 test
def script_properties():
props = obs.obs_properties_create()
obs.obs_properties_add_button(props, 'test', '测试', test)
return props
使用 Python 脚本复制 OBS 来源
obspython
模块的obs_source_duplicate
函数,可用于复制 OBS 来源。
这里需要指出,如果 OBS 来源不支持完全复制,那么obs_source_duplicate
函数所返回的来源是对原有 OBS 来源的引用。
obs_source_duplicate(source, desired_name, create_private)
- source 参数
source
参数为被复制的 OBS 来源对象。- desired_name 参数
desired_name
参数为新来源的期望名称,当发生命名冲突时,OBS 会修改期望名称,直到冲突消失。- create_private 参数
create_private
参数表示新来源是否为私有来源,仅对完全复制的 OBS 来源生效,采用引用方式得到的新来源无法成为私有来源。
使用 obs_source_release 函数释放在 Python 脚本中复制的 OBS 来源对象
对于使用obs_source_duplicate
函数复制的 OBS 来源对象,需要通过obs_source_release
释放引用,否则 OBS 可能会出现错误。
在下面的代码中,我们对已有的来源Welcome
进行了复制,由于并未将复制得到的新来源添加至场景,因此他无法作为场景项显示在 OBS 窗口中。
def test(props, prop):
# …
# 复制名称为 Welcome 的来源,并指定新名称 Bye
welcome = obs.obs_get_source_by_name('Welcome')
bye = obs.obs_source_duplicate(welcome, 'Bye', False)
# 释放来源 Welcome 和 Bye
obs.obs_source_release(welcome)
obs.obs_source_release(bye)
使用 Python 脚本获取 OBS 来源
obspython
模块的obs_get_source_by_name
函数,可用于获取指定名称的 OBS 来源(对象)。
obs_get_source_by_name(name)
- name 参数
name
参数为 OBS 来源的名称。
obspython
模块的obs_get_source_by_uuid
函数,可用于获取指定 UUID 的 OBS 来源(对象),UUID 会在来源被创建时自动分配,不同来源的 UUID 不会相同。
obs_get_source_by_uuid(uuid)
- uuid 参数
uuid
参数为 OBS 来源的 UUID。
如何使用 Python 脚本获取 OBS 私有来源?
你需要使用obs_get_source_by_uuid
函数而非obs_get_source_by_name
来获取一个 OBS 私有来源,因此,通过obs_source_get_uuid
函数记录所创建的私有来源的 UUID 是必要的。
使用 obs_data_release 函数释放在 Python 脚本中获取的 OBS 来源对象
对于使用obs_get_source_by_name
,obs_get_source_by_uuid
函数获取的 OBS 来源对象,需要通过obs_source_release
释放引用,否则 OBS 可能会出现错误。
使用 Python 脚本获取和设置 OBS 来源的设置
正如之前提到的,OBS 来源设置是一个数据设置对象,该对象的作用类似于 Python 脚本的脚本设置对象,他是实现通过 Python 脚本操作 OBS 来源的关键要素之一,不同类型的 OBS 来源,其来源设置对象所包含的内容会有所差异。OBS 的obspython
模块提供了以下关于来源设置的函数。
obs_source_get_settings
函数,可用于获取 OBS 来源对应的来源设置对象,obs_source_get_private_settings
函数,可用于获取 OBS 来源对应的私有来源设置对象,该对象应存放不希望对 OBS 用户公开的设置。
obs_source_get_settings(source)
obs_source_get_private_settings(item)
- source 参数
source
参数为需要获取来源设置对象的 OBS 来源对象。- item 参数
item
参数为需要获取私有来源设置对象的 OBS 来源对象。
obs_source_update
函数,可用于更新 OBS 来源的来源设置对象,这将直接改变来源在 OBS 中的行为或表现,当然,对于某些类型的来源,改变带来的效果可能不会立即显现。
obs_source_reset_settings
函数,可用于重置和更新 OBS 来源的来源设置对象,清除现有 OBS 来源设置的工作会首先进行,这意味着所有的设置都将恢复为默认。
obs_source_update(source, settings)
obs_source_reset_settings(source, settings)
- source 参数
source
参数为需要更新或重置更新来源设置对象的 OBS 来源对象。- settings 参数
settings
参数为用于更新来源设置对象的 OBS 数据设置对象。
obs_get_source_defaults
函数,可用于获取某类型来源的来源设置默认值,默认值将被包含在一个新的 OBS 来源设置对象(数据设置对象)中返回。
obs_get_source_defaults(id)
- id 参数
id
参数为来源类型标识符,obs_get_source_defaults
函数将返回该标识符对应的来源类型的来源设置默认值。
使用 obs_data_release 函数释放在 Python 脚本中获取的 OBS 来源设置对象
对于使用obs_source_get_settings
,obs_source_get_private_settings
,obs_get_source_defaults
函数获取的 OBS 来源设置对象,需要通过obs_data_release
释放引用,否则 OBS 可能会出现错误。
调整之前的代码,我们通过obs_source_get_settings
和obs_source_update
函数,更新了Welcome
来源的文本。
def test(props, prop):
# …
# 通过 Welcome 的来源设置对象,修改其对应的文本
settings = obs.obs_source_get_settings(welcome)
obs.obs_data_set_string(settings, 'text', '你好,欢迎!')
obs.obs_source_update(welcome, settings)
# 释放来源设置对象
obs.obs_data_release(settings)
# …
使用 Python 脚本获取 OBS 来源的原始宽度和高度
obspython
模块的obs_source_get_width
和obs_source_get_height
函数,可用于获取 OBS 来源的原始宽度和高度,这并不会将转场特效计算在内,因此obs_source_get_width
和obs_source_get_height
函数所返回的并非来源对应场景项的实际显示大小。
obs_source_get_width(source)
obs_source_get_height(source)
- source 参数
source
参数为需要获取原始宽度或高度的 OBS 来源对象。
def test(props, prop):
# …
# 显示 Weclome 来源的大小
width = obs.obs_source_get_width(welcome)
height = obs.obs_source_get_height(welcome)
obs.script_log(obs.LOG_INFO, f'Welcome 的大小 {width}x{height}')
# …
[sources.py] Welcome 的大小 1520x264
使用 Python 脚本判断 OBS 来源是否有效
OBS 来源的有效状态用于指示其是否被用于渲染输出,处于无效状态的来源并未真正的参与渲染,比如,当 OBS 用户将场景项隐藏时,其对应的来源可能将处于无效状态。需要说明的是,是否处于有效状态与来源是否可用无关。
obspython
模块的obs_source_active
函数,可用于判断 OBS 来源是否处于有效状态,返回True
表示来源处于有效状态,返回False
表示来源处于无效状态。
obs_source_active(source)
- source 参数
source
参数为需要判断有效状态的 OBS 来源对象。
使用 Python 脚本获取和设置 OBS 来源是否可用
obspython
模块的obs_source_enabled
和obs_source_set_enabled
函数,可用于获取和设置 OBS 来源是否可用(启用或禁用)。对于不可用的来源,不会在渲染中产生任何效果。需要说明的是,是否可用并不影响来源的有效状态。
obs_source_enabled(source)
obs_source_set_enabled(source, enabled)
- source 参数
source
参数为需要获取或设置是否可用的 OBS 来源对象。- enabled 参数
enabled
参数为True
时,将启用 OBS 来源,为False
时,将禁用 OBS 来源。
使用 Python 脚本获取和设置 OBS 来源是否可见
obspython
模块的obs_source_showing
函数与obs_source_active
类似,可判断 OBS 来源是否已经被渲染至最终输出,只不过obs_source_showing
的返回结果,可以通过obs_source_inc_showing
和obs_source_dec_showing
函数进行干预。
obs_source_showing(source)
- source 参数
source
参数为需要判断是否可见的 OBS 来源对象。
obspython
模块的obs_source_inc_showing
和obs_source_dec_showing
函数,可增加或减少 OBS 来源的可见计数,这将最终影响obs_source_showing
的返回结果。需要说明的是,虽然可通过obs_source_inc_showing
和obs_source_dec_showing
控制obs_source_showing
的返回结果,但最终输出可能不会改变。
obs_source_inc_showing(source)
obs_source_dec_showing(source)
- source 参数
source
参数为需要增加或减少可见计数的 OBS 来源对象。
使用 Python 脚本获取和设置 OBS 来源的名称
obspython
模块的obs_source_get_name
和obs_source_set_name
函数,可用于获取或设置 OBS 来源的名称,该名称可显示在 OBS 的相关窗口中。
obs_source_get_name(source)
obs_source_set_name(source, name)
- source 参数
source
参数为需要获取或设置名称的 OBS 来源对象。- name 参数
name
参数为修改后的名称,如果存在命名冲突,那么 OBS 会对名称进行修改,直到冲突消失。
下面的代码,通过obs_source_set_name
函数将名称为Groups
的来源改名为Group
,假设存在分组来源Groups
。
def test(props, prop):
# …
# 如果存在名称为 Groups 的来源,则将其改名为 Group
groups = obs.obs_get_source_by_name('Groups')
if groups:
obs.obs_source_set_name(groups, 'Group')
obs.obs_source_release(groups)
使用 Python 脚本获取 OBS 来源的类型
obspython
模块的obs_source_get_type
函数,可用于获取 OBS 来源的类型,其返回值可能对应以下某个obspython
模块变量,OBS_SOURCE_TYPE_INPUT
(输入,一般 OBS 来源均为此类型),OBS_SOURCE_TYPE_FILTER
(滤镜),OBS_SOURCE_TYPE_TRANSITION
(转场特效),OBS_SOURCE_TYPE_SCENE
(场景)。
obs_source_get_type(source)
- source 参数
source
参数为需要获取类型的 OBS 来源对象。
另外,obspython
模块的obs_source_is_scene
函数,可用于判断 OBS 来源是否为场景,obspython
模块的obs_source_is_group
函数,可用于判断 OBS 来源是否为分组。
obs_source_is_scene(source)
obs_source_is_group(source)
- source 参数
source
参数为需要判断是否为场景或分组的 OBS 来源对象。
在下面的代码中,我们获取了来源Groups
的类型,并判断其是否为分组。从输出的结果可以得知,分组的类型为OBS_SOURCE_TYPE_SCENE
。
def test(props, prop):
# …
# 显示 Group 来源的类型,并判断是否为分组
group = obs.obs_get_source_by_name('Group')
group_type = obs.obs_source_get_type(group)
obs.script_log(obs.LOG_INFO, f'Group 的类型 {group_type},等于 OBS_SOURCE_TYPE_SCENE?{group_type == obs.OBS_SOURCE_TYPE_SCENE}')
obs.script_log(obs.LOG_INFO, f'Group 是分组?{obs.obs_source_is_group(group)}')
obs.obs_source_release(group)
[sources.py] Group 的类型 3,等于 OBS_SOURCE_TYPE_SCENE?True
[sources.py] Group 是分组?True
使用 Python 脚本获取和设置 OBS 来源的 ID
obspython
模块的obs_source_get_id
和obs_source_get_unversioned_id
函数,可用于获取 OBS 来源的来源类型标识符,二者的区别在于是否带有版本信息。
obs_source_get_id(source)
obs_source_get_unversioned_id(source)
- source 参数
source
参数为需要获取来源类型标识符的 OBS 来源对象。
obspython
模块的obs_source_get_uuid
函数,可用于获取 OBS 来源的 UUID,每一个 OBS 来源都拥有一个唯一的 UUID。
obs_source_get_uuid(source)
- source 参数
source
参数为需要获取 UUID 的 OBS 来源对象。
def test(props, prop):
# …
# 显示 Weclome 来源的来源类型标识符和 UUID
v_id = obs.obs_source_get_id(welcome)
id = obs.obs_source_get_unversioned_id(welcome)
obs.script_log(obs.LOG_INFO, f'Welcome 的 id {v_id} {id}')
uuid = obs.obs_source_get_uuid(welcome)
obs.script_log(obs.LOG_INFO, f'Welcome 的 uuid {uuid}')
# …
[sources.py] Welcome 的 id text_gdiplus_v2 text_gdiplus
[sources.py] Welcome 的 uuid 84808b04-9373-4c21-b3b8-c506bbc8effb
使用 Python 脚本移除 OBS 来源
当你不再需要某个 OBS 来源时,可以使用obspython
模块的obs_source_remove
函数将其移除,这会使该来源以及该来源产生的场景项立即从 OBS 的相关窗口中消失,比如来源栏。
obs_source_remove(source)
- source 参数
source
参数为需要移除的 OBS 来源对象。
obspython
模块的obs_source_removed
函数,可用于判断 OBS 来源是否已经被移除,返回True
表示已经被移除。
obs_source_removed(source)
- source 参数
source
参数为需要判断是否被移除的 OBS 来源对象。
被 obs_source_remove 函数移除的 OBS 来源依然可能存在
这里需要指出,被obs_source_remove
函数移除的 OBS 来源,如果未释放所有的引用,那么他依然可以在 Python 脚本中访问,比如,通过obs_get_source_by_name
获取。
下面的代码,移除了来源Screen
,假设分组Group
包含该来源。
def test(props, prop):
# …
# 来源 Screen 如果存在,则将其移除
screen = obs.obs_get_source_by_name('Screen')
if screen:
obs.obs_source_remove(screen)
obs.script_log(obs.LOG_INFO, f'Screen 被移除?{obs.obs_source_removed(screen)}')
[sources.py] Screen 被移除?True
使用 Python 脚本添加和释放对 OBS 来源的引用
如果一个 OBS 来源(对象)不存在任何引用,那么该来源将被销毁,毫无疑问,这增加了 OBS Python 脚本的编写难度,没有或过多的释放引用,均可能导致 OBS 发生异常。假设,你不小心对来源进行了过多的释放,那么一个错误窗口可能在所难免。obspython
模块提供了以下与来源引用相关的函数。
obs_source_get_ref
函数(OBS 27.2.0 之前为obs_source_addref
函数),可用于为 OBS 来源对象添加引用。每当你额外调用一次obs_source_get_ref
函数,就需要对等增加一次obs_source_release
函数的调用。
OBS 27.2.0 之前,应使用函数obs_source_addref
,而非obs_source_get_ref
。
obs_source_release
函数,可用于为 OBS 来源对象释放引用,他适用于obs_source_create
,obs_source_create_private
,obs_source_duplicate
,obs_get_source_by_name
,obs_get_source_by_uuid
,obs_source_get_filter_by_name
,obs_get_transition_by_name
函数所返回的 OBS 来源对象。
obs_source_get_ref(source)
obs_source_release(source)
- source 参数
source
参数为需要添加或释放引用的 OBS 来源对象。
使用 Python 脚本获取和设置 OBS 来源是否隐藏
如果希望添加一些对 OBS 用户不公开的来源,那么可将其设置为隐藏,隐藏来源产生的场景项不会出现在 OBS 的来源栏中,也不会作为场景的一部分保存,这意味着你总是需要在适当的时机创建并添加他们。
obspython
模块的obs_source_is_hidden
函数,可用于判断 OBS 来源是否对 OBS 用户隐藏,返回False
表示不隐藏,True
表示隐藏。obspython
模块的obs_source_set_hidden
函数,可用于设置 OBS 来源是否对 OBS 用户隐藏,该函数需要在场景项显示在来源栏之前调用,否则其效果不会是立即的。
obs_source_is_hidden(source)
obs_source_set_hidden(source, hidden)
- source 参数
source
参数为需要设置是否隐藏的 OBS 来源对象。- hidden 参数
hidden
参数表示是否隐藏,False
表示不隐藏,True
表示隐藏。
使用 Python 脚本获取和设置 OBS 来源的输出标志
obspython
模块的obs_source_get_output_flags
和obs_get_source_output_flags
函数,可用于获取 OBS 来源类型的输出标志,输出标志表示了该类型的来源所具备的功能,你可以将其视为一组枚举成员的组合(虽然并不是真正的枚举)。由于篇幅限制,这里不再详细解释他们。
obs_source_get_output_flags(source)
obs_get_source_output_flags(id)
- source 参数
source
参数是一个 OBS 来源对象,obs_source_get_output_flags
函数将返回该对象对应的来源类型的输出标志。- id 参数
id
参数为来源类型标识符,obs_get_source_output_flags
函数将返回该标识符对应的来源类型的输出标志。
在下面的代码中,我们通过obs_source_get_output_flags
函数获取了媒体源Video
的输出标志,并判断其是否具有视频和音频功能。
def test(props, prop):
# …
# 判断来源 Video 的输出标志
video = obs.obs_get_source_by_name('Video')
flags = obs.obs_source_get_output_flags(video)
obs.script_log(obs.LOG_INFO, f'Video 具有视频功能?{flags & obs.OBS_SOURCE_VIDEO == obs.OBS_SOURCE_VIDEO}')
obs.script_log(obs.LOG_INFO, f'Video 具有音频功能?{flags & obs.OBS_SOURCE_AUDIO == obs.OBS_SOURCE_AUDIO}')
obs.obs_source_release(video)
[sources.py] Video 具有视频功能?True
[sources.py] Video 具有音频功能?True
使用 Python 脚本获取 OBS 来源类型的显示名称
obspython
模块的obs_source_get_display_name
函数,可用于获取指定 OBS 来源类型对应的显示名称,该函数的返回值由当前 OBS 的语言来确定。
obs_source_get_display_name(id)
- id 参数
id
参数为某个来源类型标识符,比如text_gdiplus
,这将使obs_source_get_display_name
函数返回字符串'文字 (GDI+)'
,如果 OBS 语言为中文的话。