如何使用 Python 脚本操作 OBS 来源?OBS 来源对象介绍

我被代码海扁署名-非商业-禁演绎
阅读 25:30·字数 7652·发布 
Bilibili 空间
关注 960

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_createobs_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_createobs_source_create_private函数创建的 OBS 来源对象,需要通过obs_source_release释放引用,否则 OBS 可能会出现错误。

我们尝试在按钮的回调函数test中,创建一个私有文本(GDI+)来源,并通过 OBS 数据设置对象对来源进行设置,最后将文本(GDI+)作为场景项添加到场景Scene中,假设Scene存在。这里涉及到与场景相关的函数,但由于篇幅限制,不再进行说明。

sources.py
# 导入模块 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 窗口中。

sources.py
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_nameobs_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_settingsobs_source_get_private_settingsobs_get_source_defaults函数获取的 OBS 来源设置对象,需要通过obs_data_release释放引用,否则 OBS 可能会出现错误。

调整之前的代码,我们通过obs_source_get_settingsobs_source_update函数,更新了Welcome来源的文本。

sources.py
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_widthobs_source_get_height函数,可用于获取 OBS 来源的原始宽度和高度,这并不会将转场特效计算在内,因此obs_source_get_widthobs_source_get_height函数所返回的并非来源对应场景项的实际显示大小。

obs_source_get_width(source)
obs_source_get_height(source)

source 参数

source参数为需要获取原始宽度或高度的 OBS 来源对象。

sources.py
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_enabledobs_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_showingobs_source_dec_showing函数进行干预。

obs_source_showing(source)

source 参数

source参数为需要判断是否可见的 OBS 来源对象。

obspython模块的obs_source_inc_showingobs_source_dec_showing函数,可增加或减少 OBS 来源的可见计数,这将最终影响obs_source_showing的返回结果。需要说明的是,虽然可通过obs_source_inc_showingobs_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_nameobs_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

sources.py
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

sources.py
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_idobs_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 来源对象。

sources.py
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包含该来源。

sources.py
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_createobs_source_create_privateobs_source_duplicateobs_get_source_by_nameobs_get_source_by_uuidobs_source_get_filter_by_nameobs_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_flagsobs_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的输出标志,并判断其是否具有视频和音频功能。

sources.py
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 语言为中文的话。

内容分类

源码

sources.py·codebeatme/obs-python-scripting·GitHub