在计时器回调中调用 set_current_scene 函数时,OBS 崩溃(Python 脚本)

问题描述 投票:0回答:2
scenes = obs.obs_frontend_get_scenes()
def script_load(settings):
    obs.obs_frontend_add_event_callback(onevent)

def script_update(settings):
    global trigger, s_minutes, s_seconds, ending, e_minutes, e_seconds
    trigger = obs.obs_data_get_string(settings, "e_trigger scene")
    s_minutes = obs.obs_data_get_int(settings, "s_minutes")
    s_seconds = obs.obs_data_get_int(settings, "s_seconds")
    e_minutes = obs.obs_data_get_int(settings, "e_minutes")
    e_seconds = obs.obs_data_get_int(settings, "e_seconds")
    ending = obs.obs_data_get_string(settings, "s_ending scene")

def timer_callback():
    global tElapsed
    if state == 0:
        print("Error: State = 0")
        obs.remove_current_callback()
    if state == 1:
        tElapsed += 1
        print(tElapsed)
        if tElapsed == timer:
            tElapsed = 0
            set_scene()
            obs.remove_current_callback()
    if state == 2:
        tElapsed += 1
        print(tElapsed)
        if tElapsed == timer:
            tElapsed = 0
            obs.obs_frontend_streaming_stop()
            obs.remove_current_callback()

def set_scene():
    index = (obs.obs_frontend_get_scene_names()).index(ending)
    scene = scenes[index]
    obs.obs_frontend_set_current_scene(scene)

def onevent(event):
    global state, timer
    if event==obs.OBS_FRONTEND_EVENT_STREAMING_STOPPED:
        state = 0
    if event==obs.OBS_FRONTEND_EVENT_STREAMING_STARTED:
        state = 1
        timer = s_minutes * 60 + s_seconds
        obs.timer_add(timer_callback,1000)
    if event==obs.OBS_FRONTEND_EVENT_SCENE_CHANGED:
        if obs.obs_source_get_name(obs.obs_frontend_get_current_scene()) == trigger:
           state = 2
           timer = e_minutes * 60 + e_seconds
           obs.timer_add(timer_callback,1000)
        else:
            obs.timer_remove(timer_callback)
            if state == 1:
                print("Start timer stopped")
            elif state == 2:
                print("End timer stopped")

当我尝试从计时器回调函数中设置场景时,OBS 最终崩溃了。我尝试在每次调用回调函数时打印数字,当我查看日志时,它显示了它应该调用的每个打印函数,但它没有告诉我OBS崩溃的原因。

这是我使用辅助函数来设置场景的代码。无论有没有辅助函数,它都会崩溃。但是,当我从计时器外部设置场景时,一切正常。

感谢任何形式的帮助!

python scripting obs obs-studio
2个回答
1
投票

我已经有一段时间没有编写这个脚本了,但我已经设法解决了这个问题,所以我会尽力回忆一下我是如何解决它的。

分辨率

看来只有当 3 个函数(

obs_frontend_add_event_callback()
timer_add()
obs_frontend_set_current_scene()
)的组合出现时才会发生崩溃,因此我没有使用前端事件回调,而是使用了信号处理程序。

我首先获取当前场景并获取该场景的信号处理程序。之后,我连接了一个回调函数,该函数在信号处理程序发送“停用”信号时运行。从那里我添加了计时器回调,当计时器达到 0 时切换场景。这阻止了崩溃的发生。我的代码供参考:

current_scene = obs.obs_frontend_get_current_scene()
current_handler = obs.obs_source_get_signal_handler(current_scene)
obs.obs_source_release(current_scene)

obs.signal_handler_connect(current_handler, "deactivate", checker)
timer = s_minutes * 60 + s_seconds
obs.timer_add(timer_callback, 1000)

备注:

  • 出于某种原因,即使在另一个脚本中使用

    obs_frontend_add_event_callback()
    ,在
    obs_frontend_set_current_scene()
    中使用
    timer_add()
    仍然会导致崩溃。我的结论是应该避免
    obs_frontend_add_event_callback()

  • 我切换到在

    script_load()
    中附加流信号处理程序,以在流启动时发出信号。但是,信号处理程序仅从 OBS 实例的第二个流开始调用回调函数。此时我们必须使用前端事件回调。因此,我的步骤是在脚本加载时添加前端事件回调,并使用回调函数删除前端事件回调立即,并将其替换为信号处理程序,而不是用于同一实例上的未来流。

def script_load(settings):
    obs.obs_frontend_add_event_callback(onevent)

def onevent(event):
    global output
    if event == obs.OBS_FRONTEND_EVENT_STREAMING_STARTED:
        stream = obs.obs_frontend_get_streaming_output()
        output = obs.obs_output_get_signal_handler(stream)
        obs.signal_handler_connect_global(output, frontevent)
        obs.obs_output_release(stream)
        obs.obs_frontend_remove_event_callback(onevent)
  • 我在信号处理程序方面遇到的另一个问题:当切换工作室模式时,当前源的信号处理程序将发出“停用”信号,我不确定如何解决。当然欢迎提出建议。

参考资料:


0
投票

这可能有点晚了,我对 OBS 编程还比较陌生,但我注意到你的代码使用了“

obs_frontend_get_current_scene()
”。有一些调用,包括这个调用,每当调用它们时都会创建指针。这些指针必须被释放,否则它们会继续消耗越来越多的资源。

根据API文档(https://obsproject.com/docs/reference-frontend-api.html?highlight=obs_frontend_get_current_scene),调用时会创建一个新的引用。尽管从该文档条目中看不出来,但可以使用“

obs.obs_source_release(<sourcename>)
”发布引用,因为
obs_frontend_get_current_scene()
返回源。

我不知道是否像您所做的那样在内联使用时创建引用(不将其分配给变量),但这可能是问题所在。尝试将

obs_frontend_get_current_scene()
分配给变量,在
obs_source_get_name(<source name>)
调用中使用该变量,然后“释放”该变量。像这样的东西:

scene_as_source = obs.obs_frontend_get_current_scene()
if obs.obs_source_get_name(scene_as_source) == trigger:
   state = 2
   timer = e_minutes * 60 + e_seconds
   obs.timer_add(timer_callback,1000)
else:
    obs.timer_remove(timer_callback)
    if state == 1:
        print("Start timer stopped")
    elif state == 2:
        print("End timer stopped")
obs.obs_source_release(scene_as_source)
© www.soinside.com 2019 - 2024. All rights reserved.